9.拍照并通过数据通道分享

你会学到什么

在此步骤中,您将学习如何:

  • 使用canvas元素拍摄照片并从中获取数据。

  • 与远程用户交换图像数据。

此步骤的完整版本在步骤-06文件夹中。

运行原理

以前,您学习了如何使用RTCDataChannel交换短信息。

此步骤可以共享整个文件:在本示例中,通过getUserMedia()捕获照片。

本步骤的核心部分如下:

  1. 建立数据通道。请注意,在此步骤中,不要将任何媒体流添加到对等连接。

  2. 用getUserMedia()捕获用户的网络摄像头视频流:

var video = document.getElementById('video');

function grabWebCamVideo() {
  console.log('Getting user media (video) ...');
  navigator.mediaDevices.getUserMedia({
    audio: false,
    video: true
  })
  .then(gotStream)
  .catch(function(e) {
    alert('getUserMedia() error: ' + e.name);
  });
}
  1. 当用户单击“捕捉”按钮时,从视频流中获取快照(视频帧),并将其显示在画布元素中:

var photo = document.getElementById('photo');
var photoContext = photo.getContext('2d');

function snapPhoto() {
  photoContext.drawImage(video, 0, 0, photo.width, photo.height);
  show(photo, sendBtn);
}
  1. 当用户单击发送按钮时,将图像转换为字节并通过数据通道发送:

function sendPhoto() {
  // Split data channel message in chunks of this byte length.
  var CHUNK_LEN = 64000;
  var img = photoContext.getImageData(0, 0, photoContextW, photoContextH),
    len = img.data.byteLength,
    n = len / CHUNK_LEN | 0;

  console.log('Sending a total of ' + len + ' byte(s)');
  dataChannel.send(len);

  // split the photo and send in chunks of about 64KB
  for (var i = 0; i < n; i++) {
    var start = i * CHUNK_LEN,
      end = (i + 1) * CHUNK_LEN;
    console.log(start + ' - ' + (end - 1));
    dataChannel.send(img.data.subarray(start, end));
  }

  // send the reminder, if any
  if (len % CHUNK_LEN) {
    console.log('last ' + len % CHUNK_LEN + ' byte(s)');
    dataChannel.send(img.data.subarray(n * CHUNK_LEN));
  }
}
  1. 接收端将数据信道消息字节转换回图像并将图像显示给用户:

function receiveDataChromeFactory() {
  var buf, count;

  return function onmessage(event) {
    if (typeof event.data === 'string') {
      buf = window.buf = new Uint8ClampedArray(parseInt(event.data));
      count = 0;
      console.log('Expecting a total of ' + buf.byteLength + ' bytes');
      return;
    }

    var data = new Uint8ClampedArray(event.data);
    buf.set(data, count);

    count += data.byteLength;
    console.log('count: ' + count);

    if (count === buf.byteLength) {
      // we're done: all data chunks have been received
      console.log('Done. Rendering photo.');
      renderPhoto(buf);
    }
  };
}

function renderPhoto(data) {
  var canvas = document.createElement('canvas');
  canvas.width = photoContextW;
  canvas.height = photoContextH;
  canvas.classList.add('incomingPhoto');
  // trail is the element holding the incoming images
  trail.insertBefore(canvas, trail.firstChild);

  var context = canvas.getContext('2d');
  var img = context.createImageData(photoContextW, photoContextH);
  img.data.set(data);
  context.putImageData(img, 0, 0);
}

获取代码

使用步骤-06的内容替换work文件夹的内容。您在work的index.html文件现在应该如下所示:

<!DOCTYPE html>
<html>
<head>
  <title>Realtime communication with WebRTC</title>
  <link rel="stylesheet" href="/css/main.css" />
</head>

<body>
  <h1>Realtime communication with WebRTC</h1>

  <h2>
    <span>Room URL: </span><span id="url">...</span>
  </h2>

  <div id="videoCanvas">
    <video id="camera" autoplay></video>
    <canvas id="photo"></canvas>
  </div>

  <div id="buttons">
    <button id="snap">Snap</button><span> then </span><button id="send">Send</button>
    <span> or </span>
    <button id="snapAndSend">Snap &amp; Send</button>
  </div>

  <div id="incoming">
    <h2>Incoming photos</h2>
    <div id="trail"></div>
  </div>

  <script src="/socket.io/socket.io.js"></script>
  <script src="js/lib/adapter.js"></script>
  <script src="js/main.js"></script>

</body>
</html>

如果您的Node服务器没有运行,请通过从您的work目录调用以下命令启动它:

node index.js

如有必要,请点击允许按钮允许应用使用您的网络摄像头。

该应用将创建一个随机的房间ID,并将该ID添加到该URL。在新的浏览器标签或窗口中从地址栏打开URL。

单击“捕捉和发送”按钮,然后查看页面底部另一个选项卡中的“传入”区域。应用程序会在标签页之间传送照片。

你应该看到这样的东西:

加分点

  1. 如何更改代码,以便共享任何文件类型?

了解更多

Last updated