Реалізація RTMP-стримінга з мобільного пристрою
RTMP — протокол 2002 року, придуманий Macromedia для Flash. У 2025 він все ще живе, тому що його приймають YouTube Live, Twitch, Facebook Live, Restream і більшість медіа-серверів. З мобільного пристрою RTMP-стрім запускається через спеціалізовані бібліотеки — нативний iOS/Android це не вміє з коробки.
Чому RTMP, а не щось інше
RTMP використовує TCP, забезпечує надійну доставку даних і працює через більшість корпоративних файрволів (порт 1935). Затримка — 1–3 секунди, що допустимо для стримінга на платформи. Для надзвичайно низької затримки (<500 мс) беруть WebRTC або SRT, але їх не приймають напряму YouTube і Twitch — потрібен re-streamer на стороні сервера.
iOS: HaishinKit
Найкращий Swift-нативний варіант. Без залежності від FFmpeg, апаратне кодування через VideoToolbox.
Мінімальна настройка:
import HaishinKit
let rtmpConnection = RTMPConnection()
let rtmpStream = RTMPStream(connection: rtmpConnection)
rtmpStream.videoSettings = VideoCodecSettings(
videoSize: CGSize(width: 1280, height: 720),
bitRate: 2_000_000,
profileLevel: kVTProfileLevel_H264_High_AutoLevel as String
)
rtmpStream.audioSettings = AudioCodecSettings(bitRate: 128_000)
// Прив'язуємо камеру
let camera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
try rtmpStream.attachCamera(camera)
try rtmpStream.attachAudio(AVCaptureDevice.default(for: .audio))
// Превью
let hkView = MTHKView(frame: previewView.bounds)
hkView.videoGravity = .resizeAspectFill
rtmpStream.addOutput(hkView)
previewView.addSubview(hkView)
// Запуск
rtmpConnection.connect("rtmp://live.example.com/live")
rtmpStream.publish("stream_key")
Переподключення при обриві: підписуємось на RTMPConnection.Event.rtmpStatus, при code == RTMPStatusCode.connectClosed — reconnectDelay(3) і повтор connect(). HaishinKit має вбудований reconnect механізм.
Моніторинг: rtmpStream.info.byteCount і RTMPStream.currentFPS — стежимо за реальним FPS. Якщо падає нижче 20 — сигнал поганого з'єднання.
Android: rtmp-rtsp-stream-client-java
Бібліотека Pedro Vicente. Підтримує Camera1, Camera2, CameraX, Screen capture. Апаратне кодування через MediaCodec.
val rtmpCamera = RtmpCamera2(binding.surfaceView, object : ConnectCheckerRtmp {
override fun onConnectionSuccessRtmp() { /* оновити UI */ }
override fun onConnectionFailedRtmp(reason: String) {
rtmpCamera.stopStream()
retryConnection()
}
override fun onDisconnectRtmp() { retryConnection() }
override fun onAuthErrorRtmp() { /* показати помилку */ }
override fun onAuthSuccessRtmp() {}
override fun onNewBitrateRtmp(bitrate: Long) { updateBitrateUI(bitrate) }
})
// Підготовка (розширення, бітрейт, FPS, аудіо)
rtmpCamera.prepareVideo(1280, 720, 30, 2_000_000) && rtmpCamera.prepareAudio(128_000, 44100, true)
rtmpCamera.startStream("rtmp://live.example.com/live/stream_key")
RtmpCamera2 приймає SurfaceView або TextureView. Для Jetpack Compose: AndroidView { RtmpCamera2(context, ...) }.
Адаптація бітрейту: rtmpCamera.setVideoBitrateOnFly(newBitrate) — міняємо бітрейт без перезапуску стрима.
RTMP аутентифікація
Twitch, YouTube, Facebook вимагають stream key в URL: rtmp://live.twitch.tv/app/{stream_key}. Деякі сервіси використовують RTMP auth: rtmp://user:pass@server/app/stream.
Для YouTube Live додатково потрібен rtmps:// (TLS): HaishinKit підтримує, rtmp-rtsp-stream-client-java — через RtmpsCamera2.
Типічні проблеми
Затримка при старті. Перші секунди стрім нестабільна — SPS/PPS NAL units ще не кешовані на сервері. Рішення: на iOS встановлюємо kVTCompressionPropertyKey_AllowFrameReordering: false — B-frames відключені, затримка знижується.
Відео без звуку у глядачів. Аудіо-потік не ініціалізувався до початку трансляції. Впевнюємось що prepareAudio() викликаний до startStream().
Чорний екран на старті. AVCaptureSession не встигла ініціалізуватися — startStream() викликаний до startPreview(). Порядок важливий: attachCamera → startPreview → rtmpConnection.connect → rtmpStream.publish.
Крах на background. AVCaptureSession потрібно зупинити при applicationDidEnterBackground якщо трансляція не повинна продовжуватися у фоні. Якщо повинна — потрібен UIBackgroundTask і відповідний UIBackgroundModes: audio.
Терміни
Інтеграція RTMP-стримінга на одну платформу з превью, підключенням до конкретного сервера і обробкою помилок підключення — 2–3 робочих дні.







