RTCPeerConnection.onicecandidate不火
RTCPeerConnection.onicecandidate not fire
我正在创建一个应用程序,它将使用 WebRTC 将摄像头视频共享到多个对等连接。服务器简单地为用户提供一个房间,房间内的所有用户都会看到摄像头视频。唯一不起作用的是 onicecandidate 没有触发,因此无法建立对等连接。
我为每个新用户创建新的对等连接。一切似乎都很好(广播员和观众可以交换消息:
1) 当观众加入房间时,广播者创建新的对等连接,创建报价,设置本地描述,并将其发送给新观众。
2) 新观众将设置远程描述,创建答案,设置本地描述并将答案返回给广播者。
3)主播可以接收应答,设置远程描述,但是我无法创建ice candidate
知道为什么 RTCPeerConnection.onicecandidate 不开火吗??
"use strict";
// config
//Acess camera from the http://localhost:2013 is allowed because it is considered a safe environment
//Acess camera from the http://192.168.10.7:2013 is considered a non secure environment (therefore require https)
//var serverIP = "http://192.168.10.7:2013";
//var serverIP = "https://172.21.2.197:2013";
//var serverIP = "https://172.20.10.12:2013";
var serverIP = "https://localhost:2013";
// RTCPeerConnection Options
var server = {
// Uses Google's STUN server
iceServers: [{
"url": "stun:stun.xten.com"
},
{
// Use my TURN server on DigitalOcean
'url': 'turn:numb.viagenie.ca',
'credential': 'sunghiep',
'username': 'nghiepnds@yahoo.com'
}]
};
//DOM Objects
var btnSend = document.getElementById('btn-send');
var btnVideoStop = document.getElementById('btn-video-stop');
var btnVideoStart = document.getElementById('btn-video-start');
var btnVideoJoin = document.getElementById('btn-video-join');
var localVideo = document.getElementById('local-video');
var remoteVideo = document.getElementById('remote-video');
var inputRoomName = document.getElementById('room-name');
//WebRTC Objects
var signallingServer;
var localStream;
var viewPeerConnection;
var sdpConstraints = {
optional: [],
mandatory: {
OfferToReceiveVideo: true
}
};
// declare RTCPeerConnection
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection ||
window.webkitRTCPeerConnection || window.msRTCPeerConnection;
// declare RTCSessionDescription (SDP)
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription ||
window.webkitRTCSessionDescription || window.msRTCSessionDescription;
// declare the getUserMedia
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia ||
navigator.webkitGetUserMedia || navigator.msGetUserMedia;
//in other example I use: navigator.mediaDevices.getUserMedia. WHY is different here???? It is because I use adapter.js
window.SignallingServer = window.SignallingServer;
var peers = [];
// start the video a Room
btnVideoStart.onclick = function(e) {
e.preventDefault();
//Create room
createRoom()
};
btnVideoJoin.onclick = function(e) {
e.preventDefault();
// View video
trace("Click on Join");
joinRoom()
};
btnVideoStop.onclick = function(e) {
e.preventDefault();
// stop video stream
if (localStream != null) {
localStream.getVideoTracks().forEach(function (track) {
track.stop();
});
}
// kill all connections
if (localPeerConnection != null) {
localPeerConnection.removeStream(localStream);
localPeerConnection.close();
signallingServer.close();
localVideo.src = "";
remoteVideo.src = "";
}
btnVideoStart.disabled = false;
btnVideoJoin.disabled = false;
btnVideoStop.disabled = true;
};
function createRoom(){
//get room's name
var room = inputRoomName.value;
if (room == undefined || room.length <= 0) {
alert('Please enter room name');
return;
}
// create local data channel, send it to remote
navigator.getUserMedia({
video: true,
audio: true
}, function(stream) {
// get and save local stream
trace('Got stream, saving it now and starting RTC conn');
//show video on video object
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}, errorHandler);
btnVideoStart.disabled = true;
btnVideoJoin.disabled = true;
btnVideoStop.disabled = false;
// create signalling server
signallingServer = new SignallingServer(room, serverIP);
//create room
signallingServer.create();
// a remote peer has joined room, initiate sdp exchange
signallingServer.onGuestJoined = function(room, socketId) {
trace('Guest(' + socketId +') joined room ['+ room +']! ');
var guestId = socketId;
var roomName = room;
// Create new peer connection for new joiner
//trace("create new RTCPeerConnection");
//var pc = new RTCPeerConnection(server);
//peers.set(guestId, pc);
peers[socketId] = new RTCPeerConnection(server);
trace(peers);
// send ice to the new joiner
trace('Collecting ices ...');
peers[socketId].onicecandidate = function(evt) {
trace('ice ready ...');
if (evt.candidate){
signallingServer.sendICECandidate(room, socketId, evt.candidate);
}
};
//create local data channel, share remote
navigator.getUserMedia({
video: true,
audio: true
}, function(stream) {
// get and save local stream
trace('Got stream, saving it now and starting RTC conn');
// Add stream to peer connection
localStream = stream;
peers[socketId].addStream(localStream);
}, errorHandler);
// Create offer,
peers[socketId].createOffer(function(sessionDescription) {
trace('Created offer');
// Set local description
peers[socketId].setLocalDescription(sessionDescription, function(){
// Send local sdp to remote
trace('Set local sdp success');
signallingServer.sendOffer(guestId, roomName, sessionDescription);
trace('Sending sdp offer');
trace(peers);
}, function(){
trace('Set local sdp failed');
});
}, function(){
trace('Create offer failed');
});
};
//Receive the answer
signallingServer.onReceiveAnswer = function(sender, sdp) {
trace('Receive remote sdp with answer');
// Step 7 - Set the remote SDP
peers[sender].setRemoteDescription(new RTCSessionDescription(sdp), function () {
trace('Set Remote Description success');
}, function () {
trace('Set Remote Description fail');
});
trace(peers);
};
// when room is full, alert user
signallingServer.onRoomFull = function(room) {
window.alert('Room "' + room +
'"" is full! Please join or create another room');
};
}
function joinRoom(){
//get room's name
var room = inputRoomName.value;
if (room == undefined || room.length <= 0) {
alert('Please enter room name');
return;
}
btnVideoStart.disabled = true;
btnVideoJoin.disabled = true;
btnVideoStop.disabled = false;
// Step 1 - Create peer connection
viewPeerConnection = new RTCPeerConnection(server);
// create signalling server
signallingServer = new SignallingServer(room, serverIP);
//join room
signallingServer.join();
// got sdp offer
signallingServer.onReceiveOffer = function(offerCreatorId, roomName, sdp) {
// Step 7 - Set remote SDP
viewPeerConnection.setRemoteDescription(new RTCSessionDescription(sdp), function() {
trace('Set Remote Description');
trace(sdp);
// Step 8 - Create an answer
var answerPromise = viewPeerConnection.createAnswer();
answerPromise.then(function(answer){
// Step 9 - Set local description from the incoming SDP
trace('Set Local Description');
trace(answer);
viewPeerConnection.setLocalDescription(answer)});
answerPromise.then(function(answer){
trace('Send Answer Description');
trace(answer);
// Step 10 - Send local sdp(answer) to remote
signallingServer.sendAnswer(offerCreatorId, roomName, answer);
}).catch(handleGetUserMediaError);
});
};
// ICE Candidate is created when cannot establish the peer connection due to NAT/FIREWALL
// when received ICE candidate info
signallingServer.onReceiveICECandidate = function(candidate) {
trace('Add ice candidate');
viewPeerConnection.addIceCandidate(new RTCIceCandidate(candidate));
};
viewPeerConnection.onaddstream = function(data) {
trace("stream ready");
remoteVideo.src = window.URL.createObjectURL(data.stream);
};
}
function errorHandler(error) {
console.error('Something went wrong!');
console.error(error);
}
function trace(text) {
console.info(text);
}
function handleGetUserMediaError(){
trace("getUserMedia Error")
}
<!DOCTYPE html>
<html lang="en">
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="">
<![endif]-->
<!--[if IE 7]>
<html class="no-js lt-ie9 lt-ie8" lang="">
<![endif]-->
<!--[if IE 8]>
<html class="no-js lt-ie9" lang="">
<![endif]-->
<!--[if gt IE 8]>
<!-->
<html class="no-js" lang="">
<!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.min.css">
<style>
body {
padding-top: 50px;
padding-bottom: 20px;
}
</style>
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.8.3-respond-1.4.2.min.js"></script>
</head>
<body>
<!--[if lt IE 8]>
<p class="browserupgrade">
You are using an <strong>outdated</strong>
browser. Please
<a href="http://browsehappy.com/">upgrade your browser</a>
to improve your experience.
</p>
<![endif]-->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">WebRTC Video Chat</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<!-- chatroom name form -->
<form class="navbar-form navbar-right form-inline">
<div class="form-group">
<input class="form-control" type="text" id="room-name" placeholder="Room name"/>
</div>
<button class="btn btn-primary" id="btn-video-start">Create Live Broadcast</button>
<button class="btn btn-default" id="btn-video-join">Join</button>
<button class="btn btn-default" disabled id="btn-video-stop">Stop</button>
</form>
</div>
<!--/.navbar-collapse --> </div>
</nav>
<div class="container main">
<div class="row videos">
<div class="remote-video">
<video width="280" height="250" autoplay="true" id="remote-video"></video>
</div>
<div class="local-video">
<video width="560" height="500" autoplay="true" id="local-video" muted></video>
</div>
</div>
</div>
</div>
<!-- /container -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.2.min.js"><\/script>')</script>
<script src="js/vendor/bootstrap.min.js"></script>
<script src="js/vendor/socket.io.js"></script>
<script src="js/main.js"></script>
<!--<script src="js/adapter.js"></script>-->
<script src="js/signalling.js"></script>
<!--<script src="//localhost:9010/livereload.js"></script>-->
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
<script>
(function (b, o, i, l, e, r) {
b.GoogleAnalyticsObject = l;
b[l] || (b[l] =
function () {
(b[l].q = b[l].q || []).push(arguments)
});
b[l].l = +new Date;
e = o.createElement(i);
r = o.getElementsByTagName(i)[0];
e.src = '//www.google-analytics.com/analytics.js';
r.parentNode.insertBefore(e, r)
}(window, document, 'script', 'ga'));
ga('create', 'UA-XXXXX-X', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>
在 onGuestJoined
中,您在 addStream
之前调用 createOffer
。这将创建一个没有任何媒体住宿的报价,或者失败:
在 Firefox 中,它会失败:
InternalError: Cannot create an offer with no local tracks, no
offerToReceiveAudio/Video, and no DataChannel.
在 Chrome 中,它似乎创建了一个无法使用的报价。
在这两种情况下,事情都不会继续,这就是 ICE 候选人没有开火的原因。
解决方案:
确保从 getUserMedia
成功回调中调用 createOffer
,或者更好,因为您似乎在此代码中混合了回调和承诺 API,请在整个过程中使用承诺以更加清晰:
navigator.mediaDevices.getUserMedia({video: true, audio: true})
.then(stream => {
localStream = stream;
peers[socketId].addStream(localStream);
return peers[socketId].createOffer();
})
.then(desc => peers[socketId].setLocalDescription(desc))
.then(() => signallingServer.sendOffer(guestId, roomName,
peers[socketId].localDescription))
.catch(errorHandler);
我正在创建一个应用程序,它将使用 WebRTC 将摄像头视频共享到多个对等连接。服务器简单地为用户提供一个房间,房间内的所有用户都会看到摄像头视频。唯一不起作用的是 onicecandidate 没有触发,因此无法建立对等连接。
我为每个新用户创建新的对等连接。一切似乎都很好(广播员和观众可以交换消息: 1) 当观众加入房间时,广播者创建新的对等连接,创建报价,设置本地描述,并将其发送给新观众。 2) 新观众将设置远程描述,创建答案,设置本地描述并将答案返回给广播者。 3)主播可以接收应答,设置远程描述,但是我无法创建ice candidate
知道为什么 RTCPeerConnection.onicecandidate 不开火吗??
"use strict";
// config
//Acess camera from the http://localhost:2013 is allowed because it is considered a safe environment
//Acess camera from the http://192.168.10.7:2013 is considered a non secure environment (therefore require https)
//var serverIP = "http://192.168.10.7:2013";
//var serverIP = "https://172.21.2.197:2013";
//var serverIP = "https://172.20.10.12:2013";
var serverIP = "https://localhost:2013";
// RTCPeerConnection Options
var server = {
// Uses Google's STUN server
iceServers: [{
"url": "stun:stun.xten.com"
},
{
// Use my TURN server on DigitalOcean
'url': 'turn:numb.viagenie.ca',
'credential': 'sunghiep',
'username': 'nghiepnds@yahoo.com'
}]
};
//DOM Objects
var btnSend = document.getElementById('btn-send');
var btnVideoStop = document.getElementById('btn-video-stop');
var btnVideoStart = document.getElementById('btn-video-start');
var btnVideoJoin = document.getElementById('btn-video-join');
var localVideo = document.getElementById('local-video');
var remoteVideo = document.getElementById('remote-video');
var inputRoomName = document.getElementById('room-name');
//WebRTC Objects
var signallingServer;
var localStream;
var viewPeerConnection;
var sdpConstraints = {
optional: [],
mandatory: {
OfferToReceiveVideo: true
}
};
// declare RTCPeerConnection
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection ||
window.webkitRTCPeerConnection || window.msRTCPeerConnection;
// declare RTCSessionDescription (SDP)
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription ||
window.webkitRTCSessionDescription || window.msRTCSessionDescription;
// declare the getUserMedia
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia ||
navigator.webkitGetUserMedia || navigator.msGetUserMedia;
//in other example I use: navigator.mediaDevices.getUserMedia. WHY is different here???? It is because I use adapter.js
window.SignallingServer = window.SignallingServer;
var peers = [];
// start the video a Room
btnVideoStart.onclick = function(e) {
e.preventDefault();
//Create room
createRoom()
};
btnVideoJoin.onclick = function(e) {
e.preventDefault();
// View video
trace("Click on Join");
joinRoom()
};
btnVideoStop.onclick = function(e) {
e.preventDefault();
// stop video stream
if (localStream != null) {
localStream.getVideoTracks().forEach(function (track) {
track.stop();
});
}
// kill all connections
if (localPeerConnection != null) {
localPeerConnection.removeStream(localStream);
localPeerConnection.close();
signallingServer.close();
localVideo.src = "";
remoteVideo.src = "";
}
btnVideoStart.disabled = false;
btnVideoJoin.disabled = false;
btnVideoStop.disabled = true;
};
function createRoom(){
//get room's name
var room = inputRoomName.value;
if (room == undefined || room.length <= 0) {
alert('Please enter room name');
return;
}
// create local data channel, send it to remote
navigator.getUserMedia({
video: true,
audio: true
}, function(stream) {
// get and save local stream
trace('Got stream, saving it now and starting RTC conn');
//show video on video object
localStream = stream;
localVideo.src = window.URL.createObjectURL(stream);
}, errorHandler);
btnVideoStart.disabled = true;
btnVideoJoin.disabled = true;
btnVideoStop.disabled = false;
// create signalling server
signallingServer = new SignallingServer(room, serverIP);
//create room
signallingServer.create();
// a remote peer has joined room, initiate sdp exchange
signallingServer.onGuestJoined = function(room, socketId) {
trace('Guest(' + socketId +') joined room ['+ room +']! ');
var guestId = socketId;
var roomName = room;
// Create new peer connection for new joiner
//trace("create new RTCPeerConnection");
//var pc = new RTCPeerConnection(server);
//peers.set(guestId, pc);
peers[socketId] = new RTCPeerConnection(server);
trace(peers);
// send ice to the new joiner
trace('Collecting ices ...');
peers[socketId].onicecandidate = function(evt) {
trace('ice ready ...');
if (evt.candidate){
signallingServer.sendICECandidate(room, socketId, evt.candidate);
}
};
//create local data channel, share remote
navigator.getUserMedia({
video: true,
audio: true
}, function(stream) {
// get and save local stream
trace('Got stream, saving it now and starting RTC conn');
// Add stream to peer connection
localStream = stream;
peers[socketId].addStream(localStream);
}, errorHandler);
// Create offer,
peers[socketId].createOffer(function(sessionDescription) {
trace('Created offer');
// Set local description
peers[socketId].setLocalDescription(sessionDescription, function(){
// Send local sdp to remote
trace('Set local sdp success');
signallingServer.sendOffer(guestId, roomName, sessionDescription);
trace('Sending sdp offer');
trace(peers);
}, function(){
trace('Set local sdp failed');
});
}, function(){
trace('Create offer failed');
});
};
//Receive the answer
signallingServer.onReceiveAnswer = function(sender, sdp) {
trace('Receive remote sdp with answer');
// Step 7 - Set the remote SDP
peers[sender].setRemoteDescription(new RTCSessionDescription(sdp), function () {
trace('Set Remote Description success');
}, function () {
trace('Set Remote Description fail');
});
trace(peers);
};
// when room is full, alert user
signallingServer.onRoomFull = function(room) {
window.alert('Room "' + room +
'"" is full! Please join or create another room');
};
}
function joinRoom(){
//get room's name
var room = inputRoomName.value;
if (room == undefined || room.length <= 0) {
alert('Please enter room name');
return;
}
btnVideoStart.disabled = true;
btnVideoJoin.disabled = true;
btnVideoStop.disabled = false;
// Step 1 - Create peer connection
viewPeerConnection = new RTCPeerConnection(server);
// create signalling server
signallingServer = new SignallingServer(room, serverIP);
//join room
signallingServer.join();
// got sdp offer
signallingServer.onReceiveOffer = function(offerCreatorId, roomName, sdp) {
// Step 7 - Set remote SDP
viewPeerConnection.setRemoteDescription(new RTCSessionDescription(sdp), function() {
trace('Set Remote Description');
trace(sdp);
// Step 8 - Create an answer
var answerPromise = viewPeerConnection.createAnswer();
answerPromise.then(function(answer){
// Step 9 - Set local description from the incoming SDP
trace('Set Local Description');
trace(answer);
viewPeerConnection.setLocalDescription(answer)});
answerPromise.then(function(answer){
trace('Send Answer Description');
trace(answer);
// Step 10 - Send local sdp(answer) to remote
signallingServer.sendAnswer(offerCreatorId, roomName, answer);
}).catch(handleGetUserMediaError);
});
};
// ICE Candidate is created when cannot establish the peer connection due to NAT/FIREWALL
// when received ICE candidate info
signallingServer.onReceiveICECandidate = function(candidate) {
trace('Add ice candidate');
viewPeerConnection.addIceCandidate(new RTCIceCandidate(candidate));
};
viewPeerConnection.onaddstream = function(data) {
trace("stream ready");
remoteVideo.src = window.URL.createObjectURL(data.stream);
};
}
function errorHandler(error) {
console.error('Something went wrong!');
console.error(error);
}
function trace(text) {
console.info(text);
}
function handleGetUserMediaError(){
trace("getUserMedia Error")
}
<!DOCTYPE html>
<html lang="en">
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="">
<![endif]-->
<!--[if IE 7]>
<html class="no-js lt-ie9 lt-ie8" lang="">
<![endif]-->
<!--[if IE 8]>
<html class="no-js lt-ie9" lang="">
<![endif]-->
<!--[if gt IE 8]>
<!-->
<html class="no-js" lang="">
<!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.min.css">
<style>
body {
padding-top: 50px;
padding-bottom: 20px;
}
</style>
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.8.3-respond-1.4.2.min.js"></script>
</head>
<body>
<!--[if lt IE 8]>
<p class="browserupgrade">
You are using an <strong>outdated</strong>
browser. Please
<a href="http://browsehappy.com/">upgrade your browser</a>
to improve your experience.
</p>
<![endif]-->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">WebRTC Video Chat</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<!-- chatroom name form -->
<form class="navbar-form navbar-right form-inline">
<div class="form-group">
<input class="form-control" type="text" id="room-name" placeholder="Room name"/>
</div>
<button class="btn btn-primary" id="btn-video-start">Create Live Broadcast</button>
<button class="btn btn-default" id="btn-video-join">Join</button>
<button class="btn btn-default" disabled id="btn-video-stop">Stop</button>
</form>
</div>
<!--/.navbar-collapse --> </div>
</nav>
<div class="container main">
<div class="row videos">
<div class="remote-video">
<video width="280" height="250" autoplay="true" id="remote-video"></video>
</div>
<div class="local-video">
<video width="560" height="500" autoplay="true" id="local-video" muted></video>
</div>
</div>
</div>
</div>
<!-- /container -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.2.min.js"><\/script>')</script>
<script src="js/vendor/bootstrap.min.js"></script>
<script src="js/vendor/socket.io.js"></script>
<script src="js/main.js"></script>
<!--<script src="js/adapter.js"></script>-->
<script src="js/signalling.js"></script>
<!--<script src="//localhost:9010/livereload.js"></script>-->
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
<script>
(function (b, o, i, l, e, r) {
b.GoogleAnalyticsObject = l;
b[l] || (b[l] =
function () {
(b[l].q = b[l].q || []).push(arguments)
});
b[l].l = +new Date;
e = o.createElement(i);
r = o.getElementsByTagName(i)[0];
e.src = '//www.google-analytics.com/analytics.js';
r.parentNode.insertBefore(e, r)
}(window, document, 'script', 'ga'));
ga('create', 'UA-XXXXX-X', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>
在 onGuestJoined
中,您在 addStream
之前调用 createOffer
。这将创建一个没有任何媒体住宿的报价,或者失败:
在 Firefox 中,它会失败:
InternalError: Cannot create an offer with no local tracks, no
offerToReceiveAudio/Video, and no DataChannel.
在 Chrome 中,它似乎创建了一个无法使用的报价。
在这两种情况下,事情都不会继续,这就是 ICE 候选人没有开火的原因。
解决方案:
确保从 getUserMedia
成功回调中调用 createOffer
,或者更好,因为您似乎在此代码中混合了回调和承诺 API,请在整个过程中使用承诺以更加清晰:
navigator.mediaDevices.getUserMedia({video: true, audio: true})
.then(stream => {
localStream = stream;
peers[socketId].addStream(localStream);
return peers[socketId].createOffer();
})
.then(desc => peers[socketId].setLocalDescription(desc))
.then(() => signallingServer.sendOffer(guestId, roomName,
peers[socketId].localDescription))
.catch(errorHandler);