zoukankan      html  css  js  c++  java
  • light-rtc: 理念与实践

     

     

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

    作者:阿里云智能技术专家 熊金水

    理念

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

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

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

    架构

    模块拆解

    file
    WebRTC 的核心模块,包括:

    音频

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

    视频

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

    通用

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

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

    仓库管理

    file
    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 硬解卡死等问题;
    • 新的音频编码器,适配商用接收端;
      ……
      file

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

    ADM

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

    另外,虽然 WebRTC 支持样本数量的监控,但是当前只用于打印日志,如果想在此基础上做更多事情(如:发现采集样本为 0 时,重启采集),则单独做一个 AudioSampleMoniter 的类,比较有利于扩展。
    file
    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 内部模块的数据流程图:
    file
    从图中可以看出,APM 其实也为插件化做了准备,但是只在近端信号的尾部、远端信号的头部。从 APM 构造函数上也可以看出来:
    file
    滤波/均衡,可以方便的实现一个 CustomProcessing 的 render_pre_processor。

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

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

    AM

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

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

    FEC

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

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

    CC

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

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

    关联模块:

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

    file

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

  • 相关阅读:
    查看mysql版本的四种方法及常用命令
    newInstance和new的区别(good)
    Citrix 服务器虚拟化之六 Xenserver虚拟机创建与快照
    Java实现 蓝桥杯 算法训练 排序
    Java实现 蓝桥杯 算法训练 排序
    Java实现 蓝桥杯 算法训练 排序
    Java实现 蓝桥杯 算法训练 2的次幂表示
    Java实现 蓝桥杯 算法训练 2的次幂表示
    Java实现 蓝桥杯 算法训练 前缀表达式
    Java实现 蓝桥杯 算法训练 前缀表达式
  • 原文地址:https://www.cnblogs.com/wjxzs/p/14244961.html
Copyright © 2011-2022 走看看