如何在Chrome中为WebRTC调用者设置远程描述而不出错? [英] How to set remote description for a WebRTC caller in Chrome without errors?
问题描述
我希望逻辑上没有任何缺陷。
I hope there is no flaw in the logic.
第1步:来电者创建优惠
第2步:来电设置localDescription
Step 2: caller sets localDescription
第3步:来电者将说明发送至callee
Step 3: caller sends the description to the callee
// -------------------------------- ---------------------- //
//------------------------------------------------------//
第4步:被叫收到优惠设置远程描述
Step 4: callee receives the offer sets remote description
步骤5:被调用者创建答案
步骤6:被调用方设置本地描述
Step 6: callee sets local description
步骤7:被叫方将描述发送给来电者
Step 7: callee send the description to caller
// --------------------------------------- --------------- //
//------------------------------------------------------//
第8步:来电者收到答案并设置远程说明
Step 8: caller receives the answer and sets remote description
这里是上面的代码
const socket = io();
const constraints = {
audio: true,
video: true
};
const configuration = {
iceServers: [{
"url": "stun:23.21.150.121"
}, {
"url": "stun:stun.l.google.com:19302"
}]
};
const selfView = $('#selfView')[0];
const remoteView = $('#remoteView')[0];
var pc = new RTCPeerConnection(configuration);
pc.onicecandidate = ({
candidate
}) => {
socket.emit('message', {
to: $('#remote').val(),
candidate: candidate
});
};
pc.onnegotiationneeded = async () => {
try {
await pc.setLocalDescription(await pc.createOffer());
socket.emit('message', {
to: $('#remote').val(),
desc: pc.localDescription
});
} catch (err) {
console.error(err);
}
};
pc.ontrack = (event) => {
// don't set srcObject again if it is already set.
if (remoteView.srcObject) return;
remoteView.srcObject = event.streams[0];
};
socket.on('message', async ({
from,
desc,
candidate
}) => {
$('#remote').val(from);
try {
if (desc) {
// if we get an offer, we need to reply with an answer
if (desc.type === 'offer') {
await pc.setRemoteDescription(desc);
const stream = await navigator.mediaDevices.getUserMedia(constraints);
stream.getTracks().forEach((track) => pc.addTrack(track, stream));
selfView.srcObject = stream;
await pc.setLocalDescription(await pc.createAnswer());
console.log(pc.localDescription);
socket.emit({
to: from,
desc: pc.localDescription
});
} else if (desc.type === 'answer') {
await pc.setRemoteDescription(desc).catch(err => console.log(err));
} else {
console.log('Unsupported SDP type.');
}
} else if (candidate) {
await pc.addIceCandidate(new RTCIceCandidate(candidate)).catch(err => console.log(err));
}
} catch (err) {
console.error(err);
}
});
async function start() {
try {
// get local stream, show it in self-view and add it to be sent
const stream = await requestUserMedia(constraints);
stream.getTracks().forEach((track) => pc.addTrack(track, stream));
attachMediaStream(selfView, stream);
} catch (err) {
console.error(err);
}
}
socket.on('id', (data) => {
$('#myid').text(data.id);
});
// this function is called once the caller hits connect after inserting the unique id of the callee
async function connect() {
try {
await pc.setLocalDescription(await pc.createOffer());
socket.emit('message', {
to: $('#remote').val(),
desc: pc.localDescription
});
} catch (err) {
console.error(err);
}
}
socket.on('error', data => {
console.log(data);
});
现在执行步骤8
DOMException:无法在
'RTCPeerConnection'上执行'setRemoteDescription':无法设置远程商品sdp:在错误的
状态下调用:kHaveLocalOffer
DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
DOMException:无法在
'RTCPeerConnection'上执行'addIceCandidate':处理ICE候选者时出错
DOMException: Failed to execute 'addIceCandidate' on 'RTCPeerConnection': Error processing ICE candidate
尝试调试但没有在逻辑或代码中发现任何缺陷。注意到一个奇怪的事情是 pc
对象有 localDescription
和 currentLocalDescription
我认为创建答案的被叫方必须同时具有 answer
的描述类型,而是显示 localDescription
将 offer
和 currentLocalDescription
类型为 answer
。
Tried to debug but didn't find any flaw in the logic or code. Noticed one weird thing that the the pc
object has localDescription
and currentLocalDescription
and i think the callee who creates the answer must have both the description type to be answer
but instead shows the localDescription
to be offer
and currentLocalDescription
type is answer
.
我不知道是否应该表现得像那样,因为我是先生。
I have no idea if it is supposed to behave like that or not as I am begginer.
提前致谢。
推荐答案
您的代码是正确的。这是一个长期存在的 Chrome中的错误, negotiationneeded
。
Your code is correct. This is a long-standing bug in Chrome with negotiationneeded
.
我在小提琴(右键单击并在两个相邻的窗口中打开,然后单击一个中的调用)。
I've instrumented it in a fiddle (right-click and open in TWO adjacent windows, then click call in one).
在Firefox中, 有用。提议者协商一次,因为你一次添加两个曲目(视频/音频):
In Firefox, it works. The offerer negotiates once because you add two tracks (video/audio) at once:
negotiating in stable
onmessage answer
并且,在回答者方面,您在之外添加的曲目'稳定'
州被添加到答案中:
and, on the answerer side, the tracks you add outside of 'stable'
state are added to the answer:
onmessage offer
adding audio track
adding video track
但是在Chrome中,它被破坏了,触发 negotiationneeded
在提供者上两次,每次跟踪添加一次:
But in Chrome, it's broken, firing negotiationneeded
twice on the offerer, once per track added:
negotiating in stable
negotiating in stable
onmessage offer
DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
onmessage offer
DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
onmessage offer
DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
并在回答者一边解雇 negotiationneeded
两次,甚至不在'稳定'
州:
and firing negotiationneeded
twice on the answerer side, which isn't even in 'stable'
state:
onmessage offer
adding audio track
adding video track
negotiating in have-remote-offer
negotiating in have-remote-offer
onmessage offer
DOMException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
Failed to set remote offer sdp: Called in wrong state: kHaveLocalOffer
这些额外事件会造成倒数的破坏这里两端都出现状态错误。
These extra events cause the havoc of reciprocal state errors seen on both ends here.
具体来说,Chrome违反了 spec 此处:
To be specific, Chrome violates two parts of the spec here:
-
排队任务以触发此事件。 排队可防止在一次性对连接进行多次修改的常见情况下过早触发协商。
如果连接的信号状态不是稳定
,则中止这些步骤[以触发事件]。
If connection's signaling state is not "stable"
, abort these steps [to fire the event].
解决方法
解决两个 Chrome错误需要(使用 async
/ await
为简洁起见):
Workaround
Working around both Chrome bugs requires (using async
/await
for brevity):
let negotiating = false;
pc.onnegotiationneeded = async e => {
try {
if (negotiating || pc.signalingState != "stable") return;
negotiating = true;
/* Your async/await-using code goes here */
} finally {
negotiating = false;
}
}
这篇关于如何在Chrome中为WebRTC调用者设置远程描述而不出错?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!