Search code examples
javascriptnode.jswebsocketwebrtcrtcdatachannel

Failed to set local answer sdp: Called in wrong state: STATE_INPROGRESS


I have two clients :

1) Chrome (version 50.0.2661.102 m) on Windows 7 PC
2) Chrome (version 50.0.2661.89) on Android tablet

Both are in the same network (so no need for STUN/TURN server).

I use my own signal server built with node.js (webSocket) on a VirtualBox VM with Centos 6.

The communication with video/sound between the clients works fine. Now I want to transfer a file from one client to another. As base of my code i use the code of this example here

As this code suggess, I create the dataChannnel exactly after the creation of PeerConnection.

function createPeerConnection() {
....
  myPeerConnection = new RTCPeerConnection(iceServers, optional);        
  myDataChannel = myPeerConnection.createDataChannel('myDataChannel');

  // Set up event handlers for the ICE negotiation process.
  myPeerConnection.onicecandidate = handleICECandidateEvent;
  myPeerConnection.onaddstream = handleAddStreamEvent;
  myPeerConnection.onnremovestream = handleRemoveStreamEvent;
  myPeerConnection.oniceconnectionstatechange =               handleICEConnectionStateChangeEvent;
  myPeerConnection.onicegatheringstatechange = handleICEGatheringStateChangeEvent;
  myPeerConnection.onsignalingstatechange = handleSignalingStateChangeEvent;
  myPeerConnection.onnegotiationneeded = handleNegotiationNeededEvent;
  myPeerConnection.ondatachannel = handleDataChannel;

  myDataChannel.onmessage = handleDataChannelMessage;
  myDataChannel.onopen = handleDataChannelOpen;
}
...
... 
function invite(peerId) {
   ...
   createPeerConnection();
   ...
}
...
...
function handleVideoOfferMsg(msg) {
   thereIsNegotiation = true;
   targetUsername = msg.name;

   // Call createPeerConnection() to create the RTCPeerConnection.
   log("Starting to accept invitation from " + targetUsername);
   createPeerConnection();

   // We need to set the remote description to the received SDP offer
   // so that our local WebRTC layer knows how to talk to the caller.
   var desc = new RTCSessionDescription(msg.sdp);

   myPeerConnection.setRemoteDescription(desc)
   .then(function(stream) {
      log("-- Calling myPeerConnection.addStream()");

      return myPeerConnection.addStream(localStream);
   })
   .then(function() {
      log("------> Creating answer");
      // Now that we've successfully set the remote description, we need to
      // start our stream up locally then create an SDP answer. This SDP
      // data describes the local end of our call, including the codec
      // information, options agreed upon, and so forth.
     return myPeerConnection.createAnswer();
   })
   .then(function(answer) {
      log("------> Setting local description after creating answer");
      // We now have our answer, so establish that as the local description.
      // This actually configures our end of the call to match the settings
      // specified in the SDP.
      return myPeerConnection.setLocalDescription(answer);
   })
   .then(function() {
      var msg = {
         name: clientId,
         room: roomId,
         target: targetUsername,
         type: "video-answer",
         sdp: myPeerConnection.localDescription
      };
    // We've configured our end of the call now. Time to send our
    // answer back to the caller so they know that we want to talk
    // and how to talk to us.
    log("Sending answer packet back to other peer");

    sendToServer(msg);
   })
   .catch(handleGetUserMediaError);
}

When the second client makes the offer, the first client when tries to make the answer, I get the error

Error opening your camera and / or microphone : failed to set local answer spd: Failed to push down transport description: Local fingerprint provided but no identity available.

or

Error opening your camera and / or microphone : failed to set local answer spd: Called in wrong state : STATE_INPROGRESS

Only one time the creation was successful.

Do I have to create DataChannel in other place? Like here :

function handleICEConnectionStateChangeEvent {

   switch(myPeerConnection.iceConnectionState) {
      ...
      case "connected":       
         createDataChannel();
         break;           
   }
}

function createDataChannel(){
    myDataChannel = myPeerConnection.createDataChannel('myDataChannel');
    myPeerConnection.ondatachannel = handleDataChannel;

    myDataChannel.onmessage = handleDataChannelMessage;
    myDataChannel.onopen = handleDataChannelOpen;      
}

Any suggestions?


Solution

  • The error in this code is that both sender and receiver create new datachannel. The right thing is, one to create the datachannel

    myDataChannel = myPeerConnection.createDataChannel('myDataChannel') 
    

    and the other to wait for the creation of dataChannel:

    myPeerConnection.ondatachannel = handleDataChannel;