SDP(会话描述协议)是一种用于描述多媒体会话的文本格式,旨在协商参与者之间的连接参数。根据IETF RFC 8866(2021),SDP定义了媒体流、编解码器、传输地址和其他参数的描述结构,而不传输媒体数据本身。该协议已成为WebRTC的关键组件,在建立点对点连接之前确保浏览器和移动应用程序之间的信息交换。
要点
SDP — 是一种应用层协议,旨在以文本格式描述多媒体会话的参数。它是在IETF的MMUSIC(多方多媒体会话控制)工作组框架内开发的,并于1998年在RFC 2327中首次标准化。2021年发布了当前规范RFC 8866,取代了之前的版本RFC 4566。
SDP的主要任务是为会话参与者提供建立连接所需的所有信息:将传输哪些媒体流,支持哪些编解码器,通过哪些网络地址和端口进行传输。SDP不传输媒体数据本身,只描述应如何组织连接。
根据IETF RFC 8866,SDP格式由一组行组成,每行以单字母类型开头,后跟等号和值。例如,行m=audio 5004 RTP/AVP 0表示会话包括端口5004上的音频流,使用RTP/AVP传输协议和PCMU编解码器(类型0)。
SDP的第一个版本于1998年4月在RFC 2327中发布,是MMUSIC小组工作的成果。该协议最初是为在Mbone(组播骨干网)框架内宣布组播会话而创建的。随着VoIP和视频会议的发展,SDP的应用范围不断扩大,2006年发布了更新的规范RFC 4566。
SDP使用的真正突破发生在2011年WebRTC的出现。Google将SDP作为其浏览器实时通信框架中媒体会话描述的主要机制。从那时起,SDP成为每个WebRTC实现的强制性组件——从浏览器到iOS和Android上的移动应用程序。
2021年,IETF工作组发布了RFC 8866——取代RFC 4566的当前SDP规范。更新版本明确了ICE(交互式连接建立)的处理,支持DTLS(数据报传输层安全),并扩展了组会话描述的能力。
SDP与传输协议的根本区别在于它不参与数据传输。它仅执行描述功能——类似于多媒体文件的元数据。当RTP(实时传输协议)传输音频和视频数据包,RTCP控制传输质量时,SDP仅指示使用哪些编解码器和端口。
来自Web开发的类比:SDP是描述页面结构的HTML标记,RTP是图像和文本本身。没有SDP,会话参与者不知道如何相互连接,即使网络连接已经建立。NAT穿越机制(ICE)也依赖SDP来传输关于网络候选者的信息。
SDP的结构组织为一系列文本行,每行遵循type=value格式。单字母类型确定行的目的,值包含相应的值。所有行由CRLF换行符分隔。
标准RFC 8866定义了多个必填和可选字段。必填字段包括协议版本(v=)、会话名称(s=)、会话开始和结束时间(t=)。其他字段是可选的,但对于WebRTC会话,还需要媒体描述(m=)、属性(a=)和网络信息(c=)。
v=0
o=- 46116397 2 IN IP4 192.168.1.100
s=-
t=0 0
a=group:BUNDLE audio video
m=audio 5004 RTP/SAVPF 111 103 104
c=IN IP4 192.168.1.100
a=rtpmap:111 opus/48000/2
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
m=video 5006 RTP/SAVPF 96 97
a=rtpmap:96 VP8/90000
a=rtpmap:97 H264/90000
上面的示例展示了一个典型的WebRTC会话的SDP片段。行v=0表示协议版本。字段o=包含会话所有者的标识符及其版本。行s=-设置会话名称(连字符表示名称为空)。字段t=0 0表示会话没有时间限制。
字段a=group:BUNDLE audio video是一个属性,将多个媒体流分组到一个传输通道中。BUNDLE机制允许通过单个连接传输音频和视频来节省网络资源。这对于带宽有限的移动设备尤其重要。
规范RFC 8866定义了一组必填和可选字段。必填字段包括v=(版本)、s=(会话名称)和t=(时间)。字段o=(所有者),虽然根据RFC并非严格必填,但在实际实现中几乎总是存在。
| 字段 | 用途 | 示例 |
|---|---|---|
| v= | SDP协议版本 | v=0 |
| o= | 会话所有者和标识符 | o=- 46116397 2 IN IP4 192.168.1.100 |
| s= | 会话名称 | s=Video Conference |
| t= | 开始和结束时间 | t=0 0 |
| m= | 媒体流描述 | m=audio 5004 RTP/SAVPF 111 |
| c= | 网络信息 | c=IN IP4 192.168.1.100 |
| a= | 会话或媒体属性 | a=rtpmap:111 opus/48000/2 |
m=(媒体)字段是最重要的字段之一。它描述特定的媒体流,包含媒体类型(audio、video、text、application)、端口、传输协议和支持的编解码器列表。在WebRTC中,最常用的类型是audio和video,使用RTP/SAVPF(安全音频/视频配置文件及反馈)或UDP/TLS/RTP/SAVPF传输协议。
a=(属性)字段是最灵活和可扩展的。它可以包含rtpmap(将编解码器编号映射到名称)、fmtp(编解码器参数)、fingerprint(DTLS密钥指纹)、ice-ufrag和ice-pwd(ICE凭据)以及许多其他属性。正是通过属性,SDP支持现代安全机制和NAT穿越。
在WebRTC架构中,SDP扮演着信令协议的角色,用于描述和协商两个参与者之间的媒体会话参数。SDP本身不定义这些描述的传输机制——这一任务由信令通道解决,开发人员通过WebSocket、HTTP或其他协议独立实现。
过程从发起者(呼叫者)创建SDP提议——Offer开始。为此,浏览器在RTCPeerConnection对象上调用createOffer()方法。生成的SDP描述包含发起方的所有会话参数:支持的编解码器、网络地址、ICE候选者和安全要求。
const configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
const pc = new RTCPeerConnection(configuration);
// 在Android上创建SDP提议
const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// 将SDP字符串发送到远程对等方
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
// Send SDP to remote peer via signaling channel
sendViaSignaling({ type: 'offer', sdp: offer.sdp });
创建Offer并通过setLocalDescription()设置本地描述后,发起者通过信令通道将SDP字符串发送给远程参与者。远程参与者收到SDP Offer后,创建SDP应答——Answer并将其发回。这种交换称为信令交换,是在建立点对点连接之前的强制性步骤。
根据W3C WebRTC规范,SDP交换应在ICE候选者交换开始之前进行。在实践中,许多实现使用ICE trickle机制与SDP并行发送ICE候选者。这缩短了连接建立时间,特别是对于高延迟的移动网络。
ICE(交互式连接建立)——是一种使用SDP属性传输关于网络候选者信息的机制。ICE候选者描述了可能的连接路径:host(本地地址)、srflx(通过STUN获取的NAT后地址)和relay(TURN服务器地址)。
在SDP中,ICE候选者通过a=candidate:属性以及用于ICE流量认证的ice-ufrag和ice-pwd字段传输。每个候选者包括传输协议(UDP、TCP)、IP地址、端口和优先级。成功的连接通过第一个通过连接性测试的候选者建立。ICE restart机制允许在网络更改时更新连接。
对于移动应用程序,ICE候选者尤其重要,因为设备通常位于NAT或公司防火墙之后。ICE机制即使在复杂的网络条件下也能找到工作路径,SDP作为这些信息的传输容器。
WebRTC中的SDP必须包含安全属性,特别是DTLS指纹(fingerprint)和SRTP参数。字段a=fingerprint:sha-256包含用于媒体流认证和加密的DTLS证书指纹。没有此属性,WebRTC连接将无法建立。
额外的安全机制包括a=setup:属性,用于确定DTLS握手的角色(active、passive、actpass),以及用于服务器端简化ICE实现的a=ice-lite:。所有这些参数都在SDP内部传输,并在开始传输媒体数据之前由双方检查。
在WebRTC模型中,存在两种类型的SDP消息:Offer(提议)和Answer(应答)。Offer由连接发起者创建,包含所需媒体会话的完整描述。Answer由远程参与者创建以响应Offer,包含其功能并考虑提议施加的限制。
Offer和Answer之间的主要区别在于属性的语义。Offer列出了发起者可以提供的所有支持的编解码器、传输协议和网络地址。Answer选择了远程方支持的这些功能的子集。例如,如果Offer提供opus、ISAC和PCMU,Answer可以选择仅opus作为最优先的编解码器。
交换过程由W3C WebRTC规范管理,包括RTCPeerConnection的多个状态。通过createOffer()创建Offer并将其设置为本地描述后,连接进入have-local-offer状态。收到Answer并通过setRemoteDescription()将其设置为远程描述后,连接进入stable状态——准备进行媒体传输的最终状态。
用于WebRTC的移动SDK——Android版Google WebRTC和iOS版WebRTC.framework——完全支持通过Offer和Answer进行SDP交换。在Android上,使用PeerConnection类及其createOffer()方法创建Offer,类似于浏览器API。获取的SDP描述作为字符串通过信令通道传输。
在iOS上,与SDP的工作通过WebRTC框架的RTCSessionDescription类进行。初始化时指定类型(RTCSdpTypeOffer或RTCSdpTypeAnswer)和SDP字符串。平台自动解析SDP并根据传输的参数配置连接。
val configuration = PeerConnection.RTCConfiguration(List())
val peerConnection = factory.createPeerConnection(configuration, object : PeerConnection.Observer {
override fun onIceCandidate(candidate: IceCandidate) { }
})
// Create SDP Offer on Android
peerConnection.createOffer(object : SdpObserver {
override fun onCreateSuccess(sdp: SessionDescription) {
peerConnection.setLocalDescription(this, sdp)
// Send SDP string to remote peer
sendSdpToRemotePeer(sdp.description)
}
}, new MediaConstraints())
直接处理SDP字符串的能力为开发人员提供了灵活性:他们可以在发送前修改SDP,添加或删除特定的编解码器,配置ICE参数或添加自定义属性。对于Android应用程序,在网络带宽低时通常需要在SDP中禁用视频——这是通过从SDP描述中删除相应的m=行来完成的。
在移动开发中,SDP主要在WebRTC的背景下使用——用于创建具有视频通话、语音聊天和流媒体功能的应用程序。Android和iOS上的移动应用程序既可以充当发起者,也可以充当SDP消息的接收者,从而允许构建对称的点对点连接。
移动应用程序的特点是需要在不稳定的网络质量条件下使用SDP。在Wi-Fi和移动互联网之间切换时,以及在带宽变化时,可能需要生成新的SDP描述。为此使用renegotiation机制——通过createOffer()和setLocalDescription()重复SDP交换。
根据Google WebRTC团队(2023年),移动设备的SDP交换优化包括在网络变化时使用ICE restart,优先使用低比特率的编解码器(音频使用opus,视频使用VP8),以及通过排除不必要的媒体流来最小化SDP字符串大小。关键优势是减少移动网络中连接建立的延迟。
在移动设备上使用SDP的关键任务之一是最小化SDP描述的大小。典型WebRTC会话的完整SDP包含音频和视频可能占用2–5 KB,这对于慢速网络来说是显著的。优化包括使用BUNDLE(合并流)、删除不支持的编解码器和压缩ICE候选者。
移动设备的另一个问题是SDP的有限生命周期。在不稳定的连接条件下,SDP可能在远程参与者处理之前就过期了。解决方案是使用短超时来接收Answer,并在必要时重新发送SDP。ICE restart机制允许在不完全重新创建RTCPeerConnection的情况下更新连接。a=ice-lite属性简化了服务器端的ICE实现。
移动应用程序开发人员可以使用现成的库来简化SDP的处理。libjingle_peerconnection(Google WebRTC)——是适用于Android的主要库,提供用于SDP管理的完整API。对于iOS,使用具有类似功能的WebRTC.framework。这两个库都自动生成和解析SDP,但在需要时提供对原始SDP字符串的访问。
为了更好地控制SDP,存在第三方解决方案:sdp-transform(JavaScript或Node.js)用于解析和修改SDP,NICENICE(Java)用于处理ICE候选者,以及来自WebRTC基础设施提供商的现成SDK,这些SDK处理包括SDP在内的整个信令交换。
常见问题
SDP — 是一种文本格式,会话参与者用它来描述他们支持的编解码器、端口和协议。它不传输视频或音频,只协商连接参数。类比:SDP是菜单,RTP是菜肴本身。
SIP — 是一种会话管理协议,用于建立、修改和终止呼叫。SDP是一种描述格式,嵌入在SIP消息体中用于传输媒体参数。SIP回答<谁在打电话给谁>的问题,而SDP回答<使用哪些编解码器和端口>。
可以,SDP字符串可以在建立连接之前修改。开发人员经常编辑SDP以强制选择特定的编解码器、添加自定义属性或删除不支持的媒体流。但是,更改必须经过双方同意,否则连接将无法建立。
SDP通过单独的信令通道传输,该通道由开发人员独立实现。典型选项是用于Web应用程序的WebSocket、HTTP POST请求(REST API)或用于移动应用程序的原生协议。WebRTC不定义SDP的传输方式,只定义其格式。
BUNDLE — 是SDP的一种机制,将多个媒体流(音频、视频、数据)合并到一个传输通道中。每个流不使用单独的端口,而是使用一个端口和一个ICE连接。这减少了移动设备的负载并降低了延迟。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。