feross / simple-peer

📡 Simple WebRTC video, voice, and data channels

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote answer sdp: Called in wrong state: stable (

kikichen77 opened this issue · comments

When I upgrade the latest version of react, react-dom, react-routers-dom, the normal previous code has the error of MException: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote answer sdp: Called in wrong state: stable
(
`client-side
import { useState,useRef,useEffect} from "react";
import io from "socket.io-client";
import SimplePeer from "simple-peer";
import { useParams } from "react-router-dom";

const Video = (props) => {
const ref = useRef();

useEffect(() => {
  props.peer.on('stream', (stream) => {
    ref.current.srcObject = stream;
  });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<video
style={{ width: "100%", transform: "rotateY(180deg)" }}
ref={ref}
autoPlay
muted
playsInline
>
);
};

const Room=()=>{
const username="wa"
const [peers, setPeers] = useState([]);
const socketRef = useRef();
const userVideo = useRef();
const peersRef = useRef([]);
const { id } = useParams();
const roomID = id;

useEffect(() => {
  socketRef.current = io.connect("http://localhost:8000/");
  navigator.mediaDevices.getUserMedia({ video: true, audio: false }).then(stream => {
    userVideo.current.srcObject = stream;
    socketRef.current.emit("join room", roomID);
    socketRef.current.on("all users", users => {
        const peers = [];
        users.forEach(userID => {
            const peer = createPeer(userID, socketRef.current.id, stream);
            peersRef.current.push({
                peerID: userID,
                peer,
            })
            peers.push(peer);
        })
        setPeers(peers);
    })

    socketRef.current.on("user joined", payload => {
        const peer = addPeer(payload.signal, payload.callerID, stream);
        peersRef.current.push({
            peerID: payload.callerID,
            peer,
        })

        setPeers(users => [...users, peer]);
    });

    socketRef.current.on("receiving returned signal", payload => {
      const item = peersRef.current.find(p => p.peerID === payload.id);
      if (!item.peer.destroyed) {
        item.peer.signal(payload.signal);
      }
    });
    
})

// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

function createPeer(userToSignal, callerID, stream) {
try {
const peer = new SimplePeer({
initiator: true,
trickle: false,
config: {
iceServers: [
{
urls: "stun:stun.l.google.com:19302",
},
],
},
stream: stream,
});

// Move error event listener to the beginning
peer.on("error", (error) => {
  console.error("Peer error:", error);
});

peer.on('signal', (signal) => {
  console.log("Peer signal:", signal);
  socketRef.current.emit('sending signal', { userToSignal, callerID, signal });
});

return peer;

} catch (error) {
console.log("Peer creation error:", error);
}
}

function addPeer(incomingSignal, callerID, stream) {
const peer = new SimplePeer({
initiator: false,
trickle: false,
config: {
iceServers: [
{
urls: "stun:stun.l.google.com:19302",
}],
},
stream: stream,
});
console.log(1)

// Move error event listener to the beginning
peer.on("error", (error) => {
console.error("Peer error:", error);
});

peer.on('signal', (signal) => {
console.log(2)
socketRef.current.emit('returning signal', { signal, callerID });
});

setTimeout(() => {
console.log(3)
// if (peer._pc.signalingState !== "stable") {
//console.log(4)
peer.signal(incomingSignal);
// }
}, 100);

return peer;
}

return (
  <div className="video-wrap">
    <span style={{ position: "absolute", top: "1px", left: "1px" }}>
      {username}
    </span>
    <video
      style={{ width: "100%", transform: "rotateY(180deg)" }}
      ref={userVideo}
      autoPlay
      muted
      playsInline
    ></video>
    {peers.map((peer, index) => {
      return <Video key={index} peer={peer} />;
    })}
  </div>
);

}
export default Room;
``server-side
require('dotenv').config();
const express = require("express");
const http = require("http");
const app = express();
const server = http.createServer(app);
const socket = require("socket.io");
const io = socket(server);

const users = {};

const socketToRoom = {};

io.on('connection', socket => {
socket.on("join room", roomID => {
// console.log("Join room event triggered for room:", roomID);
if (users[roomID]) {
const length = users[roomID].length;
// console.log(length);
if (length === 8) {
socket.emit("room full");
return;
}
// Check if socket.id is not already in the users[roomID] array before pushing it
if (!users[roomID].includes(socket.id)) {
users[roomID].push(socket.id);
}
} else {
users[roomID] = [socket.id];
}
socketToRoom[socket.id] = roomID;
const usersInThisRoom = users[roomID].filter(id => id !== socket.id);
console.log(usersInThisRoom)
socket.emit("all users", usersInThisRoom);
});

socket.on("sending signal", payload => {
    io.to(payload.userToSignal).emit('user joined', { signal: payload.signal, callerID: payload.callerID });    
  });

socket.on("returning signal", payload => {
    io.to(payload.callerID).emit('receiving returned signal', { signal: payload.signal, id: socket.id });
});

socket.on('disconnect', () => {
    const roomID = socketToRoom[socket.id];
    let room = users[roomID];
    if (room) {
        room = room.filter(id => id !== socket.id);
        users[roomID] = room;
    }
});

});

server.listen(8000, () => console.log('server is running on port 8000'));
version:
{
"name": "client",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:8000",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.10.0",
"react-scripts": "3.4.1",
"simple-peer": "^9.11.1",
"socket.io-client": "^2.3.0",
"styled-components": "^5.1.0",
"uuid": "^7.0.3",
"vite": "^4.3.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
`

i got the same error, i found i made a mistake:

correct:
create peer1 (initiator) and peer2 -->
send peer1's signal data to peer2 -->
send peer2's signal data to peer1

wrong:
create peer1 (initiator) and peer2 -->
send peer1's signal data to peer2 -->
send peer2's signal data to peer3, then peer3 output a console error:

Failed to execute 'setRemoteDescription' on 'RTCPeerConnection':
Failed to set remote answer sdp: Called in wrong state: stable

to avoid this, i add an uuid property to peer object.
everytime i send/recv/call signal data, i check if peer1(initiator) and peerx has the same uuid.
if not same, restart all.