Video streaming on iOS via RTMP

Intro

Recently I got an interesting task to work, to make an application for video streaming, this is for a startup ShopStory (ecomm live streaming). The first version of the application was implemented using the Open Source library for RTMP streaming HaishinKit . And the second version is on Larix SDK . In this article, I will analyze what problems arose in the process.





Requirements

 ShopStory.live - B2B live e-commerce, , . , , , , . ShopStory.live  , , beauty- live commerce .





ShopStory, LarixBroadcaster , Android iOS. :





  1. , , , LarixBroadcaster



    , . , , , .





  2. , , .





  3. .





  4. , (, , ).





:









  • ( , )





  • ABR - Adaptive BitRate ( )





  • , fps, ..





  • .





โ€“ . Larix SDK



โ€“ , .

, :





  • LFLiveKit โ€“ 4.2k , 2016. 115 issue, .





  • HaishinKit โ€“ 2.1k , 7 . 11 issues.





  • VideoCore โ€“ 1.5k , 2015. .





  • KSY Live iOS SDK โ€“ 0.8k , 22 2020. README .





HaishinKit. , , .





HaishinKit

, . . /, . AVCaptureSession, AVCaptureDevice, AVCaptureDeviceInput



. View



, attach



RTMPStream







:





protocol BroadcastService: AnyObject {
    func connect()
    func publish()
    func stop()
}
      
      



.





class HaishinBroadcastService: BroadcastService {}
      
      



ABR - Adaptive BitRate

, , ().





ABR, issue. RTMPStreamDelegate



.





extension HaishinBroadcastService: RTMPStreamDelegate {
    func rtmpStream(_ stream: RTMPStream, didPublishInsufficientBW connection: RTMPConnection) {
        guard self.config.adaptiveBitrate else { return }
        guard let bitrate = self.currentBitrate else {
            assertionFailure()
            return
        }
        let newBitrate = max(UInt32(Double(bitrate) * Constants.bitrateDown), Constants.minBitrate)
        self.rtmpStream.videoSettings[.bitrate] = newBitrate
    }

    func rtmpStream(_ stream: RTMPStream, didPublishSufficientBW connection: RTMPConnection) {
        guard self.config.adaptiveBitrate else { return }
        guard let currentBitrate = self.currentBitrate,
              currentBitrate < Constants.maxBitrate else {
            return
        }
        guard self.bitrateRetryCounter >= Constants.retrySecBeforeUpBitrate else {
            self.bitrateRetryCounter += 1
            return
        }

        self.bitrateRetryCounter = 0
        let newBitrate = min(Constants.maxBitrate, UInt32(Double(currentBitrate) * Constants.bitrateUp))
        if newBitrate == currentBitrate { return }

        self.rtmpStream.videoSettings[.bitrate] = newBitrate
    }
}

private struct Constants {
    static let bitrateDown: Double = 0.75
    static let bitrateUp: Double = 1.15
    static let retrySecBeforeUpBitrate = 20
}
      
      



issue โ€“ ( 2 ), . didPublishInsufficientBW



, .





:





  • , 0.75





  • , 20 ( ), 1.15





Live update resolution

, , . RTMP . VK Live . Instagram , rtmp , , , ( , ). ShopStory .





. Wi-Fi, LTE. Larix SDK



. LarixBroadcaster โ€“ .





Larix SDK

LarixBroadcaster



+ LarixDemo ( ), , StepByStepGuide.





:





  • ,





  • .





:









  • , - LarixBroadcaster



    ( , : over 2000 )









  • connect



    publish







-

โ€ฆ , LarixBroadcaster



ViewController



2100 , Streamer



1100 . SDK. โ€ฆ , . @Aquary ( ):





ยซ " ". โ€” - . , . โ€” . , , .. , .ยป





, SDK . , . c HaishinKit



, .. ( HaishinKit



).





ABR, ( ), , . . LarixBroadcaster



3 StreamConditionerMode1, 2, 3,



. ABR? ABR ( ).





, . , status = disconnected



. , .





func connectionStateDidChangeId(_ connectionID: Int32, state: ConnectionState, status: ConnectionStatus, info: [AnyHashable: Any]) {}
      
      



Larix



.

: SDK StreamerEngineProxy



bytesSent



bytesDelivered



, , . , , .





Connect Publish

RTMP, publish



connect



, Larix



( ), . - BroadcastService



.





?





  • , , , , , .





  • . , publish



    , , , , ( ). publish



    ( ). .





. , .





The choice of a free library for streaming on iOS is not very large and in fact it all comes down to one option - HaishinKit



. It has an undoubted advantage - open source, and if Larix



we fail to align graphics and increase stability, we will dive into open source and look for places that can be improved.





Buying a paid SDK - do not expect that it will solve all your problems, perhaps you will have more of them (learn vc over 2000 lines).





And some more global conclusions can be made only after we run the assembly on a larger number of streams.








All Articles