通过RTC数据通道发送图像数据

时间:2014-02-05 18:38:11

标签: javascript canvas webrtc

我正在尝试通过Data Channel发送图像数据,但它无效。 刚刚从ctx.getImageData获取数据时,我会在另一端收到字符串"[Object ImageData]"。仅将数据片段转换为blob会导致错误:Uncaught NetworkError: Failed to execute 'send' on 'RTCDataChannel': Could not send data。尝试将其转换为ArrayBuffer时出现同样的错误。我该怎么做?

3 个答案:

答案 0 :(得分:10)

这是我刚才写的一个演示: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/#!topic/discuss-webrtc/U927CZaCdKU

这是由于RTP data channel速率有限。我给你的链接提到3 KB/sec,在我的测试中听起来很正确。

好消息是,在Chrome 31之后,您可以使用基于SCTP的数据通道。见这里:https://groups.google.com/forum/#!topic/discuss-webrtc/y2A97iCByTU

这意味着代替:

window.localPeerConnection = new webkitRTCPeerConnection(servers,
    {optional: [{RtpDataChannels: true}]});

你可以这样做(可能会删除第二个参数):

window.localPeerConnection = new webkitRTCPeerConnection(servers,
    {optional: []});

我相信你仍然会受到限制,但现在是64kbps。我可能错了这个号码。找不到我从中读取的链接。

关于SCTP通道的一个好处是,您可以使用可靠的数据连接(TCP)而不是不可靠(UDP),并且数据按顺序发送。我对此并不积极。再一次,找不到链接。

现在,正因为如此,你似乎仍然需要将数据分块。您无法在Chrome中同时发送所有内容。你可以在Firefox中做到这一点。

您需要知道的第二件事是Chrome目前不支持blob数据。至少在常规Chrome 32中。这意味着如果我们想要使用Chrome,我们必须以文本形式发送数据。

所以我们可以做的是从canvas.toDataURL()开始在base64中转换我们的图像数据。这是一个如何工作的例子:

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文件传输和演示的演示。我想这取决于你的目的。

答案 1 :(得分:1)

此异常是由超出会话中约定的带宽限制引起的。

创建商品的答案时,您必须编辑属于PeerConnection的sessionDescription对象,以更改包含kb / s最大带宽的b=AS:参数:

var Bandwidth = 5000;
sessionDescription.sdp = sessionDescription.sdp.replace(/b=AS:([0-9]+)/g, 'b=AS:'+Bandwidth+'\r\n');
alert(JSON.stringify(sessionDescription));

默认值为30kb / s。

答案 2 :(得分:1)

这实际上是对斯威夫特答案的评论,但我没有足够的声誉来评论。因此:当您使用RTP数据通道时,您将在sdp中看到应用程序特定(AS)带宽(即b = AS:30)。 30是默认值。您可以使用任意值替换它(1638400可以使用,但是如果您想进一步推动它,则必须进行试验和错误)。

但是,初始化SCTP数据通道时,您的sdp中将看不到任何AS带宽。这很好。你不必担心它。