我添加了一个简单的 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(使用前将#替换为@)