13 | 在WebRTC中如何控制传输速率呢?

在上一篇《12 | RTCPeerConnection:音视频实时通讯的核心》一文中,我向你介绍了RTCPeerConnection 对象是如何在端与端之间建立连接的,以及音视频数据又是如何通过它进行传输的。而本文则更进一步,向你介绍如何使用 RTCPeerConnection 来控制音视频数据的传输速率。

通过 RTCPeerConnection 进行传输速率的控制实际上还是蛮简单的一件事儿,但在学习相关知识的时候,你不仅要能知其然,还要知其所以然。对于本文来讲,就是你不但要学习如何控制传输速率,同时还应该清楚为什么要对传输速率进行控制。

其实,之所以要进行传输速率的控制,是因为它会对音视频服务质量产生比较大的影响,对于音视频服务质量这部分知识,接下来我就与你一起做详细探讨。

在WebRTC处理过程中的位置

在此之前,我们依旧先来看看本文的内容在整个 WebRTC 处理过程中的位置。

WebRTC 处理过程图

通过上图你可以知道,本文所讲的内容仍然属于传输的范畴。

音视频服务质量

像上面所说的,虽然通过 RTCPeerConnection 在端与端之间建立连接后,音视频数据可以互通了,但你还应对传输速率有所控制。之所以要对传输速率进行控制,主要是为了提高音视频服务质量。

举个简单的例子,假设你的带宽是 1Mbps,你想与你的朋友进行音视频通话,使用的视频分辨率为720P,帧率是15帧/秒,你觉得你们通话时的音视频质量会好吗?

咱们来简单计算一下,根据经验值,帧率为15帧/秒、分辨率为720P的视频,每秒钟大约要产生1.2~1.5Mbps的流量。由此可知,你和你朋友在 1M 带宽的网络上进行通话,那通话质量一定会很差。因为你的“马路”就那么宽,却要跑超出它宽度的数据,这样超出带宽的数据会被直接丢弃掉,从而造成大量视频帧无法解码,所以最终效果一定会很差。

由此可知,如果你不对音视频传输速率进行限制的话,它一定会对音视频服务质量产生严重的影响。除了传输速率,还有哪些因素会对音视频质量产生影响呢?下面我从网络质量和数据两个方面列举了一些对音视频服务质量产生影响的因素:

  • 网络质量,包括物理链路的质量、带宽的大小、传输速率的控制等;
  • 数据,包括音视频压缩码率、分辨率大小、帧率等。

以上这些因素都会对音视频的服务质量产生影响。有这么多因素会对音视频服务质量产生影响,那在真实的场景中,你该怎么去区分它们呢?或者说怎么判断服务质量是不是由于传输速率问题引起的呢?

要想判断出是哪些因素引起的音视频服务质量变差,你就必须要知道这些因素的基本原理,下面我们就简要地对这些因素做些介绍。

1. 物理链路质量

物理链路质量包括三个方面,即丢包、延迟和抖动。下面我们来看看它们是怎样影响服务质量的吧!

  • 丢包。这个比较好理解,如果物理链路不好,经常出现丢包,这样就会造成接收端无法组包、解码,从而对音视频服务质量产生影响。
  • 延迟。指通信双方在传输数据时,数据在物理链路上花费的时间比较长。对于实时通信来说,200ms 以内的延迟是最好的,这样通话双方的感觉就像是在面对面谈话;如果延迟是在500 ms 以内,通话双方的体验也还不错,有点像打电话的感觉;如果延迟达到 800ms,还能接受,但有明显的迟滞现像;但如果延迟超过 1秒,那就不是实时通话了!
  • 抖动。指的是数据一会儿快、一会儿慢,很不稳定。如果不加处理的话,你看到的视频效果就是一会儿快播了、一会儿又慢动作,给人一种眩晕的感觉,时间长了会非常难受。不过对于 WebRTC来讲,它通过内部的 JitterBuffer(可以简单地理解为一块缓冲区)就能很好地解决该问题。

2. 带宽大小

带宽大小指的是每秒钟可以传输多少数据。比如 1M 带宽,它表达的是每秒钟可以传输1M个 bit 位,换算成字节就是 1Mbps/8 = 128KBps,也就是说 1M 带宽实际每秒钟只能传输 128K个Byte。

当带宽固定的情况下,如何才能让数据传输得更快呢?答案是充分利用带宽。这句话有点抽象,它实际的含义是把带宽尽量占满,但千万别超出带宽的限制。这里还是以 1M 带宽为例,如果每秒都传输 1M 的数据,这样传输数据的速度才是最快,多了、少了都不行。每秒传输的数据少了,就相当于有 100 辆车,本来每次可以走 10 辆,10趟就走完了,可你却让它一次走1辆,这样肯定慢;而每秒传输多了,就会发生网络拥塞,就像每天上下班堵车一样,你说它还能快吗?

3. 传输速率

在实时通信中,与传输速率相关的有两个码率:音视频压缩码率和传输控制码率。

音视频压缩码率指的是单位时间内音视频被压缩后的数据大小,或者你可以简单地理解为压缩后每秒的采样率。它与视频的清晰度是成反比的,也就是压缩码率越高,清晰度越低。我们可以做个简单的对比,你应该清楚音视频编码被称为有损压缩,所谓的有损压缩就是数据被压缩后,就无法再还原回原来的样子;而与有损压缩对应的是无损压缩,它是指数据解压后还能还原回来,像我们日常中用到的 Zip、RAR、GZ等这些压缩文件都是无损压缩。对于有损压缩,你设备的压缩码率越高,它的损失也就越大,解码后的视频与原视频的差别就越大。

传输码率是指对网络传输速度的控制。举个例子,假设你发送的每个网络包都是 1500 字节,如果每秒钟发 100个包,它的传输码率是多少呢?即 100*1.5K = 150K 字节,再换算成带宽的话就是 150KB * 8 = 1.2M。但如果你的带宽是 1M,那每秒钟发 100 个包肯定是多了,这个时候就要控制发包的速度,把它控制在 1M 以内,并尽量地接近 1M,这样数据传输的速度才是最快的。

当然,如果你的压缩码率本来就很小,比如每秒钟只有 500kbps,而你的带宽是 1Mbps,那你还有必要对传输码率进行控制吗?换句话说,一条马路可以一起跑 10辆车,但你现在只有 3辆,显然你就没必要再控制同时发车的数量了。

4. 分辨率与帧率

你应该很清楚,视频的分辨率越高,视频就越清晰,但同时它的数据量也就越大。我们还是来简单计算一下,对于1帧未压缩过的视频帧,如果它的分辨率是 1280 * 720,存储成 RGB 格式,则这一帧的数据为 1280 * 720 * 3 * 8(3表示 R、G、B 三种颜色,8表示将Byte换算成 bit),约等于 22Mb;而存成 YUV420P 格式则约等于11Mb,即1280 * 720 * 1.5 * 8。

按照上面的公式计算,如果你把视频的分辨率降到 640 * 360,则这一帧的数据就降到了原来的1/4,这个效果还是非常明显的。所以,如果你想降低码率,最直接的办法就是降分辨率

当然,对帧率的控制也一样可以起到一定的效果。比如原来采集的视频是 30帧/秒,还以分辨率是 1280 * 720 为例,之前1帧的数据是 22M,那30帧就是 22 * 30=660Mb。但如果改为15 帧/秒,则数据就变成了 330Mb,直接减少了一半。

但了解音视频压缩原理的同学应该知道,通过减少帧率来控制码率的效果可能并不明显,因为在传输数据之前是要将原始音视频数据进行压缩的,在同一个 GOP(Group Of Picture)中,除了 I/IDR帧外,B 帧和 P帧的数据量是非常小的。因此,减少帧率的方式就没有降低分辨率方式效果明显了

到这里我已经向你介绍了,在WebRTC实时通信中对音视频质量产生影响的因素有哪些,以及这些因素对音视频服务质量产生影响的基本原理,了解这些原理会更有利于你判断音视频服务质量变差的原因,从而决定是否要使用控制传输速率的方法来解决音视频服务质量的问题。

那接下来我们言归正转,看一下在 WebRTC 中具体该如何控制传输速率。

传输速率的控制

通过上面的介绍,我想你现在应该很清楚,可以通过以下两种方式来控制传输速率。第一种是通过压缩码率这种“曲线救国”的方式进行控制;第二种则是更直接的方式,通过控制传输速度来控制速率。

第二种方式虽说很直接,但是也存在一些弊端。假设你有 10M 的数据要发送,而传输的速度却被限制为5kbps,那它就只能一点一点地传。需要注意的是,由于WebRTC是实时传输,当它发现音视频数据的延迟太大,且数据又不能及时发出去时,它会采用主动丢数据的方法,以达到实时传输的要求

所以说控制传输速率虽然有两种方式,但实际上,WebRTC只允许我们使用第一种压缩码率的方式来主动控制速率,而第二种方式是它在底层自己控制的,为了保障实时性,一旦数据无法及时发送出去的话就会进行主动丢包。

了解了上面这些知识之后,下面我们就来看看在WebRTC下如何才能控制视频流的码率。具体操作如下面代码所示:

....

var vsender = null; //定义 video sender 变量
var senders = pc.getSenders(); //从RTCPeerConnection中获得所有的sender

//遍历每个sender
senders.forEach( sender => {
  if(sender && sender.track.kind === 'video'){ //找到视频的 sender
      vsender = sender; 
  }
});

var parameters = vsender.getParameters(); //取出视频 sender 的参数
if(!parameters.encodings){ //判断参数里是否有encoding域
    return;
}

//通过 在encoding中的 maxBitrate 可以限掉传输码率
parameters.encodings[0].maxBitrate = bw * 1000;

//将调整好的码率重新设置回sender中去,这样设置的码率就起效果了。
vsender.setParameters(parameters) 
       .then(()=>{
          console.log('Successed to set parameters!');
       }).catch(err => {
          console.error(err);
       })

...

上面的代码中,首先从 RTCPeerConnection中获取视频的发送者,即kind为 video的sender;然后取出 sender 中的 parameters 对象,其中的 maxBitrate 属性就是用于控制传输码率的;将你期望的最大码率设置好后,再将parameters 对象设置回去,这样WebRTC就可以控制某路流的码率大小了。

通过上面的代码你还可以看出,在 WebRTC 中速率的控制是使用压缩码率的方法来控制的,而不是直接通过传输包的多少来控制的。从另外一个角度你也可以得到这样的结论,因为maxBitrate属性来自于 sender 的 encoding 对象,而 encoding 对象就是进行编码时使用的参数。

小结

通过本文的讲解,你应该可以看出在 WebRTC 中控制传输速率其实是非常简单的事情,只要向 RTCPeerConnection 中的 sender 设置一个最大码率就可以控制某一路流的传输速率了。

另外,在本文中我还向你简要介绍了物理链路的质量、带宽的大小、码率、分辨率和帧率这几个影响音视频服务质量的重要因素,并详细分析了每个因素是如何影响到音视频服务质量的。

这里需要注意的是,在WebRTC中,通过上述的方式只能对每一路音视频流进行码率的控制,而不能进行整体的统一控制。所以,如果你的应用同时存在多路音视频流,而你又想控制一个总的码率,就只能一路一路地控制了。

思考时间

实际上,在WebRTC中除了通过 sender 的 maxBitrate 控制码率外,还可以通过 SDP 来控制传输速率,你是否可以找到这个方法呢?

欢迎在留言区与我分享你的想法,也欢迎你在留言区记录你的思考过程。感谢阅读,如果你觉得这篇文章对你有帮助的话,也欢迎把它分享给更多的朋友。

精选留言

  • 笨小孩

    2020-05-14 12:24:11

    因为在传输数据之前是要将原始音视频数据进行压缩的,在同一个 GOP(Group Of Picture)中,除了 I/IDR 帧外,B 帧和 P 帧的数据量是非常小的。
    --
    是说压缩后会变成gop一个单位吗?这个gop没看懂
    作者回复

    GOP 是一组帧,按25帧/秒,你在摄像头前停留一秒可以能没有做任务动作,那么摄像头就采集了 25帧一模一样的图片,这 25帧图片的相关系是不是很大呢?是不是只要保存一长完整的图片然后再保存每一帧图片之间的差异就会大在减少数据量呢?人们人为的将图片相关系比较大的一堆图像划分为一组,这样就可以进行压缩了。这就是 GOP的概念。

    2020-05-24 12:14:29

  • SherwinFeng

    2019-11-25 19:34:07

    这样理解是不是对的呢?
    ①码率分为音视频压缩码率和传输控制码率;
    ②由于网络质量条件是不可控的(物理链路的质量、带宽的大小、传输速率的控制),所以webRTC只能通过对数据进行控制,让单位时间内发送的数据量降下来,那么可以增加音视频压缩码率或降低传输控制码率
    增加音视频压缩码率,可以直接对SDP中的sample rate/采样率(就是帧率吗)进行控制以减少数据大小,还可以降低分辨度(这些都是有损压缩,即压缩过程不可逆),这些我们可以主动控制的。
    降低传输控制码率,指的是不对源数据进行任何处理,而是强行降低发包速度,这可能会造成严重延迟,因此这个是webRTC自己控制的。

    而对于用户来说,我们只要知道通过maxBitrate来控制码率即可
    作者回复

    没错!

    2019-12-01 10:59:01

  • Geek_91a5bd

    2020-11-28 08:04:06

    通过媒体描述字段进行控制,如a=rtpmap:103 ISAC/16000,即是控制音频的采样率=16000
    作者回复

    是的

    2021-03-30 11:22:41

  • Desmond

    2020-03-30 17:39:23

    如果涉及到无线传输的话,物理传输带宽变化很快,请问WebRTC有办法测量到当前的物理带宽吗?
    作者回复

    可以

    2020-04-10 10:15:13

  • 刘丹

    2019-08-13 09:47:28

    senders.forEach( sender => {
    if(sender && sender.track.kind === 'video'){ // 找到视频的 sender
    vsender = sender;
    }
    });
    如果有多个sender符合 sender.track.kind === 'video' ,那么只有最后一个sender被处理?
    作者回复

    这里只是一个例子,一般情况下,一个客户端只有一路视频。

    2019-08-14 23:25:01

  • ifelse

    2025-07-18 12:41:25

    学习打卡
  • 崧阳

    2023-08-18 13:18:20

    我们业务上的要求是无论如何也不能降低分辨率,但是允许丢包,请问有办法做到吗?很多时候我能看到qualityLimitationReason 里面有cpu和bandwidth,但是不知道如何禁止自动降低分辨率。
  • 2022-07-02 11:54:16

    【通过上述的方式只能对每一路音视频流进行码率的控制,而不能进行整体的统一控制。所以,如果你的应用同时存在多路音视频流,而你又想控制一个总的码率,就只能一路一路地控制了。】一对一音视频通信时,音频流和视频流是不是独立的,属于两路流?那么通过 sender 的 maxBitrate 控制码率,是同时设置的这两路流吗?
  • yoli

    2022-03-11 15:50:45

    老师您好, 我在使用webrtc的DataChannel 在局域网传输数据时, 最高只可以20M/s. 但是在查看webRtc的相关文档时。即可以实现135M/s. 关于DataChannel 的数据传输, 有哪些方面可以提高数据的传输速率 ?
  • expecting

    2022-02-17 18:52:55

    音视频压缩码率指的是单位时间内音视频被压缩后的数据大小,或者你可以简单地理解为压缩后每秒的采样率。它与视频的清晰度是成反比的,也就是压缩码率越高,清晰度越低。
    这句话有点不理解,既然是压缩后的数据大小,不应该是数据越大视频越清晰吗?那应该是正比关系。
  • Geek_6a972c

    2021-11-24 21:23:15

    请问下初始码率怎么设置呢,webRtc开始那几秒较为模糊
  • dybai

    2021-06-28 09:28:55

    老师你好,我跟一楼的问题类似。降帧率是把整个GOP作为一个整体来降低的,还是只是按照帧的数量来降低的(不区分帧类型)?
  • Geek_066e6b

    2020-06-11 10:13:23

    老师,通过getUserMedia设置的是采集的分辨率,还是编码后的分辨率呢?如果不是编码后分辨率,怎么设置呢?最后,还想咨询下,如果想同时支持上行多条不同分辨率的视频流,我们该怎么去控制呢?
    作者回复

    getUserMediaAPI设置的分辨率既是采集分辨率也是编码分辨率。

    在webrtc中可以通过simulcast来实现多条不同分辨率的视频流,这个你可以到网上搜索一下。

    2020-06-23 10:14:35

  • Benjamin

    2020-03-25 17:27:15

    还是一直好奇 SDP 控制的问题,SDP 协商控制连接完成前就做好了。

    在音视频通信中,如何再次使用 SDP 控制呢?断开一次,重新相互投递 offer ?
    作者回复

    是的,重连时要重新进行媒体协商

    2020-03-26 14:28:34

  • Benjamin

    2020-03-25 17:25:31

    其实,可以直观理解一下 WebRTC 的这个机制。

    就是你看到视频画面变模糊或者马赛克,就是在控制 sender 端的 压缩码率 被设置高了,质量就降低了。

    这个是 WebRTC 本质上去决定的,优先保证实时性。
  • 李宁

    2020-01-25 20:07:59

    老师,请教两个问题:
    1、怎么得到当前物理链路质量的信息(丢包率、延迟、抖动)
    2、帧率和延迟有没有关系,如果没有关系,是否需要根据当前延迟状况动态调节帧率
    作者回复

    通过RTCP协议来检测链路质量。帧率与延迟关系不大。延迟是因为你的网终带宽与音视频流大小不匹配。也就是说小于音视频流的大小。解决办法是减少流量,减少流量的方式有很多,帧率与延迟的关系不是特别大,实际上分辨率才是最大的。

    2020-02-23 11:59:15

  • 蔡林

    2019-12-21 18:29:38

    一对一场景中,二者是通过点到点的方式连接的,中间没有经过服务器的中转对音视频流进行中转,流的质量完全依赖于发送端和接收端本地出口的网络质量,请问老师我的理解对吗?
    作者回复

    是的

    2019-12-22 22:17:05

  • 天天

    2019-12-11 23:56:19

    码率和压缩码率是同一个概念吗?
    作者回复

    对的,这里的码率是压缩后的传输码率!

    2019-12-22 22:37:05

  • 天一

    2019-11-06 18:05:02

    老师,你好 ,代码中的
    key : fs.readFileSync('./cert/1557605_www.learningrtc.cn.key'),
    cert : fs.readFileSync('./cert/1557605_www.learningrtc.cn.pem')
    这些 key 和 pem 哪里得到?
    作者回复

    自己购买一个域名,可以免费申请试用一年的https。当然你还需要有台云主机,这样才能将域名解析到这台详尽主机上。

    2019-11-08 13:40:27

  • Derek

    2019-09-15 13:56:25

    传输信道的充分利用是由webrtc内部控制。但webrtc是否会反馈给应用层,来让应用层调整编码码率,以适应当前的信道状况?如果是,是否就是通过这个maxbitrate参数调节?
    作者回复

    当然可以!

    2019-09-18 12:16:17