我构建了一个视频通话应用程序,可以在两个点之间进行视频通信。当我在单个系统上打开具有对应于本地对等点和系统对等点的两个不同选项卡的站点(托管在 Surge 上,服务器托管在 render.com 上)时,我能够看到我的视频以及远程视频。由于两个选项卡都访问同一摄像头,因此我可以在本地和远程流上看到我的视频。 但是当我从两个不同的系统打开应用程序时,我只能看到我的视频,远程对等方的视频不可见。 这是发生的错误:
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
这是我的服务器端代码
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);
}
});
});
});
这是我的客户端代码
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>
);
}
该应用程序是使用 MERN 堆栈、socket.io 和 simple-peer.js 库构建的。
navigator.mediaDevices.getUserMedia 仅适用于 HTTPS 连接。它在同一台机器上工作的原因是因为您很可能使用 localhost 来访问它,它在 HTTP 上工作。您可以通过使用您的 IP 地址而不是本地主机在同一台计算机上打开浏览器来测试这一点。