在Webrtc中存在两种不同的audio level定义,本篇文章我们将介绍下这两种不同的audio level。 AudioDeviceBuffer中的level 在WebRTC中通过AudioDeviceBuffer传递采集播放数据,这里我们将介绍AudioDeviceBuffer中的audio level相关情况。首先先简单介绍下AudioDeviceBuffer在采集播放过程的作用。 音频采集 音频采集模块通过调用AudioDeviceBuffer的SetRecordedBuffer与DeliverRecordedData传递采集数据。 SetRecordedBuffer:把采集数据存到AudioDeviceBuffer的缓存中,调用UpdateRecStats进行采集统计 DeliverRecordedData:将刚才缓存的数据传递给AudioTransport,从而送到3A以及发送模块 音频播放 音频播放模块通过调用AudioDeviceBuffer的RequestPlayoutData以及GetPlayoutData获取要播放的数据。 RequestPlayoutData:通过AudioTransport获取要播放的数据,并存到AudioDeviceBuffer的缓存中,调用UpdatePlayStats进行播放统计 GetPlayoutData:获取刚才缓存的播放数据 统计日志 前面提到调用接口都是由采集播放线程驱动的。通过调用接口会同时调用音频的统计。 一般排查音频采集播放问题,我们可以通过AudioDeviceBuffer中的统计日志判断,如下是一个示例日志: [crayon-69c6e050209aa267343508/] 该日志会打印10s内采集播放情况。 callbacks:表示接口调用次数,一般是默认10ms采集播放一次,所以10s内会调用1000次 samples:表示实际音频采集播放样本数,由于示例中采样率为48k,所以10ms样本数为480,所以10s采集播放样本数都为480000 rate:表示实际采集播放速率,也就是每秒的采集播放样本数 rate diff:表示实际采集播放速率跟采集播放设置的采样率差异,百分数表示,这个值不为0,可能是抖动以及丢音情况 level:这里的level是通过调用WebRtcSpl_MaxAbsValueW16计算的,WebRtcSpl_MaxAbsValueW16用于计算16bit音频样本数据的最大绝对值,这个level表示10s内采集播放数据的最大绝对值,也就是最大振幅 至此我们介绍完了AudioDeviceBuffer中的level,这个level表示音频数据的最大振幅,一般我们可以通过统计日志中这个level初步判断下音频数据情况,例如是否静音。 报头扩展中的level 这节我们介绍下音频报头扩展中的audio level。 audio level header extension 根据rfc6464,audio level报头扩展的作用是方便会议转发服务器根据携带的audio level信息进行音频选择转发处理,尤其在音频流非常多情况下。转发服务器可以根据audio level信息,转发最active的几路流,一般是选择3路,从而节省带宽等资源。 rfc中的定义 audio level扩展有两种不同的格式。 one-byte header格式: [crayon-69c6e050209b7407154107/] V:1bit,标识该音频包是否包含语音(voice activity),为1含有语音。这个字段是否用到由SDP中是否包含"vad="决定,后面SDP小节介绍 level:7bit,范围为0(最大声)~127(静音),单位-dBov,也就是0到-127dBov db表示分贝,用于度量声音强度,计算公式如下: 计算分贝需要参考值Pref,db后面带的后缀表示用到的参考值,dBov的ov后缀表示overload,参考系统的overload point,也就是当前payload格式音频所能忍受的最大声。 two-byte header格式: [crayon-69c6e050209bb805786171/] WebRTC中默认都是使用one-byte header格式。这里我们看下one-byte header解析以及构造代码: [crayon-69c6e050209be656112419/] SDP中的audio level header extension 先看下一段音频示例sdp: [crayon-69c6e050209c2379917133/] 可以看到其中audio level的描述如下: [crayon-69c6e050209c5321381385/] 如果该描述尾部带有:vad=on,也就是: [crayon-69c6e050209c8458197228/] 表示用到了header extension中的V字段,如果是”vad=off“,表示没有用到V字段。没有指定"vad=",默认表示"vad=on",WebRTC生成的SDP中没有指定"vad=",所以WebRTC中默认都是"vad=on"。 Wireshark解析的audio level 根据前面一节的SDP可知audio level扩展的ID为1,根据该ID,我们看下Wireshark中的解析: 根据解析,该音频包audio level扩展数据为0xa8,可知V字段为0xa8 & 0x80 = 1,说明有语音,level字段为:0xa8 & 0x7f = 0x28,也就是audio level为40-dbov。 代码中的audio level计算 audio level通过计算均方根(Root Mean Square,RMS)得到,计算代码位于RmsLevel类中。 均方根,也叫做平方平均数(quadratic mean),是指一组数据的平方的平均数的算术平方根。 首先需要计算所有幅值平方和: [crayon-69c6e050209cb051695836/] 接着将平方和除以样本数: [crayon-69c6e050209cf493105190/] 最后根据平方和的平均数计算均方根: [crayon-69c6e050209d2628675334/] 计算后的audio level通过如下代码流程写到header extension中: [crayon-69c6e050209d5881621899/] 总结 本文介绍了WebRTC中两种audio level,其中一种表示振幅,另一种表示均方根能量。通过本文可以对音频问题初步分析以及audio level这个报头扩展增加了解。 参考 [1] A Real-time Transport Protocol (RTP) Header Extension for Client-to-Mixer Audio Level Indication.https://datatracker.ietf.org/doc/rfc6464/