webrtc不支持怎么调用设想吐_如何在Chrome中为WebRTC调用者设置远程描述而不出错?...
I hope there is no flaw in the logic.Step 1: caller creates offerStep 2: caller sets localDescriptionStep 3: caller sends the description to the callee//-----------------------------------------------
I hope there is no flaw in the logic.
Step 1: caller creates offer
Step 2: caller sets localDescription
Step 3: caller sends the description to the callee
//------------------------------------------------------//
Step 4: callee receives the offer sets remote description
Step 5: callee creates answer
Step 6: callee sets local description
Step 7: callee send the description to caller
//------------------------------------------------------//
Step 8: caller receives the answer and sets remote description
And here is the code for the above
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);
});
Now this code throws an error while executing Step 8
DOMException: Failed to execute 'setRemoteDescription' on
'RTCPeerConnection': Failed to set remote offer sdp: Called in wrong
state: kHaveLocalOffer
DOMException: Failed to execute 'addIceCandidate' on
'RTCPeerConnection': Error processing ICE candidate
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.
Thanks in advance.
解决方案
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).
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
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
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.
To be specific, Chrome violates two parts of the spec here:
"Queue a task" to fire this event. "queueing prevents negotiationneeded from firing prematurely, in the common situation where multiple modifications to connection are being made at once."
If connection's signaling state is not "stable", abort these steps [to fire the event].
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;
}
}
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)