如何在WebRTC对等连接中创建数据通道?

12

我试着学习如何创建一个RTCPeerConnection,以便我可以使用DataChannel API。这是我从理解中尝试过的内容:

var client = new mozRTCPeerConnection;
var server = new mozRTCPeerConnection;

client.createOffer(function (description) {
    client.setLocalDescription(description);
    server.setRemoteDescription(description);

    server.createAnswer(function (description) {
        server.setLocalDescription(description);
        client.setRemoteDescription(description);

        var clientChannel = client.createDataChannel("chat");
        var serverChannel = server.createDataChannel("chat");

        clientChannel.onmessage = serverChannel.onmessage = onmessage;

        clientChannel.send("Hello Server!");
        serverChannel.send("Hello Client!");

        function onmessage(event) {
            alert(event.data);
        }
    });
});

我不确定出了什么问题,但我认为连接从未建立,因为没有显示任何消息。

我在哪里可以了解更多信息?我已经阅读了入门 WebRTC - HTML5 Rocks 教程。

3个回答

13

在浏览了许多文章后,我终于弄好了: http://jsfiddle.net/LcQzV/

首先,我们创建对等连接:

var media = {};
media.fake = media.audio = true;
var client = new mozRTCPeerConnection;
var server = new mozRTCPeerConnection;

当客户端连接到服务器时,它必须打开一个数据通道:

client.onconnection = function () {
    var channel = client.createDataChannel("chat", {});

    channel.onmessage = function (event) {
        alert("Server: " + event.data);
    };

    channel.onopen = function () {
        channel.send("Hello Server!");
    };
};
当客户端创建数据通道时,服务器可能会做出响应:
server.ondatachannel = function (channel) {
    channel.onmessage = function (event) {
        alert("Client: " + event.data);
    };

    channel.onopen = function () {
        channel.send("Hello Client!");
    };
};
我们需要向客户端和服务器添加一个虚假的音频流来建立连接:
navigator.mozGetUserMedia(media, callback, errback);

function callback(fakeAudio) {
    server.addStream(fakeAudio);
    client.addStream(fakeAudio);
    client.createOffer(offer);
}

function errback(error) {
    alert(error);
}

客户端创建一个提议:

function offer(description) {
    client.setLocalDescription(description, function () {
        server.setRemoteDescription(description, function () {
            server.createAnswer(answer);
        });
    });
}

服务器接受请求并建立连接:

function answer(description) {
    server.setLocalDescription(description, function () {
        client.setRemoteDescription(description, function () {
            var port1 = Date.now();
            var port2 = port1 + 1;

            client.connectDataConnection(port1, port2);
            server.connectDataConnection(port2, port1);
        });
    });
}

哎呀,这花了一些时间才理解明白。


为什么我只想创建数据通道在点对点之间传输数据,却需要创建虚假音频流? - Suman Bogati
3
几个问题:1)虚假音频不再需要(而且已经很长一段时间了)2)根据规范,setLocalDescription()和setRemoteDescription()都必须提供成功和错误回调函数。Chrome和FF在这方面一直很宽容(尽管我们在FF32中存在一个退化,破坏了宽容性;它可能会在32.1修复,如果没有则在33修复),但这违反了规范。3)connectionDataConnection()现在不需要也不使用;这是FF中旧的临时解决方案。 - jesup

4

以下是我在Chrome中测试的一系列事件(2014年2月),这是一个简化的情况,其中peer 1将向peer 2流视频。

  1. 建立某种方式以便对等方交换消息。(不幸的是,人们如何完成这项任务的差异是导致不同WebRTC代码示例无法比较的原因。但是,在思想上和在代码组织上,尝试将此逻辑与其他逻辑分开。)
  2. 在每一方面,为重要的信令消息设置消息处理程序。您可以设置它们并保持它们处于活动状态。需要处理和发送3个核心消息:
    • 来自另一侧的ice candidate ==>使用它调用addIceCandidate
    • offer消息 ==>使用它调用SetRemoteDescription,然后制作答案并发送它
    • answer消息 ===>使用它调用SetRemoteDescription
  3. 在每一方面,创建一个新的peerconnection对象,并为重要事件附加事件处理程序:onicecandidate、onremovestream、onaddstream等。
    • ice candidate ===>将其发送到另一侧
    • 添加流 ===>将其附加到视频元素,以便您可以看到它
  4. 当两个对等方都存在且所有处理程序都已就位时,peer 1会收到某种触发消息以启动视频捕获(使用getUserMedia调用)
  5. 一旦getUserMedia成功,我们就有了一个流。在peer 1的peer connection对象上调用addStream
  6. 然后-仅此时-peer 1提供
  7. 由于我们在步骤2中设置的处理程序,因此peer 2会收到这个消息并发送答案
  8. 与此同时(有点晦涩),peer连接对象开始生成ice candidate。它们在两个对等方之间发送和处理(上述步骤2和3)
  9. 流媒体会自动启动,作为以下2个条件的结果:
    • offer/answer交换
    • 接收、交换和添加ice candidates

我还没有找到在第9步之后添加视频的方法。当我想要更改内容时,我回到步骤3。


1
虽然你的回答没有提供代码,但我认为它是迄今为止最好的。我花了几个星期才明白如何成功地连接两个WebRTC客户端,而这个答案非常准确。代码很好,但接下来的问题是你想使用ajax还是websockets - node.js、Java或php等。任何人都可以使用这个答案来按照自己的方式实现。 - JSON

4
我已经发布了一个要点, 显示如何设置数据连接,适用于Chrome和Firefox两者。
主要区别在于,在Firefox中需要等待连接建立,而在Chrome中则相反:似乎需要在任何报价发送来回之前创建数据连接。
var pc1 = new RTCPeerConnection(cfg, con);
if (!pc1.connectDataConnection) setupDC1();    // Chrome...Firefox defers per other answer

另一个区别是Chrome将事件对象传递给.ondatachannel,而FF只传递原始通道。
pc2.ondatachannel = function (e) {
    var datachannel = e.channel || e;

请注意,您目前需要使用启用了--enable-data-channels的Chrome Nightly才能使其正常工作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接