Отправить данные изображения по каналу данных RTC
Я пытаюсь отправить данные изображения через Data Channel
, Но это не работает. Когда просто получать данные из ctx.getImageData
Я получаю строку "[Object ImageData]"
на другой стороне. Преобразование фрагмента данных только в большой двоичный объект приводит к ошибке: Uncaught NetworkError: Failed to execute 'send' on 'RTCDataChannel': Could not send data
, Я получаю ту же ошибку при попытке преобразовать его в ArrayBuffer
, Как мне это сделать?
3 ответа
Вот демо, которое я написал только сейчас: http://richard.to/projects/datachannel-demo/
Обратите внимание, что я использую локальные каналы и просто отображаю изображение, а не рендеринг на холст. Это должно быть легко сделать. Вы можете столкнуться с проблемами при фактической связи с удаленным устройством. Я еще не проверял это. Также это работает только в Chrome. Но должно быть просто сделать работу в Firefox.
Это было немного сложно выяснить, так как материал WebRTC постоянно меняется. Не говоря уже о том, что Firefox и Chrome работают по-разному.
Я собираюсь сосредоточиться на Chrome, так как сообщения об ошибках, которые вы получаете, похоже, связаны с Chrome, в частности Uncaught NetworkError: Failed to execute 'send' on 'RTCDataChannel': Could not send data
, Эта проблема была описана здесь: https://groups.google.com/forum/
Это связано с RTP data channel
ограниченная скорость. Ссылка, которую я дал вам упомянул 3 KB/sec
и в моем тестировании это звучит примерно так.
Хорошей новостью является то, что после Chrome 31 вы можете использовать каналы данных на основе SCTP. Смотрите здесь: https://groups.google.com/forum/.
Это значит вместо этого:
window.localPeerConnection = new webkitRTCPeerConnection(servers,
{optional: [{RtpDataChannels: true}]});
Вы можете сделать что-то вроде этого (вероятно, можете удалить второй параметр):
window.localPeerConnection = new webkitRTCPeerConnection(servers,
{optional: []});
Я верю, что вы все равно будете ограничены в скорости, но теперь это 64kbps
, Я могу ошибаться по поводу этого числа. Не могу найти ссылку, по которой я ее прочитал.
Хорошая вещь о канале SCTP состоит в том, что вы можете использовать надежное соединение для передачи данных (TCP) вместо ненадежного (UDP), и данные будут отправляться по порядку. Я не уверен в этом. Еще раз, не могу найти ссылку.
Теперь, кажется, вам придется распределять данные по-прежнему. Вы не можете отправить все это одновременно в Chrome. Вы можете сделать это в Firefox, хотя.
Второе, что вам нужно знать, это то, что blob
данные в настоящее время не поддерживаются Chrome. По крайней мере, в обычном Chrome 32. Это означает, что мы должны отправлять данные в виде текста, если мы хотим использовать Chrome.
Итак, что мы можем сделать, это превратить наши данные изображения в base64, так как canvas.toDataURL()
, Вот пример того, как это будет работать:
var canvas = document.createElement('canvas');
canvas.width = startimage.width;
canvas.height = startimage.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(startimage, 0, 0, startimage.width, startimage.height);
var data = canvas.toDataURL("image/jpeg");
Теперь, когда у нас есть наши данные, нам просто нужно разбить строку bas64:
Вот реализация фрагментирования данных, которые я использую в моей демонстрации выше:
function sendData() {
trace("Sending data");
sendButton.disabled = true;
var canvas = document.createElement('canvas');
canvas.width = startimage.width;
canvas.height = startimage.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(startimage, 0, 0, startimage.width, startimage.height);
var delay = 10;
var charSlice = 10000;
var terminator = "\n";
var data = canvas.toDataURL("image/jpeg");
var dataSent = 0;
var intervalID = 0;
intervalID = setInterval(function(){
var slideEndIndex = dataSent + charSlice;
if (slideEndIndex > data.length) {
slideEndIndex = data.length;
}
sendChannel.send(data.slice(dataSent, slideEndIndex));
dataSent = slideEndIndex;
if (dataSent + 1 >= data.length) {
trace("All data chunks sent.");
sendChannel.send("\n");
clearInterval(intervalID);
}
}, delay);
}
Реализация довольно проста, в основном просто с использованием setInterval
, Вы можете возиться с размером среза и параметрами задержки. Также нам нужно установить символ-терминатор, чтобы знать, когда закончится сообщение. Я просто использовал \n
персонаж.
А вот как будет реализован приемник. В основном отслеживает данные, пока они не получат символ-терминатор, который я только что использовал символ новой строки.
function handleMessage(event) {
if (event.data == "\n") {
endimage.src = imageData;
trace("Received all data. Setting image.");
} else {
imageData += event.data;
//trace("Data chunk received");
}
}
Надеюсь это немного поможет. Было весело исследовать это. Не совсем уверен, что это будет идеальным решением для отправки изображения через WebRTC. Есть некоторые демонстрации, которые делают передачу файлов P2P и прочее. Я думаю, это зависит от вашей цели.
Это исключение вызвано превышением предела пропускной способности, согласованного в сеансе.
При создании ответа на предложение необходимо изменить объект sessionDescription, который является частью PeerConnection, чтобы изменить b=AS:
параметр, который содержит максимальную полосу пропускания в кбит / с:
var Bandwidth = 5000;
sessionDescription.sdp = sessionDescription.sdp.replace(/b=AS:([0-9]+)/g, 'b=AS:'+Bandwidth+'\r\n');
alert(JSON.stringify(sessionDescription));
По умолчанию значение составляет 30 КБ / с.
На самом деле это ответ на комментарий bornSwift, но у меня недостаточно репутации, чтобы комментировать. Итак: когда вы используете канал данных RTP, вы увидите полосу пропускания для конкретного приложения (AS) в пределах sdp (т. Е. B =AS:30). 30 является значением по умолчанию. Вы можете заменить это произвольным значением (1638400 работает, но если вы хотите продвинуть его дальше, вам придется проб и ошибок).
Однако, когда вы инициализируете канал данных SCTP, вы не увидите никакой пропускной способности AS в вашем sdp. Это просто отлично. Вам не нужно беспокоиться об этом.