2

Hey I'm building an app that demonstrates the capabilities of webrtc. This app involves manual exchange of offer/answer. The issue I'm running into is, if the created answer is not accepted within 10 seconds in firefox browser, (15 seconds - chrome) the iceConnectionState property returns 'failed'. However if the answer is accepted within 10 seconds, then the connection is established and iceConnectionState returns 'connected'. Can somebody look at my code, and tell me what could be causing this behavior? Is there a bug in my code?

export default class P2P {
  constructor() {
    this.peerConnection;
    this.dataChannel;
    this.configuration = {
      iceServers: [
        {
          urls: ['stun:stun4.l.google.com:19302']
        }
      ],
      iceCandidatePoolSize: 100
    };
  };

  createPeerConnection = async () => {
    this.peerConnection = new RTCPeerConnection(this.configuration);
    this.openDataChannel();

    this.peerConnection.addEventListener('connectionstatechange', (e) => {
      console.log(this.peerConnection.connectionState)
    });
  };

  openDataChannel = () => {
    let options = { 
      reliable: true 
   }; 
    
    this.dataChannel = this.peerConnection.createDataChannel('test', options);
    this.dataChannel.binaryType = "arraybuffer";
  };

  getIceCandidates = () => {
    return new Promise((resolve) => {
      this.peerConnection.onicegatheringstatechange  = () => {
        if (this.peerConnection.iceGatheringState === "complete") {
          console.log('ice gathering complete')
          resolve();    
        };
      };

      this.peerConnection.oniceconnectionstatechange = () => {
        console.log(this.peerConnection.iceConnectionState,     this.peerConnection.iceGatheringState);
      };
    });
  };

  createOffer = async () => {
    this.createPeerConnection();
    let offer = await this.peerConnection.createOffer();
    console.log("created-offer");
    offer = new RTCSessionDescription(offer);
    await this.peerConnection.setLocalDescription(offer);
    await this.getIceCandidates();
    return JSON.stringify(this.peerConnection.localDescription);
  };

  acceptOffer = async (offer) => {
    this.createPeerConnection();
    offer = new RTCSessionDescription(offer)
    await this.peerConnection.setRemoteDescription(offer);
  };

  createAnswer = async () => {
    let answer = await this.peerConnection.createAnswer();
    console.log("created-answer");
    answer = new RTCSessionDescription(answer);
    await this.peerConnection.setLocalDescription(answer);
    await this.getIceCandidates();
    return JSON.stringify(this.peerConnection.localDescription);
  };

  acceptAnswer = async (answer) => {
    if (!this.peerConnection.currentRemoteDescription) {
      this.peerConnection.setRemoteDescription(answer);
      console.log('accepted')
    };
  };
};
Cosmic
  • 25
  • 6
  • Possible duplicate of https://stackoverflow.com/questions/54167645/serverless-webrtc-sdp-ice-timeout – jch Jun 11 '23 at 13:49
  • Can you press F12 to check what error message is shown in the console? – The KNVB Jun 19 '23 at 07:41
  • @TheKNVB WebRTC: ICE failed, add a TURN server and see about:webrtc for more details – Cosmic Jun 19 '23 at 22:37
  • Adding a TURN server may make your code work, I have signed up for a free TURN server from expressturn.com. And I have created a web page that is similar to yours. Unfortunately, in the Firefox browser, it works intermittently. However, it is working properly in the Chrome browser. Can you post your peerConnection.onicecandidate event handler? – The KNVB Jun 20 '23 at 01:42
  • I used two arrays to store all ice for each party, For each party, I will add the ICE after setting the remote description. – The KNVB Jun 20 '23 at 01:45
  • @TheKNVB I am using 'onicegatheringstatechange' instead of 'onicecandidate', to detect the completion of gathering ice candidates. You can see it in the getIceCandidates method. – Cosmic Jun 21 '23 at 21:18
  • however, you have to add the remote ICE candidates to the local peerConnection object, I cannot find it in your code. – The KNVB Jun 22 '23 at 14:09
  • @TheKNVB the ICE candidates are already included in the local description, because If you notice I wait until the local ice candidates have been gathered before getting the local description. This all inclusive local description just needs to be shared and accepted by both the peers to establish the connection. – Cosmic Jun 22 '23 at 23:10
  • As I know it is wrong, you may refer to the following web page: https://webrtc.org/getting-started/peer-connections#ice_candidates – The KNVB Jun 23 '23 at 01:17
  • It is another example: https://www.w3.org/TR/webrtc/#simple-peer-to-peer-example – The KNVB Jun 23 '23 at 01:49
  • @TheKNVB its not really wrong per-say. Its just how you need to do it, for a completely server-less implementation. In the examples, you shared, signalling happens through a websocket server. My site doesn't rely one. Look at this example https://svarunan.github.io/serverless-webrtc/ if you notice, the offer and the answer already include the ice candidates, my site is similar to this. – Cosmic Jun 23 '23 at 10:49

2 Answers2

-1

Manual exchange of offer/answer is not really a supported use-case. WebRTC uses ICE (which stands for Interactive Connectivity Establishment) for NAT traversal and this consumes resources every second.

A ICE candidate pool size of 100 is a complete waste of resources btw.

Philipp Hancke
  • 15,855
  • 2
  • 23
  • 31
-1

Have you used the "perfect negotiation" logic when establishing a connection?

You may refer to the following page for detail:

https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Perfect_negotiation

The KNVB
  • 3,588
  • 3
  • 29
  • 54