Это устаревший код. Он содержит 6 проблем, которые отслеживают эволюцию WebRTC API.
TL; DR: Не работает, потому что вы не проверяете ошибки и тестировали только один браузер.
1) Префиксы старых поставщиков (удалить их):
yourConnection = new RTCPeerConnection(configuration);
theirConnection = new webkitRTCPeerConnection(configuration); // <-- wrong
webkit
-имя не будут работать в Firefox или Edge. Это не было нужно в течение многих лет. Если вы переключитесь на navigator.mediaDevices.getUserMedia
, вы можете полностью пропустить 10 строк преамбулы с префиксами.
2) Использует старый url
(используйте urls
)
Это технически неправильно, хотя я подозреваю, что большинство браузеров допускают это:
iceServers: [{url: "stun:stun.1.google.com:19302"}] // <-- wrong
Вместо этого используйте:
iceServers: [{urls: "stun:stun.1.google.com:19302"}]
... потому что сервер ICE технически может быть доступен по нескольким URL-адресам.
3) Использование старых API обратного вызова без проверки ошибок (вместо этого используйте обещания):
Это неправильно:
navigator.getUserMedia({video: true, audio: true}, function(stream) { /* ... */ });
... потому что 3-й аргумент обратного вызова не требуется . Край говорит TypeError: Argument not optional
.
Устаревшие ошибки в Chrome и Safari позволяют это, но это не будет работать в Firefox или Edge. Игнорирование ошибок лишает вас понимания, почему что-то не работает. Если пользователь отказывает в доступе к камере, вы хотите знать.
Все современные браузеры поддерживают обещание версии API для mediaDevices
. Используйте это вместо:
navigator.mediaDevices.getUserMedia({video: true, audio: true})
.then(stream => { /* use stream here */ })
.catch(error => console.log(error));
4) Вы попали в RTCPeerConnection в «ловушку для обещаний и обратных вызовов»:
Я ответил на это до , но вкратце, это похоже на # 2 выше, но с изюминкой. Это неправильно:
yourConnection.createOffer(function(offer) { /* ... */ });
Вы думаете, что вызываете старый API обратного вызова , но это не так. Требуемые два аргументы:
yourConnection.createOffer(successCallback, failureCallback /*, optionsObject */);
Вместо этого вы фактически вызываете одноименный API современных обещаний , потому что функция - это объект в JS:
const promise = yourConnection.createOffer(optionsObject);
Здесь ваш код перестает работать. Ваша функция обратного вызова никогда не вызывается, а интерпретируется как пустой объект параметров. Вы игнорируете возвращенное обещание. Вместо этого используйте API обещаний.
5) createObjectURL (поток) устарел, пропал.
Он был удален в Firefox и Chrome 71 (предупреждение , которое вы получили). Это неправильно:
theirVideo.src = URL.createObjectURL(stream);
Вместо этого используйте это:
theirVideo.srcObject = stream;
6) Для дополнительных баллов: весь API потока устарел (используйте треки).
addStream()
& onaddstream
больше не входят в спецификации и работают только в некоторых браузерах:
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];
Подробнее об этих различиях см. мой блог .
Рабочий пример
Следующие должны работать во всех браузерах :
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);
})();