移动端WebRTC开发:从零到一

说实话,移动端WebRTC开发是我个人觉得最有意思的部分。你想想看,把实时音视频能力塞进手机里,让用户随时随地都能视频通话——这本身就是件很酷的事。我在做第一个移动端项目时,踩了不少坑,今天把这些经验整理出来,希望能帮你少走弯路。

Android平台集成:Java与Kotlin

Android端的WebRTC集成,说白了就是两件事:一是把WebRTC库引进来,二是把原生API封装好。我个人习惯用Kotlin,但Java也完全没问题,核心逻辑是一样的。

第一步:添加依赖

在build.gradle里加上WebRTC的Maven依赖。注意版本号,我建议用最新的稳定版。

dependencies {
    implementation 'org.webrtc:google-webrtc:1.0.32006'
}
注意: 不同版本的WebRTC API可能有细微差异。我曾经因为版本不匹配,折腾了一整天才发现是接口变了。

第二步:初始化PeerConnectionFactory

这是WebRTC的核心工厂类。所有连接、媒体流都从这里创建。

// Kotlin版本
val initializationOptions = PeerConnectionFactory.InitializationOptions.builder(context)
    .setFieldTrials("")
    .createInitializationOptions()
PeerConnectionFactory.initialize(initializationOptions)

val factory = PeerConnectionFactory.builder()
    .setVideoDecoderFactory(DefaultVideoDecoderFactory(rootEglBase.eglBaseContext))
    .setVideoEncoderFactory(DefaultVideoEncoderFactory(rootEglBase.eglBaseContext, true, true))
    .createPeerConnectionFactory()

嗯,这里要注意:rootEglBase 需要提前创建,它负责OpenGL的上下文管理。我刚开始做的时候忘了这步,结果画面死活出不来。

第三步:创建本地媒体流

音频和视频的采集,WebRTC已经封装好了。你只需要配置好约束条件。

val mediaConstraints = MediaConstraints().apply {
    mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"))
    mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"))
}

val audioSource = factory.createAudioSource(MediaConstraints())
val audioTrack = factory.createAudioTrack("audio_track", audioSource)

val videoSource = factory.createVideoSource(false)
val surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", rootEglBase.eglBaseContext)
val videoCapturer = Camera2Enumerator(context).run {
    deviceNames.firstOrNull { isFrontFacing(it) }?.let { createCapturer(it, null) }
}
videoCapturer?.initialize(surfaceTextureHelper, context, videoSource.capturerObserver)
videoCapturer?.startCapture(1280, 720, 30)
小技巧: 分辨率别设太高。720p在大多数手机上已经够用,1080p反而会增加编码压力。我在项目中实测过,720p和1080p在手机小屏幕上几乎看不出区别。

iOS平台集成:Swift与OC

iOS端的集成思路和Android类似,但API风格更Swift化。我个人更喜欢用Swift,代码更简洁。

引入WebRTC框架

推荐用CocoaPods或Swift Package Manager。我用的是SPM,省事。

// Package.swift 或直接在Xcode中添加
// https://github.com/stasel/WebRTC

创建PeerConnectionFactory

// Swift版本
let factory = RTCPeerConnectionFactory(
    encoderFactory: RTCDefaultVideoEncoderFactory(),
    decoderFactory: RTCDefaultVideoDecoderFactory()
)

// 配置媒体约束
let mediaConstraints = RTCMediaConstraints(
    mandatoryConstraints: [
        "OfferToReceiveAudio": "true",
        "OfferToReceiveVideo": "true"
    ],
    optionalConstraints: nil
)

这里有个坑:iOS的摄像头权限需要提前申请。我记得第一次跑demo时,直接crash了,就是因为忘了在Info.plist里加摄像头权限描述。

视频渲染

iOS端用RTCMTLVideoView来渲染视频,性能比OpenGL好很多。

let videoView = RTCMTLVideoView(frame: view.bounds)
videoView.videoContentMode = .scaleAspectFill
view.addSubview(videoView)

// 将视频轨道绑定到渲染器
videoTrack.add(videoView)
核心要点: 移动端WebRTC的集成流程可以概括为:初始化工厂 → 创建媒体源 → 建立连接 → 交换SDP → 传输媒体流。无论Android还是iOS,这个骨架是不变的。

移动端适配与性能优化

说实话,集成只是第一步。真正考验人的是性能优化。我经历过视频卡顿、声音延迟、CPU过热……这些坑,今天一次性说清楚。

硬件编码器 vs 软件编码器

对比项 硬件编码 软件编码
性能 低功耗,高帧率 CPU占用高,发热
画质 中等 较高
兼容性 依赖芯片 通用
推荐场景 实时通话 录屏、直播

我的建议是:实时通话用硬件编码,省电又流畅。录屏或直播场景可以用软件编码,画质更好。

网络自适应

移动网络不稳定,WebRTC内置了拥塞控制算法。但你也可以手动调整一些参数。

// 设置比特率范围
val constraints = MediaConstraints()
constraints.mandatory.add(MediaConstraints.KeyValuePair(
    "googMinBitrate", "100000"))  // 100kbps
constraints.mandatory.add(MediaConstraints.KeyValuePair(
    "googMaxBitrate", "2000000")) // 2Mbps
避坑指南: 我曾经把最小比特率设得太高,结果弱网环境下直接断连。建议最小比特率设在100-200kbps,最大不超过2Mbps。

渲染优化

移动端屏幕小,但渲染开销不小。我建议:

  • 使用SurfaceView(Android)或RTCMTLVideoView(iOS),避免CPU参与渲染
  • 帧率控制在24-30fps,别追求60fps——手机屏幕刷新率有限
  • 分辨率动态调整:强网用720p,弱网降到480p甚至360p

Native与Web互通

这是移动端WebRTC的终极目标:让手机App和浏览器能视频通话。核心就是信令和SDP交换。

信令协议设计

我推荐用JSON格式,简单通用。Web端和Native端都容易解析。

// 信令消息示例
{
  "type": "offer",
  "sdp": "v=0\r\no=- ...",
  "from": "user_android",
  "to": "user_web"
}

SDP协商注意事项

Web端和Native端的SDP格式略有不同。我遇到过最典型的问题是:

  • Web端生成的offer里包含a=ice-options:trickle,Native端需要支持
  • Native端可能缺少某些codec,需要手动添加
// 手动添加H.264支持(Android)
val sdpMediaConstraints = MediaConstraints()
sdpMediaConstraints.mandatory.add(
    MediaConstraints.KeyValuePair("googUseRtpMp4aAac", "true"))
经验之谈: 如果你发现Native和Web连不上,先检查SDP里的codec列表。我遇到过Web端只支持VP8,而Native端只支持H.264的情况——两边都加上VP8和H.264就解决了。

知识体系总览

下面这张图概括了移动端WebRTC开发的核心脉络。你可以把它当作一个检查清单。

移动端WebRTC开发知识体系 Android集成 Java / Kotlin iOS集成 Swift / OC 互通与优化 Native ↔ Web PeerConnectionFactory 媒体流创建 SDP交换 RTCPeerConnectionFactory 视频渲染 (MTLVideoView) 音频采集 信令协议设计 Codec兼容性 网络自适应 核心原则:统一信令协议 + 动态码率适配 + 硬件加速渲染 无论平台如何变化,这三条是移动端WebRTC的基石

移动端WebRTC开发,说白了就是「平台适配 + 性能调优 + 协议统一」。Android和iOS的API虽然不同,但底层逻辑完全一样。你只要掌握了信令交换和媒体流管理,剩下的就是熟悉各平台的特性了。

最后说一句: 别怕踩坑。我刚开始做移动端WebRTC时,光SDP协商就折腾了两周。但一旦跑通了第一个视频通话,那种成就感是无可替代的。保持耐心,多调试,你一定能搞定。
公众号:蓝海资料掘金营,微信deep3321