-
WEBRTC SDP
2016-07-19 23:07:29 本端SDP形成 1.发起CreateOffer请求 或CreateAnswer响应 2.PeerConnection::CreateOffer->PeerConnection::...3.WebRtcSession::CreateOffer[每个PeerConnection一个WebRtcSession] 4.WebRtcSes本端SDP形成
1.发起CreateOffer请求 或CreateAnswer响应
2.PeerConnection::CreateOffer->PeerConnection::GetOptionsForOffer[获取SDP媒体属性]
3.WebRtcSession::CreateOffer[每个PeerConnection一个WebRtcSession]
4.WebRtcSessionDescriptionFactory::CreateOffer->WebRtcSessionDescriptionFactory::InternalCreateOffer
5.MediaSessionDescriptionFactory::CreateOffer->GetCodecsToOffer[获取音视频数据的所支持的编码]
MediaSessionDescriptionFactory::AddDataContentForOffer->FilterDataCodecs->
set_protocol(kMediaProtocolSctp)->CreateMediaContentOffer->MediaContentDescriptionImpl::AddCodecs
SessionDescription::AddContent->MediaSessionDescriptionFactory::AddTransportOffer
6.JsepSessionDescription::Initialize(SessionDescription* description)[Offer SDP已创建]
7.WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded->
Post(this, MSG_CREATE_SESSIONDESCRIPTION_SUCCESS)[生成SDP已成功]->
CreateSessionDescriptionObserver::OnSuccess(SessionDescriptionInterface* desc)[回调给用户]
|OnFailure(const std::string& error)[错误返回]
设置本端SDP
注:用户主动调用PeerConnection::CreateOffer 通过回调OnSuccess拿到了SDP对象,之后需要设置本端SDP
1.PeerConnection::SetLocalDescription->
2.WebRtcSession::SetLocalDescription->WebRtcSession::ValidateSessionDescription[合法性校验]->
VerifyCrypto-ValidateBundleSettings
3.Post(MSG_SET_SESSIONDESCRIPTION_SUCCESS)[设置SDP已成功]->
SetSessionDescriptionObserver::OnSuccess()[回调给用户]
4.WebRtcSession::MaybeStartGathering->TransportController::MaybeStartGathering->
5.P2PTransportChannel::MaybeStartGatheringOffer对象转换成SDP字符串(需要发给对端)
1.JsepSessionDescription::ToString
2.SdpSerialize[webrtcsdp.cc]->
接收对端SDP
1.CreateSessionDescription(const std::string& sdp)->JsepSessionDescription::Initialize->
2.SdpDeserialize->ParseMediaDescription->
3.ParseContentDescription->ParseContent->
4.以数据通道为例AddSctpDataCodec->MediaContentDescriptionImpl::AddCodec[google-sctp-data 90000 ]
5.SessionDescription::AddContentconst char NS_JINGLE_RTP[] = "urn:xmpp:jingle:apps:rtp:1";
sctp 的data 对应得ContentInfos中的type必须为NS_JINGLE_DRAFT_SCTP
const char NS_JINGLE_DRAFT_SCTP[] = "google:jingle:sctp";SCTP 去掉DTLS 出现如下错误:
(channel.cc:2195): Setting local data description
(channel.cc:867): Failure in SetLocalContent with action 2
(webrtcsession.cc:327): Failed to set local answer sdp: Session error code: ERROR_CONTENT. Session error description: Failed to set remote data description recv parameters..
(conductor.cc:104): OnFailure Failed to set local answer sdp: Session error code: ERROR_CONTENT. Session error description: Failed to set remote data description recv parameters..将bool IsDtlsSctp(const std::string& protocol) {
// This intentionally excludes "SCTP" and "SCTP/DTLS".
return protocol.find(cricket::kMediaProtocolDtlsSctp) != std::string::npos;
//return protocol.find(cricket::kMediaProtocolSctp) != std::string::npos;//add by sjz
}
将kMediaProtocolDtlsSctp改为kMediaProtocolSctp
a=sctpmap:5000 webrtc-datachannel 1024
========================sdp================================local:
v=0
o=- 8900646765147570832 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS stream_label
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 127 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:qiC7
a=ice-pwd:97xpdM9B0N8ox6jbS2PI+0G7
a=fingerprint:sha-256 A8:C7:B8:88:DE:B9:F6:70:A3:6E:9D:C7:FD:41:4C:1E:61:9F:B7:E1:92:5F:0A:4C:48:FD:9E:D6:B7:B2:C9:55
a=setup:actpass
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
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:127 red/8000
a=rtpmap:126 telephone-event/8000
a=ssrc:3486011156 cname:RS5piJcFSbw2XOoP
a=ssrc:3486011156 msid:stream_label audio_label
a=ssrc:3486011156 mslabel:stream_label
a=ssrc:3486011156 label:audio_label
m=video 9 UDP/TLS/RTP/SAVPF 100 101 116 117 96 97 98
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:qiC7
a=ice-pwd:97xpdM9B0N8ox6jbS2PI+0G7
a=fingerprint:sha-256 A8:C7:B8:88:DE:B9:F6:70:A3:6E:9D:C7:FD:41:4C:1E:61:9F:B7:E1:92:5F:0A:4C:48:FD:9E:D6:B7:B2:C9:55
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=sendrecv
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:100 VP8/90000
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtpmap:101 VP9/90000
a=rtcp-fb:101 ccm fir
a=rtcp-fb:101 nack
a=rtcp-fb:101 nack pli
a=rtcp-fb:101 goog-remb
a=rtcp-fb:101 transport-cc
a=rtpmap:116 red/90000
a=rtpmap:117 ulpfec/90000
a=rtpmap:96 rtx/90000
a=fmtp:96 apt=100
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=101
a=rtpmap:98 rtx/90000
a=fmtp:98 apt=116
a=ssrc-group:FID 3678723866 3268471119
a=ssrc:3678723866 cname:RS5piJcFSbw2XOoP
a=ssrc:3678723866 msid:stream_label video_label
a=ssrc:3678723866 mslabel:stream_label
a=ssrc:3678723866 label:video_label
a=ssrc:3268471119 cname:RS5piJcFSbw2XOoP
a=ssrc:3268471119 msid:stream_label video_label
a=ssrc:3268471119 mslabel:stream_label
a=ssrc:3268471119 label:video_label{
"candidate" : "candidate:430735571 1 udp 2122260223 192.168.1.102 59637 typ host generation 0 ufrag pa+u network-id 3 network-cost 50",
"sdpMLineIndex" : 0,
"sdpMid" : "audio"
}remote:
v=0
o=- 5895813448736697051 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio video
a=msid-semantic: WMS
m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 127 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:1MuA
a=ice-pwd:YAf0BbrY4nSGW5iQ3faC1MVC
a=fingerprint:sha-256 C3:A8:1B:82:A4:2C:93:4C:F6:67:9E:E4:F3:00:7B:D1:BB:56:4D:D4:C1:9E:34:E7:82:73:D9:D0:AF:02:D2:D2
a=setup:active
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=recvonly
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
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:127 red/8000
a=rtpmap:126 telephone-event/8000
m=video 9 UDP/TLS/RTP/SAVPF 100 101 116 117 96 97 98
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:1MuA
a=ice-pwd:YAf0BbrY4nSGW5iQ3faC1MVC
a=fingerprint:sha-256 C3:A8:1B:82:A4:2C:93:4C:F6:67:9E:E4:F3:00:7B:D1:BB:56:4D:D4:C1:9E:34:E7:82:73:D9:D0:AF:02:D2:D2
a=setup:active
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=recvonly
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:100 VP8/90000
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtpmap:101 VP9/90000
a=rtcp-fb:101 ccm fir
a=rtcp-fb:101 nack
a=rtcp-fb:101 nack pli
a=rtcp-fb:101 goog-remb
a=rtcp-fb:101 transport-cc
a=rtpmap:116 red/90000
a=rtpmap:117 ulpfec/90000
a=rtpmap:96 rtx/90000
a=fmtp:96 apt=100
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=101
a=rtpmap:98 rtx/90000
a=fmtp:98 apt=116============auido and data=============
v=0
o=- 1390922805343918830 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio data
a=msid-semantic: WMS
m=audio 9 RTP/AVPF 111 8
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:ShBp
a=ice-pwd:a7DnyIUa0qvcB4yEmzOZBC3c
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=recvonly
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:8 PCMA/8000
m=application 9 SCTP 5000
c=IN IP4 0.0.0.0
b=AS:30
a=ice-ufrag:ShBp
a=ice-pwd:a7DnyIUa0qvcB4yEmzOZBC3c
a=mid:data
a=sctpmap:5000 webrtc-datachannel 1024 -
webrtc sdp
2020-08-13 14:57:07sdp版本号,不包括次版本号> v=0 // 过程中有改变编码之类的操作,重新生成sdp时,session id不变,session version加1 // owner <user name> <session id> <session version> <net type> &...//------------------------------- 会话层 ------------------------------- // version <sdp版本号,不包括次版本号> v=0 // 过程中有改变编码之类的操作,重新生成sdp时,session id不变,session version加1 // owner <user name> <session id> <session version> <net type> <addr type> <addr> o=- 4571619080104764276 2 IN IP4 127.0.0.1 // session <session name> s=- // webrtc始终是0 // time <开始时间> <结束时间> t=0 0 // attribute,0 1绑定一个传输通道传输,与下方的a=mid相匹配 a=group:BUNDLE 0 1 // media stream id缩写msid,webrtc media stream缩写WMS a=msid-semantic: WMS 9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU //------------------------------- 媒体层:以下为音频描述信息 ------------------------------- // 端口9表示不接收数据;secret audio video protocol family缩写SAVPF // media <媒体类型> <port> <传输协议> <payload type集> m=audio 9 UDP/TLS/RTP/SAVPF 111 103 104 9 0 8 106 105 13 110 112 113 126 // 该属性webrtc并没有使用 // connection c=IN IP4 0.0.0.0 a=rtcp:9 IN IP4 0.0.0.0 // 以下两行ice协商过程中的安全验证信息 a=ice-ufrag:FvYc a=ice-pwd:st4MHVcrFq+pnZgFNV2qSmW0 // trickle,即sdp里面描述媒体信息和ice候选项的信息可以分开传输 a=ice-options:trickle // dtls协商过程中需要的认证信息,sha-256加密算法 a=fingerprint:sha-256 94:85:06:47:AD:89:09:7D:AF:E0:48:B7:58:55:1D:44:48:34:8F:4A:39:98:62:44:B0:19:BA:03:00:B9:94:66 // actpass既可以是客户端,也可以是服务器;active客户端;passive服务器 a=setup:actpass // 前面a=group:BUNDLE中用到的媒体标识 a=mid:0 // 要在rtp头部中加入音量信息 a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level a=extmap:2 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id // 仅发送,其他类型sendrecv,recvonly,sendonly,inactive a=sendonly // 与前面的msid相同,第二个为track id a=msid:9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU a1987158-6a67-4b19-9931-5cd2a8d2f6f8 // rtp,rtcp使用同一个端口来传输 a=rtcp-mux // payload type的描述 a=rtpmap:111 opus/48000/2 a=rtcp-fb:111 transport-cc a=fmtp:111 minptime=10;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:1196321802 cname:kDl3rfnZtJEKUJsa a=ssrc:1196321802 msid:9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU a1987158-6a67-4b19-9931-5cd2a8d2f6f8 a=ssrc:1196321802 mslabel:9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU a=ssrc:1196321802 label:a1987158-6a67-4b19-9931-5cd2a8d2f6f8 //------------------------------- 媒体层:以下为视频描述信息 ------------------------------- 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 114 115 116 c=IN IP4 0.0.0.0 // CT是设置整个会议的带宽,AS是设置单个会话的带宽,它们的单位都是kbit/s。setRemoteDescription之前修改 // bandwidth <类型>:<带宽> b=AS:100 a=rtcp:9 IN IP4 0.0.0.0 a=ice-ufrag:FvYc a=ice-pwd:st4MHVcrFq+pnZgFNV2qSmW0 a=ice-options:trickle a=fingerprint:sha-256 94:85:06:47:AD:89:09:7D:AF:E0:48:B7:58:55:1D:44:48:34:8F:4A:39:98:62:44:B0:19:BA:03:00:B9:94:66 a=setup:actpass a=mid:1 a=extmap:14 urn:ietf:params:rtp-hdrext:toffset a=extmap:13 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time a=extmap:12 urn:3gpp:video-orientation a=extmap:2 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01 a=extmap:11 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-timing a=extmap:8 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07 a=extmap:9 http://www.webrtc.org/experiments/rtp-hdrext/color-space a=extmap:3 urn:ietf:params:rtp-hdrext:sdes:mid a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id a=extmap:5 urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id a=sendonly a=msid:9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU f2b07fae-01be-4c8e-ac69-895c1d44ff87 a=rtcp-mux // 尽可能的减少rtcp包的发送,只发丢包 a=rtcp-rsize // payload type的描述,编码器VP8,时钟采样率90000 a=rtpmap:96 VP8/90000 // 对rtpmap 96的描述,google标准的接收端带宽评估 a=rtcp-fb:96 goog-remb // 对rtpmap 96的描述,传输端的带宽评估 a=rtcp-fb:96 transport-cc // 对rtpmap 96的描述,支持客户端请求i帧,codec control using RTCP feedback message缩写ccm,Full Intra Request缩写fir a=rtcp-fb:96 ccm fir // 支持丢包重传 a=rtcp-fb:96 nack // 支持i帧重传 a=rtcp-fb:96 nack pli // rtx丢包重传 a=rtpmap:97 rtx/90000 // apt关联 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=fmtp:98 profile-id=0 a=rtpmap:99 rtx/90000 a=fmtp:99 apt=98 a=rtpmap:100 VP9/90000 a=rtcp-fb:100 goog-remb a=rtcp-fb:100 transport-cc a=rtcp-fb:100 ccm fir a=rtcp-fb:100 nack a=rtcp-fb:100 nack pli a=fmtp:100 profile-id=2 a=rtpmap:101 rtx/90000 a=fmtp:101 apt=100 a=rtpmap:102 H264/90000 a=rtcp-fb:102 goog-remb a=rtcp-fb:102 transport-cc a=rtcp-fb:102 ccm fir a=rtcp-fb:102 nack a=rtcp-fb:102 nack pli a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f a=rtpmap:122 rtx/90000 a=fmtp:122 apt=102 a=rtpmap:127 H264/90000 a=rtcp-fb:127 goog-remb a=rtcp-fb:127 transport-cc a=rtcp-fb:127 ccm fir a=rtcp-fb:127 nack a=rtcp-fb:127 nack pli a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f a=rtpmap:121 rtx/90000 a=fmtp:121 apt=127 a=rtpmap:125 H264/90000 a=rtcp-fb:125 goog-remb a=rtcp-fb:125 transport-cc a=rtcp-fb:125 ccm fir a=rtcp-fb:125 nack a=rtcp-fb:125 nack pli 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:108 H264/90000 a=rtcp-fb:108 goog-remb a=rtcp-fb:108 transport-cc a=rtcp-fb:108 ccm fir a=rtcp-fb:108 nack a=rtcp-fb:108 nack pli a=fmtp:108 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f a=rtpmap:109 rtx/90000 a=fmtp:109 apt=108 a=rtpmap:124 H264/90000 a=rtcp-fb:124 goog-remb a=rtcp-fb:124 transport-cc a=rtcp-fb:124 ccm fir a=rtcp-fb:124 nack a=rtcp-fb:124 nack pli 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 goog-remb a=rtcp-fb:123 transport-cc a=rtcp-fb:123 ccm fir a=rtcp-fb:123 nack a=rtcp-fb:123 nack pli a=fmtp:123 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032 a=rtpmap:119 rtx/90000 a=fmtp:119 apt=123 // fec冗余编码,rtp头部负载类型116,否则就是各编码原生负责类型 a=rtpmap:114 red/90000 a=rtpmap:115 rtx/90000 a=fmtp:115 apt=114 //支持ULP FEC a=rtpmap:116 ulpfec/90000 // 一个cname可以对应多个ssrc a=ssrc-group:FID 790880351 2784909276 a=ssrc:790880351 cname:kDl3rfnZtJEKUJsa a=ssrc:790880351 msid:9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU f2b07fae-01be-4c8e-ac69-895c1d44ff87 a=ssrc:790880351 mslabel:9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU a=ssrc:790880351 label:f2b07fae-01be-4c8e-ac69-895c1d44ff87 a=ssrc:2784909276 cname:kDl3rfnZtJEKUJsa a=ssrc:2784909276 msid:9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU f2b07fae-01be-4c8e-ac69-895c1d44ff87 a=ssrc:2784909276 mslabel:9TH6yxQRgyF6Yna81tiidOMebGqKms24SCEU a=ssrc:2784909276 label:f2b07fae-01be-4c8e-ac69-895c1d44ff87
candiadte
{"candidate":"candidate:3575467457 1 udp 2113937151 10.15.83.23 57857 typ host generation 0 ufrag 6R0z network-cost 999","sdpMid":"0","sdpMLineIndex":0} {"candidate":"candidate:842163049 1 udp 1677729535 xxx.xxx.xxx.xxx 57857 typ srflx raddr 10.15.83.23 rport 57857 generation 0 ufrag 6R0z network-cost 999","sdpMid":"0","sdpMLineIndex":0} {"candidate":"candidate:888962573 1 udp 33562367 xxx.xxx.xxx.xxx 57153 typ relay raddr xxx.xxx.xxx.xxx rport 57857 generation 0 ufrag 6R0z network-cost 999","sdpMid":"0","sdpMLineIndex":0}
- host 主机候选者,主机自己可以提供。优先级高
- srflx 反射候选者,STUN提供。优先级中
- relay 中继候选者,TURN提供。优先级低
- 10.15.83.23 57857 ip和端口
- sdpMid 与sdp中a=mid:0一致
SDP协议的信息是文本信息,采用 UTF-8 编 码中的 ISO 10646 字符集。
SDP描述由许多文本行组成,文本行的格式为<类型>=<值>,<类型>是一个字母,<值>是结构化的文本串,其格式依<类型>而定。<type>=<value>[CRLF]
SDP会话描述如下:(标注 * 符号的表示可选字段):
v = (协议版本)
o = (所有者/创建者和会话标识符)
s = (会话名称)
i = * (会话信息)
u = * (URI 描述)
e = * (Email 地址)
p = * (电话号码)
c = * (连接信息 ― 如果包含在所有媒体中,则不需要该字段)
b = * (带宽信息)
一个或更多时间描述(如下所示):
z = * (时间区域调整)
k = * (加密密钥)
a = * (0 个或多个会话属性行)
0个或多个媒体描述(如下所示)
时间描述
t = (会话活动时间)
r = * (0或多次重复次数)
媒体描述
m = (媒体名称和传输地址)
i = * (媒体标题)
c = * (连接信息 — 如果包含在会话层则该字段可选)
b = * (带宽信息)
k = * (加密密钥)
a = * (0 个或多个会话属性行)
-
WebRTC源码研究(32)获取offer answer创建的SDP
2020-06-18 08:04:22文章目录WebRTC源码研究(32)获取offer answer创建的SDP WebRTC源码研究(32)获取offer answer创建的SDPWebRTC源码研究(32)获取offer answer创建的SDP
1. SDP简介
签名的章节主要讲了WebRTC框架的一些知识,从本章开始,我们将深入到细节实战中,更深入的理解关于WebRTC的具体实现细节。在WebRTC有一个很重要的概念就是SDP,那么什么是SDP呢?
SDP(session Description Protocol):它只是一种信令服务器格式的描述标准,本身不属于传输协议,但是可以被其他传输协议用来交换必要的信息。
SDP
最主要用的地方就是在通讯之前首先进行媒体的协商,也就是说对于呼叫者它首先要创建这个offer
,然后将自己的媒体信息拿到,然后通过信令转给被呼叫者,那被呼叫者收到这个信令之后要创建answer
,也就是说将它自己的媒体信息也获取到,然后在通过这个信令传给这个呼叫者,这样就将这个媒体信息就交换完了,这些媒体信息就是用SDP这个格式来描述的,拿到双方的SDP之后,他们就取一个交集,就是大家都可以支撑的编解码器和带宽等信息就交换完成了,后面才能进行真正的数据的传输。下面我们将通过实例来展示怎么获取到双方的SDP,我们先从整体上看SDP是什么样子的,它大概都包括哪些内容。
2. 获取SDP实战
我们先来看一下效果:
我们再来看一下js代码:
// 1、使用JS严格语法 'use strict' // 2、获取HTML中的元素标签 var localVideo = document.querySelector('video#localVideo'); var remoteVideo = document.querySelector('video#remoteVideo'); var btnStart = document.querySelector('button#start'); var btnCall = document.querySelector('button#call'); var btnHangUp= document.querySelector('button#hangup'); // 49、获取新增加的元素 var offerSdpTextarea = document.querySelector('textarea#offer'); var answerSdpTextarea = document.querySelector('textarea#answer'); // 16、定义全局变量localStream var localStream; // 22、定义全局变量pc1 var pc1; // 23、定义全局变量pc2 var pc2; // 12、在我们采集成功之后我们会调用gotMediaStream,它有个参数就是stream function gotMediaStream(stream){ // 13、在这个stream里面要做两件事 // 14、第一件事就是将它设置为localVideo,这样采集到数据之后我们本地的localVideo就能将它展示出来 localVideo.srcObject = stream; /** 15、第二件事就是我们要将它赋值给一个全局的stream,这个localStream就是为了后面我们去添加流用的,就是我们在其他地方还要用到这个流, 所以我们不能让它是一个局部的,得让他是一个全局的 */ localStream = stream; } // 17、处理错误 function handleError(err){ // 18、它有个参数err,当我们收到这个错误我们将它打印出来 console.log("Failed to call getUserMedia", err); } // 6、实现start function start(){ // 11、在调getUserMedia之前我们还有一个限制,是constraints // 这这里面我们可以写video和audio,我们这里暂不采集音频了,如果你要采集设置audio为true好了 var constraints = { video: true, audio: false } // 7、判断浏览器是否支持navigator.mediaDevices 和 navigator.mediaDevices.getUserMedia // 如果有任何一个不支持我们就要打印一个错误信息并退出 if(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia){ console.error('the getUserMedia is not supported!') return; }else { // 8、如果支持就要传人constraints使用getUserMedia获取音视频数据了 navigator.mediaDevices.getUserMedia(constraints) .then(gotMediaStream) // 9、如果成功我们就让他调gotMediaStream,这时候说明我们可以拿到这个stream了 .catch(handleError); // 10、否则就要处理这个错误 } } // 45、这样也会传入一个描述信息 function getAnswer(desc){ // 46、当远端它得到这个Answer之后,它也要设置它的setLocalDescription,当它调用了setLocalDescription之后它也开始收集candidate了 pc2.setLocalDescription(desc); // 54、设置textarea,这个也就是我们获取的answer成功之后answer的内容 answerSdpTextarea.value = desc.sdp //send sdp to caller //recieve sdp from callee /** 47、完了之后它去进行send desc to signal与pc1进行交换,pc1会接收recieve desc from signal 那么收到之后他就会设置这个pc1的setRemoteDescription 那么经过这样一个步骤整个协商就完成了 当所有协商完成之后,这些底层对candidate就收集完成了 收集完了进行交换形成对方的列表然后进行连接检测 连接检测完了之后就开始真正的数据发送过来了 */ pc1.setRemoteDescription(desc); } // 41、首先传入一个desc一个描述信息 function getOffer(desc){ /** 42、当我们拿到这个描述信息之后呢,还是回到我们当时协商的逻辑,对于A来说它首先创建Offer,创建Offer之后它会调用setLocalDescription * 将它设置到这个PeerConnection当中去,那么这个时候它会触发底层的ICE的收集candidate的这个动作 * 所以这里要调用pc1.setLocalDescription这个时候处理完了它就会收集candidate * 这个处理完了之后按照正常逻辑它应该send desc to signal到信令服务器 */ /** * 51、在这里首先是设置setLocalDescription */ pc1.setLocalDescription(desc); /** * 52、设置完了setLocalDescription之后呢,我们就可以将它的内容展示在textarea里 * desc本身并不是SDP,它下面有一个SDP的属性,它里面包含了我们第一个连接创建的offer的SDP * */ offerSdpTextarea.value = desc.sdp //send sdp to callee /** * 43、到了信令服务器之后,信令服务器会发给第二个人(b) * 所以第二个人就会receive * 所以第二个人收到desc之后呢首先pc2要调用setRemoteDescription,这时候将desc设置成它的远端 */ //receive sdp from caller pc2.setRemoteDescription(desc); /** * 44、设成远端之后呢它也要做它自己的事 * pc2就要调用createAnswer,如果调用createAnswer成功了它要调用gotAnswerDescription */ /** * 53、同样的到了我们在找找这个answer,调用createAnswer成功我们再调用getAnswer */ pc2.createAnswer().then(getAnswer) .catch(handleError); } /** * 33、在这个函数里它实际就是有多个流了, */ function gotRemoteStream(e){ // 34、所以我们只要取其中的第一个就可以了 if(remoteVideo.srcObject !== e.streams[0]){ // 35、这样我们就将远端的音视频流传给了remoteVideo,当发送ontrack的时候也就是数据通过的时候, remoteVideo.srcObject = e.streams[0]; } } // 19、实现call function call(){ // 20、这个逻辑略显复杂,首先是创建RTCPeerConnection /** * 38、创建offerOptions,那在这里你可以指定我创建我本地的媒体的时候,那都包括哪些信息, * 可以有视频流和音频流,因为我们这里没有采集音频所以offerToReceiveAudio是0 * 有了这个之后我们就可以创建本地的媒体信息了 */ var offerOptions = { offerToReceiveAudio: 0, offerToReceiveVideo: 1 } /** 21、所以在这里先设置一个pc1等于new RTCPeerConnection() 在这个Connection里面实际上是有一个可选参数的,这个可选参数就涉及到网络传输的一些配置 我们整个ICE的一个配置,但是由于是我们在本机内进行传输,所以在这里我们就不设置参数了,因为它也是可选的 所以它这里就会使用本机host类型的candidate 这个pc1我们后面也要用到,所以我给他全局化一下 */ pc1 = new RTCPeerConnection(); pc1.onicecandidate = (e) => { // 25、这些事件有几个重要的,那第一个因为这个是连接,连接建立好之后当我发送收集Candidate的时候,那我要知道现在已经收到一个了 // 收到之后我们要做一些事情,所以我们要处理addIceCandidate事件,其实做主要的就是这个事件 // send candidate to peer // receive candidate from peer /** * 27、它有个参数就是e,当有个事件的时候这个参数就传进来了,对于我们上面的逻辑,我们回顾一些此前的流程 * 当我们A调用者收到candidate之后,它会将这个candidate发送给这个信令服务器 * 那么信令服务器会中转到这个B端,那么这个B端会调用这个AddIceCandidate这个方法,将它存到对端的candidate List里去 * 所以整个过程就是A拿到它所有的可行的通路然后都交给B,B形成一个列表; * 那么B所以可行的通路又交给A,A拿到它的可行列表,然后双方进行这个连通性检测 * 那么如果通过之后那就可以传数据了,就是这样一个过程 * */ /** 28、所以我们收到这个candidate之后就要交给对方去处理,所以pc1要调用pc2的这个,因为是本机这里就没有信令了,假设信令被传回来了 * 当我们收集到一个candidate之后交给信令,那么信令传回来,这时候就给了pc2 */ /** * 29、pc2收到这个candidate之后就调用addIceCandidate方法,传入的参数就是e.candidate */ pc2.addIceCandidate(e.candidate) .catch(handleError); console.log('pc1 ICE candidate:', e.candidate); } pc1.iceconnectionstatechange = (e) => { console.log(`pc1 ICE state: ${pc.iceConnectionState}`); console.log('ICE state change event: ', e); } // 24、在创建一个pc2这样我们就创建了两个连接,拿到两个连接之后我们要添加一些事件给它 // 26、对于pc2还要处理一个onTrack,当双方通讯连接之后,当有流从对端过来的时候,会触发这个onTrack事件,所以这个事件是我们要处理的 pc2 = new RTCPeerConnection(); /** * 30、对于pc2也是同样道理,那它就交给p1 */ pc2.onicecandidate = (e)=> { // send candidate to peer // receive candidate from peer /** * 31、所以它就调用pc1.addIceCandidate,这是当他们收集到candidate之后要做的事情 */ pc1.addIceCandidate(e.candidate) .catch(handleError); console.log('pc2 ICE candidate:', e.candidate); } pc2.iceconnectionstatechange = (e) => { console.log(`pc2 ICE state: ${pc.iceConnectionState}`); console.log('ICE state change event: ', e); } /** * 32、除此之外,pc2是被调用方,被调用方是接收数据的,所以对于pc2它还有个ontrack事件 * 当它收到这个ontrack事件之后它需要调用gotRemoteStream */ pc2.ontrack = gotRemoteStream; /** * 36、接下来我们就要将本地采集的数据添加到第一添加到第一个pc1 = new RTCPeerConnection()中去 * 这样在创建媒体协商的时候才知道我们有哪些媒体数据,这个顺序不能乱,必须要先添加媒体数据再做后面的逻辑 * 二不能先做媒体协商然后在添加数据,因为你先做媒体协商的时候它知道你这里没有数据那么在媒体协商的时候它就没有媒体流 * 那么就是说在协商的时候它知道你是没有的,那么它在底层就不设置这些接收信息发收器,那么这个时候即使你后面设置了媒体流传给这个PeerConnection * 那么它也不会进行传输的,所以我们要先添加流 * 添加流也比较简单,通过localStream调用getTracks就能调用到所有的轨道(音频轨/视频轨) * 那对于每个轨道我们添加进去就完了,也就是forEach遍历进去,每次循环都能拿到一个track * 当我们拿到这个track之后直接调用pc1.addTrack添加就好了,第一个参数就是track,第二个参数就是这个track所在的流localStream * 这样就将本地所采集的音视频流添加到了pc1 这个PeerConnection */ //add Stream to caller localStream.getTracks().forEach((track)=>{ pc1.addTrack(track, localStream); }); /** * 37、那么这个时候我们就可以去创建这个pc1去媒体协商了,媒体协商第一步就是创建createOffer,创建这个createOffer实际它里面有个 * offerOptions的,那么这个offerOptions我们在上面定义一下 */ /** * 50、在哪去找SDP,实际上就是在createOffer的时候,如果创建成功了,我们就能拿到它的SDP, */ pc1.createOffer(offerOptions) .then(getOffer) // 39、它也是一个Promise的形式,当他成功的时候我们去调用getOffer .catch(handleError); // 40、如果失败了去调用一下handleError } // 48、挂断,将pc1和pc2分别关闭,在将pc1和pc2对象设为null function hangup(){ pc1.close(); pc2.close(); pc1 = null; pc2 = null; } // 3、开始 btnStart.onclick = start; // 4、当调用call的时候就会调用双方的RTCPeerConnection, // 当这个两个PeerConnection创建完成之后,它们会作协商处理, // 协商处理晚上之后进行Candidate采集,也就是说有效地址的采集, // 采集完了之后进行交换,然后形成这个Candidate pair再进行排序, // 然后再进行连接性检测,最终找到最有效的那个链路, // 之后就将localVideo展示的这个数据通过PeerConnection传送到另一端, // 另一端收集到数据之后会触发onAddStream或者onTrack就是说明我收到数据了,那当收到这个事件之后, // 我们再将它设置到这个remoteVideo里面去, // 这样远端的这个video就展示出来了,显示出我们本地采集的数据了, // 大家会看到两个视频是一摸一样的,它的整个底层都是从本机自己IO的那个逻辑网卡转过来的, // 不过这个整个流程都是一样的,当我们完成这个,在做真实的网络传输的时候就和这个一摸一样,只是将信令部分加了进来 btnCall.onclick = call; // 5、挂断 btnHangUp.onclick = hangup;
-
webrtc SDP
2020-06-15 14:16:12 -
WebRTC SDP详解
2021-01-08 18:22:36NR 更详细的 WebRTC SDP 解析请参考https://tools.ietf.org/html/draft-ietf-rtcweb-sdp-12 0x00 前言 SDP (Session Description Protocol) 格式是一种很有历史的格式,在 20 世纪的会议系统中通常都是使用 SDP ... -
WebRTC SDP协议
2018-02-20 21:32:55SDP SDP Session Description Protocol 会话描述协议 SDP协议用来在SIP终端之间...WebRTC Peer之间交换SDP包括的信息有transport protocols,ports,codecs等等 相关的IETF文档: https://tools.ietf.org/pdf/draf... -
解剖WebRTC SDP
2018-11-27 18:20:52这里有一个查询SDP的页面,鼠标覆盖在每一项上,右侧就会出现解释说明,类似一个字典一样,非常方便: Anatomy of a WebRTC SDP https://webrtchacks.com/sdp-anatomy/... -
WebRTC SDP 解析
2019-03-06 11:43:56sdp(SessionDescriptionProtocol)是一种会话描述协议,属于文本协议,即WebRTC中常说的信令(Signalling),是WebRTC用来协助建立p2p通讯的。主要用于协商双方通讯过程,传递基本信息,如:会话控制信息,用来开始... -
Webrtc SDP格式解读
2019-07-17 20:15:15因为设备端只支持H264编码方式接入,这里涉及到webrtc web端要修改默认编码器,而编码器就离不开webrtc 信令中SDP 消息的解读,读懂了 才能知道自己支持编码器的情况下对SDP的信息进行二次修改。 本文主要内容来自该... -
WebRTC核心之SDP详解 十一、第二节 WebRTC中的SDP
2020-08-02 19:20:56今天我们来看看在WebRTC中使用的SDP,在WebRTC中使用SDP相比正常的SDP规范有一些出入,那主要是为了让SDP更能适应WebRTC里面的一些设置以及会话的描述,那么下面我们来看一下,在WebRTC中的SDP组成是包括了5部分 ... -
WebRTC 之 SDP
2021-03-11 10:58:11SDP 即 Session Description Protocol 会话描述协议, 它描述了所传输的媒体信息。 之所以需要在多媒体通信之前交换 SDP, 就在于 接收方需要知道传输的是什么媒体类型,什么编码格式,以便正确的回放, 发送方需要... -
WebRTC -- SDP格式解析
2018-04-18 16:00:03如果将WebRTC SDP从语义上分解成不同组件来描述一个多媒体会话信息,那么WebRTC SDP由如下几部分组成: +---------------------+ | v= ... -
WebRTC中SDP信息详解
2019-06-04 11:29:21SDP表示Session Description Protocol,Webrtc是通过SDP进行协商,进而创建出符合通话要求的Session。SDP在webrtc应用中扮演着重要的角色,接下来我们通过一个实例来简单介绍一下SDP信息的含义。 本例是安卓手机和... -
WebRTC之SDP协议
2021-04-09 09:48:23什么是SDP SDP(Session Description Protocol) 是一种会话描述协议,基于...[一个不错的 WebRTC 的 SDP 例子分析https://webrtchacks.com/sdp-anatomy/](https://webrtchacks.com/sdp-anatomy/) 为什么需要SDP 会话. -
WebRTC SDP 详解和剖析
2020-11-24 19:37:57WebRTC 是 Web Real-Time Communication,即网页实时...本篇是阿里云视频云 WebRTC 技术专栏系列文章的第一篇,作者将从 WebRTC SDP 例子和关键属性的角度为大家深度剖析解读,其中也分享了阿里云技术专家的一些实践 -
webrtc中SDP解释
2019-10-17 21:24:12WebRTC SDP 的协议解释。 全局描述 o=- 4611731400430051336 2 IN IP4 127.0.0.1 第一个数字4611731400430051336是会话唯一标志 第二个数字2是会话的版本,当会话有新的协商或者应答时,例如(例如保持,编... -
webrtc的sdp分析
2018-07-03 00:11:45webrtc的sdp分offer和answer两个,以offer为例,简单分析 ,其实就2个m(media)就可以了:"sdp" : " v=0 //version 版本 o=- 6547339724864950015 2 IN IP4 127.0.0.1 //origin 源 IN为internet ... -
WebRTC 中 SDP 信息解析
2020-11-22 23:09:28在 20 世纪的会议系统中通常都是使用 SDP 格式的文本来交互连接属性信息和媒体属性信息,在今天 JSON 这种对象化...本文主要通过参考 RFC 4566 文档和 ORTC 思维模式来阐述一套系统化的分析 WebRTC 中 SDP 信息的方法。 -
WebRtc相关SDP修改Android端代码
2018-04-18 15:36:54WebRtc相关技术SDP修改方法,必定让你了解更多WebRtc相关技术 -
Webrtc Intro - SDP Sample
2015-06-07 09:56:45Webrtc Intro - SDP Sample