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.
navigator.mediaDevices.getUserMediaonly 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 youripaddress rather than localhost.