0

I have built a video calling app that enables video communication between two peers. When I open the site (hosted on Surge, server hosted on render.com) on a single system with two different tabs corresponding to local peer and system peer, I am able to see my video as well as remote video. Since, both tabs are accessing same camera, I see my video on both local and remote streams. But when I open the app from two different systems, I only see my video, remote peer's video is not visible. This is the error that occurs:

Uncaught ReferenceError: process is not defined
at O (_stream_readable.js:490:13)
at _stream_readable.js:469:5
at x (_stream_readable.js:240:5)
at S.push (_stream_readable.js:228:10)
at index.js:448:44

This is my server side code

onst express = require("express");
const { Server } = require("socket.io");
const multer = require("multer");
const path = require("path");
const fs = require("fs");
const cors = require("cors");

const app = express();
const upload = multer({ dest: "uploads/" });

const emailToSocketid = new Map();
const socketidToEmail = new Map();

const io = new Server(8000, {
  cors: true,
});



io.on("connection", (socket) => {
  console.log(`Socket connected with id ${socket.id}`);

  socket.on("join room", (data) => {
    const { email, room } = data;
    emailToSocketid.set(email, socket.id);
    socketidToEmail.set(socket.id, email);
    console.log(email, room, socket.id);

    io.to(room).emit("user_joined", { email: email, id: socket.id }); // To all sockets excluding sender
    socket.join(room);

    io.to(socket.id).emit("room_join", data);

    socket.on("callUser", ({ userToCall, signalData /* , from, name */ }) => {
      io.to(userToCall).emit("incomingCall", {
        signal: signalData,
        from: socket.id,
      });
    });

    socket.on("answerCall", (data) => {
      io.to(data.to).emit("callAccepted", data.signal);
    });

    socket.on("file", (fileInfo) => {
      io.emit("file", fileInfo);
    });

    socket.on("disconnect", () => {
      const email = socketidToEmail.get(socket.id);
      if (email) {
        emailToSocketid.delete(email);
        socketidToEmail.delete(socket.id);
      }
    });
  });
});

This is my client-side code

import React, { useCallback, useEffect, useState, useRef } from "react";
import { useSocket } from "../context/SocketProvider";
import Peer from "simple-peer";

export default function Room() {
  const { socket } = useSocket();
  const [remoteSocketId, setRemoteSocketId] = useState(null);
  const [myStream, setMyStream] = useState();
  const [remoteStream, setRemoteStream] = useState();
  const currentVideoRef = useRef(null);
  const remoteVideoRef = useRef(null);
  const [callAccepted, setCallAccepted] = useState(false);
  const [receivedFiles, setReceivedFiles] = useState([]);

  const [callInitiated, setCallInitiated] = useState(false);

  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,
    });
    setMyStream(stream);

    const peer = new Peer({ initiator: true, trickle: false, stream });

    peer.on("signal", (data) => {
      // Fired  when peer wants to send signalling data to remote peer
      socket.emit("callUser", {
        userToCall: remoteSocketId,
        signalData: data,
        /*  from: me, */
      });
    });

    peer.on("stream", (currentStream) => {
      setRemoteStream(currentStream); //peer.on("stream") event listener is responsible for setting the received
    }); //stream to the remoteStream state variable, allowing the remote video
    // element to display the video of the respective peer.
    socket.on("callAccepted", (signal) => {
      setCallAccepted(true);
      setCallInitiated(true);
      peer.signal(signal);
    });

    //connectionRef.current = peer;
  }, [remoteSocketId, socket]);

  const answerCall = useCallback(
    async (call) => {
      console.log("Call is", call);
      setCallAccepted(true);

      const stream = await navigator.mediaDevices.getUserMedia({
        audio: true,
        video: true,
      });
      setRemoteStream(stream);

      const peer = new Peer({ initiator: false, trickle: false, stream });

      peer.on("signal", (data) => {
        socket.emit("answerCall", { signal: data, to: call.from });
      });

      peer.on("stream", (currentStream) => {
        setRemoteStream(currentStream);
      });

      peer.signal(call.signal); // call this method whenever the remote peer emits a peer.on('signal') event.
      //The data will encapsulate a webrtc offer, answer, or ice candidate. These messages help the peers to eventually establish a direct connection to each other.
    },
    [socket]
  );

  const fileHandler = useCallback((fileData) => {
    console.log("Received file:", fileData);
    setReceivedFiles((prevFiles) => [...prevFiles, fileData]);
  }, []);

  useEffect(() => {
    socket.on("user_joined", joinUser);
    socket.on("incomingCall", answerCall);
    socket.on("file", fileHandler);

    return () => {
      socket.off("user_joined");
      socket.off("incomingCall");
      socket.off("file", fileHandler);
    };
  }, [socket, joinUser, answerCall]);

  useEffect(() => {
    if (currentVideoRef.current && myStream) {
      currentVideoRef.current.srcObject = myStream;
    }
  }, [myStream]);

  useEffect(() => {
    if (remoteVideoRef.current && remoteStream) {
      console.log("Setting remote video ref");
      remoteVideoRef.current.srcObject = remoteStream;
    }
  }, [remoteStream]);

  useEffect(() => {
    if (callAccepted && !callInitiated) {
      const updateStream = async () => {
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: true,
          video: true,
        });
        setMyStream(stream);
      };

      updateStream();
    }
  }, [callAccepted, callInitiated]);

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

          <video ref={currentVideoRef} autoPlay muted playsInline />
          <input type="file" onChange={(e) => sendFile(e.target.files[0])} />
        </>
      )}
      {remoteStream && (
        <>
          <h1>Remote Stream</h1>
          <video ref={remoteVideoRef} autoPlay muted playsInline />
        </>
      )}
    </div>
  );
}

The app is built using MERN stack, socket.io and simple-peer.js library.

  • Can someone pls bring this question's attention to Mr. Dirk V (https://stackoverflow.com/users/4051258/dirk-v). He has answered a lot of questions on this topic – Kshitij Verma Jul 05 '23 at 17:50

1 Answers1

0

navigator.mediaDevices.getUserMedia only works over an HTTPS connection. The reason it was working on the same machine is because you most likely used localhost to get to it, which works on HTTP. You can test this by opening the browser on the same machine using your ip address rather than localhost.

toyota Supra
  • 3,181
  • 4
  • 15
  • 19
Andy K
  • 3
  • 3