light-rtc: 理念与实践

简介: 在与同行交流过程中,发现很多同行对 WebRTC 改动太多,导致无法升级 WebRTC 版本。而 WebRTC 开源社区的快速迭代,让他们感到欣喜又焦虑:开源社区的迭代效果,是不是超过了他们对 WebRTC 的优化效果?我们针对特定场景优化 WebRTC 时,怎么紧跟 WebRTC 开源社区通用的优化?

作者:熊金水
来源:light-rtc: 理念与实践

理念

简言之,把 WebRTC 作为 Framework 使用,而不是 Library,即:WebRTC 仓库轻量化,核心模块插件化。

详细的,WebRTC 作为 Framework 串联核心模块;核心模块既可以以插件形式使用我们的实现,也可以 Fallback 到 WebRTC 的默认实现。目的是减少 WebRTC 冲突的可能性,提高升级 WebRTC 的敏捷性。

目标:一年升级一次 WebRTC,一次花费一个人月。

架构

模块拆解

image.png

WebRTC 的核心模块,包括:
音频

  • ADM 采集、APM、ACM 编码;
  • NetEQ 与解码、AM、ADM 渲染;

视频

  • 采集、编码;
  • JB、解码、渲染;

通用

  • RTP 打包与解包、FEC 生成与恢复、CC 与 Pacer、ICE、SDP 信令等。

WebRTC 在长期的演进中,API 已经具备了作为 Framework 的大部分能力。红色的核心模块,已经基本可以插件化,如下面的 API:
image.png

仓库管理

image.png

light-rtc 作为 WebRTC 仓库,我们需要保留两个 Remote,一个是 Alibaba,一个是 Google。升级 WebRTC 时,我们从 Google 上 Pull 最新代码, 解决冲突,然后 Push 到 Alibaba。

对插件化的模块,我们需要放到单独的仓库 lrtc-plugin 里,这样有两个好处:

  1. 对 light-rtc 仓库改动少,减少与 Google 冲突的可能性;
  2. 更重要的,让每个开发同学,在每次改动前,更主动、更有意识的思考,放到哪个仓库更合适,否则容易惯性思维,直接改动 light-rtc。

对 lrtc-plugin 依赖的第三方库,也应该以单独的仓库存在,并保留两个 Remote,比如 Opus,这样,即使修改了 Opus 源码,仍然可以像升级 light-rtc 一样,方便的单独升级 Opus 版本。

模块

Codec

  • 音频编解码器、视频编解码器,是我们最常优化的部分之一:
  • 新的编码工(AV1/SCC/ROI 等)优化视频质量和带宽;
  • 分辨率自适应,使不同能力(编码能力、发送带宽等)的发送端,发送不同分辨率的码流;
  • Simulcast,为不同能力(解码能力、显示能力、接收带宽等)的接收端,提供不同分辨率码流;
  • SVC,提供时域 / 空域分层;
  • 新的视频解码实现,规避 Mac 硬解卡死等问题;
  • 新的音频编码器,适配商用接收端;
  • ……

image.png

这部分插件化是相对简单的,只需要实现自己的 [Video|Audio][Encoder|Decoder] Factory 即可。以 Simulcast 为例,在自己实现的 VideoEncoderFactory 里,先用 WebRTC 原始的 VideoEncoderFactory,创建多个 Encoder 对象,然后封装到一个 Simulcast Encoder 里。

ADM

很可惜,ADM (Audio Device Module) 没有提供检测设备插拔的功能,需要增加 Callback 接口。

另外,虽然 WebRTC 支持样本数量的监控,但是当前只用于打印日志,如果想在此基础上做更多事情(如:发现采集样本为 0 时,重启采集),则单独做一个 AudioSampleMoniter 的类,比较有利于扩展。
image.png

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 内部模块的数据流程图:

image.png

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

滤波 / 均衡,可以方便的实现一个 CustomProcessing 的 render_pre_processor。

其他的优化,遵循轻量化 / 插件化的理念,没有现成的插件接口,我们可以创造新的插件接口,如啸叫抑制,以及 AECM 优化的部分算法。

但 APM 仍然会有很多没办法插件化的,只能修改 light-rtc 仓库,如 AECM Double Talk 优化等。

AM

AM (Audio Mixer) 的插件化,可以在不修改 light-rtc 的基础上,玩出很多花样:

  • 播放本地文件;
  • 借助语音检测算法,优化语音排序,从而选出更准确的语音做混音;
  • Mono 变成 Stereo,借助 HRTF,可以在多方同时说话时提高说话人辨识度和可懂度;
  • 对 RTP 方案的回放,倍速回放时变速不变调;
  • ……

image.png

FEC

FEC (Forward Error Correction),常见的修改:

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

image.png

CC

CC (Congestion Control),包含两个方面,一个是 CC 算法本身,一个是 CC 关联模块。

算法本身,可以用不同的算法实现,如 WebRTC 默认的 goog_cc,也可以是 BBR,甚至是满足 WebRTC::NetworkControllerFactoryInterface 接口的外部插件。

关联模块:

  • 带宽分配:不同场景可能不一样,如视频会议里,需要 “保音频、保屏幕”。可以通过 rtc::BitrateAllocationStrategy 实现插件化。

image.png

  • 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 仓库里实现。

image.png

让 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

「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

image.png

相关文章
|
6月前
|
算法 数据可视化 前端开发
第三代软件开发-简易视频播放器-自定义Slider (二)
欢迎来到我们的 QML & C++ 项目!这个项目结合了 QML(Qt Meta-Object Language)和 C++ 的强大功能,旨在开发出色的用户界面和高性能的后端逻辑。 在项目中,我们利用 QML 的声明式语法和可视化设计能力创建出现代化的用户界面。通过直观的编码和可重用的组件,我们能够迅速开发出丰富多样的界面效果和动画效果。同时,我们利用 QML 强大的集成能力,轻松将 C++ 的底层逻辑和数据模型集成到前端界面中。 在后端方面,我们使用 C++ 编写高性能的算法、数据处理和计算逻辑。C++ 是一种强大的编程语言,能够提供卓越的性能和可扩展性。我们的团队致力于优化代码,减少资
|
6月前
|
算法 数据可视化 前端开发
第三代软件开发-自定义Slider(一)
欢迎来到我们的 QML & C++ 项目!这个项目结合了 QML(Qt Meta-Object Language)和 C++ 的强大功能,旨在开发出色的用户界面和高性能的后端逻辑。 在项目中,我们利用 QML 的声明式语法和可视化设计能力创建出现代化的用户界面。通过直观的编码和可重用的组件,我们能够迅速开发出丰富多样的界面效果和动画效果。同时,我们利用 QML 强大的集成能力,轻松将 C++ 的底层逻辑和数据模型集成到前端界面中。 在后端方面,我们使用 C++ 编写高性能的算法、数据处理和计算逻辑。C++ 是一种强大的编程语言,能够提供卓越的性能和可扩展性。我们的团队致力于优化代码,减少资
|
8月前
|
传感器 存储 物联网
STM32F103产品级开源项目:iLook.Time设计解读
STM32F103产品级开源项目:iLook.Time设计解读
96 0
|
8月前
|
传感器 物联网 芯片
超轻量级网红软件定时器multi_timer(51+stm32双平台实战)
超轻量级网红软件定时器multi_timer(51+stm32双平台实战)
292 0
|
11月前
|
存储 机器学习/深度学习 Dragonfly
龙蜥社区首次突破!高性能存储 SIG 现身 LSF/MM/BPF 2023 分享 EROFS 的演进路线
Gao Xiang 在 LSF/MM/BPF 会议中做了 EROFS 文件系统的介绍:EROFS 已成为安卓系统分区推荐方案,目前它越来越不局限于原始目标场景,不断突破自身应用边界。例如,在龙蜥社区合作伙伴的努力下,EROFS 的容器镜像场景也有许多应用落地。
|
存储 编解码 缓存
RISC-V生态全景解析(十三):YoC组件介绍系列三:AV(多媒体)组件
编辑语: 芯片开放社区(OCC)面向开发者推出RISC-V系列内容,通过多角度、全方位解读RISC-V,系统性梳理总结相关理论知识,构建RISC-V知识图谱,促进开发者对RISC-V生态全貌的了解。
570 0
RISC-V生态全景解析(十三):YoC组件介绍系列三:AV(多媒体)组件
|
物联网 调度 开发工具
技术解码 | YoC组件开发系列一:如何向OCC发布芯片产品组件
技术解码栏目:是面向开发者详细解读芯片开放社区(OCC)上关于处理器、芯片、基础软件平台、集成开发环境及应用开发平台的相关技术,方便开发者学习及快速上手,提升开发效率。
379 0
技术解码 | YoC组件开发系列一:如何向OCC发布芯片产品组件
|
Go 开发工具 C#
产品百科 |零门槛玩转 RTC Unity Demo
本章节为您介绍了 Unity Demo 的集成操作步骤。
产品百科 |零门槛玩转 RTC Unity Demo
|
开发工具 iOS开发
产品百科 |零门槛玩转 RTC iOS Demo
您可以阅读本文,了解快速运行 iOS Demo 的操作方法,实现加入频道和远端用户进行音视频通信。
产品百科 |零门槛玩转 RTC iOS Demo