作者: Iñaki Baz Castillo(原文链接)
翻译:刘通
原标题:SDP: Your Fears Are Unleashed
前文连接:SDP:被释放的恐惧(一)
ORTC简单概述
在长时间从事ORTC之后我才能说这是合适的做法。这离完美差的还很远,尤其是当它处理发送/接收RTP参数的时候。但是,与SDP机制不同,它准确的将不同通信层分成单独的模型和类,使它变得更加开发者友好,更容易理解,而且提供更令人舒服的API。
ORTC建议使用基于代表不同通信层的类的完全不同的API。所以,在ORTC中我们有像RTCIceGatherer,RTCIceTransport,以及RTCDTLSTransport这类的实体。还有与WebRTC相同的实体,比如RTCRtpSender以及RTCRtpReceiver(但是不包括RTCTransceiver)。
没有SDP
ICE,DTLS以及RTP参数必须由对等端进行交换以建立多媒体会话。然而API没有规定使用特定的规范格式(比如SDP)。使用什么格式以及协商过程完全由开发人员决定。
结构
ORTC的层包括:
# ICE:通过提供一个RTCIceGatherer类(用来检索我们的ICE候选项)以及一个RTCIceTransport类(用来建立与远端对等端/服务器的一个网络路径),我们可以通过任何方式自由地将ICE相关参数发送给远端对等端。
# DTLS:RTCDtlsTransport类负责通过RTCIceTransport提供的网络路径建立一条安全的媒体/数据通道。还是一样,这些都是由开发人员来决定如何发送本地DTLS参数给远端。
# 媒体:在我们有了一条安全的路径(ICE + DTLS)之后,我们可以创建RTCRtpSender和RTCRTPReceiver实例来发送媒体给远端,以及从远端接收媒体,或者创建一个RTCDataChannel实例来发送/接收数据。是的,与这些类相关联的参数可以通过共享JSON对象来传输到远端。
要说清楚的是,我们是如何将我们的RTC参数发送给远端对等端并不那么重要。ORTC API给远端提供提取这些参数的功能,以及创建一个合适的ORTC API调用它们。
ORTC设计的优点很明确:没有过多的重协商!当RTP媒体发生变化时,RTCRtpSender和RTCRTPReceiver不需要重新协商ICE和/或DTLS参数。而是只有新的RTP参数才必须传送给远端(或者从远端接收)。
那么,WebRTC 1.0中的SDP又怎么样呢?
在WebRTC 1.0中我们不将RTC参数发送给远端,而是发送一个完整的SDP BLOB。一个SDP包括关于ICE,DTLS,RTP等等所有的信息。基本上,对等端A产生一个SDP请求,包括了有关其本地ICE参数,DTLS参数,发送媒体的信息,并且想要接收媒体。这个SDP请求被发送给远端对等端,该远端对等端将其作为远端描述应用于RTCPeerConnection。
添加新的流
对于未来添加媒体流(比如添加网络摄像头视频),对等端产生另一个完整的SDP请求,并且将其传送给远端,还是,该远端将其作为远端描述应用。但这不是完全正确的。理论上说,并没有真正再次发送完整SDP的需求。事实上,发送方可以检查其新的本地SDP请求,然后仅把添加的内容通知给远端。不管怎样,远端向浏览器指示新接收媒体的唯一方法是拥有或者重建一个完整的SDP请求,并且调用setRemoteDescription()。
要明确的是:不管对等端是如何将RTP参数发送给另一方的,最终JavaScript和浏览器的WebRTC引擎之间的通信都是通过将完整的SDP块发送给RTCPeerConnection或者从RTCPeerConnection接收而实现的。这里并没有一个“真正的API”,也就是浏览器必须对新的远端SDP进行全面的“重新检查”,以找到发生了什么变化。包括:
# 检查远端ICE参数是否发生变化
# 检查远端DTLS是否发生变化
# 检查是否添加了新的媒体轨道
# 检查现有的正在进行的媒体轨道是否被改变或者停止
# 检查正在进行的媒体轨道的参数是否被改变
用一个真实的例子解释为什么这很烦
可以很清楚的看到这其中有什么问题。如果看不出来的话,我会用一个关于SDP a=setup真实的用例来解释:
# 让我们假设Alice想要与Bob进行音频和数据通道通信,所以Alice创建了她的本地RTCPeerConnection,并且得到了相应的SDP请求。
# 根据RFC 5763,SDP请求的a=setup属性必须是“actpass”,也就是应答方(Bob)需要决定谁是DTLS用户谁是DTLS服务器。
# Bob生成相应的SDP应答,其中包括a=setup:active,意思是Bob成为了DTLS用户,而Alice成为DTLS服务器。
# 在ICE和DTLS处理之后,Alice和Bob两个人互相交换了他们的音频和数据。
# 之后,Bob想要在通信中加上网络摄像头捕捉的视频,所以他得到了一个包括网络摄像头流信息的SDP重请求。
# 还是,依据RFC 5673,这个SDP重请求中要有a=setup:actpass。
# Alice接到SDP重请求并且产生一个重响应。
# 为了保持现有的DTLS关联开放,这个SDP重响应必须有a=setup:passive项。
你注意到了吗?为了不改变传输,SDP重请求和重响应必须表示与在最初SDP交换中a=setup属性相不同的值。
这件事好像也不难是吧?好,事实上是:
# “在收到SIP重邀请之后,FreeSwitch会破坏之前的DTLS关联,因为会在SDP响应中设置一个错误的DTLS角色。”(错误报告)这个问题在2017年4月24号修复。
# “在发送重邀请的时候,Asterisk会根据规范设置一个无效的a=setup:active属性。”(错误报告)
# “Firefox会在产生重响应的时候转换到DTLS主动状态。”(错误报告)