WebRTC:无法使用DataChannel成功完成信令流程

Nic*_*ngs 5 javascript webrtc

我一直在设置WebRTC会话时遇到问题,并且尽可能地简化问题.所以我写了一个简单的复制和粘贴示例,您只需将要约/答案粘贴到网页表单中,然后点击提交即可.

HTML + JS,在一个文件中,可以在这里找到:http://pastebin.com/Ktmb3mVf

我在本地网络上,因此正在删除ICE服务器初始化过程,以使此示例尽可能简单.

以下是我在示例中执行的步骤:

第1页

  1. 第1页(加载页面),输入频道名称(例如test)并点击create.

  2. Host创建一个新对象,new PeerConnection()createDataChannel进行调用.

  3. createOffer被调用,结果offerSDP被粘贴到offer文本区域.

第2页

  1. offerSDP从第1页复制并粘贴到第2页上的offer textarea,单击join.

  2. Guest创建新对象,PeerConnectionondatachannel设置处理程序.

  3. setRemoteDescriptionGuestofferSDP数据调用对象.

  4. createAnswer被调用,结果被粘贴到answertextarea框中.

第1页

  1. answerSDP是从第2页复制并粘贴到所述answer第1页的文字区域,submit answer被点击.

  2. Host.setRemoteDescriptionanswerSDP数据调用.这会创建一个SessionDescription,然后peer.setRemoteDescription用结果数据调用.

这些是示例中执行的步骤,但似乎我遗漏了一些关键的东西.在提交者的remoteDescription设置后answerSDP,我尝试在以下位置发送测试消息dataChannel:

Chrome 40

"-- complete"
> host.dataChannel.send('hello world');
VM1387:2 Uncaught DOMException: Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open'
Run Code Online (Sandbox Code Playgroud)

Firefox 35

"-- complete"
ICE failed, see about:webrtc for more details
> host.dataChannel.send('hello world');
InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable
Run Code Online (Sandbox Code Playgroud)

我还有一个更复杂的演示操作,有一个WebSocket信令服务器和列出的ICE候选者,但是得到了同样的错误.所以我希望这种简化有助于追踪问题.

同样,单文件代码链接:http://pastebin.com/Ktmb3mVf

Som*_*one 1

要使 webRTC 客户端能够相互连接,您需要 ICE。虽然此类测试不需要 STUN 和 TURN,但它们是其中的一部分,即使没有这些帮助程序,您仍然需要使用 ICE 来告诉另一端要连接到哪个 IP/端口/协议。

有两种方法可以做到这一点:谷歌的“滴流冰”,其中 SDP(答案/提议)在没有任何 ICE 候选者的情况下传递。然后,它们通过单独的信令层进行传输,并在发现时添加。这会加快连接过程,因为 ICE 需要时间,并且可能不需要一些迟到的 ICE 候选者。

经典的方法是等到所有 ICE 候选者都已收集完毕,然后生成包含这些候选者的 SDP。

我已经修改了您的最新版本来执行此操作:http://pastebin.com/g2YVvrRd

您还需要等待数据通道/连接变得可用才能使用它,因此我已将消息的发送移至通道 onopen 事件。

对原代码的重大修改:

Host.prototype.createOffer 和 Guest.prototype.createAnswer 中删除了接口回调,而是将提供的回调函数附加到各自的对象以供以后使用。

self.cb = cb;
Run Code Online (Sandbox Code Playgroud)

Host 和 Guest 都为 PeerConnection 添加了 ICE 处理程序:

var self = this;
this.peer.onicecandidate = function (event) {
    // This event is called for every discovered ICE candidate.
    // If this was trickle ICE, you'd pass them on here.
    // An event without an actual candidate signals the end of the
    // ICE collection process, which is what we need for classic ICE.
    if (!event.candidate) {
        // We fetch the up to date description from the PeerConnection
        // It now contains lines with the available ICE candidates
        self.offer = self.peer.localDescription;
        // Now we move on to the deferred callback function
        self.cb(self.offer);
    }
}
Run Code Online (Sandbox Code Playgroud)

对于客人来说,self.offer 变为 self.answer

接口处理程序 $("#submitAnswer").click() 不再发送消息,而是在 setChannelEvents() 中定义的 onopen 事件中数据通道准备就绪时发送消息。

channel.onopen = function () {
    console.log('** channel.onopen');
    channel.send('hello world!');
};
Run Code Online (Sandbox Code Playgroud)