Javascript 本地WebRTC连接卡在“on”上;核对;脱机时
我一直在尝试获得一个hermedic开发环境,这样东西就可以在本地工作,例如在没有互联网的火车上,在一台计算机上工作。我创建了这个最小的“Hello World”页面,它试图在同一页面中的两个对象(创建者和加入者)之间创建WebRTC连接。通过这种方式,信令服务器被截短,并且步骤可以显示在一个同步日志中。然而,当我的电脑离线时,我并没有收到预期的回调Javascript 本地WebRTC连接卡在“on”上;核对;脱机时,javascript,webrtc,serverless,Javascript,Webrtc,Serverless,我一直在尝试获得一个hermedic开发环境,这样东西就可以在本地工作,例如在没有互联网的火车上,在一台计算机上工作。我创建了这个最小的“Hello World”页面,它试图在同一页面中的两个对象(创建者和加入者)之间创建WebRTC连接。通过这种方式,信令服务器被截短,并且步骤可以显示在一个同步日志中。然而,当我的电脑离线时,我并没有收到预期的回调 <!doctype html> <html> <head> <meta charset="utf-8
<!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>
离线WebRTC
html,正文{填充:0;边距:0;高度:100%}
正文{框大小:边框框;填充:50px 0 0px;颜色:#ccc;背景色:#303030;}
h1{位置:固定;边距:0;线宽:50px;填充:0 15px;顶部:0;左侧:0;字体大小:18px;宽度:100%;框大小:边框框}
为什么这个WebRTC可以在线工作而不能离线?
//
//戈巴尔
//
//这是创建者和加入者进行通信的接口。
//通常,这将涉及通过WebSocket通过服务器进行管道传输。
常量信号服务器={
giveOfferToJoiner:null,//在“创建”部分初始化
giveAnswerToCreator:null,//在“join”部分初始化
};
设logCounter=0;
函数logWithIndent(消息,缩进){
常量前缀=''.padStart(缩进,'')+(''+logCounter).padStart(4,'0')+'';
对数计数器+=1;
document.getElementById('log')。textContent+=前缀+消息+'\n';
常数窗格=[
document.getElementById('join-pane'),
document.getElementById('create-pane'),
];
}
//
//联接(右列)
//
(() => {
const log=(message)=>logWithIndent(message,50);
const pc=新的RTPeerConnection(空);
const sdpConstraints={可选:[{RtpDataChannels:true}]};
SignalingServer.giveOfferToJoiner=(offerString)=>{
日志(“收到的报价”);
const offerDesc=新的RTCSessionDescription(JSON.parse(offerString));
pc.setRemoteDescription(offerDesc);
pc.createAnswer(
(回答)=>{
日志('设置对等连接描述')
pc.setLocalDescription(answerDesc);
},
()=>{log(“错误:无法创建答案”);},
sdpConstraints
);
};
pc.ondatachannel=(e)=>{
const dataChannel=e.channel;
const sendMessage=(消息)=>{
日志(`Sending message:${message}`);
数据通道发送(消息);
};
dataChannel.onopen=()=>{log(“数据通道打开!”);};
dataChannel.onmessage=(e)=>{
const message=e.data
日志(“收到的消息:+消息”);
sendMessage('PONG:'+消息)
}
};
pc.onicecandidate=(e)=>{
如果(如候选人){
日志('等待回答的空候选者');
回来
}
const answer=JSON.stringify(pc.localDescription);
日志(“已创建应答。发送给创建者”);
信号服务器。将应答器发送给创建者(应答);
日志('正在等待连接…')
};
pc.oniceconnectionstatechange=(e)=>{
const state=pc.iceConnectionState;
日志(`iceConnectionState已更改为“${state}`)
如果(状态==“已连接”){
日志(“TODO:发送消息”);
}
};
日志(`Waiting for offer`);
})();
//
//创建(左)
//
(() => {
const log=(message)=>logWithIndent(message,0);
const pc=新的RTPeerConnection(空);
让dataChannel=null;
const sendMessage=(消息)=>{
日志(`Sending message:${message}`);
数据通道发送(消息);
};
SignalingServer.giveAnswerToCreator=(answerString)=>{
var answerDesc=新的RTCSessionDescription(JSON.parse(answerString));
日志('设置对等连接描述')
pc.setRemoteDescription(应答描述);
};
pc.oniceconnectionstatechange=(e)=>{
const state=pc.iceConnectionState;
日志(`iceConnectionState已更改为“${state}`)
};
pc.onicecandidate=(e)=>{
如果(如候选人){
日志(`Waiting for offer`)为空的候选者;
回来
}
const offer=JSON.stringify(pc.localDescription);
日志(`Offer created.Sending to joiner`);
信号服务器。给定要约加入者(要约);
日志(`等待回答…`);
}
函数createOffer(){
dataChannel=pc.createDataChannel(“聊天”);
dataChannel.onopen=()=>{log(“数据通道打开!”);sendmages('helloworld!'};
dataChannel.onmessage=(e)=>{log(“收到的消息:+e.data);}
日志(‘创建报价…’);
pc.createOffer()。然后((e)=>{
日志(“设置本地描述”);
pc.setLocalDescription(e);
});
};
createOffer();
})();
复制:
file://...
URL,无需服务器)PONG:Hello World!
)iceConnectionState更改为“checking”后,它不会继续进行
- 与chrome devtools的网络选项卡中的“脱机”复选框相比,断开计算机与internet的连接会产生不同的效果。选中此复选框对是否可以建立连接没有影响
附加问题:我假设浏览器试图在后台与某人交谈,作为检查或连接步骤的一部分。它想和谁说话?为什么这些请求没有显示在devtools的“网络”选项卡中?作为ICE过程的一部分,WebRTC从本地网络接口收集候选对象。 从查看SDP(在调试器中或chrome://webrtc-interals),脱机时,没有用于收集候选人的接口(忽略环回接口除外),onicecandidate中没有候选人,您只需发送一份没有候选人的报价 进入