WebRTC -- SDP格式解析


1 SDP組成

SDP是由多行文本組成的一個純文本協議,如果將SDP從語義上分解成不同組件來描述一個多媒體會話信息,那么SDP由以下部分組成:

  • 會話信息
  • 網絡信息
  • 媒體信息
  • 安全信息
  • 服務質量和分組信息
                                                 +---------------------+
                                                 |        v=           |
                                                 +---------------------+
                 +---------------------+         +---------------------+
         ====    |   Session Metadata  |  =====  |        o=           |
         |       +---------------------+         +----------------------
         |                                       +---------------------+
         |                                       |        t=           |
         |                                       +---------------------+
         |
         |
         |                                       +---------------------+
         |                                       |        c=           |
         |                                       +---------------------+
         |       +---------------------+
         ====    | Network Description |   =====
         |       +---------------------+
         |                                       +---------------------+
         |                                       |    a=candidate      |
         |                                       +---------------------+
         |
         |
         |                                       +---------------------+
         |                                       |        m=           |
         |                                       +---------------------+
         |        +---------------------+        +---------------------+
         ====     | Stream Description  |  ===== |      a=rtpmap       |
         |        +---------------------+        +----------------------
         |                                       +---------------------+
         |                                       |      a=fmtp         |
         |                                       +---------------------+
         |                                       +---------------------+
         |                                       |      a=sendrecv..   |
         |                                       +---------------------+
 +---------------+
 |    SEMANTIC   |
 | COMPONENTS OF |
 |     SDP       |
 +---------------+
         |                                       +---------------------+
         |                                       |      a=crypto       |
         |                                       +---------------------+
         |         +---------------------+       +---------------------+
         ====      |Security Descriptions|  =====|      a=ice-frag     |
         |         +---------------------+       +----------------------
         |                                       +---------------------+
         |                                       |      a=ice-pwd      |
         |                                       +---------------------+
         |                                       +---------------------+
         |                                       |     a=fingerprint   |
         |                                       +---------------------+
         |
         |
         |
         |                                       +---------------------+
         |                                       |      a=rtcp-fb      |
         |                                       +---------------------+
         |         +---------------------+       +---------------------+
         ====      |   Qos,Grouping      |       |                     |
                   |   Descriptions      |  =====|       a=group       |
                   +---------------------+       +----------------------
                                                 +---------------------+
                                                 |       a=rtcpmux     |
                                                 +---------------------+

 

2 SDP格式

SDP由多行組成,每行的的格式如下:

 

<type>=<value>

 

  • <type>: 區分大小寫,代表特定的屬性,例如v代表SDP版本。
  • <value>:UTF8編碼的文本,具體格式與類型有關。
  • =兩邊不允許存在空格。
  • =*表示該項是可選的。

下面是WebRTC(branch_76)的一個真實SDP樣本:

 
 
// -------------------------------- 【Session Metadata部分】 -------------------------------- 

// sdp版本號
v=0

// o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>
// username如何沒有使用-代替,3967017503571418851是整個會話的編號,2代表會話版本,如果在會話過程中有改變編碼之類的操作,重新生成sdp時,sess-id不變,sess-version加1
o=- 3967017503571418851 2 IN IP4 127.0.0.1

//會話名
s=-

// 會話的起始時間和結束時間,0代表沒有限制
t=0 0

// 表示需要共用一個傳輸通道傳輸的媒體,通過ssrc進行區分不同的流。如果沒有這一行,音視頻數據就會分別用單獨udp端口來發送.
a=group:BUNDLE audio video

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


// -------------------------------- 【Stream Description部分】 -------------------------------- 

// ------------ audio部分 -------------

// m意味着它是一個媒體行.
// m=audio說明本會話包含音頻,9代表音頻使用端口9來傳輸,但是在webrtc中現在一般不使用,如果設置為0,代表不傳輸音頻,
// UDP/TLS/RTP/SAVPF是表示用戶支持來傳輸音頻的協議,udp,tls,rtp代表使用udp來傳輸rtp包,並使用tls加密
// SAVPF代表使用srtcp的反饋機制來控制通信過程
// 后面的111 103 104 9 102 0 8 106 105 13 110 112 113 126表示本會話音頻支持的編碼,后面幾行會有詳細補充說明.
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 110 112 113 126

// 表示你要用來接收或者發送音頻使用的IP地址.
// webrtc使用ice傳輸,不使用這個地址
c=IN IP4 0.0.0.0

// 用來傳輸rtcp的地址和端口,webrtc中不使用
a=rtcp:9 IN IP4 0.0.0.0

// 下面2行是ice協商過程中的安全驗證信息
a=ice-ufrag:kSq0
a=ice-pwd:pWLGrCTwFNq6rm249ZEasHPY

// 通知對端支持trickle,即sdp里面描述媒體信息和ice候選項的信息可以分開傳輸
a=ice-options:trickle

// dtls協商過程中需要的認證信息
a=fingerprint:sha-256 A0:D6:B2:63:1B:69:0E:91:01:C3:88:A9:92:6F:E7:EF:5B:36:52:66:08:DF:94:A0:FE:0C:C9:06:BF:2C:38:A2

// 代表本客戶端在dtls協商過程中,可以做客戶端也可以做服務端, 參考rfc4145 rfc4572
a=setup:actpass

// 前面BUNDLE行中用到的媒體標識
a=mid:audio

// 指出要在rtp頭部中加入音量信息,參考 rfc6464
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level

// 指出是雙向通信,另外幾種類型是recvonly,sendonly,inactive
a=sendrecv

// 指出rtp,rtcp包使用同一個端口來傳輸
a=rtcp-mux

// 下面十幾行都是對m=audio這一行的媒體編碼補充說明,指出了編碼采用的編號,采樣率,聲道等
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
// 下面一行對opus編碼可選的補充說明,minptime代表最小打包時長是10ms,useinbandfec=1代表使用opus編碼內置fec特性
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:102 ILBC/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
// cname用來標識一個數據源,ssrc當發生沖突時可能會發生變化,但是cname不會發生變化,也會出現在rtcp包中SDEC中,用於音視頻同步
a=ssrc:2603526440 cname:AyMDWB+q6ApWdpfU
a=ssrc:2603526440 msid:stream_id audio_label
a=ssrc:2603526440 mslabel:stream_id
a=ssrc:2603526440 label:audio_label



// ------------ video部分 -------------

m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 100 101 127
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:kSq0
a=ice-pwd:pWLGrCTwFNq6rm249ZEasHPY
a=ice-options:trickle
a=fingerprint:sha-256 A0:D6:B2:63:1B:69:0E:91:01:C3:88:A9:92:6F:E7:EF:5B:36:52:66:08:DF:94:A0:FE:0C:C9:06:BF:2C:38:A2
a=setup:actpass
a=mid:video
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=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 red/90000
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:127 ulpfec/90000
a=ssrc-group:FID 1563406656 4103641903
a=ssrc:1563406656 cname:AyMDWB+q6ApWdpfU
a=ssrc:1563406656 msid:stream_id video_label
a=ssrc:1563406656 mslabel:stream_id
a=ssrc:1563406656 label:video_label
a=ssrc:4103641903 cname:AyMDWB+q6ApWdpfU
a=ssrc:4103641903 msid:stream_id video_label
a=ssrc:4103641903 mslabel:stream_id
a=ssrc:4103641903 label:video_label

2.1 協議版本

第一行v=0定義了sdp協議的版本號。

2.2 會話發起者

第二行

o=- 3967017503571418851 2 IN IP4 127.0.0.1

定義了會話發起者的信息,格式如下:

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

2.3 會話名

s=<session name>

必選,有且僅有一個s=字段,且不能為空。可以賦一個空格(即s=),或者-。

2.4 連接信息

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

每個SDP至少需要包含一個會話級別的c=字段,或者在每個媒體描述后面各包含一個c=字段,(媒體描述后的c=會覆蓋會話級別的c=)。例如,在上面的示例SDP樣本中,就不存在會話級別的連接信息。

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

2.4.1 何為會話級別和媒體級別

會話級部分以v =行開始,到第一個媒體級部分結束。
每個媒體級部分以m =行開始,持續到下一個媒體級(即下一個m=)。

2.5 媒體描述信息

SDP可以同時包含多個媒體描述信息(如音頻、視頻等),格式如下:

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

示例:

m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 110 112 113 126
c=IN IP4 0.0.0.0
  • media:媒體類型,包括 video、audio、text、application、message等。
  • port:傳輸媒體流使用的端口,具體含義取決於使用的網絡類型(在c=中聲明)和使用的傳輸協議(proto)。
  • proto:傳輸協議,具體含義取決於c=中定義的地址類型,比如c=IP4,那么這里的傳輸協議運行在IP4之上。
  • fmt:媒體格式的描述,可能有多個。根據proto的不同,fmt的含義也不同。比如proto為 RTP/SAVP 時,fmt 表示RTP payload 的類型。如果有多個,表示在這次會話中,多種payload類型可能會用到,且第一個為默認的payload類型。
    數字0-95是靜態負載類型;96-127是動態負載類型,需要在后面使用附近屬性a =
    rtpmap
    :指定具體的格式參數。具體的每個數字代表的負載類型和含義可以參考:Real-Time Transport Protocol (RTP) Parameters
    如上例中的audio類型的111表示使用opus編碼。

2.6 附加屬性

附加屬性用於擴展SDP,有2種作用范圍:會話級別、媒體級別:

  • 媒體級別:媒體描述(m=)后面可以跟任意數量的 a= 字段,對媒體描述進行擴展。
  • 會話級別:在第一個媒體字段(media field)前,添加的 a= 字段是會話級別的。

有下面2種格式:

2.7 時間

用於聲明會話的開始、結束時間,格式如下:

t=<start-time> <stop-time>

如果<stop-time>是0,表示會話沒有結束的邊界,但是需要在<start-time>之后會話才是活躍(active)的;如果<start-time>是0,表示會話是永久的。

原文地址:https://blog.csdn.net/china_jeffery/article/details/79991986

背景:預測式外呼需要服務端呼叫座席和客戶,之前話務控件一直作為主叫存在


場景 fs(73)---->opensips(72)------->194(webrtc控件)


問題一:控件收不到invite信令


這個問題,之前遇到過,原因是webrtc話務控件,注冊時,攜帶的信息是加密的,opensips的location表中的contact地址為“sip:o309vcvo@qph24fkpjojh.invalid;transport=ws ”。通過抓包和日志發現,73將invite信令發給了72,72收到后,並不能解析下一跳的地址“qph24fkpjojh.invalid”。


解決方案:使用fix_nated_contact()方法可以將contact地址中的ip修復。它將采用register信令的源地址作為contact地址保存在location中。


問題二:話務控件振鈴后,報錯DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Called with SDP without DTLS fingerprint.


從話務控件的js代碼中定位到報錯的行


this._accept(options)
.then(function (_a) {
var message = _a.message, session = _a.session;
session.delegate = {
onAck: function (ackRequest) { return _this.onAck(ackRequest); },
onAckTimeout: function () { return _this.onAckTimeout(); },
onBye: function (byeRequest) { return _this.receiveRequest(byeRequest); },
onInfo: function (infoRequest) { return _this.receiveRequest(infoRequest); },
onInvite: function (inviteRequest) { return _this.receiveRequest(inviteRequest); },
onMessage: function (messageRequest) { return _this.receiveRequest(messageRequest); },
onNotify: function (notifyRequest) { return _this.receiveRequest(notifyRequest); },
onPrack: function (prackRequest) { return _this.receiveRequest(prackRequest); },
onRefer: function (referRequest) { return _this.receiveRequest(referRequest); },
};
_this.session = session;
_this.status = Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK;
_this.accepted(message, Utils_1.Utils.getReasonPhrase(200));
})
.catch(function (error) {
_this.onContextError(error);
// FIXME: Assuming error due to async race on CANCEL and eating error.
if (!_this._canceled) {
throw error;
}
});


結合報錯信息,是在sdp協商中,設置offer sdp失敗,原因是sdp中沒有dtls 指紋。報錯信息我都認識,就是看不懂啥意思


之前webrtc話務控件注冊在freeswitch上,是可以作為被叫正常接聽的,就對比了一下兩個invite信令中攜帶的sdp信息有啥不同:


注冊在fs上,opensips發給話務控件的invite.txt
注冊在opensips上,opensips發給話務控件的invite.txt


通過對比發現,注冊在fs上的話務控件,收到的invite信令中,sdp消息中多了下面這幾行


a=msid-semantic: WMS fvORye3n7hVTLlioFlJEM5Yl604Yy0aE


// dtls協商過程中需要的認證信息
a=fingerprint:sha-256 1A:3C:B4:1D:D1:68:CA:30:B6:3C:3B:EE:8C:09:26:97:42:78:CB:9C:2A:B1:5C:4C:91:92:1F:16:5E:41:92:E3


//代表本客戶端在dtls協商過程中,既可以做客戶端也可以做服務端
a=setup:actpass


a=rtcp-mux
a=rtcp:18064 IN IP4 10.225.155.69
a=ssrc:3394676291 cname:mPmLUgYRnKAYWJds
a=ssrc:3394676291 msid:fvORye3n7hVTLlioFlJEM5Yl604Yy0aE a0
a=ssrc:3394676291 mslabel:fvORye3n7hVTLlioFlJEM5Yl604Yy0aE
a=ssrc:3394676291 label:fvORye3n7hVTLlioFlJEM5Yl604Yy0aEa0


//下面這兩行是ice協商過程中的安全認證信息
a=ice-ufrag:UMWxILIEBDt0tuvG
a=ice-pwd:9HhTN6B0H1PuBSMluzJ3biyD




a=candidate:7852700335 1 udp 659136 10.225.155.69 18064 typ host generation 0
a=candidate:7852700335 2 udp 659136 10.225.155.69 18064 typ host generation 0


fs(73)發起的originate命令是一致的,當控件注冊在fs(72)上,sdp中就會有a=fingerprint,注冊在opensips(72)上,則沒有。也可以這么理解,fs(72)知道話務控件是一個webrtc控件,所以他發給話務控件的是攜帶dtls信息的invite,而opensips(72)並不支持dtls,所以需要73發起invite的時候就攜帶dtls。


解決方案:發起originate命令時,攜帶{media_webrtc=true}參數,這樣,sdp中就會攜帶dtls信息


問題三:接通電話后,話務控件點擊掛斷,話務不能正常掛斷


通過抓包發現,194收到invite后,返給opensips(72)200ok,opensips返給fs(73)200ok,73返給72ack,72並沒有將200ok返給194,沒有收到ack消息的通話是不能通過bye請求來掛斷的。這個問題和問題一本質上是一致的,還是contact地址亂碼的問題,opensips.cfg腳本中,


if (nat_uac_test("1")){
xlog("onreply_route execute fix_nated_contact\n");
fix_nated_contact();
}


這個if條件沒有進去,刪除掉if后, ack傳輸正常,bye也正常了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM