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

news2025/7/13 6:35:45

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

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

Native调用序列:

上图中,我保留的起点是从http://channel.cc中的VoiceChannel::SetRemoteContent_w() 方法被调用开始的,再往上的调用栈就没有画了。整个序列中,需要关注的主要是 AudioEncoderOpusImpl 的 SdpToConfig 和 RecreateEncoderInstance 这两个方法。

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对应的成员变量

maxplaybackrate int max_playback_rate_hz; //默认48000

sprop-maxcapturerate 没有找到相关native属性对应

minptime, maxptime std::vector supported_frame_lengths_ms; // 20,40,60中的1个或全部

ptime int frame_size_ms; //默认20

maxaveragebitrate 参考CalculateBitrate函数实现。如果不设置,会根据通道数和maxplaybackrate来计算。例如,如果maxplaybackrate是48000,单通道,码率是32000。双通道则是64000。

stereo int num_channels; //stereo设置为1时,通道数是2

sprop-stereo 没有找到相关native属性对应

cbr bool cbr_enabled;

useinbandfec bool fec_enabled;

usedtx bool 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解码端的表现和码率之间的关系是怎样的?

……

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

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

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/379006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT学习14:QtXlsx操作Excel表

一、前言操作excel方式有:QAxObject 和QtXlsx区别:Qt自带的QAxObject库操作excel的前提是电脑已经安装微软的Office(包含EXCEL),而QtXlsx可以直接使用免装Office且操作更简单。二、QtXlsx操作示例参考:http…

C筑基——深入理解内存对齐

目录1 前言2 正文2.1 为什么要有内存对齐?2.2 内存对齐原则2.2.1 基本数据类型是自然对齐的2.2.2 包含基本数据类型成员的结构体套用结构体内存对齐原则来分析使用 gdb 查看这两个结构体的成员内存位置结构体类型变量是自然对齐的吗?2.2.3 数组类型2.3 修…

今天 4 点,龙蜥自动化运维平台SysOM 2.0的诊断中心功能介绍 | 第 66-68 期

本周 3 期「龙蜥大讲堂」预告来啦!我们邀请了系统运维 SIG Contributor 阙建明分享《SysOM 2.0 诊断中心功能介绍》,龙蜥社区云原生机密计算 SIG Maintainer、Intel 高级云计算软件工程师黄晓军分享《Intel HE Toolkit 介绍》主题演讲,龙蜥社…

【Linux】操作系统与Linux — Linux概述、组成及目录结构

目录 一、什么是操作系统?都有那些? 二、Linux概述 三、Linux组成 三、Linux目录结构 四、Linux目录结构 💟 创作不易,不妨点赞💚评论❤️收藏💙一下 一、什么是操作系统?都有那些&#x…

频率信号转电压或电流信号隔离变送器0-1KHz /0-5KHz /0-10KHz转0-2.5V/0-5V/0-20mA

主要特性:>> 精度等级&#xff1a;0.2级>> 全量程内极高的线性度&#xff08;非线性度<0.1%&#xff09; >> 辅助电源/信号输入/信号输出&#xff1a; 2500VDC 三隔离>> 辅助电源&#xff1a;5VDC&#xff0c;12VDC&#xff0c;24VDC等单电源供电&g…

2020蓝桥杯真题约数个数(填空题) C语言/C++

题目描述 本题为填空题&#xff0c;只需要算出结果后&#xff0c;在代码中使用输出语句将所填结果输出即可。 1200000 有多少个约数&#xff08;只计算正约数&#xff09;。 运行限制 最大运行时间&#xff1a;1s 最大运行内存: 128M 所需变量 int a 1200000;//初始最大数 i…

模式识别 —— 第一章 贝叶斯决策理论

模式识别 —— 第一章 贝叶斯决策理论 前言 新的学期开始了&#xff0c;当然是要给不爱吃香菜的月亮记录学习笔记呀~ 没多久了&#xff0c;待夏花绚烂之时~人山人海&#xff0c;我们如约而至&#xff01; 以后清河海风 溶溶月色 共赏之人 就在身侧 mua~ 文章目录模式识别 —…

【服务器数据恢复】HP EVA存储lun丢失的数据恢复案例

服务器故障&检测&分析&#xff1a; 某品牌EVA存储设备中的RAID5磁盘有两块硬盘掉线&#xff0c;lun丢失。硬件工程师对故障服务器进行物理故障检测&#xff0c;发现掉线硬盘能够正常读取&#xff0c;无物理故障&#xff0c;也没有发现坏道。 故障服务器掉线硬盘没有物理…

深度理解Redux原理并实现一个redux

Redux的作用是什么 Redux的作用在于实现状态传递、状态管理。在这里你可能会说了&#xff0c;如果是状态传递&#xff0c;那我props的传递不也是可以达到这样的效果吗&#xff1f;context上下文方案不也是可以达到这样的效果吗&#xff1f;没错&#xff0c;是这样的&#xff0…

汇川SV660N与基恩士 KV7500 控制器调试说明

1. 伺服相关部分配置 1.1 伺服相关版本 SV660N 试机建议使用“SV660N-Ecat_v0.09.xml”及以上设备描述文件。 SV660N 单板软件版本建议为“H0100901.4”及更高版本号。 1.2 相关参数说明 SV660N 对象字典中 60FD 的含义较 IS620N 有所更改&#xff1a;bit0、1、2 分别为负限位…

移动字母--降维与DFS

一、题目描述 2x3=6 个方格中放入 ABCDE 五个字母,右下角的那个格空着。如下图所示。 和空格子相邻的格子中的字母可以移动到空格中,比如,图中的 C 和 E 就可以移动,移动后的局面分别是: A B D E C A B C D E 为了表示方便,我们把 6 个格子中字母配置用一个串表示出…

如何创建出实用的员工手册?

员工手册主要是企业内部的人事制度管理规范&#xff0c;包含企业规章制度和企业文化&#xff0c;同时还起到了展示企业形象、传播企业文化的作用。它既覆盖了企业人力资源管理的各个方面规章制度的主要内容&#xff0c;又因适应企业独特个性的经营发展需要而弥补了规章制度制定…

【HTML】列表结构

列表结构HTML效果HTML <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdev…

HIVE --- zeppelin安装

目录 把zeppelin压缩包拷贝到虚拟机里面 解压 改名 修改配置文件 编辑zeppelin-site.xml—将配置文件的ip地址和端口号进行修改 编辑 zeppelin-env.sh—添加JDK和Hadoop环境 配置环境变量 刷新环境变量 拷贝Hive文件 拷贝外部文件 启动zeppelin 启动Hadoop&Hi…

Web API接口鉴权方式

一、什么是鉴权&#xff1f;为什么要鉴权 鉴权&#xff08;authentication&#xff09;&#xff0c;也叫做认证&#xff0c;即验证用户是否拥有访问系统的权利。 HTTP本身是无状态的请求&#xff0c;每次请求都是一次性的&#xff0c;并不会知道请求前后发生了什么。但在很多…

记一次linux服务器磁盘空间占满的问题排查

问题&#xff1a;服务器安装后两天&#xff0c;发现磁盘空间使用满了【date: write error: No space left on device】问题排查&#xff1a;1、使用df -hl命令查看2、使用du -hl --max-depth1&#xff0c;从根目录开始查起&#xff0c;最后发现&#xff0c;磁盘的空间全部被/va…

自学5个月Java找到了9K的工作,我的方式值得大家借鉴 第二部分

我的学习心得&#xff0c;我认为能不能自学成功的要素有两点。 第一点就是自身的问题&#xff0c;虽然想要转行学习Java的人很多&#xff0c;但是非常强烈的想要转行学好的人是小部分。而大部分人只是抱着试试的心态来学习Java&#xff0c;这是完全不可能的。所以能不能学成Jav…

【Linux】项目的自动化构建-make/makefile

&#x1f4a3;1.背景会不会写makefile&#xff0c;从一个侧面说明了一个人是否具备完成大型工程的能力 一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefile定义了一系列的 规则来指定&#xff0c;哪些文件需要先编译&#xff…

Java List系列(ArrayList、LinekdList 以及遍历中删除重复元素时发生的异常和解决办法)

目录List集合系列List系列集合特点List集合特有方法List集合的遍历方式ArrayList集合的底层原理分析源码LinkedList集合的底层原理集合的并发修改异常问题&#xff08;删除重复元素时&#xff09;List集合系列 List系列集合特点 ArrayList、LinekdList &#xff1a;有序&#…

HNU工训中心:电子开关与信号隔离

工训中心的牛马实验 1.实验目的&#xff1a; 1) 认识三极管和MOS管构成三端电子开关电路&#xff1b; 认识信号隔离的继电器和光电隔离方式。 2) 认识施密特触发器&#xff0c;掌握一种波形变换方法。 3) 实现一种脉冲波形发生器。 2.实验资源 HBE硬件基础电路实验箱、示波…