Intro
Recientemente tuve una tarea interesante para trabajar, hacer una aplicación para video streaming, esto es para una startup ShopStory (ecomm live streaming). La primera versión de la aplicación se implementó utilizando la biblioteca de código abierto para la transmisión de RTMP HaishinKit . Y la segunda versión está en Larix SDK . En este artículo analizaré qué problemas surgieron en el proceso.
Requisitos
ShopStory.live - B2B live e-commerce, , . , , , , . ShopStory.live , , beauty- live commerce .
ShopStory, LarixBroadcaster , Android iOS. :
, , ,
LarixBroadcaster
, . , , , .
, , .
.
, (, , ).
:
( , )
ABR - Adaptive BitRate ( )
, fps, ..
.
– . Larix SDK
– , .
, :
LFLiveKit – 4.2k , 2016. 115 issue, .
HaishinKit – 2.1k , 7 . 11 issues.
-
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
( ). .
. , .
La elección de una biblioteca libre para streaming en iOS no es muy grande y, de hecho, todo se reduce a una opción - HaishinKit
. Tiene una ventaja indudable: el código abierto, y si Larix
no logramos alinear los gráficos y aumentar la estabilidad, nos sumergiremos en el código abierto y buscaremos lugares que se puedan mejorar.
Comprar un SDK de pago: no espere que resuelva todos sus problemas, tal vez tenga más de ellos (aprenda vc en 2000 líneas).
Y se pueden sacar algunas conclusiones más globales solo después de ejecutar el ensamblaje en un mayor número de flujos.