Umer Ali
Umer Ali

Reputation: 99

[InvalidStateError: "setRemoteDescription needs to called before addIceCandidate" code: 11

I create a simple video calling app by using web Rtc and websockets. But when i run the code, the following error occured.

DOMException [InvalidStateError: "setRemoteDescription needs to called before addIceCandidate" code: 11

I don't know how to resolve this error. Here is my code below:

enter code here

var localVideo;
var remoteVideo;
var peerConnection;
var uuid;
var localStream;
var peerConnectionConfig = {
'iceServers': [
    {'urls': 'stun:stun.services.mozilla.com'},
    {'urls': 'stun:stun.l.google.com:19302'},
]
};

function pageReady() {
    uuid = uuid();
    console.log('Inside Page Ready');
    localVideo = document.getElementById('localVideo');
    remoteVideo = document.getElementById('remoteVideo');

   serverConnection = new WebSocket('wss://' + window.location.hostname + 
   ':8443');
   serverConnection.onmessage = gotMessageFromServer;

   var constraints = {
       video: true,
       audio: true,
   };

   if(navigator.mediaDevices.getUserMedia) {

   navigator.mediaDevices.getUserMedia(constraints)
   .then(getUserMediaSuccess).catch(errorHandler);
   }else
   {
       alert('Your browser does not support getUserMedia API');
   }
   }

   function getUserMediaSuccess(stream) {
        localStream = stream;
        localVideo.src = window.URL.createObjectURL(stream); 
   }

   function start(isCaller) {
       console.log('Inside isCaller');
       peerConnection = new RTCPeerConnection(peerConnectionConfig);
       peerConnection.onicecandidate = gotIceCandidate;
       peerConnection.onaddstream = gotRemoteStream;
       peerConnection.addStream(localStream);

       if(isCaller) {
            console.log('Inside Caller to create offer');
            peerConnection.createOffer().
            then(createdDescription).catch(errorHandler);
       }
      }

   function gotMessageFromServer(message) {
   console.log('Message from Server');
   if(!peerConnection) 
   {
        console.log('Inside !Peer Conn');
        start(false);
   }

   var signal = JSON.parse(message.data);

   // Ignore messages from ourself
   if(signal.uuid == uuid) return;

   if(signal.sdp) {
        console.log('Inside SDP');
        peerConnection.setRemoteDescription(new 
        RTCSessionDescription(signal.sdp)).then(function() {
        // Only create answers in response to offers
        if(signal.sdp.type == 'offer') {
            console.log('Before Create Answer');
            peerConnection.createAnswer().then(createdDescription)
            .catch(errorHandler);
        }
     }).catch(errorHandler);
     } else if(signal.ice) {
           console.log('Inside Signal Ice');
           peerConnection.addIceCandidate(new 
           RTCIceCandidate(signal.ice)).catch(errorHandler);
     }

    }

    function gotIceCandidate(event) {
         console.log('Inside Got Ice Candi');
         if(event.candidate != null) {
         serverConnection.send(JSON.stringify({'ice': event.candidate, 
         'uuid': uuid}));
    }
  }

  function createdDescription(description) {
  console.log('got description');

    peerConnection.setLocalDescription(description).then(function() {
    console.log('Inside Setting ');
    serverConnection.send(JSON.stringify({'sdp': 
    peerConnection.localDescription, 'uuid': uuid}));
   }).catch(errorHandler);
  }

  function gotRemoteStream(event) {
  console.log('got remote stream');
  remoteVideo.src = window.URL.createObjectURL(event.stream);
  }

  function errorHandler(error) {
     console.log(error);
  }

  // Taken from http://stackoverflow.com/a/105074/515584
  // Strictly speaking, it's not a real UUID, but it gets the job done here
  function uuid() {
      function s4() {
      return Math.floor((1 + Math.random()) * 
      0x10000).toString(16).substring(1);
      }

  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + 
  s4() + s4();
  }

This is my code, I don't know how to arrange the addIceCandidate and addRemoteDescription function.

Upvotes: 4

Views: 2290

Answers (3)

Maximiliano Guerra
Maximiliano Guerra

Reputation: 323

EDIT: As I have been told, this solution is an anti-pattern and you should NOT implement it this way. For more info on how I solved it while still keeping a reasonable flow, follow this answer and comment section: https://stackoverflow.com/a/57257449/779483

TLDR: Instead of calling addIceCandidate as soon as the signaling information arrives, add the candidates to a queue. After calling setRemoteDescription, go through candidates queue and call addIceCandidate on each one.

--

From this answer I learned that we have to call setRemoteDescription(offer) before we add the Ice Candidates data.

So, expanding on @Luxior answer, I did the following:

  • When signaling message with candidate arrives:
    • Check if remote was set (via a boolean flag, ie: remoteIsReady)
    • If it was, call addIceCandidate
    • If it wasn't, add to a queue
  • After setRemoteDescription is called (in answer signal or answer client action):
    • Call a method to go through the candidates queue and call addIceCandidate on each one.
    • Set boolean flag (remoteIsReady) to true
    • Empty queue

Upvotes: 1

Velexior
Velexior

Reputation: 179

You need to make sure that peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)) is called after description is set. You have sitution where you receive ice candidate and try to add it to peerConnection before peerConnection has completed with setting description.

I had similar situation, and I created array for storing candidates that arrived before setting description is completed, and a variable that checks if description is set. If description is set, I would add candidates to peerConnection, otherwise I would add them to array. (when you set your variable to true, you can also go through array and add all stored candidates to peerConnection.

Upvotes: 3

The way WebRTC works (as much as i understand) is you have to make two peers to have a deal to how to communicate eachother in the order of give an offer to your peer get your peers answer and select an ICE candidate to communicate on then if you want to send your media streams for an video conversation

for you to have a good exampe to look on how to implemet those funcitons and in which order you can visit https://github.com/alexan1/SignalRTC he has a good understading of how to do this.

you might already have a solution to your problem at this time but im replying in case you do not.

Upvotes: 0

Related Questions