Подтвердить что ты не робот

Как создать канал данных в одноранговом соединении WebRTC?

Я пытаюсь узнать, как создать RTCPeerConnection, чтобы я мог использовать API DataChannel. Вот что я пробовал из того, что понял:

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.

4b9b3361

Ответ 1

Наконец-то я получил его для работы после просеивания многих статей: 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);
        });
    });
}

Уф. Это заняло некоторое время, чтобы понять.

Ответ 2

Я разместил gist, который показывает настройку соединения для передачи данных, совместимого как с Chrome, так и с Firefox.

Основное отличие заключается в том, что в FF вам нужно подождать, пока соединение не будет настроено, в 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;

Обратите внимание, что вам в данный момент требуется Chrome Nightly, начинающийся с --enable-data-channels, чтобы он работал.

Ответ 3

Вот последовательность событий, которые я сегодня работаю (февраль 2014) в Chrome. Это для упрощенного случая, когда одноранговый узел будет передавать видео в одноранговое соединение.

  • Определите способ обмена сообщениями между сверстниками. (Различия в том, как люди это делают, - это то, что делает разные образцы кода WebRTC столь несоизмеримыми, к сожалению. Но мысленно и в вашей организации кода попытайтесь отделить эту логику от остальных.)
  • С каждой стороны настройте обработчики сообщений для важных сигнальных сообщений. Вы можете настроить их и оставить их. Существует 3 основных сообщения для обработки и отправки:
    • ледяной кандидат, отправленный с другой стороны == > вызов addIceCandidate с ним
    • сообщение с предложением == > SetRemoteDescription с ним, затем сделайте ответ и отправьте его
    • ответное сообщение === > SetRemoteDescription с ним
  • С каждой стороны создайте новый объект peerconnection и присоедините к нему обработчики событий для важных событий: onicecandidate, onremovestream, onaddstream и т.д.
    • кандидат на льду === > отправьте его на другую сторону. Добавленный поток
    • === > присоединяет его к элементу видео, чтобы вы могли его видеть.
  • Когда оба одноранговых узла присутствуют и все обработчики находятся на месте, одноранговый узел получает какое-то триггерное сообщение, чтобы начать захват видео (используя вызов getUserMedia)
  • Как только getUserMedia удастся, у нас есть поток. Вызовите addStream для однорангового соединения однорангового узла.
  • Затем - и только тогда - одноранговое предложение 1 делает предложение
  • Из-за обработчиков, которые мы установили на шаге 2, peer 2 получает это и отправляет ответ
  • Одновременно с этим (и несколько неясно), объект подключения сверстников начинает создавать кандидатов на лед. Они отправляются туда и обратно между двумя сверстниками и обрабатываются (шаги 2 и 3 выше).
  • Потоковая передача начинается сама по себе, непрозрачно, в результате 2-х условий:
    • предложение/ответный обмен
    • Получены, обменены и добавлены ледяные кандидаты.

Я не нашел способ добавить видео после шага 9. Когда я хочу что-то изменить, я возвращаюсь к шагу 3.