11

I am getting this error in my catch block when I do myPeerConnection.createAnswer()

PeerConnection cannot create an answer in a state other than have-remote-offer or have-local-pranswer.

I am using socket.io as the signalling server. I am following the tutorial from MDN

Here's my code:

myPeerConnection.setRemoteDescription(desc).then(() => {
    return navigator.mediaDevices.getUserMedia(mediaConstraints);
  }).then((stream) => {
    localStream = stream;
    document.getElementById("localVideo").srcObject = localStream;
    return myPeerConnection.addStream(localStream);
  }).then(() => {
    return myPeerConnection.createAnswer(); //No error when removed this then chain
  }).then((answer) => {
    return myPeerConnection.setLocalDescription(answer); // No error when removed this then chain
  }).then(() => {
    socket.emit('video-answer', {
      sdp: myPeerConnection.localDescription
    });
  }).catch(handleGetUserMediaError);

The answer here didn't helped me either.

I have uploaded the whole project on Github. You can look at the script file here.

Any help is appreciated.

DragonBorn
  • 1,809
  • 5
  • 20
  • 44
  • in the tutorial they use `local_video` as the element Id, did you change yours? – Cody G Jun 29 '18 at 13:04
  • @CodyG. Yes, I changed it in the Html too. – DragonBorn Jun 30 '18 at 05:09
  • Is this in Chrome? They have a [bug](https://bugs.chromium.org/p/chromium/issues/detail?id=665200). Try it in Firefox. – jib Jun 30 '18 at 12:43
  • @DragonBorn Hi, were you able to find a fix for this? I am also facing the same problem in chrome. It works fine in firefox. – helloworld Sep 19 '18 at 16:13
  • @helloworld Yes i did find a fix. I even created a basic working application. I have uploaded the file [here](https://github.com/SL-A-SH/VideoAppointment/blob/master/client/src/components/video/startOneToOneCall.js). Let me know if you need any help. – DragonBorn Sep 20 '18 at 05:40
  • @DragonBorn Thanks a lot. I will have a look. – helloworld Sep 21 '18 at 13:39
  • @DragonBorn I am not able to figure out what change you did. Can you please let me know why the issue was coming in chrome and what you did to fix this. Understanding from the code is kinda difficult for me. – helloworld Sep 22 '18 at 12:27
  • 2
    @helloworld In chrome the `negotiationneeded` event was getting fired twice when it should get called once. I stopped using `onnegotiationneeded` overall and it worked. – DragonBorn Sep 23 '18 at 09:25

2 Answers2

6

This is long-standing a bug in Chrome I filed a year and a half ago.

You're creating a peer connection in both the onclick handler and handleVideoOfferMsg, complete with an onnegotiationneeded handler that calls createOffer. That's OK and straight out of the spec example.

In handleVideoOfferMsg you go on to call setRemoteDescription(desc), bringing that peer connection to have-remote-offer state, and then you add tracks to it for your answer.

The bug in Chrome is that adding those tracks fire the negotiationneeded event, when the spec says to only set the negotiationneeded flag in "stable" state.

Try it in Firefox. It should work there.

You can work around this in Chrome somewhat, like this:

pc.onnegotiationneeded = e => {
  if (pc.signalingState != "stable") return;
  ..
}
jib
  • 40,579
  • 17
  • 100
  • 158
  • Yup it did work for me on firefox without giving any errors and I tried your work around for Chrome but it still gives me the same error. I guess I have to wait for Chrome developers to fix that bug. – DragonBorn Jul 01 '18 at 14:48
  • 1
    @DragonBorn Sorry for dropping the ball. Yes, there are actually *two* bugs in Chrome here. See [my other answer](https://stackoverflow.com/a/53035315/918910) for a workaround for both. – jib Jan 03 '19 at 15:09
3

Metaphorically speaking, you are trying to answer a question without being asked a question. This does not make sense -- and the peerconnection API tells you exactly that.

Philipp Hancke
  • 15,855
  • 2
  • 23
  • 31
  • But I did create an `offer` first then sent my local description and in the response I am creating an `answer`. You can check the the whole script file in the link in the question. – DragonBorn Jun 30 '18 at 07:38
  • looks like I need to get new glasses, i missed that. what is myPeerConnection.signalingState before you call createAnswer? Also check if the setRemoteDescription call happens twice. This might happen due to Chrome triggering the negotiationneeded event too often. – Philipp Hancke Jun 30 '18 at 10:38
  • Yes the `setRemoteDescription` for the **callee** is being called twice. I have no idea why. How can I prevent that to happen? And since it is being called twice the value for `myPeerConnection.signalingState` is **have-remote-offer** first time and **have-local-offer** the second time. – DragonBorn Jun 30 '18 at 10:49
  • 1
    ah... you are calling createPeerConnection both in the onclick handler and handleVideoOfferMsg. Both times you are adding a negotiatonneeded handler which will call createOffer. This is the wrong behaviour in handleVideoOfferMsg. – Philipp Hancke Jun 30 '18 at 12:21
  • 1
    @PhilippHancke that should be fine once Chrome fixes [their bug](https://bugs.chromium.org/p/chromium/issues/detail?id=665200). – jib Jun 30 '18 at 12:41