feross / simple-peer

📡 Simple WebRTC video, voice, and data channels
MIT License
7.43k stars 974 forks source link

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

Open kikichen77 opened 1 year ago

kikichen77 commented 1 year ago

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" ] } } `

szcuipeng commented 1 year ago

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.