WebRTC模块处理机制的实现

1. 前言

WebRTC是一个由Google发起的实时通讯解决方案,其中包含视频音频采集,编解码,数据传输,音视频展示等功能,我们可以通过技术快速地构建出一个音视频通讯应用。虽然其名为WebRTC,但是实际上它不光支持Web之间的音视频通讯,还支持Android以及IOS端,此外由于该项目是开源的,我们也可以通过编译C++代码,从而达到全平台的互通,本文主要介绍WebRTC的模块处理机制。

对于实时音视频应用来讲,媒体数据从采集到渲染,在数据流水线上依次完成一系列处理。流水线由不同的功能模块组成,彼此分工协作:数据采集模块负责从摄像头/麦克风采集音视频数据,编解码模块负责对数据进行编解码,RTP模块负责数据打包和解包。数据流水线上的数据处理速度是影响应用实时性的最重要因素。与此同时,从服务质量保证角度讲,应用需要知道数据流水线的运行状态,如视频采集模块的实时帧率、当前网络的实时速率、接收端的数据丢包率,等等。各个功能模块可以基于这些运行状态信息作相应调整,从而在质量、速度等方面优化数据流水线的运行,实现更快、更好的用户体验。

2. WebRTC数据流水线

我们可以把WebRTC看作是一个专注于实时音视频通信的SDK。其对外的API主要负责PeerConnection建立、MediaStream创建、NAT穿透、SDP协商等工作,对内则主要集中于音视频数据的处理,从数据采集到渲染的整个处理过程可以用一个数据流水线来描述,如图1所示。

WebRTC模块处理机制的实现
图1 WebRTC音视频数据流水线

音视频数据首先从采集端进行采集,一般来说音频数据来自麦克风,视频数据来自摄像头。在某些应用场景下,音频数据来自扬声器,视频数据来自桌面共享。采集端的输出是音视频Raw Data。然后Raw Data到达编码模块,数据被编码器编码成符合语法规则的NAL单元,到达发送端缓冲区PacedSender处。接下来PacedSender把NAL单元发送到RTP模块打包为RTP数据包,最后经过网络模块发送到网络。

在接收端,RTP数据包经过网络模块接收后进行解包得到NAL单元,接下来NAL单元到达接收端缓冲区(JitterBuffer或者NetEQ)进行乱序重排和组帧。一帧完整的数据接收并组帧之后,调用解码模块进行解码,得到该帧数据的Raw Data。最后Raw Data交给渲染模块进行播放/显示。

在数据流水线上,还有一系列模块负责服务质量监控,如丢帧策略,丢包策略,编码器过度使用保护,码率估计,前向纠错,丢包重传,等等。

WebRTC数据流水线上的功能单元被定义为模块,每个模块从上游模块获取输入数据,在本模块进行加工后得到输出数据,交给下游模块进行下一步处理。WebRTC的模块处理机制包括模块和模块处理线程,前者把WebRTC数据流水线上的功能部件封装为模块,后者驱动模块内部状态更新和模块之间状态传递。模块一般挂载到模块处理线程上,由处理线程驱动模块的处理函数。下面分别描述之。

3. WebRTC模块

WebRTC模块虚基类Module定义在webrtc/modules/include/modue.h中,如图2所示。

WebRTC模块处理机制的实现
图2 模块虚基类Module定义

Module虚基类对外提供三个函数作为API:TimeUntilNextProcess()用来计算距下次调用处理函数Process()的时间间隔;Process()是模块的处理函数,负责模块内部运行监控、状态更新和模块间通信;ProcessThreadAttached()用来把模块挂载到模块处理线程,或者从模块处理线程分离出来,实际实现中这个函数暂时没有被用到。

Module的派生类分布在WebRTC数据流水线上的不同部分,各自承担自己的数据处理和服务质量保证任务。

4. WebRTC模块处理线程

WebRTC模块处理线程是模块处理机制的驱动器,它的核心作用是对所有挂载在本线程下的模块,周期性调用其Process()处理函数处理模块内部事务,并处理异步任务。其虚基类ProcessThread和派生类ProcessThreadImpl如图3所示。

WebRTC模块处理机制的实现
图3 模块处理线程虚基类

ProcessThread基类提供一系列API完成线程功能:Start()/Stop()函数用来启动和结束线程;WakeUp()函数用来唤醒挂载在本线程下的某个模块,使得该模块有机会马上执行其Process()处理函数;PostTask()函数用来邮递一个任务给本线程;RegisterModule()和DeRegisterModule()用来向线程注册/注销模块。

WebRTC基于ProcessThread线程实现派生类ProcessThreadImpl,如图3所示。在成员变量方面,wake_up_用来唤醒处于等待状态的线程;thread_是平台相关的线程实现如POSIX线程;modules_是注册在本线程下的模块集合;queue_是邮递给本线程的任务集合;thread_name_是线程名字。在成员函数方面,Process()完成ProcessThread的核心任务。

5. WebRTC模块处理线程实例

WebRTC关于模块和处理线程的实现在webrtc/modules目录下,该目录汇集了所有派生类模块和模块处理线程的实现及实例分布。本节对这些内容进行总结。

WebRTC目前创建三个ProcessThreadImpl线程实例,分别是负责处理音频的VoiceProcessTread,负责处理视频和音视频同步的ModuleProcessThread,以及负责数据平滑发送的PacerThread。这三个线程和挂载在线程下的模块如图4所示。

WebRTC模块处理机制的实现
图4 模块处理线程实例

VoiceProcessThread线程由Worker线程在创建VoiceEngine时创建,负责音频端模块的处理。挂载在该线程下的模块如图4所示,其中MonitorModule负责对音频数据混音处理过程中产生的警告和错误进行处理,AudioDeviceModuleImpl负责对音频设备采集和播放音频数据时产生的警告和错误进行处理,ModuleRtpRtcpImpl负责音频RTP数据包发送过程中的码率计算、RTT更新、RTCP报文发送等内容。

ModuleProcessThread线程由Worker线程在创建VideoChannel时创建,负责视频端模块的处理。挂载在该线程下的模块如图4所示,其中CallStats负责Call对象统计数据(如RTT)的更新,CongestionController负责拥塞控制,VideoSender负责视频发送端统计数据的更新,VideoReceiver负责视频接收端统计数据更新和处理状态反馈(如请求关键帧),ModuleRtpRtcpImpl负责视频RTP数据包发送过程中的码率计算、RTT更新、RTCP报文发送等内容,OveruseFrameDetector负责视频帧采集端过载监控,ReceiveStatisticsImpl负责由接收端统计数据触发的码率更新过程,ViESyncModule负责音视频同步。

PacerThread线程由Worker线程在创建VideoChannel时创建,负责数据平滑发送。挂载在该线程下的PacedSender负责发送端数据平滑发送;RemoteEstimatorProxy派生自RemoteBitrateEstimator,负责在启用发送端码率估计的情况下把接收端收集到的反馈信息发送回发送端。

由以上分析可知,WebRTC创建的模块处理线程实例基本上涵盖了音视频数据从采集到渲染过程中的大部分数据操作。

6. 总结

本文在深入分析WebRTC源代码基础上,学习研究其模块处理机制的实现细节,为进一步全面理解WebRTC的技术原理奠定基础。

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(1)

相关推荐

发表回复

登录后才能评论