WebRTC未捕获的InvalidStateError:在RTCDataChannel上执行 'send' 时未等待0.5秒
我已经为WebRTC API开发了一个最简可运行的测试页面,参见 WebRTC_test.html 及相关的JS文件。问题在于它依赖于 datachannel.js 第20行的0.5秒休眠。把它注释掉时,我收到了错误
Uncaught InvalidStateError: Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open' at datachannel.js:21:1
有人能看出原因吗?
WebRTC_test.html:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>WebRTC test</title>
<script type="module" src="datachannel.js"></script>
</head>
<body>
<h1>WebRTC test</h1>
<input id="inputmessage" type="text" placeholder="message" />
<button id="buttonsend" onclick="buttonsendclick()">send</button>
<div id="messagelog"</div>
</body>
</html>
datachannel.js:
// WebRTC
import { pcOffInit } from "./offer.js";
import { pcAnsInit, addDatachannelListenerAns } from "./answer.js";
export const configuration = {
iceServers: [{ urls: "stun:stun.stunprotocol.org" }],
};
console.log("===1 pc1 configuration", configuration);
export const webrtc = {
dc: {}, // implement datachannel as an object member to allow updates from modules
};
await pcOffInit(); // intitiate offering RTCPeerConnection
await pcAnsInit(); // intitiate answering RTCPeerConnection
addDatachannelListenerAns();
// If the following sleep is commented out, receive error -
// Uncaught InvalidStateError: Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel.readyState is not 'open' at datachannel.js:21:1
await new Promise((r) => setTimeout(r, 500)); // sleep
webrtc.dc.send("message sent from datachannel.js");
console.log("===8.5 message sent from answer.js");
const buttonsendclick = () => {
const message = document.getElementById("inputmessage").value;
webrtc.dc.send(message);
console.log("===11 inputmessage: ", message);
};
window.buttonsendclick = buttonsendclick; //allow access from HTML
offer.js:
// Offering peer connection
import { webrtc, configuration } from "./datachannel.js";
import { getAnswer, setRemoteDescriptionAns } from "./answer.js";
let pcOff; // offering RTCPeerConnection
const icecandidatefn = async (event) => {
if (event.candidate !== null) {
console.log("===5 pcOff event.candidate", event.candidate);
} else {
console.log("===6 pcOff all ice candidates");
setRemoteDescriptionAns(pcOff.localDescription);
pcOff.setRemoteDescription(await getAnswer());
}
};
export const pcOffInit = async () => {
try {
pcOff = new RTCPeerConnection(configuration);
console.log("===2 pcOff: ", pcOff);
console.log("===2.5 pcOff.connectionState: ", pcOff.connectionState);
} catch (err) {
console.log("error: " + err);
}
webrtc.dc = pcOff.createDataChannel("chat");
console.log("===3 webrtc.dc: ", webrtc.dc);
pcOff.setLocalDescription(await pcOff.createOffer());
console.log("===4 pcOff.localDescription: ", pcOff.localDescription);
pcOff.addEventListener("icecandidate", icecandidatefn);
webrtc.dc.addEventListener("open", (event) => {
console.log("===9 pcOff event: ", event);
});
webrtc.dc.addEventListener("message", (message) => {
const messagelog = document.getElementById("messagelog");
messagelog.innerHTML += message.data;
messagelog.innerHTML += "<br />";
console.log("===10 dc message received: ", message.data);
});
};
anwser.js:
// Answering peer connection
import { webrtc, configuration } from "./datachannel.js";
let pcAns; // answering RTCPeerConnection
export const pcAnsInit = async () => {
try {
pcAns = new RTCPeerConnection(configuration);
console.log("===4.5 pcAns: ", pcAns);
} catch (err) {
console.log("error: " + err);
}
};
export const getAnswer = async () => {
const answer = await pcAns.createAnswer();
console.log("===7 getAnswer(): ", answer);
pcAns.setLocalDescription(answer);
return answer;
};
const datachannelfn = (event) => {
console.log("===7.5 webrtc.dc.readyState: ", webrtc.dc.readyState);
console.log("===7.5 pcAns.connectionState: ", pcAns.connectionState);
webrtc.dc = event.channel;
console.log("===8 webrtc.dc: ", event.channel);
webrtc.dc.send("message sent from answer.js");
console.log("===8.5 message sent from answer.js");
};
export const setRemoteDescriptionAns = (offer) => {
pcAns.setRemoteDescription(offer);
console.log("===7 offer: ", offer);
console.log("===8 pcAns: ", pcAns);
};
export const addDatachannelListenerAns = () => {
pcAns.addEventListener("datachannel", datachannelfn);
};
解决方案
你需要等待datachannel open 事件。这里(有意地)没有缓冲。把你的sleep Promise替换成下面这个:
await (new Promise(r => {
if (webrtc.dc.readyState === 'open') { retun resolve(); }
webrtc.dc.addEventListener('open', resolve, {once: true});
}));
webrtc.dc.send("message sent from datachannel.js");
https://webrtc.github.io/samples/src/content/datachannel/basic/ 包含完整示例。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。