WebRTC:更新和解决方法

您可能已经注意到,我们在 WebRTC 实现方面取得了很大进展,并且预计在接下来的几个版本中会有更多改进。

我们正在进行的工作旨在改善音频质量问题(是的,我们知道我们仍然有一些问题!)并协助解决 NAT 穿越问题(您可以在 Bug 904622 中跟踪进度)。

现有限制

除了即将进行的改进之外,我还想花点时间来了解您可能已经注意到的几个现有限制,并提供一些有关编写在这些限制内工作的应用程序的建议。

第一个问题,在 Bug 857115 中进行了描述,是 mozRTCPeerConnection 目前不支持对正在进行的会话进行重新协商。一旦会话建立,其参数就会固定。实际上,这意味着您无法例如在该会话的后期启动仅音频呼叫然后向同一对等连接添加视频。我们还有另一个类似的限制,即我们目前不支持单个对等连接上的一个以上的音频和视频流(请参阅 Bug 784517Bug 907339)。

目前的解决方案

我们将尽快解决这些限制,但我们的代码更改需要几个月的时间才能通过 Firefox 发布流程发布。在此之前,我想提供一些解决方法,以便您可以继续使用 Firefox 创建很棒的东西。

静音音频和视频流

媒体重新协商有两个主要用例:在会话过程中静音和取消静音媒体;以及在会话过程中添加/删除视频。对于静音和取消静音,技巧在于明智地使用 MediaStreamTrack 对象上的“enabled”属性:当您要静音时,只需将轨道上的 enabled 设置为“false”。

var pc = new mozRTCPeerConnection;

navigator.mozGetUserMedia({video: true},
  function (mediaStream) {

    // Create a new self-view video element
    var video = document.createElement("video");
    video.setAttribute("width", 640);
    video.setAttribute("height", 480);
    video.setAttribute("style", "transform: scaleX(-1)");
    video.src = window.URL.createObjectURL(mediaStream);
    document.body.appendChild(video);
    video.play();

    // Add a button to hold/unhold video stream
    var button = document.createElement("button");
    button.appendChild(document.createTextNode("Toggle Hold"));
    button.onclick = function(){
      mediaStream.getVideoTracks()[0].enabled =
         !(mediaStream.getVideoTracks()[0].enabled);
    }
    document.body.appendChild(document.createElement("br"));
    document.body.appendChild(button);

    // Add the mediaStream to the peer connection
    pc.addStream(mediaStream);

    // At this point, you're ready to start the call with
    // pc.setRemoteDescription() or pc.createOffer()
  },
  function (err) { alert(err); }
);

请注意,将 MediaStreamTrack 的“enabled”属性设置为“false”不会停止媒体流,但它会更改正在编码为黑色正方形(对于视频)和静音(对于音频)的媒体,这两者都压缩得非常好。根据您的应用程序,使用浏览器到浏览器信令(例如,WebSockets 或数据通道)让另一个浏览器知道它应该隐藏或显示视频窗口(当相应的视频被静音时)也可能是有意义的。

呼叫过程中添加视频

对于呼叫过程中添加视频,最用户友好的解决方法是销毁仅音频的对等连接,并创建一个新的对等连接,同时包含音频和视频。当您执行此操作时,它会提示用户使用摄像头和麦克风;但是,由于 Firefox 在单个对话框中执行此操作,因此用户体验通常非常好。添加视频后,您可以通过反向执行此技巧(从而释放摄像头)将其删除,或者您可以简单地执行上面我描述的“静音视频”技巧(这将使摄像头继续工作 - 这可能会让一些用户感到不适)。

发送多个音频或视频流

要发送多个音频或视频流,您可以在浏览器之间使用多个同时对等连接:每个您希望发送的音频/视频对一个。您还可以使用此技术作为添加和删除会话中视频的替代方法:设置初始仅音频呼叫;如果用户稍后决定添加视频,您可以创建一个新的对等连接并协商单独的仅视频连接。

使用第一种方法添加视频的一个细微缺点是,它在您添加视频时会重新启动音频连接,这可能会导致音频流出现一些明显的故障。但是,一旦我们实现了音频和视频同步,确保音频和视频轨道在同一个 MediaStream 中将确保它们保持同步。对于多个 MediaStream 或多个对等连接,这种同步并不保证。

临时解决方法和实现目标

我们认识到这些解决方法并不理想,我们正在尽快努力实现规范兼容性。在此期间,我们希望这些信息能帮助您构建当今的应用程序。好消息是,即使在我们解决了上面描述的限制之后,这些技术也应该继续有效,因此您可以根据需要迁移到最终解决方案。

最后,我建议任何对重新协商和/或多媒体流感兴趣的人关注我上面提到的错误。一旦我们实现了这些功能,它们应该在 Firefox 的发布版本中出现大约 18 周内。在那之后,您需要切换到“标准”方法来确保最佳的音频和视频质量。

感谢您的耐心等待。出去创造伟大的事物吧!

关于 Adam Roach

Adam Roach 与 Mozilla 的 WebRTC 实现团队合作,将实时技术引入 Firefox 和 FirefoxOS 共享的核心库。自 1997 年以来,他一直在通过协议标准化、架构、设计和实施来构建基于 IP 的实时通信世界。

更多 Adam Roach 的文章…

关于 Robert Nyman [荣誉编辑]

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

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


9 条评论

  1. Kyle Simpson

    DataChannels 有任何更新吗?具体来说

    1. 跨浏览器互操作性?
    2. 不需要“伪造”的音频流?
    3. 可靠的 DataChannels?

    2013年9月30日 05:23

  2. Randell Jesup

    1. 跨浏览器互操作性:Chrome 已提交其代码,并且正在解决与旧版 Mozilla 协作时的一些错误;我目前的看法是 Chrome 31 和 Firefox Nightly 将能够互操作。我相信 Chrome 31 发布后将与所有当前版本的 Firefox 兼容。

    2. Firefox 一段时间以来不需要“伪造”的音频流了。Firefox 24 不需要它。

    3. Firefox 一直完全支持可靠的 DataChannels(并且是默认设置);当前和旧版 Chrome 版本中不兼容标准的 DataChannel 实现仅不可靠。

    2013年9月30日 08:10

  3. piranna

    Firefox 是否支持来自 Web Workers、Shared Workers 和 Service Workers 内部 的 PeerConnection 对象?

    https://bugzilla.mozilla.org/show_bug.cgi?id=922363

    2013年9月30日 15:15

    1. Robert Nyman [编辑]

      这取决于 W3C 将如何规定。WebRTC 周围有很多需要考虑的事情,随着事情的进展,我们正在仔细评估所有这些事情。

      2013年10月2日 10:11

    2. Randell Jesup

      请参阅错误 922363(由您提交);它已被讨论过,但需要工作组达成一致才能值得考虑。这是一项大量的工作(既要制定规范,又要实施)。

      2013年10月2日 10:31

  4. Fabian Gort

    感谢各位提供的更新。ICE 候选者互操作性怎么样?Mozilla 会将 SDP 中的 ICE 候选者移动到“onicecandidate”事件中吗?

    我们现在是否应该只从 FF SDP 中解析第一个相关的 ICE 候选者以与 Chrome 建立连接?

    2013年10月1日 07:00

    1. Adam Roach

      ICE 候选者在浏览器之间互操作,无需任何特殊技巧,这从我们几个月前的第一次互操作时刻开始就一直如此。也就是说,我们确实在 Chrome 和 Firefox 之间存在一些您可能注意到的行为差异。

      在 Firefox 27 之前,Firefox 不会生成涓滴式 ICE 候选者,尽管它很乐意接受并正确处理 Chrome 生成的候选者。它通过确保在允许处理初始 CreateOffer 或 SetRemoteDescription 操作之前完全收集其所有网络信息来做到这一点。

      从 Firefox 27 开始,我们也将*生成*涓滴式 ICE 候选者,但仅当我们在初始 SDP 处理后发现有关新候选者的信息(例如,来自 TURN 或 STUN 服务器)时。Firefox 尽快开始收集其候选者,并在其初始 SDP 中包含它已知的所有候选者。这意味着在正常网络条件下,完全可以预期我们在 JavaScript 应用程序启动呼叫时可能已收集到*所有*候选者。发生这种情况时,所有候选者都存在于初始提议(或应答)中,并且不会发生涓滴。

      相比之下,Chrome 的初始提议或应答 - 至少在其当前实现中 - 永远不会包含任何 ICE 候选者。所有地址信息,包括本地接口,都将使用 onicecandidate 涓滴到应用程序。这与 Firefox 所做的没有更正确或更不正确;它只是不同。Chrome 也非常乐意在初始提议(或应答)中获取所有 ICE 候选者:它不需要它们被涓滴进来。因此,它对 Firefox 生成的 SDP 非常满意,即使它已经包含了我们所有的候选者。

      无论哪种情况,只要您的 JavaScript 应用程序将整个初始提议或应答发送到另一个浏览器,并确保随后发送任何涓滴式 ICE 候选者 - 如果有的话 - 一切都应该可以正常工作。您永远不需要解析、合成、剥离、复制或修改 ICE 候选者以使 Firefox 与 Chrome 互操作。

      最后一条警告:Firefox 的 WebRTC 实现的早期版本根本没有调用 onicecandidate,即使使用指示收集已完成的“null”候选者也是如此。虽然这在浏览器方面运行良好,但有时会使依赖于查看此回调的脚本感到困惑。此行为已在 Firefox 23 中修复。如果您有特殊代码来解决此问题,则现在可以安全地将其删除。(Nightly 27 中存在一个导致此问题再次出现的回归 - Bug 921656 - 但它应该很快就会得到修复)。

      如果您在阅读了以上关于此工作原理的解释后仍然认为需要解决 Chrome 互操作性的方法,请告诉我们有关您看到的意外行为的更多详细信息。据我所知,您不需要执行任何特殊操作。

      2013年10月2日 09:30

  5. Fabian Gort

    Adam,非常感谢您的解释。我不知道 SDP 中的 ICE 候选者只是被简单地添加了。很高兴知道它这么简单。

    我看到它也起作用了。也就是说,使用 FF 稳定版 24/Nightly 27 与 Chrome Canary 31。使用 FF 与稳定的 Chrome 29,我确实收到了 onaddstream 事件,但流并没有变得可见。

    对我来说,现在在 FF 和 Canary 之间获得了视频就足够了,但如果您想看看我的意思,这里有一个示例
    { “iceServers”: [{ “url”: “stun:stun.l.google.com:19302” }] }

    2013年10月2日 13:14

  6. Fabian Gort

    抱歉,这是链接
    http://peersquared.info/gvc/test-cam.html

    2013年10月2日 13:19

本文的评论已关闭。