一般的なデータのピア 2 ピア通信を必要とするアプリケーションを構築していますが、webRTC はそれを行うための良い方法のように思えました。ただし、DataChannel との p2p 接続を確立しようとすると、特定のネットワークで ICE Candidate の障害が発生し続けます。しかし、この同じネットワークでは、MediaChannel p2p 接続は正常に機能します。
次のレポ https://github.com/fireship-io/webrtc-firebase-demoの最小限の適応でも、datachannel バリアントは機能しません。
UDP ではなく TCP に関係していると思われますが、tcp 候補を許可しないことは問題を解決しません。
DataChannel が機能しないのに MediaChannel が機能する理由は何ですか? ネットワークは大学の公衆ネットワークです。シグナリング サーバーとして firebase を使用します。Google STUN サーバー。
HTML は、ICECandidates + オファーをシグナリング サーバーにプッシュする callButton で構成され、answerButton によって別のインスタンスから接続するために使用できる ID を生成します。
ほとんどの 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 が機能する理由は何ですか?