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

时间:2015-02-05 18:04:37

标签: javascript webrtc

我一直无法建立WebRTC会话,并且正在尽可能地简化问题。所以我写了一个简单的副本&粘贴示例,您只需将商品/答案粘贴到网络表单中,然后单击“提交”。

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

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

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

Page 1

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

  2. 创建了一个新的Host对象,并调用了new PeerConnection()createDataChannel

  3. createOffer被调用,生成的offerSDP被粘贴到offer textarea。

  4. 第2页

    1. 从第1页复制offerSDP并粘贴到第2页的商品textarea,点击join

    2. 创建了新的Guest对象,PeerConnection并设置了ondatachannel处理程序。

    3. 使用setRemoteDescription数据为Guest对象调用
    4. offerSDP

    5. createAnswer被调用,结果将粘贴到answer textarea框中。

    6. Page 1

      1. 从{2}复制answerSDP并粘贴到第1页的answer文本区域,点击submit answer

      2. 使用Host.setRemoteDescription数据调用
      3. answerSDP。这会创建SessionDescription,然后使用生成的数据调用peer.setRemoteDescription

      4. 这些是示例中执行的步骤,但似乎我遗漏了一些关键的东西。在使用answerSDP设置提议者的remoteDescription之后,我尝试在dataChannel上发送测试消息:

        Chrome 40

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

        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
        

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

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

1 个答案:

答案 0 :(得分: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;

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);
    }
}

对于来宾self.offer变为self.answer

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

channel.onopen = function () {
    console.log('** channel.onopen');
    channel.send('hello world!');
};