1

我正在构建一个需要对等 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 起作用的原因是什么?

4

0 回答 0