WebRTC 中的多路复用

AbstractWebRTC 中多路复用
AuthorsWalter Fan
Categorylearning note
Statusv1.0
Updated2022-4-30
LicenseCC-BY-NC-ND 4.0

回顾一下这张经典的图

我改了一下 audio 和 video 的 codec, 现在 Opus 和 H.264 用的比较多
Web API 中最主要的就是 MediaStream, RTCPeerConnection 和 DataChannel.

在两个端点之间所传输的消息有这样几种

媒体数据一般都是优先走 UDP

0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |           Source Port          |        Destination port      |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |               Length           |        Checksum              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     |                        data octets ...                        |
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

1. 区分 STUN, DTLS 和 RTP 包

注: 这里提到的 RTP 包括 RTP, RTCP, SRTP, SRTCP

在 UDP 传输通道上会跑 STUN, DTLS 和 RTP(SRTP) 的数据,我们首先要区分这几种数据

  • STUN 消息头如下
0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |0 0|     STUN Message Type     |         Message Length        |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         Magic Cookie                          |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     |                     Transaction ID (96 bits)                  |
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • DTLS 消息,包含 SRTP 密钥的传输及用于 Datat Channel 的 SCTP 消息
struct {
        ContentType type;
        ProtocolVersion version;
        uint16 epoch;                                     // New field
        uint48 sequence_number;                           // New field
        uint16 length;
        opaque fragment[DTLSPlaintext.length];
 } DTLSPlaintext;
0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     | ContentType |        Version     |        epoch               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         sequence_number                       |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |    sequence_number              |         length              |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     |                     opaque fragment                           |
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • RTP 消息,包含音频或视频的媒体数据, SRTP 的头与 RTP 头是相同的
0                   1                   2                   3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |V=2|P|X|  CC   |M|     PT      |       sequence number         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                           timestamp                           |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |           synchronization source (SSRC) identifier            |
   +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
   |            contributing source (CSRC) identifiers             |
   |                             ....                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • RTCP 包括各种报告和反馈消息, SRTCP 的头与 RTCP 头是相同的
0                   1                   2                   3
        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |V=2|P| RC/FMT  |       PT      |             length            |
       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
       |                         SSRC of sender                        |
       |                              ...                              |

我们从包头的第一个字节就能够区分

+----------------+
                   | 127 < B < 192 -+--> forward to RTP
                   |                |
       packet -->  |  19 < B < 64  -+--> forward to DTLS
                   |                |
                   |       B < 2   -+--> forward to STUN
                   +----------------+

代码示例如下:

if((buffer[0]==0) || (buffer[0]==1))
      return stun; // STUN packet

 if((buffer[0]>=128) && (buffer[0]<=191))
      return rtp; // RTP packet

 if((buffer[0]>=20)  && (buffer[0]<=64))
      return dtls; // DTLS packet

2. 区分 RTP 和 RTCP

在一个端口上传输 RTP 和 RTCP 包会面临 payload 冲突的问题。RTCP 头的第二个字节是 payload type, RTP 头的第二个字节的低 7 位是 payload type, RFC 5761 总结了一下,有如下冲突

  • RTP 有效载荷类型 64-65 与原始“H.261 视频流的 RTP 有效载荷格式”(由 RFC 2032 定义,由 RFC 4587 废弃)中定义的(过时的)RTCP FIR 和 NACK 数据包冲突。

  • RTP 有效载荷类型 72-76 与 RTP 规范 (RFC3550) 中定义的 RTCP SR、RR、SDES、BYE 和 APP 数据包冲突。

  • RTP 有效负载类型 77-78 与 RTP/AVPF 配置文件 (RFC 4585) 中定义的 RTCP RTPFB 和 PSFB 数据包冲突。

  • RTP 负载类型 79 与 RTCP 扩展报告 (XR) (RFC 3611) 数据包冲突。

  • RTP 有效负载类型 80 与“具有单播反馈的单源多播会话的 RTCP 扩展”(RFC 5760) 中定义的接收器摘要信息 (RSI) 数据包冲突。

也就是 RTP payload type 64 ~ 95 会和 RTCP 有冲突,所以根据 RFC3551 RTP/AVP profile 的规定,RFC 5761 建议 RTP payload 64 ~ 95 不要再使用, RTP 的动态 payload type 的选择最好在 96 ~ 127 之间

3. 区分不同的媒体流

传统上,一个传输通道只传输一路媒体流,其 RTP 包 的 SSRC 也用来标识这路媒体流。 RTCP 会使用一个单独的传输
媒体协商的 SDP 中的一个 m-line 也只包含一路或者一对(包括重传 RTX 的媒体流 )媒体流。

WebRTC 中为避免过多地使用 NAT 技术来穿透防火墙,可用多路复用技术在一个传输通道中传输多路媒体,包括RTCP, 重传的媒体流。

一个传输通道(五元组: protocol, srcHost, srcPort, destHost, destPort)中包含多路媒体流,也就是有多个 m-line。而一个 m-line 中也可包含多个 ssrc, 即通过联播 Simulcast 技术让 MediaStream 包含多个 MediaStreamTrack(分辨率或码率不同)。

那么如何辨别这些 MediaStream 和 MediaStreamTrack 呢? SSRC 和 Payload Type 显然不够,因为 SSRC 会变化,Payload Type 会重复。

WebRTC 将这些媒体流放在一个 bundle group 中, 通过 mid 来标识媒体流 MediaStream, 通过 rid 来标识媒体流中不同的 MediaStreamTrack, 例如来自相同源的不同质量,分辨率或帧率的流

v=0
o=- 708564895714429943 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1 2 3 4
a=extmap-allow-mixed
a=msid-semantic: WMS rb3Uanb7CQq8HfZe0gexpjwoNCQai0AbUoQB
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 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:u8aT
a=ice-pwd:nTH+98fL7o+XacAd//X7uStI
a=ice-options:trickle
a=fingerprint:sha-256 6E:FD:8F:7C:E7:6B:DF:2B:6F:D6:32:B6:A6:00:62:D5:7E:4E:11:91:91:37:95:BE:2C:00:3F:B2:67:6F:DF:3C
a=setup:actpass
a=mid:0
//...省略若干属性
a=ssrc:104648773 cname:XQRmiLwREWI1CiN0
a=ssrc:104648773 msid:rb3Uanb7CQq8HfZe0gexpjwoNCQai0AbUoQB fc805128-e98d-47d2-a9a6-b8976c91a404
a=ssrc:104648773 mslabel:rb3Uanb7CQq8HfZe0gexpjwoNCQai0AbUoQB
a=ssrc:104648773 label:fc805128-e98d-47d2-a9a6-b8976c91a404

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127 121 125 107 108 109 124 120 123 119 35 36 41 42 114 115 116
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:u8aT
a=ice-pwd:nTH+98fL7o+XacAd//X7uStI
a=ice-options:trickle
a=fingerprint:sha-256 6E:FD:8F:7C:E7:6B:DF:2B:6F:D6:32:B6:A6:00:62:D5:7E:4E:11:91:91:37:95:BE:2C:00:3F:B2:67:6F:DF:3C
a=setup:actpass
a=mid:1
//...省略若干属性
a=rtcp-mux
//...省略若干属性
a=rid:high send
a=rid:middle send
a=rid:low send
a=simulcast:send high;middle;low

m=audio 9 UDP/TLS/RTP/SAVPF 111 63 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:u8aT
a=ice-pwd:nTH+98fL7o+XacAd//X7uStI
a=ice-options:trickle
a=fingerprint:sha-256 6E:FD:8F:7C:E7:6B:DF:2B:6F:D6:32:B6:A6:00:62:D5:7E:4E:11:91:91:37:95:BE:2C:00:3F:B2:67:6F:DF:3C
a=setup:actpass
a=mid:2
//...省略若干属性
a=rtcp-mux

//...省略若干属性

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 102 122 127 121 125 107 108 109 124 120 123 119 35 36 37 38 39 40 41 42 114 115 116 43
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:u8aT
a=ice-pwd:nTH+98fL7o+XacAd//X7uStI
a=ice-options:trickle
a=fingerprint:sha-256 6E:FD:8F:7C:E7:6B:DF:2B:6F:D6:32:B6:A6:00:62:D5:7E:4E:11:91:91:37:95:BE:2C:00:3F:B2:67:6F:DF:3C
a=setup:actpass
a=mid:3
//...省略若干属性
a=rtcp-mux
a=rtcp-rsize
//...省略若干属性

m=application 9 UDP/DTLS/SCTP webrtc-datachannel
c=IN IP4 0.0.0.0
a=ice-ufrag:u8aT
a=ice-pwd:nTH+98fL7o+XacAd//X7uStI
a=ice-options:trickle
a=fingerprint:sha-256 6E:FD:8F:7C:E7:6B:DF:2B:6F:D6:32:B6:A6:00:62:D5:7E:4E:11:91:91:37:95:BE:2C:00:3F:B2:67:6F:DF:3C
a=setup:actpass
a=mid:4
a=sctp-port:5000
a=max-message-size:262144

RTP 包 会带上 mid 和 rid 的扩展头

0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|       0xBE    |    0xDE       |           length=3            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  ID   | L=0   |     mid       |  ID   |  L=1  |   rid
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      ...data   |    0 (pad)    |    0 (pad)    |  ID   | L=3   |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                          other extension                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

这样我们就能够通过 mid 和 rid 来区分不同的媒体流

注意:

  1. mid 通常用来区分不同的媒体源(麦克风,摄像头或共享屏幕),而 rid 通常用来区分来自一个媒体源所发送的不同质量的媒体流
  2. mid 和 rid 并不会始终附加在 RTP 包中,通常只会在开头一直到收到第一个 RTCP RR 包

参考资料

  • RFC3550: RTP 核心协议
  • RFC3711: SRTP 安全的 RTP
  • RFC5761: Multiplexing RTP Data and Control Packets on a Single Port
  • RFC7941: RTP Header Extension for the RTP Control Protocol (RTCP) Source Description Items - 旧版为 draft-ietf-avtext-sdes-hdr-ext-07
  • RFC8843: Negotiating Media Multiplexing Using the Session Description Protocol(SDP)
  • RFC8851: RTP Payload Format Restrictions - 旧版为 draft-ietf-mmusic-rid-15
  • RFC8852: RTP Stream Identifier Source Description (SDES) draft-ietf-avtext-rid-09
  • RFC8853: Using Simulcast in Session Description Protocol (SDP) and RTP Sessions
  • RFC8858: Indicating Exclusive Support of RTP and RTP Control Protocol (RTCP) Multiplexing Using the Session Description Protocol (SDP)
  • RFC8860: Sending Multiple Types of Media in a Single RTP Session
  • RFC8872: Guidelines for Using the Multiplexing Features of RTP to Support Multiple Media Streams
  • RFC 8834: Media Transport and Use of RTP in WebRTC
  • RFC 5245: Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal for Offer/Answer Protocols
  • RFC 8445: Interactive Connectivity Establishment (ICE): A Protocol for Network Address Translator (NAT) Traversal
  • RFC 8489: Session Traversal Utilities for NAT (STUN)
  • RFC 5766: Traversal Using Relays around NAT (TURN):Relay Extensions to Session Traversal Utilities for NAT (STUN)


本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WebRTC的多路混音算法,主要考虑了人耳在同一时间内最多只能感知3路音频的特性。因此,在多路混音时,选择三路能力值最大的音频作为主要混音,其他参与者判断是否上一帧参与过混音,如果参与过,则当前帧进行淡出处理,然后一起进行混音。最终的混音算法是简单的线性叠加并进行饱和运算。\[1\] 然而,在使用WebRTC的GCC算法进行多路混音时,可能会出现下行带宽估计码率的竞争失衡问题。为了保证下行的秒开速度,起始的码率设置较大,约为2Mbps。同时,屏幕分享的码率动态差距很大,字数较多的情况下可以达到2Mbps,但常规状态下码率较低,只有约300kbps。这样的环境下,GCC算法可能会面临一些异常情况。为了验证整个算法在传输的异常情况,进行了全面的仿真实验。\[2\] 总结来说,WebRTC的多路混音算法考虑了人耳感知的特性,并采用简单的线性叠加和饱和运算进行混音。在使用GCC算法进行多路混音时,可能会出现下行带宽估计码率的竞争失衡问题,需要进行相应的优化和验证。\[1\]\[2\] #### 引用[.reference_title] - *1* [webRTC混音流程](https://blog.csdn.net/u013692429/article/details/100778297)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [流媒体弱网优化之路(WebRTC)——GCC带宽估计算法调优](https://blog.csdn.net/qw225967/article/details/131464688)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值