即使我没有在对等候选者中添加ice候选者,Webrtc呼叫也会连接

Cha*_*mar 5 javascript webrtc

const pc1 = new RTCPeerConnection(null);
const pc2 = new RTCPeerConnection(null);
async function call(){
    const offer = await pc1.createOffer();
    pc1.setLocalDescription(offer);
    pc2.setRemoteDescription(offer);
    const answer = await pc2.createAnswer();
    pc2.setLocalDescription(answer);
    pc1.setRemoteDescription(pc2.localDescription);
}
async function showVideo(){
    const config={audio:true,video:true};
    stream = await navigator.mediaDevices.getUserMedia(config);
    pc1.addStream(stream);
}
Run Code Online (Sandbox Code Playgroud)

这是我的代码的简化版本。

现在,在此代码中,我没有将icecandidate添加到对等方,也没有收听onicecandidate。但是,如果我两次调用call(),则建立连接。

我使用事件处理程序更改iceconnectionstate的状态,发现当我第一次调用call时,iceconnection状态处于检查状态,而当我第二次调用它时,iceconnection状态被调用并且状态完成。

因此,我想知道即使不将icecandidate添加到另一个对等方又如何启动检查并第二次连接?

jib*_*jib 5

四个原因:代码中的错误、Chrome 的行为、没有防火墙以及有关涓流 ICE 工作原理的信息。

1)代码中的错误

首先,以下几组pc1.setRemoteDescription(null)

pc2.setLocalDescription(answer);
pc1.setRemoteDescription(pc2.localDescription); // pc2.localDescription == null here
Run Code Online (Sandbox Code Playgroud)

...因为setLocalDescription是一个异步方法,不会立即完成。

现在最终pc2.localDescription会被设置,所以当你第二次调用它时,它就在那里,并且谈判可以进行。call()

要解决此问题,您必须使用或等待承诺awaitthen

await pc2.setLocalDescription(answer);
pc1.setRemoteDescription(pc2.localDescription); // pc2.localDescription is set!
Run Code Online (Sandbox Code Playgroud)

2) 如果没有 NAT,则不需要 ICE 服务器。

浏览器可以使用“主机”候选者(您计算机的 IP)与同一 LAN 上的其他计算机或自身进行通信。不需要 ICE 服务器来发现这些。

3)Trickle ICE是一种优化。

个别冰候选人使用的信号(滴流)onicecandidate是一种旨在加快谈判速度的优化。一旦setLocalDescription成功,浏览器的内部ICE 代理就会启动,将发现的 ICE 候选者插入到浏览器自身中localDescription。等待几秒钟进行协商,根本不需要滴流:所有 ICE 候选人都将包含在要约和答案中传输。

4) Chrome 中一个有趣的行为。

我怀疑在第二次调用call()Chrome 的 ICE 代理时会记住它上次收集的候选主机,并将它们插入到 Offer 中,并localDescription立即在setLocalDescription成功回调运行完成之前进行竞赛。这可能是一个错误,也可能是规范规定的工作方式。无论如何,行为似乎根据浏览器 atm 的不同而有所不同,所以我今天不会依赖它。

在 SDP 中复制/证明 ICE 的步骤

  1. 在 Chrome 和 Firefox 中运行这个小提琴
  2. 单击该Call!按钮一次,然后再单击一次。
  3. 观察Firefox:你会看到0 candidates(输出两次);两次;无连接。
  4. 观察Chrome:它与候选人进行3 candidates第二 联系。
  5. 现在取消注释该行// await wait(2000);
  6. 现在,两个4浏览器都会在 2 秒或8 candidates之后进行连接。

候选人的实际数量可能会因您的系统而异,但行为应该不会。

当我在 Firefox 中运行它时,它两次都不会连接,除非我将其修改为等待或滴流候选者)。

浏览器更新: 两种浏览器都有缺陷:Firefox在从 ICE 故障中恢复方面限制过于严格,Chrome过于宽松。