我一直在尝试建立一个Hermedic开发环境,以使事情在本地运行,例如在没有互联网的火车上在一台计算机上。我创建了这个最小的“ Hello World”页面,该页面试图在同一页面中的两件事(“创建者”和“连接器”)之间创建WebRTC连接。这样,信令服务器就可以存根,并且可以在一个同步日志中显示步骤。但是,我没有在计算机脱机时获得预期的回调。
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Offline WebRTC</title>
<style>
html, body {padding:0;margin:0;height:100%}
body {box-sizing:border-box;padding:50px 0 0px;color:#ccc;background-color:#303030;}
h1 {position:fixed;margin:0;line-height:50px;padding:0 15px;top:0;left:0;font-size:18px;width:100%;box-sizing:border-box}
</style>
</head>
<body>
<h1>Why does this WebRTC work online but not offline?</h1>
<pre id="log"></pre>
<script type="text/javascript">
//
// Gobals
//
// This is the interface through which the Creator and Joiner communicate.
// Usually this would involve piping through the server via websockets.
const signallingServer = {
giveOfferToJoiner: null, // initialized in the "create" section
giveAnswerToCreator: null, // initialized in the "join" section
};
let logCounter = 0;
function logWithIndent(message, indent) {
const prefix = ''.padStart(indent, ' ') + (''+logCounter).padStart(4, '0') + ' ';
logCounter += 1;
document.getElementById('log').textContent += prefix + message + '\n';
const panes = [
document.getElementById('join-pane'),
document.getElementById('create-pane'),
];
}
//
// Join (right column)
//
(() => {
const log = (message) => logWithIndent(message, 50);
const pc = new RTCPeerConnection(null);
const sdpConstraints = { optional: [{RtpDataChannels: true}] };
signallingServer.giveOfferToJoiner = (offerString) => {
log('Received offer');
const offerDesc = new RTCSessionDescription(JSON.parse(offerString));
pc.setRemoteDescription(offerDesc);
pc.createAnswer(
(answerDesc) => {
log('Setting peer connection description')
pc.setLocalDescription(answerDesc);
},
() => { log("ERROR: Couldn't create answer"); },
sdpConstraints
);
};
pc.ondatachannel = (e) => {
const dataChannel = e.channel;
const sendMessage = (message) => {
log(`Sending message: ${message}`);
dataChannel.send(message);
};
dataChannel.onopen = () => { log("Data channel open!"); };
dataChannel.onmessage = (e) => {
const message = e.data
log("Received message: " + message);
sendMessage('PONG: ' + message)
}
};
pc.onicecandidate = (e) => {
if (e.candidate) {
log('waiting for null candidate for answer');
return;
}
const answer = JSON.stringify(pc.localDescription);
log('Answer created. Sending to creator');
signallingServer.giveAnswerToCreator(answer);
log('waiting for connection...')
};
pc.oniceconnectionstatechange = (e) => {
const state = pc.iceConnectionState;
log(`iceConnectionState changed to "${state}"`)
if (state == "connected") {
log('TODO: send message');
}
};
log(`Waiting for offer`);
})();
//
// Create (left)
//
(() => {
const log = (message) => logWithIndent(message, 0);
const pc = new RTCPeerConnection(null);
let dataChannel = null;
const sendMessage = (message) => {
log(`Sending message: ${message}`);
dataChannel.send(message);
};
signallingServer.giveAnswerToCreator = (answerString) => {
var answerDesc = new RTCSessionDescription(JSON.parse(answerString));
log('Setting peer connection description')
pc.setRemoteDescription(answerDesc);
};
pc.oniceconnectionstatechange = (e) => {
const state = pc.iceConnectionState;
log(`iceConnectionState changed to "${state}"`)
};
pc.onicecandidate = (e) => {
if (e.candidate) {
log(`Waiting for null candidate for offer`);
return;
}
const offer = JSON.stringify(pc.localDescription);
log(`Offer created. Sending to joiner`);
signallingServer.giveOfferToJoiner(offer);
log(`waiting for answer...`);
}
function createOffer() {
dataChannel = pc.createDataChannel("chat");
dataChannel.onopen = () => { log("Data channel open!"); sendMessage('Hello World!')};
dataChannel.onmessage = (e) => { log("Received message: " + e.data); }
log('Creating offer...');
pc.createOffer().then((e) => {
log('setting local description');
pc.setLocalDescription(e);
});
};
createOffer();
})();
</script>
</body>
</html>
复制:
连接到Internet时,请在本地打开此.html文件(应具有
file://...
URL,无需服务器)观察它是否正常工作(应该进入
PONG: Hello World!
)断开计算机与互联网的连接
刷新页面
注意在
iceConnectionState changed to "checking"
之后它不会继续进行附加信息:
与chrome devtools的网络标签中的“离线”复选框相比,断开计算机与互联网的连接会产生不同的影响。选中此复选框对是否可以建立连接没有影响。
所以我的主要问题是:当计算机离线时,如何打开本地WebRTC连接?
其他问题:作为检查或连接步骤的一部分,我认为浏览器正在尝试与后台某人交谈。想和谁说话?为什么这些请求未显示在devtools的“网络”选项卡中?
最佳答案
WebRTC作为ICE流程的一部分,从您的本地网络接口收集候选对象。
从查看SDP(在调试器中或在chrome:// webrtc-interals上)来看,离线时没有任何接口(除了被忽略的环回接口)可以从中收集候选,onicecandidate中没有候选,而您只是发送没有任何候选人的报价。
进入“检查” ICE连接状态似乎是一个错误,https://w3c.github.io/webrtc-pc/#rtcicetransportstate为此需要远程候选。