light-rtc: 理念与实践
在与同行交流过程中,发现很多同行对 WebRTC 改动太多,导致无法升级 WebRTC 版本。而 WebRTC 开源社区的快速迭代,让他们感到欣喜又焦虑:开源社区的迭代效果,是不是超过了他们对 WebRTC 的优化效果?我们针对特定场景优化 WebRTC 时,怎么紧跟 WebRTC 开源社区通用的优化?
作者:阿里云智能技术专家 熊金水
理念
简言之,把 WebRTC 作为 Framework 使用,而不是 Library,即:WebRTC 仓库轻量化,核心模块插件化。
详细的,WebRTC 作为 Framework 串联核心模块;核心模块既可以以插件形式使用我们的实现,也可以 Fallback 到 WebRTC 的默认实现。目的是减少 WebRTC 冲突的可能性,提高升级 WebRTC 的敏捷性。
目标:一年升级一次 WebRTC,一次花费一个人月。
架构
模块拆解

WebRTC 的核心模块,包括:
音频
- ADM 采集、APM、ACM 编码;
- NetEQ 与解码、AM、ADM 渲染;
视频
- 采集、编码;
- JB、解码、渲染;
通用
- RTP 打包与解包、FEC 生成与恢复、CC 与 Pacer、ICE、SDP 信令等。
WebRTC 在长期的演进中,API 已经具备了作为 Framework 的大部分能力。红色的核心模块,已经基本可以插件化,如下面的 API:

仓库管理

light-rtc 作为 WebRTC 仓库,我们需要保留两个 Remote,一个是 Alibaba,一个是 Google。升级 WebRTC 时,我们从 Google 上 Pull 最新代码, 解决冲突,然后 Push 到 Alibaba。
对插件化的模块,我们需要放到单独的仓库 lrtc-plugin 里,这样有两个好处:
- 对 light-rtc 仓库改动少,减少与 Google 冲突的可能性;
- 更重要的,让每个开发同学,在每次改动前,更主动、更有意识的思考,放到哪个仓库更合适,否则容易惯性思维,直接改动 light-rtc。
对 lrtc-plugin 依赖的第三方库,也应该以单独的仓库存在,并保留两个 Remote,比如 Opus,这样,即使修改了 Opus 源码,仍然可以像升级 light-rtc 一样,方便的单独升级 Opus 版本。
模块
Codec
音频编解码器、视频编解码器,是我们最常优化的部分之一:
- 新的编码工(AV1/SCC/ROI 等)优化视频质量和带宽;
- 分辨率自适应,使不同能力(编码能力、发送带宽等)的发送端,发送不同分辨率的码流;
- Simulcast,为不同能力(解码能力、显示能力、接收带宽等)的接收端,提供不同分辨率码流;
- SVC,提供时域/空域分层;
- 新的视频解码实现,规避 Mac 硬解卡死等问题;
- 新的音频编码器,适配商用接收端;
……

这部分插件化是相对简单的,只需要实现自己的 [Video|Audio][Encoder|Decoder]Factory 即可。以 Simulcast为例,在自己实现的 VideoEncoderFactory 里,先用 WebRTC 原始的 VideoEncoderFactory,创建多个 Encoder 对象,然后封装到一个 Simulcast Encoder 里。
ADM
很可惜,ADM(Audio Device Module)没有提供检测设备插拔的功能,需要增加 Callback 接口。
另外,虽然 WebRTC 支持样本数量的监控,但是当前只用于打印日志,如果想在此基础上做更多事情(如:发现采集样本为 0 时,重启采集),则单独做一个 AudioSampleMoniter 的类,比较有利于扩展。

ADM 是一个适配难点,相信是困扰 RTC 同行的共同难题。不同操作系统、不同机型,都可能有不一样的问题。例如:
- Mac 3.5mm 耳机插拔时,偶尔崩溃;
- Mac 获取的设备 ID 在插拔后发生变化,不能做持久化;
- 联想 X1 电脑,多次插拔后,整个 Audio 后台服务失效;
- 某些 Windows 机型采集不到声音;
- 某些手机采音权限问题;
……
这些修改大部分属于 Bugfix,参考“Bugfix”章节。
APM
APM(Audio Processing Module)可能是 light-rtc 相对难处理的部分。
APM 与 NetEQ 一起,可能是 WebRTC 核心模块中,开源价值最大的部分。在我对 APM 有限的认知里,对 APM 常见的优化可能有:
- 混音后的远端信号,做滤波/均衡处理。这是业界不少音频算法的必要条件;
- 利用 Android 手机特性,优化 AECM,尤其是 Double Talk 时的效果;
- 啸叫检测与抑制;
- 利用机型特性,优化 AGC,提高语音音量;
……
下图是 WebRTC APM 内部模块的数据流程图:

从图中可以看出,APM 其实也为插件化做了准备,但是只在近端信号的尾部、远端信号的头部。从 APM 构造函数上也可以看出来:

滤波/均衡,可以方便的实现一个 CustomProcessing 的 render_pre_processor。
其他的优化,遵循轻量化/插件化的理念,没有现成的插件接口,我们可以创造新的插件接口,如啸叫抑制,以及 AECM 优化的部分算法。
但 APM 仍然会有很多没办法插件化的,只能修改 light-rtc 仓库,如 AECM Double Talk 优化等。
AM
AM(Audio Mixer)的插件化,可以在不修改 light-rtc 的基础上,玩出很多花样:
- 播放本地文件;
- 借助语音检测算法,优化语音排序,从而选出更准确的语音做混音;
- Mono 变成 Stereo,借助 HRTF,可以在多方同时说话时提高说话人辨识度和可懂度;
- 对 RTP 方案的回放,倍速回放时变速不变调;
……

FEC
FEC(Forward Error Correction),常见的修改:
- 调参,如冗余度、MaxFrames、Table 类型,包括固定参数和动态自适应调参两类,已有的插件接口 WebRTC::FecControllerFactoryInterface 即可满足;
- RSFEC,需要创造新的插件接口;
- Opus Inband FEC。WebRTC 动态配置的 Opus FEC 参数,不能很好的解决弱网时声音卡顿问题。这时,一个办法是把 Opus 独立成仓库,直接修改 Opus 编码器。

CC
CC(Congestion Control),包含两个方面,一个是 CC 算法本身,一个是 CC 关联模块。
算法本身,可以用不同的算法实现,如 WebRTC 默认的 goog_cc,也可以是 BBR,甚至是满足 WebRTC::NetworkControllerFactoryInterface 接口的外部插件。
关联模块:
- 带宽分配:不同场景可能不一样,如视频会议里,需要“保音频、保屏幕”。可以通过 rtc::BitrateAllocationStrategy 实现插件化。

- Pacer 调优:对于屏幕内容,I帧往往非常大,WebRTC 的 2.5 倍的发送带宽,会导致巨大的首帧时间。具体解法见仁见智。
……
VideoRender
Android、iOS、Mac,WebRTC 都提供了默认的实现,虽然有少量 Bug,但是基本满足需求。
Windows 平台,早期 WebRTC 提供了 D3D 的实现,最新版已经剔除,我们可以在 lrtc-plugin 仓库实现自己的 D3D,或者其他的渲染,如 QT OpenGL。
VideoProcess
WebRTC 并没有提供视频前处理(如:美颜)、后处理(如:超分辨率)的接口,但是我们完全可以像 rtc::BitrateAllocationStrategy 一样,创造 VideoProcessInterface 接口, 并在 lrtc-plugin 仓库里实现。

让 VideoProcessInterface 同时继承 Sink 和 Source 接口,可以方便的把多个对象串联起来。
其他 & Bugfix
其他核心模块,如 JitterBuffer、ICE 等,目前接触的主要是 Bugfix,还没有发现自己定制重写的必要。
Bugfix,往往只能修改 light-rtc 仓库。一方面,是尽量把 Bugfix 内聚成函数,减少对已有代码的修改;另一方面,尽量把 Bugfix 贡献到开源社区(Issue Tracker),既为开源社区做了贡献,也彻底避免了升级的冲突。
贡献到开源社区,往往比想象的要复杂,但也更能锻炼人。在特定场景,往往只用了 WebRTC 一部分能力,如视频 JitterBuffer,一个 Bugfix 可能只考虑到了 H264,贡献到开源社区时,则需要同时兼顾 VP8/VP9,甚至是将来的 AV1。在这个过程中,Google 工程师会在 Code Review 中与你亲密切磋,其实是非常好的锻炼机会,进一步提高对 WebRTC 的认识。
参考
WebRTC m74 源码
RSFEC:
- WebRTC RSFEC 详解和剖析;
- ARTP 技术探秘之:WebRTC 中支持 RS FEC。
(以上两篇文章之后将会在本号推送)
CC
「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。
light-rtc: 理念与实践的更多相关文章
- [置顶]
来自 Google 的高可用架构理念与实践
转自: https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=402738153&idx=1&sn=af5e76aad ...
- CODING 敏捷实践完全指南
你好,欢迎使用 CODING! 这份最佳实践将帮助你掌握 CODING 敏捷管理工具,更好地实践敏捷开发流程. 更多实践案例持续更新中 什么是敏捷研发 敏捷研发是涉及整个软件工程的理念与实践,它的核心 ...
- 全球IT管理最佳实践之DevOps Master 认证
原文:http://soft.chinabyte.com/30/13940030.shtml 作者:国际最佳实践管理联盟 孙振鹏 关键字: DevOps.DevOps认证.DevOpsDays.Dev ...
- 企业DevOps研发模式下CI/CD实践详解指南
阅读全文大概需要 10分钟. 1. 前言 借着公司今年新组建的中台研发部东风,我作为其中的主要负责人,在研发中心主导推行DevOps研发管理模式转变及质量管理创新建设,本篇文章摘取自今年9月底,笔者在 ...
- 腾讯 Techo 开发者大会首发来袭!云原生中间件技术实践等你来!
腾讯 Techo 开发者大会是由腾讯云发起的面向全球开发者和技术爱好者的年度盛会,2019 年 11 月 6 日 - 7 日将在北京嘉里大酒店首次召开. 作为一个专注于前沿技术研讨的非商业大会,Tec ...
- Java 理论与实践: 哈希
有效和正确定义hashCode()和equals() 每个Java对象都有 hashCode() 和 equals() 方法.许多类 Override 这些方法的缺省实施,以在对象实例之间提供更深层次 ...
- 围绕 Kubernetes 的 8 大 DevOps 生产关键实践
本文主要介绍 DevOps 的 8 大关键实践在 Kubernetes 平台下如何落地,结合我们目前基于 Kubernetes 平台的 DevOps 实践谈谈是如何贯彻相关理念的,这里不会对其具体实现 ...
- 重磅:前端 MVVM 与 FRP 的升阶实践 —— ReRest 可视化编程
ReRest (Reactive Resource State Transfer) 是前端开发领域新兴的方法论体系,它继承了 MVVM 与 FRP 编程理念,在技术上有不少创新.本文从专利稿修改而来, ...
- CI Weekly #5 | 微服务架构下的持续部署与交付
CI Weekly 围绕『 软件工程效率提升』 进行一系列技术内容分享,包括国内外持续集成.持续交付,持续部署.自动化测试. DevOps 等实践教程.工具与资源,以及一些工程师文化相关的程序员 Ti ...
随机推荐
- windows下多Python环境指定pip安装模块到对应Python环境下
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿在windows下装了2套Python,一套是直接安装的Pytho ...
- PyQt(Python+Qt)学习随笔:复选框状态枚举类Qt.CheckState取值及含义
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 老猿Python,跟老猿学Python! 老猿Python博文目录 专栏:使用PyQt开发图形界面P ...
- AtCoder Regular Contest 109
Contest Link 为什么还没有 Official Editorial 啊--哦,原来是日文题解,那没事了. A - Hands 有两幢 100 层的楼房 \(A,B\) ,将地面所在的楼层称为 ...
- 【题解】「CF1352A」Sum of Round Numbers
应该是纯模拟吧. 直接输入一个字符串,然后一位一位看,如果不是0,就 k++,并计算这个数的真实的值,最后输出就行了. #include<iostream> #include<cst ...
- AcWing 330. 估算
大型补档计划 题目链接 若 \(K = 1\),显然,\(B[i]\) 取 \(A\) 序列的中位数时最优. 考虑扩展,我们只需要把 \(A\) 分成 \(K\) 段,每段内, \(B\) 最优的取值 ...
- 四、Zookeeper伪集群搭建
伪集群模式 Zookeeper不但可以在单机上运行单机模式 Zookeeper,而且可以在单机模拟集群模式 Zookeeper的运 行,也就是将不同实例运行在同一台机器,用端口进行区分,伪集群模式为我 ...
- C++ 虚函数表与多态 —— 虚函数表的内存布局
C++面试经常会被问的问题就是多态原理.如果对C++面向对象本质理解不是特别好,问到这里就会崩. 下面从基本到原理,详细说说多态的实现:虚函数 & 虚函数表. 1. 多态的本质: 形 ...
- 我用 go-zero 一周实现了一个中台系统,已开源!
作者:Jack 最近发现golang社区里出了一个新星的微服务框架,来自好未来,光看这个名字,就很有奔头,之前,也只是玩过go-micro,其实真正的还没有在项目中运用过,只是觉得 微服务,grpc ...
- swift笔记简录
一,变量和常量 /***************************基本数据类型*************************/ /****************************** ...
- C#读取DLL文件获取所有类
说明 调用Web.dll 文件,获取其中的所有的WebService 参考 https://blog.csdn.net/huoliya12/article/details/78873123 流程 使用 ...