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

相关推荐
启雀AI10 小时前
培训平台移动端离线学习方案设计与实现:视频缓存、断点续传与进度同步的工程实践
android·学习·缓存·音视频·企业lms
我命由我1234511 小时前
RxJava - 冷数据流与热数据流
android·java·java-ee·android studio·rxjava·android-studio·android runtime
2601_9665635213 小时前
愤怒的小鸟单机版 去广告 安卓+PC端离线纯净版 益智耐玩小游戏 不需联网 老旧手机都可以玩 怀旧手机小游戏
android·智能手机
hunterandroid13 小时前
[Android 从零到一] Retrofit 请求取消与生命周期绑定:从 Call.cancel 到协程可取消设计
android
爱跑马的程序员13 小时前
安卓专有的通信子系统-Binder IPC
android·binder·ipc·安卓间通信机制
ue星空14 小时前
【安卓逆向】为什么用Frida?
android
小驰行动派14 小时前
Camx架构全景图:从V4L2到Pipeline的完整拆解
android·camera·android camera
hunterandroid15 小时前
[Android 从零到一] Custom View 触摸反馈与手势冲突解决
android
coderSong256816 小时前
Android | 四大组件之 BroadcastReceiver(广播接收器)
android
爱笑鱼19 小时前
Android 系统启动机制(二):init.rc 不是普通脚本,service、action 和 property 怎样驱动启动?
android