Как создать канал данных в одноранговом соединении 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.
Ответы
Ответ 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.