安卓上WebRtc

在 Android 上使用 WebRTC,可分为「官方 SDK」和「自己编译源码」两条路线。

多数业务场景直接依赖官方发布的 AAR 即可,下面给出一套从 0 到 1 的落地步骤(基于官方 AAR)。


一、准备工作

  1. Android Studio ≥ 4.0
  2. minSdkVersion ≥ 21(建议 23+)
  3. 真机或模拟器(模拟器需支持 Camera2)

二、在工程里引入 WebRTC

app/build.gradle

java 复制代码
implementation 'org.webrtc:google-webrtc:1.0.32006'   // 官方最新稳定版
implementation 'org.java-websocket:Java-WebSocket:1.5.3' // 仅示例,用 WebSocket 做信令

三、Manifest 权限与特性

xml 复制代码
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

<uses-feature android:name="android.hardware.camera" android:required="true"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>

动态权限申请代码略(可用 EasyPermissions / RxPermission)。


四、初始化 WebRTC(一次性在 Application 或 Activity 中做)

java 复制代码
PeerConnectionFactory.InitializationOptions init =
        PeerConnectionFactory.InitializationOptions.builder(context)
                .setEnableInternalTracer(true)
                .setFieldTrials("WebRTC-H264HighProfile/Enabled/")
                .createInitializationOptions();
PeerConnectionFactory.initialize(init);

五、创建 PeerConnectionFactory

java 复制代码
// EGL 上下文,用于硬件加速编解码 & 渲染
EglBase rootEgl = EglBase.create();

// 视频编解码工厂
VideoEncoderFactory encoderFactory =
        new DefaultVideoEncoderFactory(rootEgl.getEglBaseContext(), true, true);
VideoDecoderFactory decoderFactory =
        new DefaultVideoDecoderFactory(rootEgl.getEglBaseContext());

// 音频模块
AudioDeviceModule adm = JavaAudioDeviceModule.builder(context).createAudioDeviceModule();

PeerConnectionFactory factory = PeerConnectionFactory.builder()
        .setAudioDeviceModule(adm)
        .setVideoEncoderFactory(encoderFactory)
        .setVideoDecoderFactory(decoderFactory)
        .setOptions(new PeerConnectionFactory.Options()) // 可关闭加密/网络监控
        .createPeerConnectionFactory();

六、采集本地音视频

  1. 视频源
java 复制代码
SurfaceTextureHelper surfaceHelper =
        SurfaceTextureHelper.create("CaptureThread", rootEgl.getEglBaseContext());

CameraEnumerator enumerator = new Camera1Enumerator(true);  // Camera2Enumerator 亦可
String camName = enumerator.getDeviceNames()[0];            // 默认后置
VideoCapturer capturer = enumerator.createCapturer(camName, null);

VideoSource videoSource = factory.createVideoSource(capturer.isScreencast());
capturer.initialize(surfaceHelper, context, videoSource.getCapturerObserver());
capturer.startCapture(1280, 720, 30);

VideoTrack localVideoTrack = factory.createVideoTrack("ARDAMSv0", videoSource);
  1. 音频源
java 复制代码
AudioSource audioSource = factory.createAudioSource(new MediaConstraints());
AudioTrack localAudioTrack = factory.createAudioTrack("ARDAMSa0", audioSource);

七、本地渲染(SurfaceViewRenderer)

xml 复制代码
<org.webrtc.SurfaceViewRenderer
    android:id="@+id/localRenderer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
java 复制代码
SurfaceViewRenderer localRenderer = findViewById(R.id.localRenderer);
localRenderer.init(rootEgl.getEglBaseContext(), null);
localVideoTrack.addSink(localRenderer);

八、创建 PeerConnection & 信令交换

  1. 配置 ICE 服务器
java 复制代码
List<PeerConnection.IceServer> iceServers = new ArrayList<>();
iceServers.add(PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer());
// 有 TURN 账号也可加
  1. 创建 PeerConnection
java 复制代码
PeerConnection.RTCConfiguration rtcConfig = new PeerConnection.RTCConfiguration(iceServers);
PeerConnection pc = factory.createPeerConnection(rtcConfig, new PeerConnectionObserver() {
    @Override public void onIceCandidate(IceCandidate iceCandidate) {
        // 通过信令通道发送给对方
        sendIceCandidateToRemote(iceCandidate);
    }
    @Override public void onAddTrack(RtpReceiver rtpReceiver, MediaStream[] mediaStreams) {
        VideoTrack remoteVideoTrack = (VideoTrack) mediaStreams[0].videoTracks.get(0);
        remoteVideoTrack.addSink(remoteRenderer); // 远端渲染
    }
});
// 把本地轨道加入
pc.addTrack(localVideoTrack, Collections.singletonList("ARDAMS"));
pc.addTrack(localAudioTrack, Collections.singletonList("ARDAMS"));
  1. 信令流程(伪代码)
  • 收到 room 中新成员通知 → createOffer → setLocalDescription → 发送 Offer
  • 收到 Answer → setRemoteDescription
  • 收到 ICE candidate → addIceCandidate

信令通道可用 WebSocket、Socket.IO、FCM 任意实现。


九、远端渲染

与本地渲染完全一样,再准备一个 SurfaceViewRenderer 即可。


十、释放资源

java 复制代码
capturer.stopCapture();
capturer.dispose();
pc.close();
factory.dispose();
rootEgl.release();

十一、常见坑排查

现象 可能原因
黑屏 未调用 startCapture/addSink,或 EGL 线程冲突
听不到声音 未动态申请 RECORD_AUDIO,或 AudioTrack 未 addTrack
连不上 防火墙拦截 UDP,需要 TURN
崩溃 so not found 64 位 so 未打入,检查 Gradle abiFilters

十二、进阶方向

  • 多人会议:SFU(Janus/mediasoup)
  • 数据通道:DataChannel 传文件 / 白板
  • 编译源码:定制编解码器、裁剪包大小
  • 性能调优:硬件编解码、带宽估计、抖动缓冲

至此,即可在 Android 上完成一次完整的 WebRTC 点对点通话。

相关推荐
青莲8433 小时前
内联函数 inline noinline crossinline reified
android
wayne2143 小时前
从 MVC 到 MVI:Android 架构演进全景剖析与示例代码
android
我又来搬代码了5 小时前
【Android】【bug】Json解析错误Expected BEGIN_OBJECT but was STRING...
android·json·bug
CANI_PLUS14 小时前
ESP32将DHT11温湿度传感器采集的数据上传到XAMPP的MySQL数据库
android·数据库·mysql
来来走走15 小时前
Flutter SharedPreferences存储数据基本使用
android·flutter
安卓开发者16 小时前
Android模块化架构深度解析:从设计到实践
android·架构
雨白17 小时前
HTTP协议详解(二):深入理解Header与Body
android·http
阿豪元代码17 小时前
深入理解 SurfaceFlinger —— 如何调试 SurfaceFlinger
android
阿豪元代码17 小时前
深入理解 SurfaceFlinger —— 概述
android