
MediaMTX 移动端流媒体播放WebRTC 与 LL-HLS 双路线的选型、配置与排障【免费下载链接】mediamtxReady-to-use Media-over-QUIC / SRT / WebRTC / RTSP / RTMP / LL-HLS / MPEG-TS / RTP live media server and media proxy that allows to read, publish, proxy, record and playback real-time video and audio streams.项目地址: https://gitcode.com/GitHub_Trending/me/mediamtxMediaMTX 是一个开源的实时流媒体服务器内置 WebRTCWHEP与 HLS 读取端点能把同一路流同时分发给 iOS 与 Android 客户端。本文面向在移动应用里接入它的开发者覆盖移动端流媒体播放的两条路线WebRTC 低延迟直播与 HLS 大规模分发按「选型 → 服务端配置 → 客户端代码 → 排障」的顺序给出最小可运行方案。协议选型一张表决定走 WebRTC 还是 HLS先按场景做决定再写代码。维度WebRTCWHEPHLSmpegts 变体LL-HLS端到端延迟亚秒级首帧约 0.5s5~10s1~3s并发规模受服务器限制每个观众一条 peer connection可经 CDN 扩展观众数不设限同 HLS分片请求频率更高安全DTLS-SRTP 强制加密握手可叠加 HTTPS明文或 HTTPS 可选建议 HTTPSApple 设备要求 HTTPS设备要求需引入 WebRTC SDK且媒体端口对客户端可达系统播放器直接支持无需 SDK系统播放器可播低版本系统按普通 HLS 的延迟表现选择标准一对一查看、实时互动、延迟敏感的场景走 WebRTC观众量大、需要 CDN 或只需分钟级时效的场景走 HLS其中追求秒级延迟时选 LL-HLS。服务端准备MediaMTX 最小可用配置先让路径里有流用任意客户端如 FFmpeg 推 RTSP 到rtsp://服务器:8554/mystream发布到某路径移动端之后读取同一路径即可。开启 WebRTCWHEP读取在mediamtx.yml中# mediamtx.yml webrtc: true # 开启 WebRTC 服务含 WHEP 读取端点 webrtcAddress: :8889 # WHEP 握手与网页播放的 HTTP 端口 webrtcEncryption: false # 握手层是否走 HTTPS媒体流本身始终有 DTLS 加密 webrtcLocalUDPAddress: :8189 # ICE 媒体通道 UDP 端口客户端必须能直连 webrtcAdditionalHosts: [192.168.1.100] # 下发给客户端的服务器可达地址跨 NAT/容器场景必填 webrtcHandshakeTimeout: 10s # 握手等待上限超时即断开WHEP 端点固定为http://服务器:8889/路径/whep客户端向它 POST 一个 SDP offer服务器返回 answer。连接通不通八成取决于webrtcAdditionalHosts和 UDP 端口放行细节见 WebRTC 连接问题文档。开启 HLS 读取含 LL-HLS# mediamtx.yml hls: true # 开启 HLS 服务 hlsAddress: :8888 # HTTP 端口播放入口为 http://服务器:8888/路径/index.m3u8 hlsEncryption: true # 启用 HTTPSApple 设备上 LL-HLS 要求 HTTPS hlsServerKey: server.key # 证书私钥路径 hlsServerCert: server.crt # 证书文件路径 hlsVariant: lowLatency # 三选一mpegts / fmp4 / lowLatency hlsPartDuration: 200ms # LL-HLS 分片时长直接决定延迟下限 hlsSegmentDuration: 1s # 完整分段时长决定播放器缓冲粒度 hlsSegmentCount: 7 # 保留分段数只影响可回看长度不影响延迟完整参数列表见 配置文件参考。实时场景落地iOS/Android 端 WHEP 最小接入代码两端的流程一致创建 PeerConnection → 生成 offer → POST 到 WHEP 端点 → 用响应里的 answer 设置远端描述 → 在 track 到达回调中渲染。iOS 端 WHEP 最小接入代码依赖 GoogleWebRTCCocoaPods 引入GoogleWebRTC核心如下import WebRTC final class WHEPPlayer: NSObject { private let pc RTCPeerConnectionFactory() .peerConnection(with: RTCConfiguration(), constraints: nil, delegate: nil) func connect(_ whepUrl: String) { pc.offer(for: RTCMediaConstraints()) { [weak self] offer, _ in guard let offer else { return } self?.pc.setLocalDescription(offer) { _ in self?.post(offer.sdp, to: whepUrl) // 关键一步POST offer } } } private func post(_ sdp: String, to url: String) { var req URLRequest(url: URL(string: url)!) req.httpMethod POST req.setValue(application/sdp, forHTTPHeaderField: Content-Type) req.httpBody sdp.data(using: .utf8) URLSession.shared.dataTask(with: req) { data, _, _ in guard let sdp data.flatMap({ String(data: $0, encoding: .utf8) }) else { return } // 响应 body 即 answer设置后媒体流开始到达 self.pc.setRemoteDescription(RTCSessionDescription(type: .answer, sdp: sdp)) { _ in } }.resume() } }出画面在RTCPeerConnectionDelegate的 track 到达回调中把videoTrack加到RTCMTLVideoView上即可其余样板代码从略。Android 端 WHEP 最小接入代码依赖org.webrtc:google-webrtc核心如下class WHEPPlayer(private val surface: SurfaceViewRenderer) { private val pc PeerConnectionFactory().createPeerConnection(RTCConfiguration(), observer) // observer 的 onAddTrack 回调里track?.addSink(surface) fun connect(whepUrl: String) { val c MediaConstraints().apply { mandatory[OfferToReceiveVideo] true mandatory[OfferToReceiveAudio] true } pc.createOffer(object : SdpObserver { override fun onCreateSuccess(sdp: SessionDescription) { pc.setLocalDescription(localCb, sdp) postOffer(sdp.description, whepUrl) // 成功后再执行 post } override fun onCreateFailure(e: String) {} override fun onSetSuccess() {} override fun onSetFailure(e: String) {} }, c) } // postOfferPOST application/sdp 到 whepUrl响应 body 为 answer // pc.setRemoteDescription(answer) 后媒体流触发 onAddTrack }验证连接成功用 curl 向/whep发 POST返回201 Created且响应头Location给出会话地址说明握手成功。客户端 PeerConnection 状态变为connectedtrack 回调开始触发并渲染画面。服务器日志出现该路径的 WebRTC 读取事件说明服务器侧已建链。快速自检浏览器直接打开http://服务器:8889/路径能播放说明端点本身可用问题可聚焦在客户端网络。大规模分发落地LL-HLS 低延迟模式怎么配播放入口是http://服务器:8888/路径/index.m3u8。低延迟模式的取舍很直接hlsPartDuration越小延迟越低但分片请求频率越高对服务器与 CDN 压力越大mpegts变体兼容最旧但延迟停留在 5 秒以上。弱网或需要兼容大量旧设备时退回mpegts其余情况用lowLatency。要横向扩展观众数把分片目录交给 CDN并设置hlsCDNSecret识别 CDN 回源请求。iOS 端 HLS 播放系统 AVPlayer 即可无需额外依赖let url URL(string: https://192.168.1.100:8888/mystream/index.m3u8)! let item AVPlayerItem(url: url) item.preferredForwardBufferDuration 2 // 压缩前向缓冲让播放位置贴近直播边缘 let player AVPlayer(playerItem: item) player.play()Android 端 LL-HLS 低延迟播放ExoPlayer 开启 chunkless preparationplaylist 就绪即可播放不必等完整分段下载val dataSource DefaultHttpDataSource.Factory() .setUserAgent(MTX-Player) .createDataSource() val source HlsMediaSource.Factory(dataSource) .setAllowChunklessPreparation(true) // LL-HLS 关键开关不等整段分段/分片即播 .createMediaSource(MediaItem.fromUri(https://192.168.1.100:8888/mystream/index.m3u8)) exoPlayer.setMediaSource(source) exoPlayer.playWhenReady true exoPlayer.prepare()验证方式curl 该.m3u8能返回含分段列表的 playlistLL-HLS 下还会带#EXT-X-PART行服务器日志出现 HLS 读取事件即链路可用。问题定位连接失败、延迟高、播放卡顿排查表现象可能原因处理动作POST/whep返回 404该路径没有正在发布的流先向同路径发布流或核对路径名与查询参数POST/whep返回 403无 read 权限检查authInternalUsers中对应路径的read权限WHEP 返回 201 但不出画面ICE 不通UDP 8189 未放行或webrtcAdditionalHosts缺少客户端可达地址填对webrtcAdditionalHosts、放行 8189/udp仍不通则启用webrtcLocalTCPAddress或配置 STUN/TURNLL-HLS 延迟高于预期hlsPartDuration/hlsSegmentDuration过大或播放器缓冲过大将 part 降到 200ms 左右调小播放器缓冲iOS 用preferredForwardBufferDurationiOS 上 LL-HLS 没有低延迟效果未启用 HTTPS将hlsEncryption设为 trueLL-HLS 在 Apple 设备上要求 HTTPS播放间歇性卡顿UDP 丢包或服务器出口带宽不足调大udpReadBufferSize或改走 HLS 并由 CDN 分发配合hlsCDNSecret首帧慢关键帧间隔过大在编码端缩短 GOP如-g 30降到-g 15每段需含 IDR 帧WebRTC 连通性的更多排查顺序UDP → TCP → STUN → TURN见 WebRTC 特定特性文档。两种场景的推荐组合实时查看、互动类场景WebRTC/WHEPhlsVariant保持默认即可把精力放在 UDP 端口与webrtcAdditionalHosts上。面向大量观众或需要 CDN 的场景LL-HLShlsVariant: lowLatencyhlsPartDuration: 200ms需要兼容旧设备时退回mpegts。协议与端点的完整说明见 读取流文档、WebRTC 客户端文档 与 HLS 文档。【免费下载链接】mediamtxReady-to-use Media-over-QUIC / SRT / WebRTC / RTSP / RTMP / LL-HLS / MPEG-TS / RTP live media server and media proxy that allows to read, publish, proxy, record and playback real-time video and audio streams.项目地址: https://gitcode.com/GitHub_Trending/me/mediamtx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考