如何使用提议/答案交换来自两个对等连接的流

Posted

技术标签:

【中文标题】如何使用提议/答案交换来自两个对等连接的流【英文标题】:How to exchange streams from two peerconnections with offer/answer 【发布时间】:2015-06-13 05:32:58 【问题描述】:

我正在尝试设置两个对等连接交换视频的视频聊天。这发生在创建数据通道之后。所以这是事件的过程:

    offerer 创建数据通道,offerer 创建并提供,answerer 创建答案。到目前为止,一切都很好。我们有一个数据通道。 offerer 通过 getUserMedia 获取视频流并将其添加到对等连接,然后 offereronnegotiation 事件触发, offerer 创建一个新的 offer,而 answerer 则回复一个答案。还是一切都好。 要约正在流式传输。 answerer 通过 getUserMedia 获取视频流并将其添加到对等连接,offerer 创建新的 offer,而 answerer回答。还可以。 应答器也在直播。

但是,如果我切换第 2 步和第 3 步(因此 answerer 首先开始流式传输),那么事情就会开始出错。只有在第 1、3 和 2 步都发生后,双方才能开始流式传输。

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

当我让回答者在有 onnegotiationneeded 事件时创建新报价时,行为有所不同但仍然不稳定。

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

代码如下:

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);
    ;
;

【问题讨论】:

【参考方案1】:

我认为问题出在第 3 步,当回答者添加视频时,您需要提供者发起。在真正的远程通话中,提供者怎么会知道这样做?

据我了解,当答复者需要重新谈判时,角色实际上会颠倒过来,因为出于重新谈判的目的:重新谈判者充当提议者,而非重新谈判者充当提议者回答者。

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

    createOffer(), 然后setLocalDescription(description) 然后发送pc.localDescription到对方

不管哪边。

我不是 SDP 的权威,所以我不确定这是不是正确的方法,但 the examples in the spec 至少向我建议上述步骤是正确的,并且我以这种方式工作.

我已经在this Firefox jsfiddle 中对此进行了测试,它似乎有效。小提琴使用说明:

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

这会产生眩光吗?我敢肯定,并且可能有更好的方法来处理这个问题,但这似乎对我有用。

【讨论】:

您好 Jib,感谢您的解释!我也让它像那样工作,并更新了我自己的示例以使其在开发人员版本中工作。我一定以某种方式混淆了奉献和回答。尽管如此,Chrome 还是无法正常工作,所以我可能还是会在某处做错事。 注意:我在 code.google 上询问过,他们确认它目前并没有像那样工作。 @Fab:Chrome 肯定支持重新协商,所以不清楚你所说的“还没有真正开始工作”。您是否在他们的跟踪器中打开了一个错误,或者找到了一个?有什么问题? 嗨,Jesup,我做到了。有一些关于颠倒 SSL 角色的事情。见这里:code.google.com/p/webrtc/issues/…

以上是关于如何使用提议/答案交换来自两个对等连接的流的主要内容,如果未能解决你的问题,请参考以下文章

如何使用多对等连接框架在两部 iPhone 之间流式传输音频文件?

如何修改正在进行的连接上的流以暂停/恢复流传输

如何与 Nest 门铃建立双向音频通信?

如何使用 socket.io-p2p 在房间内建立对等连接?

连接 两个机房 局域网

BGP 是啥技术?