安卓上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 点对点通话。

相关推荐
踢球的打工仔21 小时前
PHP面向对象(7)
android·开发语言·php
安卓理事人21 小时前
安卓socket
android
安卓理事人1 天前
安卓LinkedBlockingQueue消息队列
android
万能的小裴同学1 天前
Android M3U8视频播放器
android·音视频
q***57741 天前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober1 天前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
城东米粉儿1 天前
关于ObjectAnimator
android
zhangphil1 天前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我1 天前
从头写一个自己的app
android·前端·flutter
lichong9511 天前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端