我知道,在P2P和更动态的环境中,缓存ICE候选者和sdp不是一个好的做法,因为您缓存的内容可能无法应用于下一个WebRTC连接。但是,在我们确切知道连接路线应该如何的情况下,情况如何呢?
更具体地说,
- 假设我们有1个TURN服务器(没有负载平衡,所以没有内部路由)
- 以及2个具有固定IP的对等体,它们希望不时地与WebRTC连接
在这种情况下,我们确切地知道对等端的IP是什么,也确切地知道TURN服务器的IP是多少(假设它不会改变),缓存ICE候选(TURN)和SDP或SDP的部分以绕过ICE候选和SDP交换部分可以吗?
否。报价和答案不仅仅包含如何进行连接。它们包含该连接实例的唯一指纹,因为可以在相同的两个已知IP之间建立任何数量的安全连接,甚至可以同时建立。
比较两个不同的RTCPeerConnection对象的createOffer()结果,您会发现它们有所不同。除了指纹之外,它们还包含本地RTCPeerConnection决定通过哪些端口发送/接收单个媒体,这些端口可能会有所不同。
要使用早期的缓存版本,您不仅需要告诉远程RTCPeerConnection对象要使用什么端口,还需要告诉本地端口。这显然是行不通的:
const [pc1, pc2, pc3] = [1,2,3].map(() => new RTCPeerConnection());
(async () => {
try {
[pc1, pc2].forEach(pc => pc.createDataChannel("dummy"));
pc3.ondatachannel = () => console.log("pc3 ondatachannel");
await pc1.createOffer();
await pc1.setLocalDescription(await pc2.createOffer()); // Uh oh! pc2 not pc1
await pc3.setRemoteDescription(pc1.localDescription);
await pc3.setLocalDescription(await pc3.createAnswer());
await pc1.setRemoteDescription(pc3.localDescription);
} catch (e) {
console.log(e);
}
})();
pc1.onicecandidate = e => pc3.addIceCandidate(e.candidate);
pc3.onicecandidate = e => pc1.addIceCandidate(e.candidate);
pc1.oniceconnectionstatechange = e => console.log(pc1.iceConnectionState);
pc3.ontrack = e => video.srcObject = e.streams[0];
在最新的Chrome中,这会产生:
InvalidModificationError: The SDP does not match the previously generated SDP for this type
这是正确的,因为最新的WebRTC规范禁止在createOffer和setLocalDescription之间进行SDP调制。
在Firefox中,协商实际上已经完成,但没有媒体或数据通道事件触发。
即使使用TURN服务器,指纹也不可能不匹配。