WebRTC學習筆記五 SDP(Session Description Protocol)

才高八斗船帆ub 發佈 2022-12-02T01:08:38.094076+00:00

Transceivers is a WebRTC specific concept that you will see in the API. What it is doing is exposing the 『Media Description』 to the JavaScript API. Each Media Description becomes a Transceiver. Every time you create a Transceiver a new Media Description is added to the local Session Description.

SDP裡面內容雖然很多,但是條理很清楚。SDP值為字符串,通過換行符生成一行一行的SDP報文,所有行可分為三類:全局行、音頻行、視頻行

  • v - Version,版本,版本,應等於0
  • o - Origin,源,包含一個唯一ID,用於重新協商
  • s - Session Name,會話名稱,應等於-
  • t - Timing,時間,應等於0 0
  • m - Media Description,媒體描述,下面有詳細說明
  • a - Attribute,屬性,一個自由文本欄位,這是webrtc中最常見的行
  • c - Connection Data,連接數據,應等於IN IP4 0.0.0.0

一、全局行

v=0

sdp版本號,一直為0,rfc4566規定

o=- 7017624586836067756 2 IN IP4 127.0.0.1

o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>

各欄位含義如下:

  • username:發起者的用戶名,不允許存在空格,如果應用不支持用戶名,則為-。
  • sess-id:會話id,由應用自行定義,規範的建議是NTP(Network Time Protocol)時間戳。
  • sess-version:會話版本,用途由應用自行定義,只要會話數據發生變化時(比如編碼),sess-version隨著遞增就行。同樣的,規範的建議是NTP時間戳。
  • nettype:網絡類型,比如IN表示Internet。
  • addrtype:地址類型,比如IP4、IV6
  • unicast-address:域名,或者IP位址。

s=<session name>

會話名,沒有的話使用 - 代替

t=0 0

它給出了開始和結束時間。 當它們被設置為0時,意味著會話不受特定時間限制,換句話說,它在任何時候都是永久有效的。

a=group:BUNDLE audio video

BUNDLE分組建立了SDP中包含的幾個媒體線之間的關係,通常是音頻和視頻。在WebRTC中,它用於在相同的rtp會話中復用多個媒體流。 在這種情況下,瀏覽器提供多路復用音頻和視頻,但另一方也必須支持和接受。 如果沒有這一行,音視頻,數據就會分別單獨用一個udp埠來發送

a=msid-semantic: WMS h1aZ20mbQB0GSsq0YxLfJmiYWE9CBfGch97C

WMS是WebRTC Media Stream簡稱,這一行定義了本客戶端支持同時傳輸多個流,一個流可以包括多個track, 一般定義了這個,後面a=ssrc這一行就會有msid,mslabel等屬性

二、視頻行

2.1 媒體描述

m=video 60372 UDP/tls/RTP/SAVPF 100 101 116 117 96

m=video說明本會話包含音頻,60372代表視頻使用埠60372來傳輸,但是在webrtc中一現在一般不使用,如果設置為0,代表不傳輸音頻, UDP/TLS/RTP/SAVPF是表示用戶來傳輸視頻支持的協議,udp,tls,rtp代表使用udp來傳輸rtp包,並使用tls加密SAVPF代表使用srtcp的反饋機制來控制通信過程, 後台100 101 116 117 96表示本會話視頻支持的編碼。

m=<media> <port> <proto> <fmt> ...

其中:

  • media:媒體類型。包括 video、audio、text、application、message等。
  • port:傳輸媒體流的埠,具體含義取決於使用的網絡類型(在c=中聲明)和使用的協議(proto,在m=中聲明)。
  • proto:傳輸協議,具體含義取決於c=中定義的地址類型,比如c=是IP4,那麼這裡的傳輸協議運行在IP4之上。比如:
    • UDP:傳輸層協議是UDP。
    • RTP/AVP:針對視頻、音頻的RTP協議,跑在UDP之上。
    • RTP/SAVP:針對視頻、音頻的SRTP協議,跑在UDP之上。
  • fmt:媒體格式的描述,可能有多個。根據 proto 的不同,fmt 的含義也不同。比如 proto 為 RTP/SAVP 時,fmt 表示 RTP payload 的類型。如果有多個,表示在這次會話中,多種payload類型可能會用到,且第一個為默認的payload類型。 舉例,下面表示媒體類型是視頻,採用SRTP傳輸流媒體數據,且RTP包的類型可能是122、102...119,默認是122。
m=video 9 UDP/TLS/RTP/SAVPF 122 102 100 101 124 120 123 119

對於 RTP/SAVP,需要注意的是,payload type 又分兩種類型:

  • 靜態類型:參考 RTP/AVP audio and video payload types。
  • 動態類型:在a=fmtp:里進行定義。(a=為附加屬性,見後面小節)

舉例,下面的SDP中:

  • 對於audio,111 是動態類型,表示opus/48000/2
  • 對於video,122 是動態類型,表示H264/90000
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 126
a=rtpmap:111 opus/48000/2
m=video 9 UDP/TLS/RTP/SAVPF 122 102 100 101 124 120 123 119
a=rtpmap:122 H264/90000

【騰訊文檔】FFmpegWebRTCRTMPRTSPHLSRTP播放器-音視頻流媒體高級開發-資料領取
FFmpegWebRTCRTMPRTSPHLSRTP鎾斁鍣�-闊寵棰戞祦濯掍綋楂樼駭寮€鍙�-璧勬枡棰嗗彇

2.2 連接數據(c=)

c=IN IP4 217.130.243.155

c=<nettype> <addrtype> <connection-address>

每個SDP至少需要包含一個會話級別的c=欄位,或者在每個媒體描述後面各包含一個c=欄位。(媒體描述後的c=會覆蓋會話級別的c=)

  • nettype:網絡類型,比如IN,表示 Internet。
  • addrtype:地址類型,比如IP4、IP6。
  • connection-address:如果是廣播,則為廣播地址組;如果是單播,則為單播地址;

舉例01:

c=IN IP4 224.2.36.42/127

舉例02:

c=IN IP4 host.anywhere.com

2.3 屬性(a=)

a=rtcp:64891 IN IP4 217.130.243.155

a=<attribute> | <attribute>:<value>

屬性(attribute)是擴展SDP的主要手段,分為會話級屬性和媒體級屬性:

(a)會話級屬性:添加在第一個媒體描述之前,傳達的信息適用於整個會議而不是單個媒體。

  • a=group:BUNDLE audio video 通過mid標識符把多個媒體屬性連接起來;
  • a=msid-semantic: WMS ma 表示是webrtc媒體流(Webrtc Media Streams);

(b)媒體級屬性:媒體描述中添加有關媒體流的信息。

  • a=mid:audio 上述BUNDLE中用到的媒體標識;
  • a=msid:ma ta 連接不同的媒體描述,使用相同的MediaStreams;
  • a=sendonly 表示媒體發送端,其他類型:recvonly,sendrecv,inactive;
  • a=rtcp:9 IN IP4 0.0.0.0 用來傳輸rtcp地地址和埠;
  • a=rtcp-mux 表示rtp,rtcp包使用同一個埠來傳輸;
  • a=ice-xxx:xxx ice協商過程中的安全驗證信息;
  • a=fingerprint:xxx 表示dtls協商過程中需要的認證信息;
  • a=setup:actpass 表示本客戶端在dtls協商過程中,可以做客戶端也可以做服務端;
  • a=rtpmap:111 opus/48000/2 負載類型111,編碼格式opus,48000是時鐘,2是通道數;
  • a=rtcp-fb:111 nack 支持丟包重傳;
  • a=rtcp-fb:111 nack pli 支持關鍵幀丟包重傳;
  • a=rtcp-fb:111 transport-cc 表示opus編碼支持使用rtcp來控制擁塞;
  • a=fmtp:111 minptime=10;useinbandFEC=1;maxplaybackrate=16000 對opus編碼可選的補充說明,minptime代表最小打包時長是10ms,useinbandfec=1代表使用opus編碼內置fec特性;
  • a=ssrc:1370113029 cname:NMediaAudio cname用來標識一個數據源,ssrc當發生衝突時可能會發生變化,但是cname不會發生變化,也會出現在rTCP包中SDEC中,用於音視頻同步;
  • a=candidate:1 1 udp 2013266431 x.x.x.x 43342 typ host generation 0 表示候選人的傳輸地址,查看詳情。

2.1 ICE候選者

a=candidate:1467250027 1 udp 2122260223 192.168.0.196 56143 typ host generation 0

2.2 ICE參數

a=ice-ufrag:Oyef7uvBlwafI3hT a=ice-pwd:T0teqPLNQQOf+5W+ls+P2p16

2.3 DTLS參數

a=fingerprint:sha-256 49:66:12:17:0D:1C:91:AE:57:4C:C6:36:DD:D5:97:D2:7D:62:C9:9A:7F:B9:A3:F4:70:03:E7:43:91:73:23:5E a=setup:actpass

2.4 Codec參數

a=rtpmap:100 VP8/90000

這條線表示VP8與有效載荷類型100對齊。這意味著此會話中包含VP8視頻幀的RTP數據包的有效載荷類型欄位的值將為100. 現在VP8是視頻的MTI編解碼器,未來可能會發生變化。

a=rtcp-fb:100 ccm fir

指明使用全內幀請求(Full Intraframe Request, FIR)

a=rtcp-fb:100 nack

此行請求使用RFC 4585中指示的否定ACK(nack)。這允許另一端知道數據包丟失。

a=rtcp-fb:100 nack pli

此行表明支持PLI NACK RTCP消息。 這允許在視頻包丟失時向另一端點請求新的VP8關鍵幀。

a=rtcp-fb:100 goog-remb

它定義了RTCP消息對Receiver Estimated Maximum Bitrate的使用。前綴goog-意味著仍然只能由Google和非標準實現。

a=rtpmap:101 VP9/90000

Chrome支持版本48的VP9。您可以在Web M項目站點了解此視頻編解碼器的功能。 默認情況下,它在VP8之後顯示為SDP中的第二個選項。

a=rtcp-fb:101 ccm fir a=rtcp-fb:101 nack a=rtcp-fb:101 nack pli a=rtcp-fb:101 goog-remb a=rtpmap:116 red/90000

該行請求使用RFC2198,其定義有效載荷格式以編碼冗餘媒體數據。在WebRTC中,這用於封裝有效載荷VP8(視頻有效載荷本身)和FEC(Forward Error Correction)。

a=rtpmap:117 ulpfec/90000

此行請求使用ULP FEC(在RFC5109中定義)。 FEC(前向糾錯)允許通過基於原始分組發送冗餘信息來糾正數據傳輸中的某種錯誤。 當丟包(在RTCP-RR數據包中報告)時使用FEC。

a=rtpmap:96 rtx/90000

參數rtx和apt在RFC4588中定義。 該RFC定義了RTP有效載荷格式,僅用於執行另一方尚未接收的分組的重傳。 無法使用原始有效負載重新發送數據包,因為它會破壞RTP和RTCP機制,因此它們會在具有不同有效負載的重新傳輸流中重新傳輸。 90000指的是重傳流的時鐘速率,其與原始VP8流相同,原始VP8流與其他視頻協議90000相同。

a=fmtp:96 apt=100

該行表示具有有效載荷96的RTP分組將傳輸那些已經在該SDP(VP8)中對有效載荷100進行了編碼的編解碼器的rtx消息。

2.5 SSRC參數

a=ssrc-group:FID 2231627014 632943048

此行聲明SSRC 632943048是RFC5576中指定的2231627014的rtx修複流程

a=ssrc:2231627014 cname:4TOk42mSjXCkVIa6 a=ssrc:2231627014 msid:lgsCFqt9kN2fVKw5wg3NKqGdATQoltEwOdMS daed9400-d0dd-4db3-b949-422499e96e2d a=ssrc:2231627014 mslabel:lgsCFqt9kN2fVKw5wg3NKqGdATQoltEwOdMS a=ssrc:2231627014 label:daed9400-d0dd-4db3-b949-422499e96e2d

** 註:未特別說明,則與audio一致

三、音頻行

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 126

m=audio說明本會話包含音頻,9代表音頻使用埠9來傳輸,但是在webrtc中一現在一般不使用,如果設置為0,代表不傳輸音頻, UDP/TLS/RTP/SAVPF是表示用戶來傳輸音頻支持的協議,udp,tls,rtp代表使用udp來傳輸rtp包,並使用tls加密SAVPF代表使用srtcp的反饋機制來控制通信過程, 後台111 103 104 9 0 8 106 105 13 126表示本會話音頻支持的編碼。

c=IN IP4 0.0.0.0

這一行表示你要用來接收或者發送音頻使用的IP位址,webrtc使用ice傳輸,不使用這個地址

a=rtcp:9 IN IP4 0.0.0.0

明確指定傳輸RTCP的IP和埠,而不是從基礎媒體埠派生的。請注意,與SRTP的埠相同,因為支持RTCP Multiplex。webrtc中不使用。

a=mid:audio

在前面BUNDLE這一行中用到的媒體標識。如果我們有不同的媒體,我們每個都應該有不同的標識符。

a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level

此行定義將在RTP標頭中使用的擴展,以便接收器可以正確解碼並提取元數據。

a=sendrecv

上一行指出我是雙向通信,另外幾種類型是recvonly,sendonly,inactive。

a=rtcp-mux

指出rtp,rtcp包使用同一個埠來傳輸

3.1 ICE候選者

a=candidate:1467250027 1 udp 2122260223 192.168.0.196 46243 typ host generation 0

a=candidate:1467250027 2 udp 2122260222 192.168.0.196 56280 typ host generation 0

UDP上RTP的主機候選者 - 在此ICE行中,我們的瀏覽器為其主機候選者 - 瀏覽器正在計算機上監聽的接口或接口的IP。 瀏覽器可以在該IP上接收/發送SRTP和SRTCP,以防遠程對等端的候選者具有IP可見性。例如,如果另一台計算機位於同一LAN上,則將使用主機候選項。 協議(udp) - 2122260223之後的數字是候選者的優先級。請注意,宿主候選者的優先級高於其他候選者, 因為使用宿主候選者在資源使用方面更有效。第一行(component = 1)用於RTP,第二行(component = 2)用於RTCP。 請注意,瀏覽器不知道另一端是否支持rtcp-mux,因此它必須在要約中包含RTCP埠。

a=candidate:435653019 1 tcp 1845501695 192.168.0.196 0 typ host tcptype active generation 0

a=candidate:435653019 2 tcp 1845501695 192.168.0.196 0 typ host tcptype active generation 0

TCP上RTP的主機候選者 - 這些線路與之前的兩條ICE線路相同,但是對於TCP流量。 請注意,優先級較低 - 即1845501695較大 - 因為TCP不是實時媒體傳輸的最佳選擇。

a=candidate:1853887674 1 udp 1518280447 47.61.61.61 36768 typ srflx raddr 192.168.0.196 rport 36768 generation 0

a=candidate:1853887674 2 udp 1518280447 47.61.61.61 36768 typ srflx raddr 192.168.0.196 rport 36768 generation 0

UDP上RTP的自反性候選者(reflexive candidates) - 這裡我們有伺服器反身候選人。 請注意,它們的優先級低於主機候選者。 這些候選人是由STUN伺服器發現的。

a=candidate:750991856 2 udp 25108222 237.30.30.30 51472 typ relay raddr 47.61.61.61 rport 54763 generation 0

a=candidate:750991856 1 udp 25108223 237.30.30.30 58779 typ relay raddr 47.61.61.61 rport 54761 generation 0

UDP上RTP的中繼候選者(Relay candidates) - 接下來我們有中繼候選。這些候選者是從TURN伺服器獲得的,必須在創建對等連接時進行配置。 請注意,此處的優先級低於主機和反射候選者(25108222更高),因此僅當主機和反射候選者之間沒有IP連接時才使用中繼。

3.2 ICE參數

a=ice-ufrag:khLS

a=ice-pwd:cxLzteJaJBou3DspNaPsJhlQ

以上兩行是ice協商過程中的安全驗證信息

3.3 DTLS參數

a=fingerprint:sha-256 FA:14:42:3B:C7:97:1B:E8:AE:0C2:71:03:05:05:16:8F:B9:C7:98:E9:60:43:4B:5B:2C:28:EE:5C:8F3:17

此指紋是DTLS-SRTP協商中使用的證書的哈希函數的結果。 此行在信令(應該是可信的)和DTLS中使用的證書之間創建綁定,如果指紋不匹配,則應拒絕會話。

a=setup:actpass

代表本客戶端在dtls協商過程中,可以做客戶端也可以做服務端

3.4 Codec參數

a=rtpmap:111 opus/48000/2

Opus是WebRTC的MTI音頻編解碼器之一。 它具有可變比特率(6kbps-510kbps),並且不受任何版稅限制,因此可以在任何瀏覽器中自由實現。 Opus支持開始變得普遍,它已成為大多數WebRTC應用程式的關鍵。

a=fmtp:111 minptime=10; useinbandfec=1

此行包括Chrome支持的音頻Opus編解碼器的可選有效載荷格式特定參數。 minipitime = 10指定分組化時間的最低值(ptime:由單個分組傳輸的音頻的毫秒數)。 useinbandfec = 1指定解碼器能夠利用Opus帶內FEC(前向錯誤連接)。

a=rtpmap:103 ISAC/16000

ISAC(網際網路語音音頻編解碼器)是用於高質量會議的寬帶語音編解碼器。 16000表示ISAC將以16kbps的速度使用。

a=rtpmap:104 ISAC/32000

32000表示ISAC將以32kbps的速度使用。

a=rtpmap:9 G722/8000

G722是一款工作頻率為48,56和64 kbit/s的寬帶音頻編解碼器,與G.711等窄帶語音編碼器相比,由於50-7000 Hz的語音帶寬更寬,因此可提供更高的語音質量。

a=rtpmap:0 PCMU/8000

a=rtpmap:8 PCMA/8000

這是使用不同壓擴法則的經典電信64kbps脈衝編碼調製(PCM)編解碼器。 0和8分別是PCMU和PCMA的靜態有效載荷類型。從技術上講,這些線路不存在,因為這些信息可以通過媒體線中的編解碼器列表 - PCMU或PCMA來推斷。

a=rtpmap:106 CN/32000

a=rtpmap:105 CN/16000

a=rtpmap:13 CN/8000

上面的動態RTP有效載荷類型(除了有效載荷類型13,它是靜態的)表示舒適噪聲(Comfort Noise, CN)將用於速率為48000,32000,16000和8000kbits/s的編解碼器。

a=rtpmap:126 telephone-event/8000

此行表示瀏覽器支持RFC4733,允許它在RTP內發送DTMF,而不是通常的數位化正弦波,而是作為特殊有效載荷(在這種情況下,RTP數據包中有效載荷126)。 該DTMF機制確保DTMF將獨立於音頻編解碼器和信令協議進行傳輸。

a=maxptime:60

maxptime指定可以封裝在每個數據包中的最大媒體數量,以毫秒為單位表示。數據包的大小可能會對音頻和BW的質量產生副作用。可以在SDP中修改此值。

3.5 SSRC參數

a=ssrc:3570614608 cname:4TOk42mSjXCkVIa6

cname源屬性將媒體源與其Canonical端點標識符相關聯,即使在發現衝突時ssrc標識符發生更改,該標準端點標識符也將保持RTP媒體流的常量。 這是媒體發送方將在其RTCP SDES數據包中放置的值。

a=ssrc:3570614608 msid:lgsCFqt9kN2fVKw5wg3NKqGdATQoltEwOdMS 35429d94-5637-4686-9ecd-7d0622261ce8

該線用於使用SDP信令通知SSRC的RTP概念與「媒體流」/「媒體流軌道」的WebRTC概念之間的關聯。 第一個參數對應於媒體流(media stream)的id,第二個參數對應於媒體流軌道的if。這些ID在WebRTC API中處理。 第一個數字是SSRC標識符,它將包含在RTP數據包的SSRC欄位中。

a=ssrc:3570614608 mslabel:lgsCFqt9kN2fVKw5wg3NKqGdATQoltEwOdMS

label屬性指的是Media Stream對象的id。不推薦使用該參數,並將msid替換為該參數。標籤是為了向後兼容而保留。

a=ssrc:3570614608 label:35429d94-5637-4686-9ecd-7d0622261ce8

label屬性也被msid棄用,並在使用SDP的任意網絡應用程式的上下文中攜帶指向RTP媒體流的指針。 此標籤與WebRTC API中的Media Stream Track ID相對應,該ID包含在msid行中。

四、WebRTC實例

下面例子來自騰訊雲WebRTC服務的遠端offer。

// sdp版本號為0
v=0
// o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
// 用戶名為空,會話id是8100750360520823155,會話版本是2
//(後面如果有類似改變編碼的操作,sess-version加1),
// 地址類型為IP4,地址為127.0.0.1(這裡可以忽略)
o=- 7595655801978680453 2 IN IP4 112.90.139.105
// 會話名為空
s=-
// 會話的起始時間,都為0表示沒有限制
t=0 0
a=ice-lite
// 音頻、視頻的傳輸的傳輸採取多路復用,通過同一個RTP通道傳輸音頻、視頻,
// 可以參考 https://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-54
a=group:BUNDLE 0 1
// WMS是WebRTC Media Stram的縮寫,這裡給Media Stream定義了一個唯一的標識符。
// 一個Media Stream可以有多個track(video track、audio track),
//這些track就是通過這個唯一標識符關聯起來的,具體見下面的媒體行(m=)以及它對應的附加屬性(a=ssrc:)
// 可以參考這裡 http://tools.ietf.org/html/draft-ietf-mmusic-msid
a=msid-semantic: WMS 5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV
// m=<media> <port> <proto> <fmt> ...
// 本次會話有音頻,埠為9(可忽略,埠9為Discard Protocol專用),
// 採用UDP傳輸加密的RTP包,並使用基於SRTCP的音視頻反饋機制來提升傳輸質量
//,111、103、104等是audio可能採用的編碼(參見前面m=的說明)
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 126
// 音頻發送者的IP4地址,WebRTC採用ICE,這裡的 0.0.0.0 可直接忽略
c=IN IP4 0.0.0.0
// RTCP採用的埠、IP位址(可忽略)
a=rtcp:9 IN IP4 0.0.0.0
// ice-ufrag、ice-pwd 分別為ICE協商用到的認證信息
a=ice-ufrag:58142170598604946
a=ice-pwd:71696ad0528c4adb02bb40e1
// DTLS協商過程的指紋信息
a=fingerprint:sha-256 7F:98:08:AC:17:6A:34:DB:CF:3B:EC:93:ED:57:3F:5A:9E:1F:4A:F3:DB:D5:BF:66:EE:17:58:E0:57:EC:1B:19
// 當前客戶端在DTLS協商過程中,既可以作為客戶端,也可以作為服務端,具體可參考 RFC4572
a=setup:actpass
// 當前媒體行的標識符(在a=group:BUNDLE 0 1 這行裡面用到,這裡0表示audio)
a=mid:0
// RTP允許擴展首部,這裡表示採用了RFC6464定義的針對audio的擴展首部,
// 用來調節音量,比如在大型會議中,有多個音頻流,就可以用這個來調整音頻混流的策略
// 這裡沒有vad=1,表示不啟用這個音量控制
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
// 表示既可以發送音頻,也可以接收音頻
a=sendrecv
// 表示啟用多路復用,RTP、RTCP共用同個通道
a=rtcp-mux
// 下面幾行都是對audio媒體行的補充說明(針對111),包括rtpmap、rtcp-fb、fmtp
// rtpmap:編解碼器為opus,採樣率是48000,2聲道
a=rtpmap:111 opus/48000/2
// rtcp-fb:基於RTCP的反饋控制機制,可以參考 https://tools.ietf.org/html/rfc5124、
//https://webrtc.org/experiments/rtp-hdrext/transport-wide-cc-02/
a=rtcp-fb:111 transport-cc
a=rtcp-fb:111 nack
// 最小的音頻打包時間
a=fmtp:111 minptime=20
// 跟前面的rtpmap類似
a=rtpmap:126 telephone-event/8000
// ssrc用來對媒體進行描述,格式為a=ssrc:<ssrc-id> <attribute>:<value>,具體可參考 RFC5576
// cname用來唯一標識媒體的數據源
a=ssrc:16864608 cname:YZcxBwerFFm6GH69
// msid後面帶兩個id,第一個是MediaStream的id,第二個是audio track的id(跟後面的mslabel、label對應)
a=ssrc:16864608 msid:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV 128f4fa0-81dd-4c3a-bbcd-22e71e29d178
a=ssrc:16864608 mslabel:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV
a=ssrc:16864608 label:128f4fa0-81dd-4c3a-bbcd-22e71e29d178
// 跟audio類似,不贅述
m=video 9 UDP/TLS/RTP/SAVPF 122 102 125 107 124 120 123 119
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:58142170598604946
a=ice-pwd:71696ad0528c4adb02bb40e1
a=fingerprint:sha-256 7F:98:08:AC:17:6A:34:DB:CF:3B:EC:93:ED:57:3F:5A:9E:1F:4A:F3:DB:D5:BF:66:EE:17:58:E0:57:EC:1B:19
a=setup:actpass
a=mid:1
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:4 urn:3gpp:video-orientation
a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:122 H264/90000
a=rtcp-fb:122 ccm fir
a=rtcp-fb:122 nack
a=rtcp-fb:122 nack pli
a=rtcp-fb:122 goog-remb
a=rtcp-fb:122 transport-cc
a=fmtp:122 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:102 rtx/90000
a=fmtp:102 apt=122
a=rtpmap:125 H264/90000
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 transport-cc
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtpmap:124 H264/90000
a=rtcp-fb:124 ccm fir
a=rtcp-fb:124 nack
a=rtcp-fb:124 nack pli
a=rtcp-fb:124 goog-remb
a=rtcp-fb:124 transport-cc
a=fmtp:124 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d0032
a=rtpmap:120 rtx/90000
a=fmtp:120 apt=124
a=rtpmap:123 H264/90000
a=rtcp-fb:123 ccm fir
a=rtcp-fb:123 nack
a=rtcp-fb:123 nack pli
a=rtcp-fb:123 goog-remb
a=rtcp-fb:123 transport-cc
a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtpmap:119 rtx/90000
a=fmtp:119 apt=123
a=ssrc-group:FID 33718809 50483271
a=ssrc:33718809 cname:ovaCctnHP9Asci9c
a=ssrc:33718809 msid:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV 1d7fc300-9889-4f94-9f35-c0bcc77a260d
a=ssrc:33718809 mslabel:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV
a=ssrc:33718809 label:1d7fc300-9889-4f94-9f35-c0bcc77a260d
a=ssrc:50483271 cname:ovaCctnHP9Asci9c
a=ssrc:50483271 msid:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV 1d7fc300-9889-4f94-9f35-c0bcc77a260d
a=ssrc:50483271 mslabel:5Y2wZK8nANNAoVw6dSAHVjNxrD1ObBM2kBPV
a=ssrc:50483271 label:1d7fc300-9889-4f94-9f35-c0bcc77a260d

五、Uncaught (in promise) DOMException: Answer tried to set recv when offer did not set send

chrome 中可以播放,firefox報錯

搜索一下,參考https://stackoverflow.com/questions/35166456

RFC 3264: " If a media stream is listed as recvonly in the offer, the answer MUST be marked as sendonly or inactive in the answer. "

這裡可以參考SDP模型介紹,獲取更詳細的知識

1.情態動詞術語解釋

  • MUST必須、一定要;
  • MUST NOT禁止;
  • REQUIRED需要;
  • SHALL、SHOULD應該;
  • SHALL NOT、SHOULD NOT不應該;
  • RECOMMENDED推薦;
  • MAY可以

以上情態動詞術語可參考RFC2119[3],這些動詞要求我們在產品實現時,需要遵守或靈活變更約束。

2.初始協商的Offer請求

實體A <-> 實體B,實體首先發起Offer請求,內容如2節所示,對於作何一個媒體流/媒體通道,這時實體A必須:

  • 如果媒體流方向標為recvonly/sendrecv,即a=recvonly或a=sendrecv,則A必須(MUST)準備好在這個IP和埠上接收實體B發來的媒體流;
  • 如果媒體流方向標為sendonly/inactive,即a=recvonly或a=sendrecv,則A不需要進行準備。

3.Answer響應

實體B收到A的請求offer後,根據自身支持的媒體類型和編碼策略,回復響應。

  • 如果實體B回復的響應中的媒體流數量和順序必須(MUST)和請求offer一致,以便實體A進行甄別和決策。即m行的數量和順序必須一致,B不能(MUST NOT)擅自增加或刪除媒體流。如果B不支持某個媒體流,可以在對應的埠置0,但不能不帶這個m行描述。
  • 對於某種媒體,實體B必須(MUST)從請求offer中選出A支持且自己也支持的該媒體的編碼標識集,並且可以(MAY)附帶自己支持的其它類型編碼。
  • 對於響應消息中各個媒體的方向: 如果請求某媒體流的方向為sendonly,那麼響應中對應媒體的方向必須為recvonly; 如果請求某媒體流的方向為recvonly,那麼響應中對應媒體的方向必須為sendonly; 如果請求某媒體流的方向為sendrecv,那麼響應中對應媒體的方向可以為sendrecv/sendonly/recvonly/inactive中的一種; 如果請求某媒體流的方向為inactive,那麼響應中對應媒體的方向必須為inactive;
  • 響應answer里提供IP和埠,指示Offerer本端期望用於接收媒體流的IP和埠,一旦響應發出之後,Offerer必須(MUST)準備好在這個IP和埠上接收實體A發來的媒體流。
  • 如果請求offer中帶了ptime(媒體流打包間隔)的a行或帶寬的a行,則響應answer也應該(SHOULD)相應的攜帶。
  • 實體B Offerer應該(SHOULD)使用實體A比較期望的編碼生成媒體流發送。一般來說對於m行,如m=video 0 RTP/AVP 31 34,排充越靠前的編碼表示該實體越希望以這個編碼作為載體,這裡示例31(H261),34(H263)中H261為A更期望使用的編碼類型。同理,當實體A收到響應answer後也是這樣理解的。

4.實體收到響應後的處理

當實體A收到B回復的響應後,可以(MAY)開始發送媒體流,如果媒體流方向為sendonly/sendrecv,

  • 必須(MUST)使用answer列舉的媒體類型/編碼生成媒體發送;
  • 應該(SHOULD)使用answer中的ptime和bandwidth來打包發送媒體流;
  • 可以(MAY)立即停止監聽埠,該埠為offer支持answer不支持的媒體所使用的埠。

5.修改媒體流(會話)

修改媒體流的offer-answer操作必須基於之前協商的媒體形式(音頻、視頻等),不能(MUST NOT)對已有媒體流進行刪減。

(a)刪除媒體流 如果實體認定新的會話不支持之前媒商的某個媒體,新的offer只須對這種媒體所在m行的埠置0,但不能不描述這種媒體,即不帶對應m行。當answerer收到響應之後,處理同初始協商一樣。

(b)增加媒體流 如果實體打算新增媒體流,在offer里只須加上描述即可或者占用之前埠被置0的媒體流,即用新的媒體描述m行替換舊的。當answerer收到offer請求後,發現有新增媒體描述,或者過於埠被置0的媒體行被新的媒體描述替換,即知道當前為新增媒體流,處理同初始協商。

(c)修改媒體流 修改媒體注主要是針對初始協商結果,如果有變更即進入修改流程處理,可能的變更包括IP位址、埠,媒體格式(編碼),媒體類型(音、視頻),媒體屬性(ptime,bandwidth,媒體流方向變更等)。

6.解決問題:

查看請求offer發送的Sdp,發現在沒有設置的情況下,全是默認的recvonly。

m=audio ...
...
a=recvonly
...
m=video ...
a=recvonly

而伺服器返回的

m=audio ...
...
a=recvonly
...
m=video ...
a=sendrecv

參照上述要求,可以將請求offer設置成sendrecv即可解決firefox中的報錯

        this.pc.addTransceiver("video", {
            'direction': 'sendrecv'
        });
        this.pc.addTransceiver("audio", {
            'direction': 'sendrecv'
        });

7.Transceivers

Transceivers are for sending and receiving

Transceivers is a WebRTC specific concept that you will see in the API. What it is doing is exposing the 『Media Description』 to the JavaScript API. Each Media Description becomes a Transceiver. Every time you create a Transceiver a new Media Description is added to the local Session Description.

Each Media Description in WebRTC will have a direction attribute. This allows a WebRTC Agent to declare 『I am going to send you this codec, but I am not willing to accept anything back』. There are four valid values:

  • send
  • recv
  • sendrecv
  • inactive
關鍵字: