我正在尝试在两个对等连接交换视频的地方设置视频聊天.创建数据通道后会发生这种情况.因此,这是事件的过程:
>要约人创建数据渠道,要约人创建并报价,答应人创建答案.到现在为止还挺好.我们有一个数据通道.
>要约人通过getUserMedia获取视频流并将其添加到对等连接中,然后要约人的协商事件将触发,要约人创建新要约,而应答者将回答.仍然一切都很好.要约人正在流式传输.
>应答者通过getUserMedia获取视频流并将其添加到对等连接中,提议者创建一个新的提议,而应答者以一个答案进行响应.还可以应答者也在流式传输.
但是,如果我切换第2步和第3步(因此应答程序首先开始流式传输),那么事情就会开始出错.双方都必须在步骤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.onnegotiationneed的响应始终是:
> createOffer(),
>然后setLocalDescription(description)
>然后将pc.localDescription发送到另一侧
不分面.
我不是SDP的授权机构,因此我不确定这是否是正确的方法,但是the examples in the spec至少向我表明上述步骤是正确的,并且我以这种方式进行了工作.
我已经在this Firefox jsfiddle中对此进行了测试,它似乎可以正常工作.使用小提琴的说明:
>没有服务器(因为它是小提琴),因此请按“报价”按钮并复制报价.
>将报价粘贴到另一标签或另一台机器上相同提琴中的相同位置.
>按ENTER,然后复制您得到的答案并将其粘贴回第一个小提琴中.
>现在,您连接到两个数据通道:一个用于聊天,另一个用于信令.
>现在,在任一端按addTrack,视频应在另一端显示.
>向另一个方向按addTrack,则视频应该双向播放.
这会产生眩光吗?我敢肯定,也许会有更好的方法来解决这个问题,但这似乎对我有用.