如何通过提供/应答从两个对等连接交换流

2023-12-02

我正在尝试设置视频聊天,其中两个对等连接交换视频。创建数据通道后会发生这种情况。那么事件的流程是这样的:

  1. offerer创建数据通道,offerer创造并提供,answerer创建一个答案。到目前为止,一切都很好。我们有一个数据通道。
  2. offerer获取视频流获取用户媒体并将其添加到对等连接中,然后谈判的事件offerer fires, offerer创建新报价,同时answerer给出答案。还是一切都好。这offerer正在流式传输。
  3. answerer获取视频流获取用户媒体并将其添加到对等连接中,offerer创建新报价,同时answerer给出答案。还在。这answerer也在流媒体。

但是,如果我交换步骤 2 和 3 (所以answerer首先开始流式传输)然后事情开始出错。只有在步骤 1、3 和 2 全部完成后,双方才可以开始直播。

我很确定这与 SDP 提供和答案的顺序有关。

当我让应答者创建一个新的报价时需要谈判如果行为不同但仍然不稳定。

我现在对如何添加优惠和答案一无所知。

这是代码:

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
PeerConnection = window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.RTCPeerConnection;
IceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate || window.RTCIceCandidate;
SessionDescription =  window.mozRTCSessionDescription || window.webkitRTCSessionDescription || window.RTCSessionDescription;

var videoOfferer = document.getElementById('videoOfferer');
var videoAnswerer = document.getElementById('videoAnswerer');
var buttonOfferer = document.getElementById('buttonOfferer');
var buttonAnswerer = document.getElementById('buttonAnswerer');

var servers = {
    iceServers: [
        {url: "stun:23.21.150.121"},
        {url: "stun:stun.1.google.com:19302"}
    ]
};

var offerer = new PeerConnection(servers), answerer = new PeerConnection(servers);
var channelOfferer = null, channelAnswerer = null;

offerer.onicecandidate = function(e) {
    if(e.candidate == null) return;
    answerer.addIceCandidate(new IceCandidate(e.candidate), function(){}, error);
};

offerer.onaddstream = function(e) {
    videoOfferer.src = URL.createObjectURL(e.stream);
    videoOfferer.play();
};

answerer.onicecandidate = function(e) {
   if(e.candidate == null) return;
    offerer.addIceCandidate(new IceCandidate(e.candidate), function(){}, error);
};

answerer.onaddstream = function(e) {
    videoAnswerer.src = URL.createObjectURL(e.stream);
    videoAnswerer.play();
};

function offerCreated(sdp) {
    console.log('offer');
    offerer.setLocalDescription(new SessionDescription(sdp), function() {
        answerer.setRemoteDescription(new SessionDescription(sdp), function() {
            answerer.createAnswer(answerCreated, error);
        }, error);
    }, error);
}

function answerCreated(sdp) {
    console.log('answer');
    answerer.setLocalDescription(new SessionDescription(sdp), function() {
    }, error);
    offerer.setRemoteDescription(new SessionDescription(sdp), function() {
    }, error);
}

function error() {}

buttonOfferer.addEventListener('click', function() {
    navigator.getUserMedia({audio: true, video: true}, function(stream) {
        offerer.addStream(stream);
    }, function(){});
});

buttonAnswerer.addEventListener('click', function() {
    navigator.getUserMedia({audio: true, video: true}, function(stream) {
        answerer.addStream(stream);
    }, function(){});
});

channelOfferer = offerer.createDataChannel('channel', {reliable: true});

offerer.createOffer(offerCreated, error);

answerer.ondatachannel = function(e) {
    channelOfferer = e.channel;
    channelOfferer.onmessage = function(e) {
        console.log(e.data);
    };
    channelOfferer.onmessage = function(e) {
        console.log(e.data);
    };

      // these are added later
    offerer.onnegotiationneeded = function() {
        offerer.createOffer(offerCreated, error);
    };

    answerer.onnegotiationneeded = function() {
        offerer.createOffer(offerCreated, error);
    };
};

我认为问题出在第 3 步,当应答者添加视频时,要约者启动。在真正的远程调用中,报价者如何知道要这样做?

据我了解,当应答者需要重新协商时,角色实际上就会颠倒过来,因为为了重新谈判的目的:谈判者充当要约者,非谈判者充当应答者。

换句话说:响应pc.onnegotiationneeded总是:

  1. createOffer(),
  2. then setLocalDescription(description)
  3. 然后发送pc.localDescription到另一边

无论一边。

我不是 SDP 的权威,所以我不确定这是正确的方法,但是规范中的示例至少向我表明上述步骤是正确的,并且我是这样工作的。

我已经对此进行了测试这个 Firefox jsfiddle这似乎有效。小提琴使用说明:

  1. 没有服务器(因为它是一个小提琴),所以按Offer按钮并复制报价。
  2. 将报价粘贴到另一个选项卡或另一台计算机上同一小提琴中的同一位置。
  3. 按 ENTER 键,然后复制您得到的答案并将其粘贴回第一个小提琴中。
  4. 您现在已连接到两个数据通道:一个用于聊天,另一个用于发送信号。
  5. 现在按addTrack在任一端,视频应显示在另一端。
  6. Press addTrack在另一个方向,你应该有双向视频。

这样会产生眩光吗?我确信,可能有更好的方法来处理这个问题,但这似乎对我有用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何通过提供/应答从两个对等连接交换流 的相关文章

随机推荐

  • Flask WTForms 在 validate_on_submit() 上总是给出 false

    我使用 wtforms 创建了一个注册表单 我在其中使用 FormField 这样我就不必再次重复表单的某些元素 但每当我单击 提交 按钮时 它总是在 validate on submit 方法调用上给出 false 不明白为什么会发生这种
  • 如何处理与 Google 游戏服务的断开连接?

    我使用 Google 游戏服务作为排行榜 像这样显示它 static public void showLeaderboard String lid if isLogined 1 Log i TAG Showing leaderboard I
  • 使用 awk 或 sed 解析来自 ifconfig 的数据?

    我正在尝试使用 sed 解析 ifconfig 输出中的一些数据 但我无法正确执行此操作 我希望该命令只提取我想要的数字 例如 我有兴趣提取发送的字节 eth1 Link encap Ethernet HWaddr 00 00 00 09
  • CUDA 支持的 Windows 编译器

    我是一个正在尝试入门的 CUDA 程序员新手 我在 5 5 版本中遇到了这里提到的问题 Visual Studio 2010 Express 中 CUDA 5 5 出现 干净 错误 谁能确认这只是 5 5 版本的问题吗 是否有我可以安装的早
  • Firebase 推送通知添加操作按钮

    我正在服务器端发送推送通知 并且我正在使用这个 http 协议 https firebase google com docs cloud messaging http server ref 并且我想添加像这样的操作按钮https githu
  • 函数未定义

    我的 jquery 脚本出现函数未定义错误 我不知道为什么 jQuery 代码 http maps google com maps file api v 2 key ABQIAAAAhTrgZ5jvdqcEQouEpPcZ hS81NmJw
  • 如何通过CSS或javascript给句子赋予句首字母? [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 如何通过CSS或javascript给句子赋予句首字母 我已经尝试过这些 CSS 属性
  • 为 jax rs 客户端设置超时

    我想为 jax rs 客户端设置连接超时 ClientConfig configuration new ClientConfig configuration property ClientProperties CONNECT TIMEOUT
  • 将 GestureOverlayView 添加到我的 SurfaceView 类,如何添加到视图层次结构?

    在后来的回答中我被告知 我必须将我在代码中创建的 GestureOverlayView 添加到我的视图层次结构中 但我并不 100 知道如何做到这一点 以下是为了完整性而提出的原始问题 我希望我的游戏能够识别手势 我有一个很好的 Surfa
  • iOS 中的后台录音

    我广泛搜索了有关如何在后台录制音频的文档 并得出结论 在 plist 文件中指定 音频 可能有效 但是 由于 iOS 4 在内存不足时会终止后台应用程序 因此当我们转换到后台时 我们还必须采取一些措施来减少内存使用量 我们如何减少内存使用
  • 在 pycrypto 中使用 RSA 的致盲因子

    在Python中 我试图对消息进行盲化和取消盲化 当我取消隐藏消息时 我没有收到原始消息 有谁知道我可能做错了什么 以下是我的代码 s Hello loadedPublic get publickey loadedPrivate get p
  • SQLite 和自定义排序依据

    我有一个包含类别的表 ID Category 1 Baking 3 Family 4 Entertaining 5 Children 6 Desserts 现在我想将 select 语句的结果排序为 ID Category 4 Entert
  • 使用c#将一个字节数组插入到另一个字节数组的特定位置

    这可能是一个愚蠢的问题 但尚未找到简单的答案 我正在尝试将一个简单的 C 字节数组插入到另一个字节数组的特定位置 例如 现有字节不应被覆盖 而应向后移动 真的就像您在现有文本块中复制页面某些文本块一样 到目前为止 我将创建一个具有两个现有数
  • jQuery SlideToggle 一次一个 div 而不是全部独立

    我使用下面的函数来切换 div 通过它 任何一个条目内容 div 都可以独立打开或关闭 如果任何时候只打开一个条目内容 div 那就太好了 单击关闭的条目标题 div 将关闭任何其他条目内容 div 然后打开单击的条目 我需要保留 html
  • 如何通过 javax.xml.ws.Service 进行调用

    在 Eclipse 中创建了一个新的标准 java 7 项目 并成功获得了一个实例javax xml ws Service像这样 String wsdlURL http example com 3000 v1 0 foo bar SomeS
  • hiveconf 变量可以从文件加载吗? (与 HiveQL 文件分开)

    我经常有一大块 HiveQL 我想使用某些变量的不同设置来运行多次 一个简单的例子是 set mindate 2015 01 01 00 00 00 set maxdate 2015 04 01 00 00 00 select from m
  • 二维数组java中的最小值和最大值

    我想输出二维数组的最大值和最小值 Max 效果很好 但即使数组中没有零 min 也始终输出零 我设置Math random 到 99 以防止在此示例中数组中出现零的可能性较小 完整代码如下 public class e public sta
  • 从终端创建项目时 Gitlab 默认项目可见性

    每当我开始一个新项目时 我都会将其添加到我的 Gitlab VCS 本地 中 git init git add git commit m Commit message git remote add origin gi email prote
  • Ghostscript - PS 到 PDF - 反转图像问题

    我正在尝试使用 Ghostscript 将 postscript 转换为 PDF 一切都可以正常转换 除了在某些情况下图像由于某种原因被反转 报告的错误信息 http bugs ghostscript com show bug cgi id
  • 如何通过提供/应答从两个对等连接交换流

    我正在尝试设置视频聊天 其中两个对等连接交换视频 创建数据通道后会发生这种情况 那么事件的流程是这样的 offerer创建数据通道 offerer创造并提供 answerer创建一个答案 到目前为止 一切都很好 我们有一个数据通道 offe