当前使用的是Chrome 70,Firefox 64和Safari12。
另一个用户的远程视频没有在两侧显示,我不确定这可能是问题所在。
任何浏览器都没有错误,这些错误无助于调试代码。
我正在使用chrome的内部WebRTC调试工具(chrome:// webrtc-internals),发送或接收的数据包为零。
该工具中有一个参数googCandidatePair,但这在通话过程中根本不显示。
ICEgatheringstatechange事件触发并声明它已经完成,但是仅当主机是chrome用户时。
我也尝试使用
pc.oniceconnectionstatechange = () => console.log(pc.iceConnectionState);
检查ICE状态是否更改,但这根本不会触发。
我认为它可能无法正常运行的一个原因可能是由于RTCPeerconnection是如何配置的(如上图所示),Ice候选池的大小为0,但从未在代码本身中声明。
下面是两张图片,其中第一张是当主机是chrome时,另一张是接收者
代码如下:
'use strict';
var configuration = {
iceServers: [
{
urls: 'stun:stun.l.google.com:19302'
}
]
};
var pc = new RTCPeerConnection(configuration);
// Define action buttons.
const callButton = document.getElementById('callButton');
const hangupButton = document.getElementById('hangupButton');
/////////////////////////////////////////////
window.room = prompt('Enter room name:');
var socket = io.connect();
if (room !== '') {
console.log('Message from client: Asking to join room ' + room);
socket.emit('create or join', room);
}
socket.on('created', function(room) {
console.log('Created room ' + room);
startVideo();
});
socket.on('full', function(room) {
console.log('Message from client: Room ' + room + ' is full :^(');
});
socket.on('joined', function(room) {
console.log('joined: ' + room);
startVideo();
callButton.disabled = true;
});
socket.on('log', function(array) {
console.log.apply(console, array);
});
////////////////////////////////////////////////
async function sendMessage(message) {
console.log('Client sending message: ', message);
await socket.emit('message', message);
}
// This client receives a message
socket.on('message', message => {
if (message.sdp) {
pc.setRemoteDescription(new RTCSessionDescription(message.sdp))
.then(function() {
if (pc.setRemoteDescription.type === 'offer') {
pc.setLocalDescription(pc.createAnswer())
.then(function() {
sendMessage({ sdp: pc.localDescription });
})
.catch(function(err) {
console.log(err.name + ': ' + err.message);
});
}
})
.catch(error => console.error(error));
} else if (message.candidate) {
pc.addIceCandidate(new RTCIceCandidate(message.candidate))
.then(() => {
console.log('Candidates received');
})
.catch(error => console.error(error));
}
});
pc.onicecandidate = event => {
if (event.candidate) {
sendMessage({ candidate: event.candidate });
}
};
pc.ontrack = event => {
if (remoteVideo.srcObject !== event.streams[0]) {
remoteVideo.srcObject = event.streams[0];
console.log('Got remote stream');
}
};
////////////////////////////////////////////////////
const localVideo = document.querySelector('#localVideo');
const remoteVideo = document.querySelector('#remoteVideo');
// Set up initial action buttons status: disable call and hangup.
callButton.disabled = true;
hangupButton.disabled = true;
// Add click event handlers for buttons.
callButton.addEventListener('click', callStart);
hangupButton.addEventListener('click', hangupCall);
function startVideo() {
navigator.mediaDevices
.getUserMedia({
audio: true,
video: true
})
.then(function(stream) {
localVideo.srcObject = stream;
stream.getTracks().forEach(track => pc.addTrack(track, stream));
})
.catch(function(err) {
console.log('getUserMedia() error: ' + err.name);
});
callButton.disabled = false;
}
async function callStart() {
callButton.disabled = true;
hangupButton.disabled = false;
console.log('Sending offer to peer');
await pc
.setLocalDescription(await pc.createOffer())
.then(() => {
sendMessage({ sdp: pc.localDescription });
})
.catch(err => {
console.log(err.name + ': ' + err.message);
});
}
/////////////////////////////////////////////////////////
function hangupCall() {
pc.close();
pc = null;
callButton.disabled = false;
hangupButton.disabled = true;
console.log('Call Ended');
}
答案 0 :(得分:2)
您正在混合您的诺言样式,并且这里有一个错误:
pc.setLocalDescription(pc.createAnswer()) // bug!
.then(function() {
以上将本地描述设置为Promise对象。始终选择async
/ await
:
await pc.setLocalDescription(await pc.createAnswer());
...或.then()
链:
pc.createAnswer()
.then(answer => pc.setLocalDescription(answer))
.then(function() {
如果选择后者,请不要忘记return all the promises。
这是仅使用async
/ await
完成的消息处理程序:
// This client receives a message
socket.on('message', async message => {
try {
if (message.sdp) {
await pc.setRemoteDescription(message.sdp);
if (pc.setRemoteDescription.type === 'offer') {
await pc.setLocalDescription(await pc.createAnswer());
sendMessage({sdp: pc.localDescription});
}
} else if (message.candidate) {
await pc.addIceCandidate(message.candidate);
console.log('Candidates received');
}
} catch (err) {
console.log(err.name + ': ' + err.message);
}
}
答案 1 :(得分:0)
如果有人可能对远程视频没有显示有问题,我发现这是因为该消息不是通过第二条IF语句来检查message.type === offer的,并且因为它无法创建因此,它无法将其本地描述发送给其他用户。但是通过在开始时将消息拆分为sdp和候选人,它就可以工作了。
socket.on('message', async ({ sdp, candidate }) => {
if (sdp) {
await pc.setRemoteDescription(new RTCSessionDescription(sdp));
if (sdp.type === 'offer') {
await pc
.setLocalDescription(await pc.createAnswer())
.then(function() {
sendMessage({ sdp: pc.localDescription });
})
.catch(function(err) {
console.log(err.name + ': ' + err.message);
});
}
} else if (candidate) {
await pc
.addIceCandidate(new RTCIceCandidate(candidate))
.then(() => {
console.log('Candidates received');
})
.catch(error => console.error(error));
}
});