Android平台WebRTC实时通信Demo项目实战
简介:WebRTC是由Google主导的开源项目,支持浏览器和原生应用间的实时音视频通信。本Android Demo项目提供了完整的WebRTC集成示例,涵盖音视频流传输、PeerConnection初始化、信令交互、媒体设备权限处理等核心功能,帮助开发者快速掌握在Android平台上实现视频通话、语音聊天和数据共享的关键技术。项目通过Gradle依赖集成WebRTC库,包含Activity、Service及媒体处理组件的实际代码,具有较强的参考价值,是学习Android端实时通信开发的理想实践资源。
WebRTC技术全栈解析:从零构建Android实时音视频通信系统
在智能家居设备日益复杂的今天,确保无线连接的稳定性已成为一大设计挑战。而当我们将视角转向更广义的“实时互动”领域——比如远程医疗问诊、在线教育直播、跨洲团队协作会议时,一个更核心的问题浮出水面:如何让两个地理上相隔千里的用户,像面对面交谈一样自然流畅地交流?✨
这正是 WebRTC(Web Real-Time Communication) 技术诞生的初衷。它不是魔法,却近乎奇迹般地实现了浏览器与移动设备之间的点对点音视频通话,无需插件、不依赖中间服务器转发媒体流,一切都在用户端直接完成。
想象一下:你打开手机App,点击“开始视频”,下一秒对方的画面就出现在屏幕上,声音清晰同步,延迟低到几乎察觉不到。这一切的背后,是一整套精密协同的技术栈在默默工作——从摄像头采集图像,到麦克风拾取声音;从网络穿透NAT防火墙,到加密传输防止窃听;再到远端解码渲染,还原成你能看到和听到的内容。
今天,我们就以 Android 平台为切入点,深入剖析这套系统的每一个齿轮是如何咬合运转的。准备好进入这个充满工程智慧的世界了吗?🚀
🛠️ 搭建你的第一个 WebRTC 开发环境
要动手之前,先得有个干净的工作台。对于 Android 开发者来说,集成 WebRTC 并不像引入 Retrofit 或 Glide 那样简单一句 implementation 就完事了。为什么?
因为 WebRTC 的核心是用 C++ 写的高性能引擎,封装了音频处理、视频编解码、网络协议栈等底层能力。为了让 Java 层能调用这些功能,Google 提供了一个叫做 WebRTC Android SDK 的 AAR 包,里面不仅有 Java 接口,还包含了多个 CPU 架构的 .so 动态库文件(armeabi-v7a, arm64-v8a, x86, x86_64),总大小轻松超过 50MB。
所以第一步,就是把这个“大家伙”请进你的项目里。
📦 获取 SDK 的三种方式:手动 vs JitPack vs Google Maven
目前主流的获取方式有三种:
- 手动下载 AAR 文件
- 使用 JitPack 自动构建
- 通过 Google 官方 Maven 仓库引用
我们来逐个看看它们的特点:
✅ 方式一:手动集成 AAR(适合离线环境)
最原始但也最可控的方式是从官方或社区维护的地址下载预编译好的 .aar 文件。
例如,访问 https://github.com/oney/WebRTC-android/releases ,你可以找到不同版本的 WebRTC AAR 包。选择对应架构后,复制到项目的 app/libs/ 目录下:
// build.gradle (Module: app)
dependencies {
implementation files('libs/webrtc-release.aar')
}
或者如果你有多个 AAR,可以用 flatDir :
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation(name: 'webrtc-release', ext: 'aar')
}
⚠️ 注意:如果遗漏某个 ABI(CPU 架构),App 可能在部分设备上因找不到 native so 库而闪退。建议优先采用自动依赖管理方案。
✅ 方式二:JitPack(开发调试利器)
JitPack 是社区广泛使用的工具,它可以根据 GitHub 上的源码仓库自动拉取并编译生成 AAR。
首先,在项目根目录的 settings.gradle 中添加仓库:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' } // 添加这一行
}
}
然后在模块级 build.gradle 引入依赖:
dependencies {
implementation 'com.github.oney:WebRTC-android:r@79'
}
这里的 r@79 表示使用 WebRTC 的 M79 版本(基于 Chrome 浏览器主版本号)。JitPack 会自动为你编译该分支代码。
优点是更新方便,缺点是首次构建较慢,且每次都要联网拉源码。
✅ 方式三:Google Maven(生产首选!)
终于,在经历了多年等待之后,Google 官方推出了托管在 maven.google.com 的 WebRTC 库:
dependencies {
implementation 'org.webrtc:google-webrtc:1.0.380'
}
无需额外配置仓库(默认已包含),版本经过官方签名和优化,稳定性高,推荐所有生产项目使用!
| 方式 | 是否自动更新 | 构建速度 | 控制粒度 | 推荐场景 |
|---|---|---|---|---|
| 手动 AAR | ❌ 否 | ✅ 快 | ✅ 高 | 内部私有部署、离线环境 |
| JitPack | ✅ 是 | ⚠️ 中等(首次需编译) | ✅ 高 | 开发调试、小团队快速迭代 |
Google Maven ( google-webrtc ) | ✅ 是 | ✅ 快 | ⚠️ 中等 | 生产环境首选 |
💡 强烈建议 :除非特殊需求,否则一律使用 org.webrtc:google-webrtc 。
🔍 如何选择合适的 SDK 版本?
WebRTC 版本迭代非常频繁,通常跟随 Chromium 浏览器发布周期(每6周一次大版本)。选择哪个版本直接影响功能支持、API 稳定性和兼容性。
一般规则如下:
- 偶数版本(如 M100、M102) :相对稳定,适合生产环境。
- 奇数版本(如 M101、M103) :可能包含实验性功能,存在 Breaking Change。
- LTS(长期支持)版本 :极少发布,需关注官方公告。
可以通过 Chromium Dash 查询各版本生命周期状态。
此外还需评估以下几点:
- 最低支持 API 等级(minSdkVersion)
- 编解码器支持情况(H.264 是否默认启用)
- 是否支持硬件编码(Hardware Acceleration)
- 是否修复关键 Bug(如回声抑制失效、黑屏问题)
举个例子,从 WebRTC M100 开始, VideoEncoderFactory 和 VideoDecoderFactory 接口发生了重大变更:
// 旧写法(Deprecated)
VideoEncoderFactory encoderFactory = new DefaultVideoEncoderFactory(
eglContext,
true, // enable hardware acceleration
false // no fallback to software
);
// 新写法(Recommended)
VideoEncoderFactory encoderFactory = new DefaultVideoEncoderFactory(
rootEglBase.getEglBaseContext(),
/* enableIntelVp8Encoder */ true,
/* enableH264HighProfile */ true
);
这类变化要求开发者密切关注迁移文档,避免运行时崩溃。
下面这张流程图可以帮助你做出决策👇
graph TD
A[确定项目上线时间] --> B{是否追求最新特性?}
B -->|是| C[选择最新稳定版 MXX]
B -->|否| D[选择已验证的 LTS 或偶数版本]
C --> E[检查 release notes 是否含 Breaking Changes]
D --> F[确认 minSdkVersion 兼容性]
E --> G[测试关键功能: 音视频采集/编解码]
F --> G
G --> H{测试通过?}
H -->|是| I[锁定版本号]
H -->|否| J[降级尝试前一版本]
J --> G
🧩 Android 项目结构适配与权限声明
SDK 引入只是第一步。接下来我们需要对项目本身做一些必要的调整。
minSdkVersion 与 targetSdkVersion 设置
虽然 WebRTC 核心可在 API 16+ 运行,但为了获得完整的硬件编解码支持和 Camera2 API 功能,推荐设置如下:
android {
compileSdk 34
defaultConfig {
applicationId "com.example.webrtcdemo"
minSdkVersion 21
targetSdkVersion 34
versionCode 1
versionName "1.0"
}
}
-
minSdkVersion 21:保证 ART 运行时性能,支持 Lollipop 以上系统的 EGL 渲染上下文。 -
targetSdkVersion 34:适配 Android 14 的隐私变更和后台限制。
📌 提示:若需支持 Android 5.0 以下设备,请关闭硬件加速并使用 Camera1 API,但会牺牲画质和流畅性。
权限配置不能少!
WebRTC 需要访问摄像头、麦克风和网络,因此必须在 AndroidManifest.xml 中声明以下权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- 可选:防止屏幕休眠 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
其中:
- MODIFY_AUDIO_SETTINGS :用于自动切换音频路由(扬声器/听筒)。
- WAKE_LOCK :保持设备唤醒,避免通话中断。
- FOREGROUND_SERVICE_* :Android 9+ 要求前台服务声明具体用途。
同时,别忘了动态请求敏感权限:
private void requestPermissions() {
String[] permissions = {
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO
};
ActivityCompat.requestPermissions(this, permissions, REQUEST_PERMISSIONS);
}
未授权时调用 getUserMedia() 将导致 MediaStream 创建失败。
ProGuard 混淆规则配置
当你开启代码压缩( minifyEnabled true )时,ProGuard 可能误删 WebRTC 关键类,导致 UnsatisfiedLinkError 或空指针异常。
应在 proguard-rules.pro 中添加保留规则:
# WebRTC 核心类保留
-keep class org.webrtc.** { *; }
-keep class org.chromium.** { *; }
# JNI 方法不混淆
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
# 枚举类保留名称
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# 避免 PeerConnection Observer 被优化
-keep class * implements org.webrtc.PeerConnection$Observer {
public protected *;
}
🔍 建议在 Release 构建后使用 APK Analyzer 检查 libwebrtc.so 是否完整嵌入。
🛠️ Gradle 构建脚本精细化配置
正确书写 implementation 依赖
dependencies {
implementation 'org.webrtc:google-webrtc:1.0.380'
// 若使用 DataChannel,注意 Gson 冲突
implementation 'com.google.code.gson:gson:2.8.9'
}
注意:
- 使用 implementation 替代已废弃的 compile 。
- 固定版本号,避免使用 + 导致意外升级。
多渠道打包时的动态依赖管理
对于免费版/专业版等多变体项目,可通过 productFlavors 控制:
android {
flavorDimensions "version"
productFlavors {
free {
dimension "version"
minSdkVersion 21
}
pro {
dimension "version"
minSdkVersion 24
buildConfigField "boolean", "ENABLE_HEVC", "true"
}
}
}
dependencies {
freeImplementation 'org.webrtc:google-webrtc:1.0.380'
proImplementation 'org.webrtc:google-webrtc:1.0.380'
}
这样可以在不同版本中启用差异化功能,同时共享大部分代码。
常见构建失败问题排查
❌ 问题1:依赖冲突(Duplicate class)
Duplicate class org.webrtc.VideoDecoder found in modules ...
解决方案:排除重复依赖:
implementation ('some-library') {
exclude group: 'org.webrtc', module: 'google-webrtc'
}
❌ 问题2:NDK 缺失或 ABI 不匹配
错误提示: couldn't find "libwebrtc.so"
原因:未包含对应 CPU 架构的 so 库。
解决方法:
android {
packagingOptions {
pickFirst "**/*.so"
}
ndkVersion "25.1.8937393"
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64'
}
pickFirst 确保多个 AAR 中的 so 文件不会冲突。
✅ 验证开发环境:跑通第一个连接测试
现在我们来创建一个简单的 Activity,验证 SDK 是否正确加载。
创建布局文件
<!-- activity_main.xml -->
<SurfaceViewRenderer
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
初始化渲染器
public class MainActivity extends AppCompatActivity {
private SurfaceViewRenderer localView;
private EglBase rootEglBase;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rootEglBase = EglBase.create();
localView = findViewById(R.id.surface_view);
localView.setMirror(true); // 自拍镜像
localView.init(rootEglBase.getEglBaseContext(), null);
}
}
初始化 PeerConnectionFactory
private void initializePeerConnectionFactory() {
PeerConnectionFactory.initialize(
PeerConnectionFactory.initializeParams(this)
);
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
options.networkIgnoreMask = 0;
factory = PeerConnectionFactory.builder()
.setOptions(options)
.setVideoEncoderFactory(encoderFactory)
.setVideoDecoderFactory(decoderFactory)
.createPeerConnection();
if (factory == null) {
Log.e("WebRTC", "Failed to create PeerConnectionFactory");
return;
}
Log.d("WebRTC", "PeerConnectionFactory initialized successfully");
}
initializeParams() 会自动加载 native 库,若失败则抛出 UnsatisfiedLinkError 。
启用日志输出
Logging.enableLogToDebugOutput(Logging.Severity.INFO);
Logging.enableLogOutput(Logging.Severity.WARNING);
在 Logcat 过滤 WebRTC 查看 ICE 连接、编解码器选择等信息。
还可以通过 USB 调试连接 Chrome 浏览器,访问 chrome://webrtc-internals ,实时监控统计指标如:
- 发送/接收比特率
- 视频帧率
- RTT(往返延迟)
- 丢包率
该工具是诊断连接质量的利器!
✅ 至此,开发环境已准备就绪,可以进入下一步——建立真正的 P2P 连接了!
🔗 PeerConnection 初始化与 ICE 服务器配置
如果说 WebRTC 是一辆车,那么 RTCPeerConnection 就是它的发动机。它负责管理两个对等端之间的音视频流传输、数据通道以及网络连接。
而 PeerConnectionFactory 则是制造这台发动机的工厂。
🏭 PeerConnectionFactory 的创建与线程模型理解
PeerConnectionFactory 是整个 WebRTC 系统的起点。它的初始化过程决定了硬件加速能力、编码器选择及跨线程协作机制的有效性。
PeerConnectionFactory.initialize(
PeerConnectionFactory.initializeAndroidGlobals(context, true, true, true, true)
);
PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
options.networkIgnoreMask = 0;
final PeerConnectionFactory factory = PeerConnectionFactory.builder()
.setOptions(options)
.setVideoEncoderFactory(new DefaultVideoEncoderFactory(
rootEglBase.getEglBaseContext(), true, true))
.setVideoDecoderFactory(new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext()))
.createPeerConnection();
参数说明:
-
initializeAndroidGlobals(...)第二个参数启用硬件编码,第三个启用硬件解码,第四第五分别为 AEC(回声消除)和 AGC/NS(自动增益与噪声抑制)。 -
networkIgnoreMask = 0表示监听所有网络接口(Wi-Fi、移动数据等)。 -
DefaultVideoEncoderFactory传入 EGL 上下文可支持 GPU 渲染加速。
⚠️ 注意:若未正确绑定 EGLContext,可能导致 SurfaceTexture 更新失败或黑屏问题。
EGLContext 初始化与视图绑定流程
graph TD
A[Application Context] --> B[PeerConnectionFactory.initialize]
B --> C[EglBase.create()]
C --> D[SurfaceViewRenderer.init(EGLContext)]
D --> E[VideoTrack.addSink(SurfaceViewRenderer)]
E --> F[OpenGL 渲染线程绘制帧]
这个流程体现了 WebRTC 多层线程隔离的设计思想——媒体采集运行于 native 音频/视频线程,渲染则由独立的 GL 渲染线程处理,避免阻塞主线程 UI。
🧩 RTCPeerConnection 的构造与配置详解
RTCPeerConnection 是 WebRTC 实现点对点通信的核心类,封装了完整的 ICE、DTLS、SCTP 和 RTP 协议栈。
RTCConfiguration 对象配置
List<PeerConnection.IceServer> iceServers = Arrays.asList(
PeerConnection.IceServer.builder("stun:stun.l.google.com:19302").createIceServer(),
PeerConnection.IceServer.builder("turn:your-turn-server.com:3478")
.setUsername("webrtc-user")
.setPassword("secure-pass!")
.createIceServer()
);
RTCConfiguration rtcConfig = new RTCConfiguration(iceServers);
rtcConfig.iceTransportsType = PeerConnection.IceTransportsType.ALL;
rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE;
rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE;
rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.ENABLED;
rtcConfig.candidateNetworkPolicy = PeerConnection.CandidateNetworkPolicy.ALL;
| 属性 | 作用 |
|---|---|
iceTransportsType | 控制候选地址生成范围(ALL / RELAY / NOHOST) |
bundlePolicy | 是否复用单一传输通道(音频+视频共用) |
rtcpMuxPolicy | 是否强制使用 RTCP 复用减少端口占用 |
tcpCandidatePolicy | 是否尝试 TCP 打洞(穿透 NAT 更强) |
✅ 推荐配置:生产环境推荐使用 MAXBUNDLE + REQUIRE 以节省带宽和连接数。
🌐 ICE 候选收集过程与网络拓扑发现
ICE(Interactive Connectivity Establishment)是 WebRTC 实现 NAT 穿透的核心机制。
ICE Agent 工作机制
stateDiagram-v2
[*] --> NEW
NEW --> CHECKING: gather candidates
CHECKING --> CONNECTED: successful connectivity check
CONNECTED --> COMPLETED: all checks done
CONNECTED --> FAILED: no valid pairs
FAILED --> DISCONNECTED: network lost
DISCONNECTED --> CONNECTING: re-gather
应用层应在 onIceConnectionChange 中监听这些状态,及时反馈用户“正在连接”、“已断开”等提示。
候选类型说明
| 类型 | 获取方式 | 示例 |
|---|---|---|
| Host Candidate | 本地网卡IP | 192.168.1.10:50000 |
| Server Reflexive | STUN 返回公网IP | 203.0.113.45:61000 |
| Relayed Candidate | TURN 分配中继地址 | 198.51.100.20:35000 |
只有当 iceTransportType == ALL 且 TURN 配置存在时才会生成 relay 候选。
🔔 事件监听与回调接口实现
PeerConnection.Observer 是异步事件的主要入口:
private final PeerConnection.Observer pcObserver = new PeerConnection.Observer() {
@Override
public void onIceCandidate(IceCandidate candidate) {
signalingClient.send("candidate", toJson(candidate));
}
@Override
public void onIceConnectionChange(IceConnectionState state) {
if (state == IceConnectionState.FAILED) {
Toast.makeText(context, "网络中断,尝试重新连接...", Toast.LENGTH_LONG).show();
reconnect();
}
}
@Override
public void onTrack(RemoteStream stream) {
VideoTrack remoteVideoTrack = stream.videoTracks.get(0);
remoteVideoTrack.addSink(remoteRenderer);
}
};
建议定期采集 StatsReport 进行 QoS 监控:
peerConnection.getStats(report -> {
for (StatsReport.Value value : report.values) {
if ("ssrc".equals(value.id)) {
Log.d("WebRTC-STATS", value.name + ": " + value.value);
}
}
}, null);
常用指标:
| 指标 | 建议阈值 | 优化方向 |
|---|---|---|
googRtt | < 300ms | 切换更近的 TURN 节点 |
framerateOutput | ≥ 24fps | 启用硬件解码 |
packetsLost | < 5% | 开启 FEC/NACK |
cpuLoad | < 60% | 降低分辨率或帧率 |
结合 Firebase Performance 或自建 Prometheus+Grafana 可实现可视化监控。
🎥 音视频采集与本地流创建
高质量的音视频采集是用户体验的基础。
📸 视频采集模块设计
WebRTC 抽象出 VideoCapturer 接口,推荐使用 Camera2Capturer 以获得更好的控制能力。
surfaceTextureHelper = SurfaceTextureHelper.create("CameraSurfaceTexture", eglBase.getEglContext());
Camera2Enumerator enumerator = new Camera2Enumerator(context);
String cameraId = enumerator.getDeviceNames()[0]; // 选择前置摄像头
videoCapturer = new Camera2Capturer(context, cameraId, new Camera2Capturer.CameraEventsHandler() {
@Override
public void onFirstFrameAvailable() {
Log.d("WebRTC", "首帧已到达");
}
@Override
public void onCameraError(String error) {
Log.e("WebRTC", "摄像头错误: " + error);
}
});
videoCapturer.initialize(surfaceTextureHelper, context, videoSource.getCapturerObserver());
videoCapturer.startCapture(1280, 720, 30); // 720p@30fps
支持动态切换分辨率:
videoCapturer.stopCapture();
videoCapturer.startCapture(640, 480, 15); // 降级至 VGA@15fps
🔊 音频采集链路构建
使用 JavaAudioDeviceModule 统一管理输入输出:
audioDeviceModule = JavaAudioDeviceModule.builder(context)
.setUseHardwareAcousticEchoCanceler(true)
.setUseHardwareNoiseSuppressor(true)
.setSamplesPerSec(16000)
.createAudioDeviceModule();
factory = PeerConnectionFactory.builder()
.setAudioDeviceModule(audioDeviceModule)
.createPeerConnection();
开启 AEC、AGC、NS 可显著提升音质,尤其在嘈杂环境中。
🤝 SDP 协商与 Offer/Answer 流程
会话建立依赖于 SDP(Session Description Protocol)描述媒体能力,并基于 Offer/Answer 模型完成协商。
📄 SDP 语法结构剖析
典型 SDP 片段:
v=0
o=- 1928374650 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
m=audio 9 UDP/TLS/RTP/SAVPF 111
a=rtpmap:111 opus/48000/2
a=fmtp:111 minptime=10; useinbandfec=1
a=setup:actpass
a=fingerprint:sha-256 0A:1B:2C:...
关键字段:
- m= :媒体描述行
- a=rtpmap :映射 Payload Type 到编码格式
- a=fmtp :提供额外编码参数
- a=fingerprint :DTLS 证书哈希,防中间人攻击
🔄 协商流程中的角色定义
一方创建 Offer,另一方回复 Answer:
peerConnection.createOffer(new SdpObserver() {
@Override
public void onCreateSuccess(SessionDescription sdp) {
peerConnection.setLocalDescription(sdpObserver, sdp);
signaling.send("offer", sdp.description);
}
}, constraints);
收到 Offer 后应答:
peerConnection.setRemoteDescription(new SdpObserver() {
@Override
public void onSetSuccess() {
peerConnection.createAnswer(answerObserver, constraints);
}
}, offerSdp);
顺序不能乱:必须先 setRemoteDescription 再 createAnswer 。
📡 ICE Candidate 交换机制
当本地收集到新候选地址时触发:
@Override
public void onIceCandidate(IceCandidate candidate) {
signaling.send("candidate", toJson(candidate));
}
远端收到后添加:
peerConnection.addIceCandidate(candidate, new AddIceObserver() {
@Override
public void onAddSuccess() {
Log.d("WebRTC", "ICE candidate added.");
}
});
建议缓存所有 Candidate,在 setRemoteDescription 完成后再批量添加。
🖼️ 远程音视频流接收与渲染
📺 远程轨道监听
现代应用应使用 onTrack 替代过时的 onAddStream :
@Override
public void onTrack(RtpTransceiver transceiver) {
MediaStreamTrack track = transceiver.getReceiver().track();
if (track instanceof VideoTrack) {
runOnUiThread(() -> remoteRenderer.addSink((VideoTrack) track));
}
}
🎨 高性能渲染优化
推荐主画面使用 SurfaceViewRenderer ,子窗口可用 TextureView 提升动画流畅度。
注入帧监听器检测卡顿:
public class FrameMonitor implements VideoSink {
private long lastTimestamp = 0;
private int frameCount = 0;
@Override
public void onFrame(VideoFrame frame) {
frameCount++;
long now = System.currentTimeMillis();
if (now - lastTimestamp > 2000) {
double fps = (frameCount * 1000.0) / (now - lastTimestamp);
Log.i("FrameMonitor", "Render FPS: %.2f", fps);
frameCount = 0;
lastTimestamp = now;
}
delegate.onFrame(frame);
}
}
🔁 全生命周期管理与性能调优
🔄 连接状态追踪
使用状态机统一管理:
stateDiagram-v2
[*] --> Idle
Idle --> Connecting : createOffer/setLocalDescription
Connecting --> Connected : onIceConnectionState(CONNECTED)
Connected --> Reconnecting : onIceConnectionState(DISCONNECTED)
Reconnecting --> Connected : reconnect success
Reconnecting --> Failed : timeout/retry exhausted
Connected --> Closed : user close()
Failed --> Closed : auto cleanup
Closed --> [*]
💣 资源释放最佳实践
按顺序关闭:
public void teardownConnection() {
if (peerConnection != null) {
peerConnection.close();
peerConnection.dispose();
peerConnection = null;
}
if (localVideoTrack != null) {
localVideoTrack.removeSink(localRenderer);
localVideoTrack.dispose();
localVideoTrack = null;
}
if (factory != null) {
factory.dispose();
factory = null;
}
}
📈 性能调优策略
- 动态切换编码器(VP8/VP9/H.264)适应带宽
- 启用 FEC、NACK 提升抗弱网能力
- 调节 Jitter Buffer 减少抖动
- 采集端到端延迟热力图定位瓶颈
这种高度集成的设计思路,正引领着智能音频设备向更可靠、更高效的方向演进。👏
简介:WebRTC是由Google主导的开源项目,支持浏览器和原生应用间的实时音视频通信。本Android Demo项目提供了完整的WebRTC集成示例,涵盖音视频流传输、PeerConnection初始化、信令交互、媒体设备权限处理等核心功能,帮助开发者快速掌握在Android平台上实现视频通话、语音聊天和数据共享的关键技术。项目通过Gradle依赖集成WebRTC库,包含Activity、Service及媒体处理组件的实际代码,具有较强的参考价值,是学习Android端实时通信开发的理想实践资源。
更多推荐
所有评论(0)