本文根据霍锴(七牛云 音视频客户端架构师)于 2021 年 6 月 26 日举办的「ECUG Meetup 第 1 期 | 2021 音视频技术最佳实践·杭州站」上的分享整理而成。
获取「讲师完整版 PPT」 ,请添加 ECUG 小助手微信(微信ID:ECUGCON)并备注「ECUG PPT」。其余讲师的分享也将于后续陆续放出,敬请期待。
以下为分享正文:
大家好,我先进行一个自我介绍。我叫霍锴,是七牛云的音视频客户端架构师,2017 年加入七牛云,主导和参与开发了短视频、推流、播放器等多个音视频相关 SDK,目前工作主要是集中在实时音视频 SDK 的设计和研发,主要精力还是在客户端上。
这是我今天为大家讲的内容:
1)实时音视频 SDK 的技术与挑战
2)七牛实时音视频 SDK 的架构
3)实时音视频 SDK 的实践经验
简单来说就是分享在开发实时音视频SDK的过程中,我们经常遇到的问题,以及怎么去做优化,可以说是我们的一些实践经验。
一、实时音视频 SDK 的技术与挑战
今天是音视频专场,相信在座各位肯定对音视频技术都有所了解或者是有所经验的,但是不知道有多少人曾经做过或者设计过 SDK,它其实也有其独特的挑战。
1. 客户对实时音视频 SDK 的诉求
七牛云作为一家提供技术服务的公司,经常会听到很多的客户声音,比如客户经常会问, 视频的码率应该配置多少,某个接口调用之后为什么没有效果,第三方美颜如何接入等问题。
此外,一些客户在使用过程中有可能遇到一些异常的现象,比如说出现花屏、黑屏、加入房间失败等等。
还有就是,客户也经常会给我们提出一些功能需求,比如有些客户想同时发布摄像头和手机屏幕上两部分的视频内容,或者想获取每路的视频或音频帧数据等等。
遇到这些问题之后,我们按照发现问题、分析问题和解决问题的步骤,一点一点的把问题解决。首先让我们静下心来好好去分析一下,这些问题背后的诉求是什么。简单来说,我们总结了三点:
1)接入者的音视频技术水平参差不齐,但是无一例外,都希望能够快速接入。
我们不能强制要求客户的音视频技术要达到某一个高度才能接入这个SDK,所以我们只能给自己提要求:SDK 要设计得极为简单易用,这样才能让用户尽可能快地去接入。
2)接入者的使用场景和环境复杂多变,但是对音视频的体验要求都很高。
比如,视频会议场景对于延迟的要求很高,超过 300 毫秒就能会很明显地感知到对方说话有所延迟。而在直播的场景下,用户则对清晰度的要求很高,一个主播可能会面对海量观众,主播的画面不清晰,对观众的影响是非常大的。再比如,同样是直播场景,户外直播和室内直播是两个截然不同的环境,但我们都要保证在现有环境下能够给用户最好的音视频体验。
3)接入者需要“安全感”,对服务的稳定性、监测手段、排障能力都有要求。
接入者需要真实地感知到线上用户的使用情况,包括音视频的实时质量,发生的错误或异常,另外就是一旦出现了问题,无论是 SDK 的原因还是用户使用姿势的原因,都要能够迅速排障,把影响减到最低。
2. 实时音视频 SDK 的核心要求
根据客户的诉求,我们可以去定义一款优秀的实时音视频 SDK 的规格:
1)接口简单,边界清晰。
不能让接入者调用我们 API 的时候有模棱两可的感觉,接口一定要简单清晰,从而方便用户调用。
2)扩展性强,生态化好。
在 SDK 的基础上能方便地扩展功能,比如高级美颜、人脸审核、语音转文字等。我们的做法是在 SDK 上层根据不同的场景,为用户做了不同的插件,最大程度地方便用户进行扩展。
3)按场景进行抽象和优化,扩展功能。
刚才已经提到,对于视频会议和直播场景,音视频质量的要求是有所区别的,所以我们应该针对不同的场景进行优化,并尽可能地提供覆盖该场景的核心功能。
4)首帧、卡顿、延迟、回声等音视频体验极致优化。
这些都是影响音视频体验的最核心的指标,所以在 QoS 的优化方面,我们无论做多少努力都不会过分。
5)服务稳定可靠,丰富的数据埋点,可视化的数据监测与分析。
可靠性是一个技术服务的前提,而数据化又是保证可靠性的前提。
3. 实时音视频 SDK 的技术难点
说了这么多,大家也能够感知到,想把一款实时音视频 SDK 做好还是非常难的,更加详细的来说,它的技术难点都有什么呢?我稍微给大家列举了一些:
包括音视频的采集、编码、传输。还有视频处理和音频处理,比如美颜滤镜和混音。以及弱网的优化,数据的打点上报,崩溃分析,音频的 3A 算法等等。
除此之外,还有兼容性的适配,性能的优化等方面。这些都是我们需要面对和解决的技术难点,后面我会在第三部分实践篇为大家简单介绍一下我们的一些经验。
二、七牛云实时音视频 SDK 的架构
接下来,我为大家介绍一下七牛云实时音视频 SDK 是怎么设计的。首先,让我们看一下七牛云实时音视频 SDK 的迭代历程。
2018 年,我们上线了 1.0 版本,支持核心的音视频通信功能,之后,我们发现越来越多的客户都会在房间内发布不止一路的流,比如屏幕内容和摄像头采集的内容,所以我们就在 2.0 的版本上支持了多 track,也就是支持用户发布多路流的方案。再往后到 3.0,我们想做到让每个人在当前的网络环境下能够体验到的音视频的体验是最好的,所以我们又做了大小流策略。
另外,我们不仅只是做了 SDK 的正常迭代,同时还发布了一些配套的解决方案,比如视频会议方案、互动直播方案、在线面试方案。除此之外,还提供了一些插件,比如美颜插件,方便客户去接入美颜 SDK,还有马上要推出的白板插件,方便教育场景的用户方便接入。
1. 七牛云实时音视频 SDK 的模块划分
这是七牛云实时音视频 SDK 的模块划分:
最底层是我们依赖的一些外部库,比如我们通过 WebRTC 实现 SDK 的通信,通过 WebSocket 做信令的传输,其他还有我们自研的像 HappyDNS,QNBeautyLib,QNEncoderLib, QNAECLib 等等。
往上面一层,我们在底层基础之上,按照业务模块做了一些封装,其中有:
- CameraManager,负责摄像头的采集,旋转、曝光值、对焦等功能。
- MicrophoneManager,负责麦克风的采集。
- RenderProcesser,负责视频处理,比如水印,剪裁,美颜,滤镜等功能。
- AudioProcesser,负责音频处理,比如音频的重采样,混音等功能。
- RoomManager,负责加入房间、发布、订阅等核心功能。
- CrashReporter,负责在发生崩溃的时候,及时把堆栈信息给上报上来。
再往上的一层,我们提供了核心的 API,另外还有高级美颜,白板等插件。
最上层的就是用户自己的业务层。
2. 七牛云实时音视频 SDK 数据流程
接下来为大家简单介绍一下七牛云实时音视频 SDK 的数据流转是怎样的。
1)采集数据:从摄像头或者屏幕去采集视频数据,从麦克风采集音频数据,采集到的视频数据有 YUV 和纹理数据,音频的 PCM 数据。
2)数据处理:采集完以后,就送到音频处理和视频处理模块,视频可以做美颜、水印、镜像等处理,音频可以做重采样和混音等处理。
3)编码:处理完之后,把数据送到视频编码器和音频编码器里,可以选择软编或者硬编。编码后输出的是 H.264 和 Opus 数据包。
4)封装:把编码之后的这些数据送到音视频的封装模块里进行封装。
5)上传:把封装好的数据包通过 RTP 协议传输到我们的流媒体服务器。
6)转发:流媒体服务器进行转发,把数据传输给房间内的订阅端用户。
订阅端和发布端的流程刚好是逆向的,通过解封装,解码,音视频的处理,最后渲染!
三、实时音视频 SDK 的实践经验
接下来为大家介绍一下我们在实时音视频 SDK 的一些实践经验。
1. 可扩展性美颜插件
首先,给大家介绍的是我们的可扩展性美颜插件。不少用户觉得在接入美颜 SDK 的时候,和音视频 SDK 的结合会很难。因为使用美颜 SDK 前可能会需要使用 OpenGL 对视频帧做一些预处理,而这一点对用户来说是比较难的,所以我们在美颜 SDK 和 RTC SDK 之间做了一个插件,如下图:
首先,我们通过 RTC SDK 去做摄像头的采集,然后把采集的数据先给美颜插件这一层。美颜插件处理哪些事情呢?包括美颜特效资源的加载,或者把 OES 纹理转为 2D 纹理,又或者把摄像头采集的纹理的角度转正。我们把经过插件处理之后、符合美颜 SDK 规格的纹理数据输入进去,经过美颜 SDK 的美颜、美妆、滤镜、贴纸等处理,处理完之后,再把这张纹理返回到 RTC SDK 里,最后再进行预览、编码和传输。
这是我们内部实现的细节,内部处理过程还是比较复杂的,但对外其实非常简单,对外我们只提供最简单的只个接口,比如说 setBeauty、setSticker、setFilter 等,从而让用户减少接入成本。
2. 大小流策略
接下来为大家介绍一下大小流的策略。
为什么要有大小流策略?我们想做到在每个用户的网络环境下,它的音视频体验能够达到最好。举个例子:用户A发布了一路视频,这路视频送到编码器里会出来三路,分别是高、中、低分辨率三路视频,然后给到流媒体服务器。
流媒体服务器进行转发的时候,会根据用户 B 和 C、D 的网络带宽情况进行订阅。比如说用户 B 的网络环境比较好,那么就直接订阅最高分辨率的这一路;D 的网络环境不好,且在弱网环境下,就订阅最低的分辨率。用户 B 的网络环境如果发生变化,一开始订阅高分辨率,之后网络环境变差了,那就自动回退到低分辨率,用户就不会出现卡顿现象,能保持流畅性。
3. QoS 优化
QoS 优化在整个音视频体验中是非常重要的一个地位,无论怎么强调都不过分。我们在 WebRTC 的基础上,主要从以下方面做的优化。
1)带宽估计:带宽估计我们主要使用了 GCC、BBR 等算法。
2)抗丢包:抗丢包方面我们主要针对数据冗余包和丢包重传的智能结合方面做了优化。
3)平滑抖动:平滑抖动包括 Neteq、Jitterbuffer 等方面的优化。
4)带宽分配:带宽分配包括音频优先、视频分层、发送兼顾上下行等策略,或者结合用户的场景和业务来制定对应的分配策略
4. 回声消除优化
接下来我通过两个场景给大家介绍一下我们对回声消除的优化。
上面左右两张频谱图分别代表着两种场景,每幅图都有三行数据:
第一行:原声音的声音信号图像;
第二行:用 WebRTC 自带的回声消除过滤后的图像;
第三行:用七牛云自研的回声消除过滤后的图像。
左边这张图的场景是一个人说话的时候,背景会放一个特别嘈杂的背景音乐,我们想要把后面的背景音乐消掉。可以看到,中间这一行还是可以看到下面有明显的连续横线,这是残留的音乐声音图像。左边第三行可以很明显地看到这些音乐声音毫无残留地被消除,消除得比较彻底。
右边这张图是一个语音通话的场景,主要是双讲模式:A 正在说话,忽然对方 B 也开始说话,此时我们不希望把 A 用户的声音消掉。但用 WebRTC 自带的回声消除算法,会把 A 的一些声音过滤掉,而从右图第三行对比看出,我们自研的回声消除算法,“吃字”现象要好得多。
5. 兼容性优化
兼容性是我们遇到的非常头疼的一件事情。比如在第一页上用户提出的在某个机器上出现的花屏或者回声的现象,都可以归结到兼容性的问题上。兼容性的优化,总体来说我们分为两种策略:
第一种策略,动态切换策略。在运行的过程中,编码器是能够动态切换的。
比如我们设置的编码配置,在某一款手机上打开硬编码器的时候,会出现开启失败的异常,此时我们首先要捕获异常,然后在用户无感知的情况下去切换为软编码器,而使得这个功能正常使用。
另一个例子,在用户使用软编码器的时候,某个手机上的编码效率极低,FPS 远远低于我们的预期值,此时我们也会打开硬编码器进行对比,看看哪个编码器的效率更为出色,从而在用户无感知的时候动态切换最为适合的编码器进行编码。
第二种策略,白名单策略。在初始化 RTC SDK 的时候,要根据探测到的一些设备,让服务器自动下发配置白名单。
比如某一款 Android 手机,在硬编场景下,分辨率如果不是 16 的倍数则会出现花屏现象。我们就把这些机型归纳总结,整理到我们的配置白名单上,当检测到是这种机型时,我们就把分辨率调整为 16 的倍数,或者说把手机的硬编码器切换成软编码器进行编码,从而解决花屏的兼容性问题。
再举个例子,采样率为 48K 的时候,我们发现有一些手机的回声消除效果非常不好,所以当检测到这个设备后,可以把 48K 的采样率调到 16K,或者切换成自研的回声消除策略,从而解决回声的兼容性问题。
6. 数据的采集与上报
对于数据的采集与上报模块,我们提出了三个要求:
1)实时上报。RTC SDK,不能在整个操作结束以后再上报,而是需要实时地把一些数据给上报上来。
2)动作还原。要能够通过采集到的 SDK 日志,真实地去还原用户调用 SDK 的情况。比如在第一页有客户提到为什么调用某个接口没有效果,或者为什么进入房间会失败,我们通过上报的日志还原经常帮用户发现其接口调用的顺序,或者传递的参数错误,从而迅速帮客户进行排障。
3)模块隔离。数据采集与上报模块,一定不能够影响到正常的音视频通信模块,也就是不能影响主业务模块,哪怕出现了一些异常,也要把这些异常捕获,不能因为采集率上报出现了问题,导致用户用不了这个服务。
我们采集哪些内容呢?首先向大家申明,七牛云不会去采集用户的私有数据,这是绝对不允许的。从大的方面来说,包括两部分内容:SDK基础信息和音视频质量信息。
- SDK基础信息:包括SDK的调用日志、错误与崩溃信息、设置型号信息、SDK内部状态等信息。
- 音视频质量信息:包括首帧时间、实时帧率、实时码率、实时丢包率等信息。
7. 数据的监测与分析
最后,我们要把采集到的数据进行可视化的监测和分析。
这张图举的例子就是我刚才说的动作还原,我们可以通过这张图很清楚地看到用户调用了哪些接口、调用顺序是什么样的、内部的状态又是什么样的。从初始化,到加入房间、发布、订阅,最后退出房间,在后台我们都可以看清楚,只要用户使用姿势错误,我们能够马上感知到。
这张图是某一路流实时码率的数据。
因为是实时上报,所以我们能够看到当前的码率、帧率、丢包率、rtt 等一系列影响音视频体验的核心指标,当这些曲线有很大幅度变化的时候,我们可以在一些门槛上做一些阀值,从而触发报警机制。
Q & A
提问:今天这个主题是关于音视频的,但我们可能平时接触的还是摄像头的人脸识别这种比较多,能不能用到SDK技术?
霍锴:我们之后会基于实时音视频 SDK 提供一套包括人脸识别,活体检测,语音转文字等功能的插件,这套插件的背后是和我们七牛云的智能多媒体服务相通的,从而方便用户在音视频通话的过程中去实现人脸识别等相关功能。
提问:不同的手机机型的硬编能力是不一样的,各个厂家实现的底层技术也不一样,刚才您提到一些兼容性的问题,但是在实际做的时候,硬编要依赖于厂家的编码器能力,所以它在编码的时候要保持码率的,但是硬编的一些编码器是做不到的。那么,七牛云是首先推硬编,还是优先推荐软编?
霍锴:我们优先推荐使用硬编码,因为硬编的效率比较好。但是有一个前提,硬编码器出现问题的时候,需要立即感知到,感知到之后,通过动态切换的策略,自动切换成软编。
关于七牛云、ECUG 和 ECUG Meetup
七牛云:七牛云成立于 2011 年,作为国内知名的云计算及数据服务提供商,七牛云持续在海量文件存储、CDN 内容分发、视频点播、互动直播及大规模异构数据的智能分析与处理等领域的核心技术进行深度投入,致力于以数据科技全面驱动数字化未来,赋能各行各业全面进入数据时代。
ECUG:全称为 Effective Cloud User Group(实效云计算用户组),成立于 2007 年的 CN Erlounge II,由许式伟发起,是科技领域不可或缺的高端前沿团体。作为行业技术进步的一扇窗口,ECUG 汇聚众多技术人,关注当下热点技术与尖端实践,共同引领行业技术的变革。
ECUG Meetup :ECUG、七牛云联合打造的技术分享系列活动,定位于开发者以及技术从业者的线下聚会,目标是为开发者打造一个高质量的学习与社交平台,期待每一位参会者之间知识的共创、共建和相互影响,产生新知推动认知发展以及技术进步,通过交流促进行业共同进步,为开发者以及技术从业者打造更好的交流平台与发展空间。