Error while connecting a call using webRTC in React App: Failed to set remote answer sdp: Called in wrong state: stable

256 Views Asked by At

Whenever I am clicking on Call button, apparently call is accepted, I am getting my video but then I am getting this error

Failed to set remote answer sdp: Called in wrong state: stable

It shows the error in this function:

async setLocalDescription(ans) {
    if (this.peer) {
      await this.peer.setRemoteDescription(new RTCSessionDescription(ans));
    }
  } 

in peer.js

I looked up the internet, I am setting my LocalDescription before Remote Description, so that is fine.

MDN docs says

This may mean that the RTCPeerConnection object is new, in which case both the localDescription and remoteDescription are null; it may also mean that negotiation is complete and a connection has been established.

How do I resolve it?

This is my code in React

import React, { useCallback, useEffect, useState } from "react";
import { useSocket } from "../context/SocketProvider";
import ReactPlayer from "react-player";
import peer from "../service/peer";

export default function Room() {
  const socket = useSocket();
  const [remoteSocketId, setRemoteSocketId] = useState(null);
  const [myStream, setMyStream] = useState();
  const [remoteStream, setRemoteStream] = useState(null);

  const joinUser = useCallback((data) => {
    const { email, id } = data;
    setRemoteSocketId(id);
    console.log(`Email ${email} joined the room`, remoteSocketId);
  }, []);

  const handleCallUser = useCallback(async () => {
    const stream = await navigator.mediaDevices.getUserMedia({
      audio: true,
      video: true,
    });
    const offer = await peer.getOffer();
    //console.log("Offer is", offer);
    socket.emit("user:call", { to: remoteSocketId, offer: offer });
    setMyStream(stream);
    //stream.getTracks().forEach(track => peer.addTrack(track, stream));
  }, [remoteSocketId, socket]);

  const handleIncomingCall = useCallback(
    async ({ from, offer }) => {
      setRemoteSocketId(from);
      const stream = await navigator.mediaDevices.getUserMedia({
        audio: true,
        video: true,
      });
      setMyStream(stream);
      console.log(`Incoming Call`, from, offer);
      //await peer.setLocalDescription(offer);
      const ans = await peer.getAnswer(offer);
      socket.emit("call:accepted", { to: from, ans });
    },
    [socket]
  );

  

  const handleCallAccepted = useCallback(
    ({ from, ans }) => {
      peer.setLocalDescription(ans);
      console.log("Call Accepted!");
    },
    [    ]
  );

  useEffect(() => {
    socket.on("user_joined", joinUser);
    socket.on("incoming:call", handleIncomingCall);
    socket.on("call:accepted", handleCallAccepted);
    return () => {
      socket.off("user_joined");
      socket.off("incoming:call", handleIncomingCall);
      socket.off("call:accepted", handleCallAccepted);
    };
  }, [
    socket,
    joinUser,
    handleIncomingCall,
    handleCallAccepted,
  ]);

  return (
    <div>
      <h1> This is the Room</h1>
      <h2>{remoteSocketId ? "Connected" : "Not"}</h2>
      {/* {myStream && <button onClick={sendStreams}>Send Stream</button>} */}
      {remoteSocketId && <button onClick={handleCallUser}>CALL</button>}
      {myStream && (
        <>
          <h1>My Stream</h1>

          <ReactPlayer
            playing
            muted
            height="100px"
            width="200px"
            url={myStream}
          />
        </>
      )}
    </div>
  );
}

This is my peer.js which is using all the WebRTC APIs

class PeerService {
  constructor() {
    if (!this.peer) {
      this.peer = new RTCPeerConnection({
        iceServers: [
          {
            urls: [
              "stun:stun.l.google.com:19302",
              "stun:global.stun.twilio.com:3478",
            ],
          },
        ],
      });
    }
  }

  async getAnswer(offer) {
    if (this.peer) {
      await this.peer.setRemoteDescription(offer);
      const ans = await this.peer.createAnswer();
      await this.peer.setLocalDescription(new RTCSessionDescription(ans));
      return ans;
    }
  }

  async setLocalDescription(ans) {
    if (this.peer) {
      await this.peer.setRemoteDescription(new RTCSessionDescription(ans));
    }
  }

  async getOffer() {
    if (this.peer) {
      const offer = await this.peer.createOffer();
      await this.peer.setLocalDescription(new RTCSessionDescription(offer));
      //console.log("Offer 2 is", offer);
      return offer;
    }
  }
}

export default new PeerService();

This is what my webRTC internals says

http://localhost:3000/, { iceServers: [stun:stun.l.google.com:19302, stun:global.stun.twilio.com:3478], iceTransportPolicy: all, bundlePolicy: balanced, rtcpMuxPolicy: require, iceCandidatePoolSize: 0 }

ICE connection state: new
Connection state: new
Signaling state: new
ICE Candidate pair: (not connected)
ICE candidate grid
Stats Tables
Filter statistics by type including 
separate multiple values by `,`
media-playout (kind=audio, id=AP)
peer-connection (id=P)
Filter statistics graphs by type including 
separate multiple values by `,`
Stats graphs for media-playout (kind=audio, id=AP)
Stats graphs for peer-connection (id=P)
0

There are 0 best solutions below