一文解决WebRTC|Android 客户端编译
Posted 音视频开发老马
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文解决WebRTC|Android 客户端编译相关的知识,希望对你有一定的参考价值。
目录
- 前言
- 重要分支描述
- 准备工作
- 验证
- Other
- Q&A
- 参考
前言
之前在Linux服务器上编译过Webrtc,现在需要将部分功能移植到Client端,需要重新编译,本文章将介绍如何编译客户端WebRTC、编译过程中遇到了哪些坑,以及编译前的准备工作。
笔者开始是在MAC上虚拟Docker 编译,因机器性能原因,又重新找了台Win本,重装了双系统,在Ubuntu 上最终编译完成。
WebRTC 版本变更频繁,各版本编译时差异较大,本次笔者基于m84分支,文章最后也给出了其他分支编译出现的问题。
重要分支描述
- 关键版本对应分支
-
- m84 branch-heads/4147 (2020年6月稳定)
- m89 branch-heads/4389 (2021年2月稳定)
- m93 branch-heads/4577 (2022年1月稳定)
- 关键版本支持的android 版本
-
- m84/4147 android:minSdkVersion="16" android:targetSdkVersion="23"
- m89/4389 android:minSdkVersion="21" android:targetSdkVersion="23"
- m93/4577 android:minSdkVersion="21" android:targetSdkVersion="23"
关注+后台私信我,领取2022最新最全学习提升资料包《Andoird音视频开发必备手册+音视频最新学习视频+大厂面试真题+2022最新学习路线图+项目实战源码》资料内容包括(C/C++,Linux,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)等等
准备工作
安装 depot_tools(需要用到depot_tools工具来下载webrtc源码)
-
git 命令获取 depot_tools
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git 复制代码
配置环境变量
echo "export PATH=$PWD/depot_tools:$PATH" > $HOME/.bashrc source $HOME/.bashrc 复制代码
-
检测配置是否成功
echo $PATH 复制代码
源码下载
-
创建文件夹
mkdir webrtc_android && cd webrtc_android 复制代码
-
获取源码(18G 左右,需要稳定代理)
fetch --nohooks webrtc_android 复制代码
fetch --nohooks webrtc_android
失败直接执行gclient sync --nohooks
进行同步 -
分支切换
cd src git checkout -b m84/4147 branch-heads/4147 复制代码
-
同步目标分支代码
cd .. gclient sync --nohooks gclient runhooks 复制代码
注:gclient sync --nohooks、gclient runhooks 哪个失败,重新执行哪个
源码编译
-
安装编译依赖(30 分钟左右)
./src/build/install-build-deps.sh ./src/build/install-build-deps-android.sh 复制代码
-
设置编译参数,生成
ninja
文件cd src gn gen out/build --args='target_os="android" target_cpu="arm" is_debug=false' 复制代码
cd src gn gen out/build --args='target_os="android" target_cpu="arm" is_debug=false'
out/build
:编译生成文件的目录,随意指定``target_os
:编译目标平台
android、ios` 等target_cpu
:CPU架构平台arm、arm64、x86、x64
等is_debug
:Release
模式或者Debug
模式 -
开始编译
编译(1w 多个构建任务,编译时长 2 个小时左右)
-
全量编译
ninja -C out/build 复制代码
非全量编译
ninja -C out/build AppRTCMobile 复制代码
注:out/build 即编译生成文件的目录,两者必须一致
-
主要获取的文件
-
- out/build/lib.java/sdk/android/libwebrtc.jar
- out/build/libjingle_peerconnection_so.so
-
生成 aar
python tools_webrtc/android/build_aar.py --output "libwebrtc.aar" --arch "armeabi-v7a" "arm64-v8a" --build-dir out/Release 复制代码
成功后会在 src 目录下看到 libwebrtc.aar 文件,里面就是 Android 开发需要用到的 SDK 了。out/Release目录是编译目录,第一编译会全量编译速度很慢(预计30~40分钟),以后就增量编译很快(预计10s内)。
验证
验证 aar 是否可用
官方 demo 在 src/examples
目录中,可导入编译生成的 aar 验证是否可用。
Other
-
生成动态库.so文件,生成so文件首次会全量编译,后续增量编译速度非常快。如果以后只改C层代码不生成Java的API,这种方法非常适合测试
ninja -C out/Debug sdk/android:libjingle_peerconnection_so
-
生成静态库.a文件
ninja -C out/Debug
生成的.a文件在out/Debug/obj/libwebrtc.a
-
配置android studio工程
使用Android Studio直接打开webrtc_android/src/examples/aarproject/,编辑app/build.gradle:删除
implementation 'org.webrtc:google-webrtc:1.0.+' 复制代码
替换为 native 步骤编译的 libwebrtc.aar
implementation fileTree(dir: '../../../', include: ['libwebrtc.aar']) 复制代码
Q&A
-
执行 gclient runhooks 时
python src/build/linux/sysroot_scripts/install-sysroot.py --arch=i386 复制代码
下载失败
将
install-sysroot.py
中range(3)
重试次数由 3 调大一些 -
M84/4147 分支编译报错
[996/11199] ACTION //base:base_build_config_gen_...c(//build/toolchain/android:android_clang_arm64) FAILED: gen/base/base_build_config_gen/java_cpp_template/org/chromium/base/BuildConfig.java python ../../../build/android/gyp/gcc_preprocess.py --depfile gen/base/base_build_config_gen_BuildConfig.d --include-path ../../../ --output gen/base/base_build_config_gen/java_cpp_template/org/chromium/base/BuildConfig.java --template=../../../base/android/java/templates/BuildConfig.template Traceback (most recent call last): File "../../../build/android/gyp/gcc_preprocess.py", line 54, in <module> sys.exit(main(sys.argv[1:])) File "../../../build/android/gyp/gcc_preprocess.py", line 47, in main DoGcc(options) File "../../../build/android/gyp/gcc_preprocess.py", line 31, in DoGcc build_utils.CheckOutput(gcc_cmd) File "../../WebRTC/src/build/android/gyp/util/build_utils.py", line 261, in CheckOutput sys.stderr.write(stderr) TypeError: write() argument must be str, not bytes 复制代码
解决方案:
python 版本不兼容,M84 需要使用 python2 编译
查看 python 版本
python --version
移除原默认 python
sudo rm -rf /usr/bin/python
指定新默认 python
sudo ln -s /usr/bin/python2 /usr/bin/python
重新编译
-
M93/4577 分支编译报错
Command failed because it wrote to stderr You can often set treat_warnings_as_errors=false to not treat output as failure (useful when developing locally). 复制代码
重新编译
gn gen out/m89/release --args='target_os="android" target_cpu="arm64" is_debug=false treat_warnings_as_errors=false' 复制代码
-
编译报错:ModuleNotFoundError: No module named 'dataclasses'
-
-
python2
sudo apt install python-pip pip install dataclasses 复制代码
-
python3
sudo apt install python3-pip pip3 install dataclasses 复制代码
-
-
编译报错:ERROR: The installation of the Chrome OS default fonts failed.
ERROR: The installation of the Chrome OS default fonts failed. This is expected if your repo is installed on a remote file system. It is recommended to install your repo on a local file system. You can skip the installation of the Chrome OS default founts with the command line option: --no-chromeos-fonts. 复制代码
重新安装依赖
./src/build/install-build-deps.sh --no-chromeos-fonts 复制代码
-
M89/4389 编译 aar 报错
Traceback (most recent call last): ... File "../../../../../build/android/gyp/compile_java.py", line 501, in _RunCompiler fail_on_output=options.warnings_as_errors) File "../../WebRTC/src/build/android/gyp/util/build_utils.py", line 292, in CheckOutput raise CalledProcessError(cwd, args, MSG.format(stream_string)) util.build_utils.CalledProcessError: .... You can often set treat_warnings_as_errors=false to not treat output as failure (useful when developing locally). [2415/3419] CXX obj/api/libjingle_peer...ection_api/peer_connection_interface.o ... subprocess.CalledProcessError: Command '['../../WebRTC/src/third_party/depot_tools/ninja', '-C', 'out/m89/build/aar/armeabi-v7a', 'sdk/android:libwebrtc', 'sdk/android:libjingle_peerconnection_so']' returned non-zero exit status 1 复制代码
重新编译
python tools_webrtc/android/build_aar.py --output "libwebrtc-m89.aar" --arch "armeabi-v7a" "arm64-v8a" --build-dir out/m89/build/aar --extra-gn-args='treat_warnings_as_errors=false' 复制代码
参考
WebRTC官网(webrtc.org/)
Android|WebRTC(webrtc.github.io/webrtc-org/…
一文带你了解webrtc基本原理(动手实现1v1视频通话)
webrtc (Web Real-Time Communications) 是一个实时通讯技术,也是实时音视频技术的标准和框架。
大白话讲,webrtc是一个集大成的实时音视频技术集,包含了各种客户端api、音视频编/解码lib、流媒体传输协议、回声消除、安全传输等。
对于开发者来说可以借助webrtc非常方便的实现低延时视频通话能力。
现在主流的直播系统、会议系统基本都是基于webrtc来实现。
一、webrtc 三种架构
我们先大概了解下webrtc的几种架构及各自适用场景。
【Mesh】
Mesh架构,需要所有参与连接的peer建立与所有其他peer的媒体连接。
该架构需要n-1个上下行,以此带来的带宽消耗(流量)、编/解码消耗(手机性能)成线性增长。
该架构只能适用3-4个人的小型会议场景。
【MCU】
所有本房间的peer将本地媒体流推到远程媒体服务器,由媒体服务器进行混流,然后再推到所有连接的peer端。
该架构的优点就是只需要1路上下行,随着peer人数不断增加,依然不会对用户造成带宽、手机性能影响。
该架构将压力转嫁到服务端,由专用媒体服务器来完成混流,转推等功能。
【SFU】
相对于MCU来说SFU只做转发,媒体服务器压力有限。与mesh架构相比,只需要n-1个下行,1个上行。
在大规模的场合该架构具有伸缩性。
二、实现 1v1 视频通话
废话不多说,动手实践下。
(麻雀虽小,五脏俱全。通过实现1v1的功能,来整体了解下webrtc协议的原理。)
github:https://github.com/Plen-wang/webrtc-demo-1v1
由于是私有证书问题,chrome会有安全提示。(demo地址暂时还能用 -_- )
有两个方法可以试下。
第一个方法,手动设置一个类似不安全白名单列表,然后重启浏览器。
chrome://flags/#unsafely-treat-insecure-origin-as-secure
如果不行,我们试下第二个方法肯定可以。
点击空白页输入 thisisunsafe
字符。
动手之前,我们先简单了解下webrtc的连接的大致流程和涉及的相关技术点。
【WebRTC P2P】
【NAT穿透】
peer基本都在内网,需要通过nat穿透技术来与peer建立连接。
根据nat的拓扑情况大致分为如下几种:完全锥形、IP锥形、端口锥形、对称形。
stun\\turn协议:stun协议用来拿到peer公网ip,turn用来做relay数据转发。
【SDP】
sdp是会话描述协议。
是媒体协商时使用,用于将本地支持的媒体(编解码等)信息、candidate(连接候选者)信息打包发送到信令服务器。
sdp的交换是通过中间服务器(信令服务器)来完成的。
【ICE】
ICE是一个不断尝试连接的协议,不同的网络情况下ICE大概会尝试如下几种方式来建立通讯通道。
host(peers都在内网)、 srflx(nat穿透)、prflx(nat穿透-Full Cone)、relay(中继)
【服务端】
在整个连接生命周期中都是需要服务端参与。参与webrtc协作的服务端大概分为这几种类型。
stun/turn服务器(p2p穿透)、信令服务器、媒体服务器(媒体信息处理)、业务服务器(可选)
整体流程大致如下。
(上述技术点较多,感兴趣可以自行查询相关资料)
【部署STUN\\TURN服务器】
为了支持1v1公网访问,我们需要搭建一个stun/turn服务器。
这里我们使用 Coturn 开源组件,coturn的镜像有很多,可自行选择。
(注意准备coturn配置文件时,记得设置用户名和密码。)
docker run -d --rm --name turn-server --network=host \\
-v $pwd/turnserver.conf:/etc/coturn/turnserver.conf \\
instrumentisto/coturn
部署好之后可以通过ICE测试工具测试下
https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice
stun:1.15.11.173:3478?transport=tcp
turn:1.15.11.173:3478?transport=tcp:user:pwd
如果正常返回了ICE尝试的连接类型,说明部署没有问题。
【实现信令服务器与客户端代码】
我们采用golang来实现一个简单的信令服务器,使用开源组件go-socket。
同时还需要实现一个web客户端。
demo代码就不贴到文章里了,放在github上。整体代码比较简单,感兴趣可以看下。
git@github.com:Plen-wang/webrtc-demo-1v1.git
【部署信令服务器】
当在本地debug的差不多了,我们把信令服务器打个镜像发到云主机上。
(如果部署本demo,可以直接使用此镜像。)
docker push wangqingpei/rtc-signal-server:latest
docker run --name signal-server -d -p:8080:8080 wangqingpei/rtc-signal-server
【部署web服务器】
部署好信令服务器之后,我们把静态文件放到web服务器里,直接使用nginx镜像部署非常简单。
docker run -d -p 80:80 -p 443:443 --rm --name webrtc-nginx \\
-v /data/rtc-nginx.conf:/etc/nginx/nginx.conf \\
-v /data/pem/server.key:/etc/nginx/server.key \\
-v /data/pem/server.pem:/etc/nginx/server.pem \\
-v /data/rtc-static-file:/usr/share/nginx/html nginx
部署前,记得修改js里的stun服务器地址。
//创建RTCPeerConnection对象
function createRTCPeerConnection()
try
const configuration = 'iceServers': ['urls': 'stun:1.15.11.173:3478?transport=tcp']
rtcConnObject = new RTCPeerConnection(configuration);
rtcConnObject.onicecandidate = handleRtcICECandidate;//ice 交互
rtcConnObject.onaddstream = handleRtcAddStream;//远程stream加入
rtcConnObject.onremovestream = handleRtcRemoveStream;//远程stream移除
rtcConnObject.addStream(localStreamObject);//添加本地stream
console.log("create local RTCPeerConnection object ok.");
catch (e)
console.error("create RTCPeerConnection err.", e);
两边peer就可以借助stun服务器拿到公网ip实现nat穿透。
三、实现MCU/SFU 多人通话
MCU/SFU架构需要 专用媒体服务器 参与。
【媒体服务器选择】
专用媒体服务器有 OWT(open webrtc toolkit)、TWS(Kurento Media Server)等重量级的开源产品。
这两款开源框架都支持MCU、SFU架构功能。
我们选择OWT捣鼓下。
先看下部署起来的效果,默认MCU模式。
红框部分是服务端混流之后的效果。
【部署OWT】
注意,owt-server-4.3镜像与最新版chrome有兼容性问题,会报错 Empty candidate 错误。
我们直接使用5.0的镜像部署。
docker run -d --name owt-demo --network host lmshao/owt-server
由于该镜像是使用默认配置打的,启动后手动进入容器修改下相关配置,换成你云主机的公网ip,然后重启服务。
配置文件路径
vi dist/webrtc_agent/agent.toml
配置项,这里修改成你的公网ip
network_interfaces = [name = "eth0", replaced_ip_address = "1.116.175.232"] # default: []
stun服务器可选
stunport = 3478 #default: 0
stunserver = "1.15.11.173" #default: ""
然后修改下portal.toml文件,文件路径。
vi dist/portal/portal.toml
修改成公网ip
ip_address = "1.116.175.232" #default: ""
重启下相关服务
./bin.restart-all.sh
注意启动日志里有一个id、key,这是用来进入管理页面用的。(没错,owt提供了后台管理页面 -_-)
superServiceId: xxx
superServiceKey: xxx
sampleServiceId: xxx
sampleServiceKey: xxx
默认3004端口下是mcu模式,连线的人多了就会明显卡顿(看服务器配置)。
我们切到SFU模式试下流畅度和服务器负载情况。
通过 ?forward=true 参数控制
https://1.116.175.232:3004/?forward=true
OWT还配有管理后台用于控制媒体服务器的相关参数。
OWT还是比较强大的,有兴趣可以研究研究。
参考资料:
github.com/googollee/go-socket.io
《WebRTC技术详解:从0到1构建多人视频会议系统》
《WebRTC音视频实时互动技术:原理、实战与源码分析》
《FFmpeg 音视频开发基础与实战》
以上是关于一文解决WebRTC|Android 客户端编译的主要内容,如果未能解决你的问题,请参考以下文章
Webrtc入门——基于阿里云ubuntu 最新webrtc Android平台编译详细说明