这是过时的代码。它包含 6 个跟踪 WebRTC API 演变的问题。
TL;DR:它不起作用,因为您没有检查错误并且只测试了一种浏览器。
1) 旧的供应商前缀(删除它们):
yourConnection = new RTCPeerConnection(configuration);
theirConnection = new webkitRTCPeerConnection(configuration); // <-- wrong
webkit
-names 在 Firefox 或 Edge 中不起作用。这些年来都不需要了。假设你切换到navigator.mediaDevices.getUserMedia
,您可以完全跳过 10 行前缀修饰前导码。
2)使用旧的url
(use urls
)
这在技术上是错误的,尽管我怀疑大多数浏览器都允许这样做:
iceServers: [{url: "stun:stun.1.google.com:19302"}] // <-- wrong
而是使用:
iceServers: [{urls: "stun:stun.1.google.com:19302"}]
...因为 ICE 服务器在技术上可以通过多个 URL 访问。
3) 使用旧的回调 API 而不进行错误检查(使用 Promise 代替):
这是错误的:
navigator.getUserMedia({video: true, audio: true}, function(stream) { /* ... */ });
...因为一个需要第三个失败回调参数 https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-navigator-partial-2。边缘说TypeError: Argument not optional
.
Chrome 和 Safari 中的遗留错误允许这样做,但它在 Firefox 或 Edge 中不起作用。忽略错误会让你无法了解为什么事情不起作用。如果用户拒绝摄像头访问,您想知道。
所有现代浏览器都支持promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises API 版本 https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-mediadevices-partial-1 on mediaDevices
。使用它来代替:
navigator.mediaDevices.getUserMedia({video: true, audio: true})
.then(stream => { /* use stream here */ })
.catch(error => console.log(error));
4) 你陷入了 RTCPeerConnection 的“promise/callback mix-up trap”:
I've 之前回答过这个 https://stackoverflow.com/a/36406985/918910,但简而言之,这与上面的#2 类似,但有所不同。这是错误的:
yourConnection.createOffer(function(offer) { /* ... */ });
你认为你正在打电话旧的回调 API https://w3c.github.io/webrtc-pc/#legacy-interface-extensions,但你不是。那些需要的two论点:
yourConnection.createOffer(successCallback, failureCallback /*, optionsObject */);
相反,您实际上是在调用同名的现代承诺API https://w3c.github.io/webrtc-pc/#idl-def-rtcpeerconnection,因为函数在JS中是一个对象:
const promise = yourConnection.createOffer(optionsObject);
这是您的代码停止工作的地方。您的回调函数永远不会被调用,而是被解释为空选项对象。您忽略返回的承诺。请改用 Promise API。
5) createObjectURL(stream) 已弃用,消失了。
它在 Firefox 和 Chrome 71 中被删除(warning https://i.stack.imgur.com/kIupZ.png你收到)。这是错误的:
theirVideo.src = URL.createObjectURL(stream);
而是使用这个:
theirVideo.srcObject = stream;
6)额外加分:整个流API已被弃用(使用轨道)。
addStream()
& onaddstream
不再在the spec https://w3c.github.io/webrtc-pc/#idl-def-rtcpeerconnection-partial-3,并且仅适用于某些浏览器:
yourConnection.addStream(stream);
theirConnection.onaddstream = e => theirVideo.srcObject = e.stream;
相反,对等连接现在完全基于轨道。使用这个代替:
for (const track of stream.getTracks()) {
yourConnection.addTrack(track, stream);
}
theirConnection.ontrack = e => theirVideo.srcObject = e.streams[0];
有关这些差异的更多信息,请参阅my blog https://blog.mozilla.org/webrtc/the-evolution-of-webrtc/.
工作示例
下列应该适用于所有浏览器 https://jsfiddle.net/jib1/rob3zxLa/:
const yourVideo = document.querySelector("#face_cam_vid");
const theirVideo = document.querySelector("#thevid");
(async () => {
if (!("mediaDevices" in navigator) || !("RTCPeerConnection" in window)) {
alert("Sorry, your browser does not support WebRTC.");
return;
}
const stream = await navigator.mediaDevices.getUserMedia({video:true, audio:true});
yourVideo.srcObject = stream;
const configuration = {
iceServers: [{urls: "stun:stun.1.google.com:19302"}]
};
const yours = new RTCPeerConnection(configuration);
const theirs = new RTCPeerConnection(configuration);
for (const track of stream.getTracks()) {
yours.addTrack(track, stream);
}
theirs.ontrack = e => theirVideo.srcObject = e.streams[0];
yours.onicecandidate = e => theirs.addIceCandidate(e.candidate);
theirs.onicecandidate = e => yours.addIceCandidate(e.candidate);
const offer = await yours.createOffer();
await yours.setLocalDescription(offer);
await theirs.setRemoteDescription(offer);
const answer = await theirs.createAnswer();
await theirs.setLocalDescription(answer);
await yours.setRemoteDescription(answer);
})();