WebRTC 远程视频流不工作

2023-12-06

我添加了一个简单的 webRTC 应用程序,它将浏览器窗口连接到自身,从我的相机流式传输视频数据。最终目标是在页面上获取两个视频流,一个直接来自摄像头,另一个来自浏览器本地建立的 WebRTC 连接。

不幸的是,远程视频流没有显示。知道为什么吗?

<video id="yours" autoplay></video>
<video id="theirs" autoplay></video>

这是 JavaScript

function hasUserMedia() {
     navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia ||
        navigator.msGetUserMedia;

     return !!navigator.getUserMedia;
    }

    function hasRTCPeerConnection() {
     window.RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection 
        || window.mozRTCPeerConnection;

     return !!window.RTCPeerConnection;
    }

    var yourVideo = document.querySelector('#yours'),
     theirVideo = document.querySelector('#theirs'),
     yourConnection, theirConnection;


    if (hasUserMedia()) {
        navigator.getUserMedia({ video: true, audio: false }, function(stream) {
         yourVideo.src = window.URL.createObjectURL(stream);
         if (hasRTCPeerConnection()) {
            startPeerConnection(stream);
         } else {
         alert("Sorry, your browser does not support WebRTC.");
         }
         }, function (error) {
         console.log(error);
         });
        }else{
            alert("Sorry, your browser does not support WebRTC.");
        }


    function startPeerConnection(stream){
        var configuration = {
            "iceServers": [{ "url": "stun:stun.1.google.com:19302"
            }]
        };

        yourConnection = new RTCPeerConnection(configuration);
        theirConnection = new RTCPeerConnection(configuration);



         // Setup stream listening
         yourConnection.addStream(stream);

         theirConnection.onaddstream = function (event) {
            theirVideo.src = window.URL.createObjectURL(event.stream);
            console.log('stream added');
         };

         // console.log(yourConnection);
          //console.log(theirConnection);

         // Setup ice handling
         yourConnection.onicecandidate = function (event) {
         if (event.candidate) {
                 theirConnection.addIceCandidate(new RTCIceCandidate(event.
                candidate));
             }
         };
         theirConnection.onicecandidate = function (event) {
             if (event.candidate) {
                 yourConnection.addIceCandidate(new RTCIceCandidate(event.
                candidate));
             }
         };

          // Begin the offer
         yourConnection.createOffer(function (offer) {
            yourConnection.setLocalDescription(offer);
            theirConnection.setRemoteDescription(offer);

            theirConnection.createAnswer(function (offer) {
                theirConnection.setLocalDescription(offer);
                yourConnection.setRemoteDescription(offer);
            });
         });
    };

我正在关注 Dan Ristic 关于 WebRTC 的书,并了解他对编码做了什么。不幸的是,远程视频没有显示。


Add 失败回调使其发挥作用。否则你不仅不会看到错误,而且这样做实际上会让它工作,因为一个非常奇怪的原因:

您是 WebIDL 超载的受害者。 发生的情况是 WebRTC API 有两个版本,而您将它们混合在一起。

有一个现代承诺API, e.g.:

pc.createOffer(options).then(successCallback, failureCallback);

and a 已弃用的回调版本, e.g.:

pc.createOffer(successCallback, failureCallback, options);

换句话说,有两个createOffer采用不同数量参数的函数。

不幸的是,你击中了第一个createOffer因为你只传递一个参数!首先createOffer期望一个options不幸的是,WebIDL 中的对象与函数无法区分。因此,它被视为有效参数(空选项对象)。即使这已经引起了TypeError,它不会导致异常,因为 Promise API 会拒绝返回的 Promise,而不是抛出异常:

pc.createOffer(3).catch(e => console.log("Here: "+ e.name)); // Here: TypeError

您也没有检查返回的承诺,因此错误会丢失。

这是一个工作版本(https 小提琴对于 Chrome):

navigator.getUserMedia = navigator.getUserMedia ||
                         navigator.webkitGetUserMedia ||
                         navigator.mozGetUserMedia;
window.RTCPeerConnection = window.RTCPeerConnection ||
                           window.webkitRTCPeerConnection;

var yourConnection, theirConnection;

navigator.getUserMedia({ video: true, audio: false }, function(stream) {
    yourVideo.src = window.URL.createObjectURL(stream);

    var config = { "iceServers": [{ "urls": "stun:stun.1.google.com:19302"}] };
    yourConnection = new RTCPeerConnection(config);
    theirConnection = new RTCPeerConnection(config);

    yourConnection.addStream(stream);

    theirConnection.onaddstream = function (event) {
        theirVideo.src = window.URL.createObjectURL(event.stream);
    };

    yourConnection.onicecandidate = function (e) {
        if (e.candidate) {
            theirConnection.addIceCandidate(new RTCIceCandidate(e.candidate),
                                            success, failure);
         }
     };
     theirConnection.onicecandidate = function (e) {
         if (e.candidate) {
             yourConnection.addIceCandidate(new RTCIceCandidate(e.candidate),
                                            success, failure);
         }
     };

     yourConnection.createOffer(function (offer) {
         yourConnection.setLocalDescription(offer, success, failure);
         theirConnection.setRemoteDescription(offer, success, failure);
         theirConnection.createAnswer(function (offer) {
             theirConnection.setLocalDescription(offer, success, failure);
             yourConnection.setRemoteDescription(offer, success, failure);
         }, failure);
     }, failure);
}, failure);

function success() {};
function failure(e) { console.log(e); };
<video id="yourVideo" width="160" height="120" autoplay></video>
<video id="theirVideo" width="160" height="120" autoplay></video>

但回调很费力。我强烈推荐新的 Promise API(https对于 Chrome):

var pc1 = new RTCPeerConnection(), pc2 = new RTCPeerConnection();

navigator.mediaDevices.getUserMedia({video: true, audio: true})
  .then(stream => pc1.addStream(video1.srcObject = stream))
  .catch(log);

var add = (pc, can) => pc.addIceCandidate(can).catch(log);
pc1.onicecandidate = e => add(pc2, e.candidate);
pc2.onicecandidate = e => add(pc1, e.candidate);

pc2.ontrack = e => video2.srcObject = e.streams[0];
pc1.oniceconnectionstatechange = e => log(pc1.iceConnectionState);
pc1.onnegotiationneeded = e =>
  pc1.createOffer().then(d => pc1.setLocalDescription(d))
  .then(() => pc2.setRemoteDescription(pc1.localDescription))
  .then(() => pc2.createAnswer()).then(d => pc2.setLocalDescription(d))
  .then(() => pc1.setRemoteDescription(pc2.localDescription))
  .catch(log);

var log = msg => console.log(msg);
<video id="video1" height="120" width="160" autoplay muted></video>
<video id="video2" height="120" width="160" autoplay></video><br>
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WebRTC 远程视频流不工作 的相关文章

随机推荐

  • 显示按日期排序的数据

    public class Person public string Name get set public DateTime Created get set public class MyData public List
  • 在c中读取python的全局变量

    我正在尝试学习如何正确使用 Python C API 我实际上需要做的就是读取一个全局变量 在我的例子中是字典 但我从一个简单的整数变量开始 使用讨论 如何从 C 访问 Python 全局变量 以及答案的来源 http bytes com
  • 如何在所有活动中显示导航抽屉?

    我有一个Navigation Drawer这应该出现在我所有的活动中 我看到了很多与此类似的问题 并找到了一个解决方案 例如 Extending the MainActivity with the Other Activity 所以我将我的
  • 扩展基于 Acumatica 投影的 DAC 查询

    有没有办法扩展 修改投影 DAC 的投影查询 例如 如果我需要向投影添加连接语句 然后将新连接的表用于可用字段 向 PXCacheExtension 添加自定义字段可以按预期工作 但在 PXCacheExtension DAC 顶部指定 P
  • SQL查询查找当月的最后一天?

    SELECT DATEADD s 1 DATEADD mm DATEDIFF m 0 GETDATE 1 0 LastDay CurrentMonth 大家好 我有一个查询来查找当月的最后一天 这肯定运行良好 但我无法理解它 因为我有其他类
  • 为什么原子语句需要锁提示?

    Question 对以下语句应用锁有什么好处 同样 如果我们不包含这些提示 我们会 看到什么问题 即它们是否可以防止竞争条件 提高性能或其他什么 询问它们可能是为了防止出现一些我没有考虑过的问题 而不是我假设的竞争条件 注意 这是此处提出的
  • 如何在设置属性后仅初始化一次 UserControl

    Code public partial class MyControl UserControl int size 8 public int Size get return size set size value Initialize pub
  • jQuery 与 document.querySelectorAll

    我多次听说 jQuery 最强大的资产是它查询和操作 DOM 中元素的方式 您可以使用 CSS 查询来创建复杂的查询 而这在常规 javascript 中很难做到 但是 据我所知 您可以通过以下方式获得相同的结果document query
  • 如何更改onclick视频源?

    HTML div class source Source 1 div
  • 为什么这个 jQuery 不向下滑动/显示隐藏(向上滑动)元素?

    我在 C 中创建 ID 为 foapalrow3 和 foapalrow4 的行 使它们暂时不可见 foapalrow3 new HtmlTableRow foapalrow3 ID foapalrow3 foapalrow3 Visibl
  • 我应该如何单独发送表格?

    我编写了打击代码 当我单击每个表单提交按钮时 我会发送我的表单 我的问题是如何单独发送每个表单并分别指示每个结果 因为当我的代码运行时 所有表单将同时提交 这是我的代码 done click function e var url secon
  • 可以原子地进行提取与运算的最大数据类型?

    我想尝试使用如下方式自动重置 256 位 include
  • 如何在 HDP 3.1 中不使用仓库连接器的情况下从 Spark 将表写入 Hive

    当尝试在 HDP 3 1 上使用 Spark 2 3 写入 Hive 表时 无需使用仓库连接器直接写入 Hive 模式 spark shell driver memory 16g master local 3 conf spark hado
  • Firebase 规则:动态授予特定用户访问权限

    我正在构建一个 Android 应用程序 它需要我为用户存储一些图片 假设我有 2 个用户 A 和 B 他们应该能够读取 写入其特定文件夹 用户 A 可以读取和写入存储桶 images userA 用户 B 可以读取和写入存储桶 image
  • 选择下拉宽度 - Chrome 问题

    我想控制
  • unset 和 = null 之间的区别

    From a 随机 php net 帖子 如果你正在做 whatever null 那么你正在重写变量的 数据 您可能会更快地释放 缩小内存 但它可能会窃取 CPU 更快地从真正需要它们的代码中循环 从而产生 整体执行时间更长 显然这是无可
  • 使用 React Native 和 Tensorflow.js 对实时视频源进行预测

    我已经设置了我的 React Native 应用程序 所有 unimodules 和包的安装和配置都按预期工作 没有依赖性等问题 现在我想实现一个我从谷歌的可教机器上训练的张量流模型 但我无法理解如何将它与相机一起使用 因为我想实时处理帧
  • 如何使用Python解压gz文件

    我需要将从 FTP 站点下载的 gz 文件提取到本地 Windows 文件服务器 我已经为文件的本地路径设置了变量 并且我知道它可以被 GZIP muddle 使用 我怎样才能做到这一点 GZ 文件内的文件是 XML 文件 import g
  • 如何使 jQuery UI 选项卡出现在页面底部

    有没有办法让 jQuery UI 选项卡小部件选项卡出现在页面底部 使用 jQuery 站点中的示例
  • WebRTC 远程视频流不工作

    我添加了一个简单的 webRTC 应用程序 它将浏览器窗口连接到自身 从我的相机流式传输视频数据 最终目标是在页面上获取两个视频流 一个直接来自摄像头 另一个来自浏览器本地建立的 WebRTC 连接 不幸的是 远程视频流没有显示 知道为什么