我正在构建一个需要对等 2 对等通用数据进行通信的应用程序,而 webRTC 似乎是一种不错的方法。但是,当尝试与 DataChannel 建立 p2p 连接时,我不断遇到特定网络上的 ICE Candidate 失败。但在同一个网络上,MediaChannel p2p 连接工作正常。
即使在以下 repo 的最小改编中, https://github.com/fireship-io/webrtc-firebase-demo,datachannel变体也不起作用。
怀疑它与 TCP 而不是 UDP 有关,但不允许 tcp 候选者并不能解决问题。
DataChannel 不起作用但 MediaChannel 起作用的原因是什么?该网络是大学公共网络。我们使用 firebase 作为信号服务器。谷歌 STUN 服务器。
HTML 由 callButton 组成,它将 ICECandidates + offer 推送到信令服务器,并生成一个 ID,该 ID 可用于通过 answerButton 从不同的实例进行连接。
处理大部分 webRTC 连接的 js 片段,其中pc
是 RTCPeerConnection 实例:
function startup() {
sendChannel = pc.createDataChannel("sendChannel");
pc.ondatachannel = receiveChannelCallback;
//update HTML depending on open connection
sendChannel.onopen = handleSendChannelStatusChange;
sendChannel.onclose = handleSendChannelStatusChange;
callButton.disabled = false;
answerButton.disabled = false;
};
// Create an offer
callButton.onclick = async () => {
// Reference Firestore collections for signaling
const callDoc = firestore.collection('calls').doc();
const offerCandidates = callDoc.collection('offerCandidates');
const answerCandidates = callDoc.collection('answerCandidates');
callInput.value = callDoc.id;
// Get candidates for caller, save to Firebase
pc.onicecandidate = (event) => {
// only add ICE that are not tcp
if (event.candidate && event.candidate.protocol !== 'tcp') {
offerCandidates.add(event.candidate.toJSON())
}
};
// Create offer
const offerDescription = await pc.createOffer();
await pc.setLocalDescription(offerDescription);
const offer = {
sdp: offerDescription.sdp,
type: offerDescription.type,
};
await callDoc.set({ offer });
// Listen for remote answer
callDoc.onSnapshot((snapshot) => {
const data = snapshot.data();
if (!pc.currentRemoteDescription && data?.answer) {
const answerDescription = new RTCSessionDescription(data.answer);
pc.setRemoteDescription(answerDescription);
}
});
// When answered, add candidate to peer connection
answerCandidates.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === 'added') {
const candidate = new RTCIceCandidate(change.doc.data());
pc.addIceCandidate(candidate);
}
});
});
};
// 3. Answer the call with the unique ID
answerButton.onclick = async () => {
const callId = callInput.value;
const callDoc = firestore.collection('calls').doc(callId);
const answerCandidates = callDoc.collection('answerCandidates');
const offerCandidates = callDoc.collection('offerCandidates');
pc.onicecandidate = (event) => {
event.candidate && answerCandidates.add(event.candidate.toJSON());
};
const callData = (await callDoc.get()).data();
const offerDescription = callData.offer;
await pc.setRemoteDescription(new RTCSessionDescription(offerDescription));
const answerDescription = await pc.createAnswer();
await pc.setLocalDescription(answerDescription);
const answer = {
type: answerDescription.type,
sdp: answerDescription.sdp,
};
await callDoc.update({ answer });
offerCandidates.onSnapshot((snapshot) => {
snapshot.docChanges().forEach((change) => {
console.log(change);
if (change.type === 'added') {
let data = change.doc.data();
pc.addIceCandidate(new RTCIceCandidate(data));
}
});
});
};
DataChannel 不起作用但 MediaChannel 起作用的原因是什么?