我正在尝试启动从本机客户端到 Web 浏览器的桌面屏幕流式传输。当我开始连接时,sdp 交换正常并且媒体流按它应该开始。但是数据通道会立即触发“关闭”事件。据我了解,数据通道应该在 sdp 交换之前创建,并且我将协商设置为 false。所以它应该自动通知其他对等方这个通道并启动数据通道。但这不是我的情况。
我尝试了许多不同的方法,例如使用选项设置数据通道或使用或不使用选项的对等连接。
我错过了什么吗?
以下是来自 Web 浏览器的启动器代码。
var pcConstraints = {};
var servers = {
//iceTransportPolicy: 'relay', // force turn
iceServers:
[
{ url: 'stun:stun.l.google.com:19302' },
{ url: 'stun:stun.stunprotocol.org:3478' },
{ url: 'stun:stun.anyfirewall.com:3478' }
]
};
var offerOptions = {
offerToReceiveAudio: 0,
offerToReceiveVideo: 1,
trickle: false
};
function startStream() {
console.log("startStream...");
remotestream = new RTCPeerConnection(servers, pcConstraints);
if (localstream) {
remotestream.addStream(localstream);
}
// optional data channel
dataChannel = remotestream.createDataChannel('testchannel', {});
setDataChannel(dataChannel);
remotestream.onaddstream = function (e) {
try {
console.log("remote media connection success!");
var vid2 = document.getElementById('vid2');
vid2.srcObject = e.stream;
vid2.onloadedmetadata = function (e) {
vid2.play();
};
var t = setInterval(function () {
if (!remotestream) {
clearInterval(t);
}
else {
Promise.all([
remotestream.getStats(null).then(function (o) {
var rcv = null;
var snd = null;
o.forEach(function (s) {
if ((s.type == "inbound-rtp" && s.mediaType == "video" && !s.isRemote) ||
(s.type == "ssrc" && s.mediaType == "video" && s.id.indexOf("recv") >= 0))
{
rcv = s;
}
else if((s.type == "outbound-rtp" && s.mediaType == "video" && !s.isRemote) ||
(s.type == "ssrc" && s.mediaType == "video" && s.id.indexOf("send") >= 0))
{
snd = s;
}
});
return dumpStat(rcv, snd);
})
]).then(function (s) {
statsdiv.innerHTML = "<small>" + s + "</small>";
});
}
}, 100);
} catch (ex) {
console.log("Failed to connect to remote media!", ex);
socket.close();
}
};
remotestream.onicecandidate = function (event) {
if (event.candidate) {
var ice = parseIce(event.candidate.candidate);
if (ice && ice.component_id == 1 // skip RTCP
//&& ice.type == 'relay' // force turn
&& ice.localIP.indexOf(":") < 0) { // skip IP6
console.log('onicecandidate[local]: ' + event.candidate.candidate);
var obj = JSON.stringify({
"command": "onicecandidate",
"candidate": event.candidate
});
send(obj);
localIce.push(ice);
}
else {
console.log('onicecandidate[local skip]: ' + event.candidate.candidate);
}
}
else {
console.log('onicecandidate: complete.')
if (remoteAnswer) {
// fill empty pairs using last remote ice
//for (var i = 0, lenl = localIce.length; i < lenl; i++) {
// if (i >= remoteIce.length) {
// var c = remoteIce[remoteIce.length - 1];
// var ice = parseIce(c.candidate);
// ice.foundation += i;
// c.candidate = stringifyIce(ice);
// remotestream.addIceCandidate(c);
// }
//}
}
}
};
remotestream.createOffer(function (desc) {
console.log('createOffer: ' + desc.sdp);
remotestream.setLocalDescription(desc, function () {
var obj = JSON.stringify({
"command": "offer",
"desc": desc
});
send(obj);
},
function (errorInformation) {
console.log('setLocalDescription error: ' + errorInformation);
});
},
function (error) {
alert(error);
},
offerOptions);
}
function setDataChannel(dc) {
dc.onerror = function (error) {
alert("DataChannel Error:", error);
};
dc.onmessage = function (event) {
alert("DataChannel Message:", event.data);
};
dc.onopen = function () {
dataChannel.send("Hello World!");
};
dc.onclose = function (error) {
alert("DataChannel is Closed");
alert(error.data)
};
}