PeerSquared – 基于 WebRTC 的一对一在线教学

大约在 2010 年年中,我第一次了解到爱立信实验室的人员正在开发一种用于 P2P 视频聊天的“开放标准”浏览器实现。我当时非常兴奋。事实上,您只能通过 Flash 或其他插件在 Web 浏览器中使用视频聊天,这让我感到困扰。网络摄像头已经存在多年了,但其用途主要限于 MSN Messenger 和 Skype 等专有程序。

现在三年过去了,一切都将改变。就在几天前,P2P 视频聊天功能已进入 Firefox 22 的最终版本。这意味着,随着 Google Chrome 也即将支持这项技术,现在有超过 10 亿人能够在他们的浏览器中使用原生网络摄像头聊天。我认为这真是太棒了,它可能会引发互联网上新一轮的重大变革。想象一下,在未来的几年里,老式的电话线将变得过时,我们都将通过浏览器进行视频通话。

PeerSquared

在阅读了 Google Chrome 和 Firefox 将数据通道添加到 P2P 连接的消息后,我变得更加高兴,因为它提供了大量新的可能性。我对电子学习非常感兴趣,因此我萌生了构建一个名为 PeerSquared 的在线辅导白板系统的想法。

当前版本是一个概念验证,用于我自己验证使用 PeerConnection API 和数据通道(尤其是数据通道)的真正可能性。要使用 PeerSquared,只需在两个不同的屏幕上分别以教师和学生的身份登录,但使用相同且唯一的房间名称。在两个屏幕上登录后,将建立 P2P 连接,教师就可以开始在白板上进行创作。

教师执行的操作,例如绘画、书写和创建形状,也会即时显示在学生的电子白板上,使其成为一种屏幕共享。大多数功能是不言自明的,但一个不太明显的特性是能够将文件系统中的图像拖放到白板上以向学生展示它们,如下面的图片所示(地球和月球作为数据 URL 图像绘制在画布上,画布本身以宇宙图像作为背景)。

注意:PeerSquared 目前尚不能在 Google Chrome 中运行,因为它尚未实现可靠的数据通道。

逐步上传数据

通过数据通道发送的所有数据消息都将被很好地排队。这意味着,例如,当教师向学生发送一个大图像,然后立即绘制一条线(发送的数据量很小)时,不会出现学生先收到线数据的情况。此外,它们也适用于上传更大的数据块。我已经将高达 6MB 的图片上传到学生的电子白板画布上,没有任何问题。

但是,对于较大的数据,能够查看上传进度会很好。因此,我开始思考教师是否能够可靠地将数据分块发送给学生。这似乎非常简单。只需将文件读取到 ArrayBuffer 中,使用slice 方法将其切片,然后通过数据通道发送这些块。


<pre lang="javascript">
// 从 FileReader 获取 'arrayBuffer' 后
var chunkSize = 1000, byteLength = arrayBuffer.byteLength;
for(i = 0; i < byteLength; i = i + chunkSize) {
dataChannel.send(arrayBuffer.slice(i, i + chunkSize));
}
</pre>

当然,还需要发送元信息(例如文件名、大小和类型),以便在学生端创建下载链接,但这很容易做到。只需发送原始的 ArrayBuffer 数据和作为字符串化 JSON 对象的文件元数据。然后,在学生端的 onmessage 事件处理程序中,您可以区分两者。


<pre lang="javascript">
/*
1. 教师发送元信息,例如:JSON.stringify({status : 'start', name: 'image.jpg', type: 'image/jpg', chunkCount : 20});
2. 教师发送文件块,请参阅上面的代码。
3. 发送最后一个块后,教师发送一条消息,表示上传已完成,例如:JSON.stringify({status : 'complete'});
*/
var arrayBufferChunks = [], blob = null, meta = {}, container = document.getElementById('some_div');

dataChannel.onmessage = function(evt) {
var data = evt.data;
if(typeof data == 'object') {
// 步骤 2:将块重新组合在一起
arrayBufferChunks.push();
// 注意:arrayBufferChunks.length / meta.chunkCount 将是进度状态的度量。
}
else if(typeof data == 'string') {
data = JSON.parse(data);
if(data.status == 'start') {
// 步骤 1:临时存储元数据
meta = data;
}
else if(data.status == 'complete') {
// 步骤 3:为下载链接创建对象 URL
blob = new Blob(arrayBufferChunks, { "type" : meta.type });
container.innerHTML = '<a href="' + URL.createObjectURL(blob) + '" download="' + meta.name + '">' + meta.name + '</a> 已完成
}
}
}
</pre>

像这样,我已经能够连续上传多个文件,并且文件大小超过 200 MB。对于更大的文件,浏览器开始占用大量内存,并可能冻结(这似乎是由于读取文件造成的,而不是发送文件)。另一个问题是,当从文件选择器中添加 8 个或更多文件时,有时会出现浏览器崩溃的情况。这可能是由于为每个读取的文件动态实例化独立的数据通道造成的,因此值得尝试将所有文件排队到一个数据通道中。

我还注意到几次文件上传冻结的情况。这可能是由于网络连接不畅造成的。因此,很高兴知道使渐进式下载可恢复也不应该太难。只要接收方跟踪最后一个接收到的数据块,它就可以在暂停或中断上传后向发送方发送一条消息:“请发送文件 X,但从块 Y 开始”。这样,您就可以轻松地创建相当复杂的 P2P 文件共享工具。

您可以通过在教师端的聊天输入框中选择系统上的一个或多个文件并将它们拖放到该框中来尝试 PeerSquared 中的渐进式文件上传,如下面的屏幕截图所示。

向 PeerConnection 添加和删除

目前,Firefox 中的 PeerConnection 对象的一个缺点是(尚)无法简单地向单个 PeerConnection 对象添加和删除多个数据通道和视频流,因为每次添加/删除都需要重新协商会话。来自http://www.w3.org/TR/webrtc/

特别是,如果 RTCPeerConnection 对象正在使用 MediaStream,并且通过例如调用 add() 方法向其中一个流的 MediaStreamTrackList 对象添加了轨道,则 RTCPeerConnection 对象必须触发 negotiationneeded 事件。媒体组件的删除也必须触发 negotiationneeded

negotiationneeded 事件尚未出现。作为 PeerSquared 中的替代方案,我使用了多个独立的 PeercConnection 对象:一个用于所有数据通道,另一个用于每个视频流。这样就可以正常工作。

P2P 共享的下一步

我相信 PeerSquared 的白板和网络摄像头结合在一起,是进行一对一在线教学的绝佳工具,并且可以在白板的基础上构建更多交互选项。但是,有时需要共享视频甚至整个桌面。如何做到这一点呢?一种方法是使用像 manycam 这样的虚拟网络摄像头驱动程序,它能够将来自视频或桌面的流捕获到您的网络摄像头中。缺点是您再次依赖外部专有软件。

从版本 26 开始,Google Chrome 实验性地允许 getUserMedia() 访问屏幕并通过对等连接共享它,您可以在 WebRTC 无插件屏幕共享 中进行测试。我不确定这是否或何时会成为 Web 标准。我能想到的最后一个选项(仅捕获当前选项卡内容)是使用像 html2canvas 这样的库。我自己还没有尝试过,我想知道它是否足够快和可靠,能够提供良好的“选项卡共享体验”。

总结

Mozilla Hacks 上已经有一些关于使用 HTML5 进行在线多人游戏视频会议的精彩演示。我希望我的 PeerSquared 演示能够让您对使用它进行在线协作和教学的一些令人惊叹的可能性有一个很好的了解,并激励您转向 P2P。有任何问题或建议吗?请不要犹豫,联系我。

关于 Fabian Gort

Fabian Gort 目前是居住在阿姆斯特丹的独立企业家,也是 PeerSquared 的开发者。作为一名生物学学生,他早在 2001 年就开始为荷兰的一所大学开发教育软件。从那时起,他一直参与了多个面向非政府组织和大学的基于 Web 的项目。

更多 Fabian Gort 的文章…

关于 Robert Nyman [荣誉编辑]

Mozilla Hacks 的技术布道师和编辑。发表演讲和撰写关于 HTML5、JavaScript 和开放 Web 的博客文章。Robert 是 HTML5 和开放 Web 的坚定支持者,自 1999 年以来一直从事 Web 前端开发工作 - 在瑞典和纽约市。他还定期在 http://robertnyman.com 上发表博客文章,并且喜欢旅行和结识新朋友。

更多 Robert Nyman [荣誉编辑] 的文章…


12 条评论

  1. shavounet

    我试了一下,哇,它真的可以!干得漂亮;)

    (除了视频共享,但我们还没做到!)

    2013 年 7 月 4 日 08:23

    1. shavounet

      好的,我用我的手机(安装了 Aurora)重新试了一下,哇哇哇。

      现在这真是太棒了=)

      2013 年 7 月 4 日 08:45

      1. Robert Nyman [编辑]

        很高兴您喜欢它!:-)

        2013 年 7 月 4 日 09:12

  2. Daniel

    很棒的努力!

    对于获取当前选项卡的屏幕截图,这里有一个更好的解决方案:https://mdn.org.cn/en/docs/HTML/Canvas/Drawing_DOM_objects_into_a_canvas

    2013 年 7 月 4 日 09:55

  3. Fabian Gort

    感谢您的建议,Daniel。这实际上是我用于将文本写入画布的技术,我怀疑 html2canvas 库也是基于此技术构建的。

    2013 年 7 月 4 日 10:46

    1. Daniel

      不客气。

      我尝试过使用该库,但除了 Twitter 之外,所有网站都失败了。在查看 GitHub 上的源代码后,我感觉它直接访问 DOM,读取样式信息并生成已绘制的屏幕截图。在网络上还有其他几个使用这种不安全技术的实现。

      Firefox 有一个 chrome 特权方法。我在这里使用它:https://builder.addons.mozilla.org/package/193932/latest/

      感谢您提到 Chrome 的功能。能够尝试一下会很棒。:-)

      2013 年 7 月 4 日 14:18

      1. Fabian

        我昨天才发现实际上无法向 SVG 元素添加图像,之后又了解到 html2canvas 存在相同的问题(这是一个安全问题)。当然,您可以将它们添加为图像,但这使得捕获屏幕变得非常困难,尤其是在网页中存在图层的情况下。

        2013 年 7 月 5 日 00:26

  4. Jeroen

    这听起来像是用于在线教学和协作的绝佳工具。我将立即尝试一下。

    2013年7月4日 15:09

  5. Brett Zamir

    虽然从某种意义上说,它仍然是“专有的”(因为它不是标准的,尽管是开源的并在 Firefox 插件中实现),但您可以使用 AsYouWish (https://addons.mozilla.org/en-US/firefox/addon/as-you-wish/) 来提供一种共享剪贴板、共享用户标签/窗口信息或帮助他们打开这些标签/窗口等的方法,或者利用任何 Mozilla 的特权 API……

    (但是,这取决于用户是否安装了插件,是否配置了插件以允许从您的网站发出权限请求,以及是否批准了您的特定请求——鉴于对用户的潜在安全风险,这需要绕很多弯。)

    2013年7月4日 20:45

  6. Fabian

    感谢 Brett,这也是一个不错的建议。但是,我个人的意图是开发一个无需插件的东西。这也与教育机构对其安装策略的严格性有关。

    2013年7月5日 00:29

  7. vrobbi

    这是一个 HTML5 实时白板协作工具,
    您可以上传图像或从您的网络摄像头
    直接捕捉图像。

    http://vrobbi-nodedrawing.herokuapp.com/

    使用 Node.js 和 Socket.IO。

    2013年7月10日 21:17

  8. Mathew Porter

    很高兴看到 WebRTC 的发展方向,尤其是 P2P 的可能性。

    2013年7月24日 09:49

本文评论已关闭。