peers / peerjs

Simple peer-to-peer with WebRTC.
https://peerjs.com
MIT License
12.5k stars 1.43k forks source link

peerjs not calling unless warped with setTimeout() method for 1 second #1297

Closed aynuayex closed 2 months ago

aynuayex commented 2 months ago

Please, check for existing issues to avoid duplicates.

What happened?

when a new meeting is created and a new user joins the room i want the already existing or joined users to be able to call the new joined user, but it does not seem to work unless warped with setTimeout method as shown below. note that i have tried to run the peerjs server locally but still doesn't work unless i use the setTimeout method.

import Peer from "peerjs";
import { createContext, useEffect, useReducer, useState } from "react";
import { useNavigate } from "react-router-dom";
import socketIO from "socket.io-client";
import { v4 as uuidV4 } from "uuid";
import { peersReducer } from "./peerReducer";
import { addPeerAction, removePeerAction } from "./peerActions";

const server = "http://localhost:8080";
const ws = socketIO(server);

export const RoomContext = createContext<any | null>(null);

export const RoomProvider = ({ children }: { children: React.ReactNode }) => {
  const navigate = useNavigate();
  const [me, setMe] = useState<Peer>();
  const [stream, setStream] = useState<MediaStream>();
  const [roomId, setRoomId] = useState<string>("");
  const [peers, dispatch] = useReducer(peersReducer, {});

  const enterRoom = ({ roomId }: { roomId: string }) => {
    navigate(`/room/${roomId}`);
  };

  const removePeer = (peerId: string) => {
    dispatch(removePeerAction(peerId));
  };

  useEffect(() => {
    const meId = uuidV4();
    const peer = new Peer(
      meId
        , {
        host: "localhost",
        port: 9000,
        path: "/myapp",
      }
    );
    peer && setMe(peer);
    try {
      navigator.mediaDevices
        .getUserMedia({ video: true, audio: true })
        .then((stream) => setStream(stream));
    } catch (err) {
      console.error("Error accessing media devices.", err);
    }
    ws.on("room-created", enterRoom);
    ws.on("user-disconnected", removePeer);

    return () => {
      ws.off("room-created");
      ws.off("user-disconnected");
    };
  }, []);

  useEffect(() => {
    console.log({ me, stream });
    if (!me || !stream) return;
    ws.on("user-joined", (peerId) => {
      console.log("user joined a room!", peerId);
      // here if setTimeout is commented out it does not work
      // setTimeout(() => {
        const call = me.call(peerId, stream);
        call.on("stream", (peerStream) => {
          console.log("hi inside");
          dispatch(addPeerAction(peerId, peerStream));
        });
      // }, 1000);
    });
    me.on("call", (call) => {
      call.answer(stream);
      call.on("stream", (peerStream) => {
        dispatch(addPeerAction(call.peer, peerStream));
      });
    });
  }, [me, stream]);

  return (
    <RoomContext.Provider
      value={{ ws, me, stream, peers, shareScreen, screenSharingId, setRoomId }}
    >
      {children}
    </RoomContext.Provider>
  );
};

How can we reproduce the issue?

you can go a head and clone the code from this repo and you can run both the client and server with npm run dev after installing the packages needed for each of them using npm i

What do you expected to happen?

i already explained it above, so no needed to repeat my self, i guess.

Environment setup

Is this a regression?

No response

Anything else?

No response

aynuayex commented 2 months ago

this is caused by the way i use peerjs and it is not related to the library in any way. the issue was caused by not registering the call event early in my code and that is why it is sometimes working after adding setTimeout of 1 second before calling, giving enough time for the event to be registered.so to fix this issue just register the call event immediately after the peer connection creation which is on the first useEffect as shown bellow

useEffect(() => {
    const savedId = sessionStorage.getItem("userId");
    const userId = savedId || uuidV4();

    sessionStorage.setItem("userId", userId);
    const peer = new Peer(userId, {
      // host: "localhost",
      // port: 9000,
      // path: "/myapp",
    });
    meRef.current = peer;

    // Register event handlers for the peer
    peer.on("open", () => {
      console.log("Peer connection is open with ID:", peer.id);
    });

    peer.on("error", (err) => {
      console.error({ err });
    });
    peer.on("call", (call) => {
    // handle your logic here.
    });

    // Set up media stream
    navigator.mediaDevices
      .getUserMedia({ video: true, audio: true })
      .then((stream) => {
        setStream(stream);
      })
      .catch((err) => {
        console.error("Error accessing media devices.", err);
      });

  }, []);

and also you can add call retry logic on the call implementation so that if the call fails for some reason you can retry it for some amount.