WebRTC Opus编码器的创建与参数细节分析( sdp -> native )

1 篇文章 0 订阅

这几天在做一些WebRTC音频改进方面的调查工作,在阅读Chromium源码的过程中,就顺便记录下来,便于日后回顾。本文基于Chromium 85源码分析,由于Chromium的快速发展,很有可能不适合于跨度太大的Chromium版本。

大家知道Opus内置了两种编码器:CELT和SILK,并且可以针对采样率、采样间隔、码率、通道数……等属性进行设置。创建的参数设置,是从sdp来的。本文的主要目的,是来看看sdp中的信息,是如何对应到native世界里的代码的。

Native调用序列:
Opus编码器创建序列图
上图中,我保留的起点是从channel.cc中的VoiceChannel::SetRemoteContent_w() 方法被调用开始的,再往上的调用栈就没有画了。整个序列中,需要关注的主要是 AudioEncoderOpusImpl 的 SdpToConfigRecreateEncoderInstance 这两个方法。

SdpToConfig,顾名思义,它会把sdp的内容(SdpAudioFormat)转换成 AudioEncoderOpusConfig 对象。AudioEncoderOpusConfig类的头文件件位于:webrtc\api\audio_codecs\opus\audio_encoder_opus_config.h。它定义了十几个Opus的相关属性,如采样率sample_rate_hz、帧长度frame_size_ms、通道数num_channels、音频模式application(决定内部编码使用celt还是silk)、fec_enabled、cbr_enabled……等等。

OK,接下来,让我们拿一个具体的例子来展开说明。假设SDP中音频部分是这样:

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:d3VL
a=ice-pwd:5ccIbts7ExcJCOlQXdRs+lzp
a=ice-options:trickle
a=fingerprint:sha-256 67:E5:3E:05:AC:F4:CE:56:06:4B:7B:74:AB:DA:92:D2:CE:88:1E:2E:78:13:49:69:EA:F3:2B:A0:BB:04:40:DA
a=setup:actpass
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;stereo=1; sprop-stereo=1;useinbandfec=1
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
a=ssrc:286098906 cname:/7O5RyfmfX+yNmDJ
a=ssrc:286098906 msid:Cs59oGPYCoRopRCJ6lNE8Rw2B5QuuBRD0Dqq 4db71fa8-4266-409a-869c-d6eecc7e98b8
a=ssrc:286098906 mslabel:Cs59oGPYCoRopRCJ6lNE8Rw2B5QuuBRD0Dqq
a=ssrc:286098906 label:4db71fa8-4266-409a-869c-d6eecc7e98b8

让我们根据这份SDP,来分析一下它里面几个关键的部分,对应native的实现是怎么样的。

a=rtpmap:111 opus/48000/2

这一行是固定格式不能更改。因为从 SdpToConfig 函数的开头就能看出来:

if (!absl::EqualsIgnoreCase(format.name, "opus") ||
      format.clockrate_hz != kRtpTimestampRateHz || format.num_channels != 2) {
  return absl::nullopt;
}

其中 kRtpTimestampRateHz = 48000。所以,SDP中这一行,并不代表默认Opus就是使用48KHz和双通道来创建编码器,这个只是一个约束而已。

a=rtcp-fb:111 transport-cc

这一行是启用RTCP的一种反馈机制。它对应的文档规范URL在sdp中是这个:

a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01

但似乎这个链接已经失效了,最新的是这个:https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01

a=fmtp:111 minptime=10;stereo=1; sprop-stereo=1;useinbandfec=1

这一行比较重要。我们如果需要额外设置Opus参数,基本上就是要修改这一行SDP来达到我们的目的。例子SDP中,主要设置了4个属性: minptime,stereo,sprop-stereo,useinbandfec。其实还有很多,都有哪些Opus属性可以设置呢?参考 RFC7587(RTP Payload Format for the Opus Speech and Audio Codec) 的 6.1 Opus Media Type Registration 这一节。列举如下:

SDP属性含义(谷歌翻译)
maxplaybackrate接收器能够呈现的最大输出采样率,以Hz为单位。 解码器必须能够解码任何音频带宽,但是由于硬件限制,只能播放指定采样率以下的信号。 发送具有更高音频带宽的信号会导致超出必要的网络使用率和编码复杂度,因此编码器不应编码高于maxplaybackrate指定的音频带宽的频率。 尽管通常该值将与Opus带宽之一匹配(表1),但是该参数可以采用8000到48000之间的任何值。 缺省情况下,假设接收机没有限制,即48000。
sprop-maxcapturerate发送方可能产生的最大输入采样率。 这不能保证发送方永远不会发送任何更高的带宽(例如,它可以发送使用更高带宽的预先录制的提示),但可以向接收方指示可以安全地丢弃高于此最大值的频率。 通过以高于必要的速率操作音频处理管道(例如回声消除)来避免浪费接收机资源,该参数是有用的。 尽管通常该值将与Opus带宽之一匹配(表1),但该参数可以采用8000到48000之间的任何值。 缺省情况下,假设发送方没有限制,即48000。
maxptime解码器要接收的数据包所代表的最大媒体持续时间(根据[RFC4566]第6节),以毫秒为单位,四舍五入到下一个完整整数值。 可能的值为3、5、10、20、40、60或Opus帧大小的任意倍数,四舍五入为下一个完整整数值,最大为120,如第4节中所定义。 指定,默认值为120。
minptime数据包所代表的媒体的最短持续时间(根据[RFC4566]的第6节),应该封装在接收到的数据包中,以毫秒为单位,四舍五入到下一个完整整数值。 可能的值为3、5、10、20、40和60,或者Opus帧大小的任意倍数舍入为第4节中定义的下一个完整整数值,最大为120。 默认值为3。此值是解码端的建议,以确保解码器具有最佳性能。 解码器必须能够接受任何允许的包大小,以确保最大的兼容性。
ptime解码器想要接收的由数据包表示的媒体的首选持续时间(根据[RFC4566]第6节),以毫秒为单位,四舍五入到下一个完整整数值。 可能的值为3、5、10、20、40、60或Opus帧大小的任意倍数,四舍五入为下一个完整整数值,最大为120,如第4节中所定义。 指定,默认值为20。
maxaveragebitrate指定会话的最大平均平均接收比特率,以每秒比特数(b / s)为单位。 比特率的实际值可能会有所不同,因为它取决于数据包中媒体的特性。 注意最大平均比特率可以在会话期间动态修改。 允许使用任何正整数,但应忽略范围在6000到510000之间的值。 如果未指定任何值,则默认值是在3.1.1节中为相应的Opus模式指定的最大值和相应的maxplaybackrate。
stereo指定解码器是喜欢接收立体声信号还是单声道信号。 可能的值为1和0,其中1表示首选立体声信号,0表示仅首选单声道信号。 每个接收器都必须独立于立体声参数而能够接收和解码立体声信号,但是将立体声信号发送给接收器,该信号指示对单声道信号的偏爱可能会导致网络利用率和编码复杂性高于必要水平。 如果未指定任何值,则默认值为0(单声道)
sprop-stereo指定发送者是否可能产生立体声音频。 可能的值是1和0,其中1指定可能发送立体声信号,0指定发送方可能仅发送单声道。 这不能保证发送方将永远不会发送立体声音频(例如,它可以发送使用立体声的预先录制的提示),但是可以向接收方指示可以安全地将接收到的信号降混为单声道。 该参数对于避免不必要时通过以立体声操作音频处理管道(例如回声消除)来避免浪费接收机资源很有用。 如果未指定任何值,则默认值为0(单声道)
cbr指定解码器是否更喜欢使用恒定比特率而不是可变比特率。 可能的值为1和0,其中1表示恒定比特率,0表示可变比特率。 如果未指定任何值,则默认值为0(vbr)。 当cbr为1时,最大平均比特率仍然可以更改,例如 适应不断变化的网络条件
useinbandfec指定解码器具有利用Opus带内FEC的能力。 可能的值为1和0。建议在接收方无法使用FEC时提供0。 如果未指定任何值,则useinbandfec假定为0。此参数仅是一个首选项,并且即使表示FEC部分已被丢弃,接收方也必须能够处理包含FEC信息的数据包。
usedtx指定解码器是否更喜欢使用DTX。 可能的值为1和0。如果未指定任何值,则默认值为0。

OK,我们来看看这些属性和native的 AudioEncoderOpusConfig 的对应关系:

SDP属性AudioEncoderOpusConfig对应的成员变量
maxplaybackrateint max_playback_rate_hz; //默认48000
sprop-maxcapturerate没有找到相关native属性对应
minptime, maxptimestd::vector supported_frame_lengths_ms; // 20,40,60中的1个或全部
ptimeint frame_size_ms; //默认20
maxaveragebitrate参考CalculateBitrate函数实现。如果不设置,会根据通道数和maxplaybackrate来计算。例如,如果maxplaybackrate是48000,单通道,码率是32000。双通道则是64000。
stereoint num_channels; //stereo设置为1时,通道数是2
sprop-stereo没有找到相关native属性对应
cbrbool cbr_enabled;
useinbandfecbool fec_enabled;
usedtxbool dtx_enabled;

除了上面一些属性以外,AudioEncoderOpusConfig 还有一个 ApplicationMode {kVoip, kAudio}的属性。当通道数是1时,取值kVoip(语音),否则是kAudio(音频)。它其实对应的是Opus的application属性。关于这个属性,参考:https://www.opus-codec.org/docs/html_api/group__opusencoder.html。其实Opus一共有三种application模式:

OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice signals. It enhances the input signal by high-pass filtering and emphasizing formants and harmonics. Optionally it includes in-band forward error correction to protect against packet loss. Use this mode for typical VoIP applications. Because of the enhancement, even at high bitrates the output may sound different from the input. 可在给定的比特率下为语音信号提供最佳质量。它通过高通滤波并强调共振峰和谐波来增强输入信号。可选地,它包括带内前向纠错,以防止数据包丢失。对典型的VoIP应用程序使用此模式。由于增强,即使在高比特率下,输出听起来也可能与输入不同。
OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most non-voice signals like music. Use this mode for music and mixed (music/voice) content, broadcast, and applications requiring less than 15 ms of coding delay. 可在给定的比特率下为音乐等大多数非语音信号提供最佳质量。对于音乐和混合(音乐/声音)内容,广播以及要求少于15 ms编码延迟的应用程序,请使用此模式。
OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that disables the speech-optimized mode in exchange for slightly reduced delay. 配置低延迟模式,该模式禁用语音优化模式,以换取稍微减少的延迟。

而第三种WebRTC并没有使用。因此,我们可以看出,WebRTC默认是单通道走VoIP模式,如果想采用Audio模式,则只需要设置双通道(sdp中 stereo设置为1)即可。因此,根据你的使用场景,例如是音乐老师教乐器,建议还是在sdp中设置 stereo为1。如果只是日常沟通,如视频会议,默认的 VoIP就足够啦。

好了,到这里为止,我们已经十分清楚了SDP中的设置和native层的对应关系。接下来如何根据需要改变Opus编码器参数设置,想必就是一件很容易的事了。不过,到这里,还有一些疑问我还没有找到答案:

  • Opus 的两种 application mode (VoIP、Audio),在RTC应用中真实的差别到底有多大?
  • 弱网下如何改进音频表现?除了NACK和FEC,是否需要动态调整音频码率?双通道改为单通道?
  • maxptime给不同的取值,对真实使用中,尤其复杂网络条件下的影响几何?
  • 6kbps - 510kbps的码率允许范围内,不同的码率,如果在相同的弱网条件下,WebRTC解码端的表现和码率之间的关系是怎样的?
    ……

这些问题,还需要做一些工作和试验才能找到答案了。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你提到的是视频流传输协议和对应的视频封装格式,其中: - MMS(Microsoft Media Server)是微软开发的流媒体传输协议,可以传输音频、视频和其他多媒体数据。MMS流可以保存为WMV(Windows Media Video)或ASF(Advanced Systems Format)格式文件。 - RTSP(Real-Time Streaming Protocol)是一种实时流媒体传输协议,通常用于 IP 网络上的音频、视频和其他多媒体流传输。RTSP流可以保存为RMVB(RealMedia Variable Bitrate)或RM(RealMedia)格式文件。 - RTMP(Real-Time Messaging Protocol)是一种实时流媒体传输协议,通常用于通过 Flash 插件在 Web 上播放音频、视频和其他多媒体流。RTMP流可以保存为F4V(Flash Video)或FLV(Flash Video)格式文件,也可以以 SWF(Shockwave Flash)格式嵌入到网页中。 - HLS(HTTP Live Streaming)是一种基于 HTTP 协议的流媒体传输协议,可以实现多码率自适应流媒体播放。HLS流可以保存为MP4(MPEG-4 Part 14)、MKV(Matroska Multimedia Container)或MOV(Apple QuickTime)格式文件。 - MPEG-DASH(Dynamic Adaptive Streaming over HTTP)是一种基于 HTTP 协议的自适应流媒体传输协议,可以实现多码率自适应流媒体播放。MPEG-DASH流可以保存为H.264(Advanced Video Coding)和AAC(Advanced Audio Coding)编码的MP4格式文件。 - WebRTC(Web Real-Time Communication)是一种实时通信技术标准,包括音频、视频、数据传输等。WebRTC可用于实现视频聊天软件和视频会议等功能,对应的视频格式取决于具体的实现方式。 需要注意的是,上述流传输协议和封装格式只是其中的一部分,实际上还有很多其他的协议和格式可供选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值