I am trying to make a React
web chat platform using webRTC
, socket.io-client
, and simple-peer
. I followed a tutorial and used their code but I keep getting this error.
The error happens every second or so and I'm not sure why.
Here is my code for the component (Room.js
) that I am importing in my App.js
:
import React, { useEffect, useState, useRef } from 'react';
import '../App.css';
import io from "socket.io-client";
import Peer from "simple-peer";
import styled from "styled-components";
const Container = styled.div`
height: 100vh;
width: 100%;
display: flex;
flex-direction: column;
`;
const Row = styled.div`
display: flex;
width: 100%;
`;
const Video = styled.video`
border: 1px solid blue;
width: 50%;
height: 50%;
`;
function Room() {
const [yourID, setYourID] = useState("");
const [users, setUsers] = useState({});
const [stream, setStream] = useState();
const [receivingCall, setReceivingCall] = useState(false);
const [caller, setCaller] = useState("");
const [callerSignal, setCallerSignal] = useState();
const [callAccepted, setCallAccepted] = useState(false);
const userVideo = useRef();
const partnerVideo = useRef();
const socket = useRef();
useEffect(() => {
socket.current = io.connect("/");
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(stream => {
setStream(stream);
if (userVideo.current) {
userVideo.current.srcObject = stream;
}
})
socket.current.on("yourID", (id) => {
setYourID(id);
})
socket.current.on("allUsers", (users) => {
setUsers(users);
})
socket.current.on("hey", (data) => {
setReceivingCall(true);
setCaller(data.from);
setCallerSignal(data.signal);
})
}, []);
function callPeer(id) {
const peer = new Peer({
initiator: true,
trickle: false,
config: {
iceServers: [
{
urls: "stun:numb.viagenie.ca",
username: "sultan1640@gmail.com",
credential: "98376683"
},
{
urls: "turn:numb.viagenie.ca",
username: "sultan1640@gmail.com",
credential: "98376683"
}
]
},
stream: stream,
});
peer.on("signal", data => {
socket.current.emit("callUser", { userToCall: id, signalData: data, from: yourID })
})
peer.on("stream", stream => {
if (partnerVideo.current) {
partnerVideo.current.srcObject = stream;
}
});
socket.current.on("callAccepted", signal => {
setCallAccepted(true);
peer.signal(signal);
})
}
function acceptCall() {
setCallAccepted(true);
const peer = new Peer({
initiator: false,
trickle: false,
stream: stream,
});
peer.on("signal", data => {
socket.current.emit("acceptCall", { signal: data, to: caller })
})
peer.on("stream", stream => {
partnerVideo.current.srcObject = stream;
});
peer.signal(callerSignal);
}
let UserVideo;
if (stream) {
UserVideo = (
<Video playsInline muted ref={userVideo} autoPlay />
);
}
let PartnerVideo;
if (callAccepted) {
PartnerVideo = (
<Video playsInline ref={partnerVideo} autoPlay />
);
}
let incomingCall;
if (receivingCall) {
incomingCall = (
<div>
<h1>{caller} is calling you</h1>
<button onClick={acceptCall}>Accept</button>
</div>
)
}
return (
<Container>
<Row>
{UserVideo}
{PartnerVideo}
</Row>
<Row>
{Object.keys(users).map(key => {
if (key === yourID) {
return null;
}
return (
<button onClick={() => callPeer(key)}>Call {key}</button>
);
})}
</Row>
<Row>
{incomingCall}
</Row>
</Container>
);
}
export default Room;
Here is my App.js
file:
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import './App.css';
import { ApolloProvider } from '@apollo/react-hooks';
import ApolloClient from 'apollo-boost';
import coverImg from './assets/videochat.jpg';
//components
import Room from './pages/Room';
import Cover from './components/Cover'
const client = new ApolloClient({
request: operation => {
const token = localStorage.getItem('User_token');
operation.setContext({
headers: {
authorization: token ? `Bearer ${token}` : ''
}
});
},
uri: '/graphql'
});
function App() {
return (
<ApolloProvider client={client}>
<Router>
<>
<Navbar />
<Switch>
<Route exact path="/" component={Cover}/>
<Route path='/create-room' component={Room} />
</Switch>
</>
</Router>
</ApolloProvider>
);
}
export default App;
And then here is my server.js
file:
// const express = require('express')
// const app = express()
// const server = require('http').Server(app)
// const io = require('socket.io')(server)
// const { v4: uuidV4 } = require('uuid')
// app.set('view engine', 'ejs')
// app.use(express.static('public'))
// app.get('/create-room', (req, res) => {
// console.log("does this work")
// res.redirect(`/${uuidV4()}`)
// })
// app.get('/:room', (req, res) => {
// res.render('../client/src/pages/room', { roomId: req.params.room })
// })
// io.on('connection', socket => {
// socket.on('join-room', (roomId, userId) => {
// if (!person[socket.id]) {
// person[socket.id] = socket.id;
// }
// socket.emit("yourID", socket.id);
// io.sockets.emit("allUsers", person);
// socket.on("disconnect", () => {
// delete person[socket.id];
// });
// socket.on("callUser", (data) => {
// io.to(data.userToCall).emit("hey", {
// signal: data.signalData,
// from: data.from,
// });
// });
// socket.on("acceptCall", (data) => {
// io.to(data.to).emit("callAccepted", data.signal);
// });
// socket.join(roomId)
// socket.to(roomId).broadcast.emit('user-connected', userId)
// socket.on('disconnect', () => {
// socket.to(roomId).broadcast.emit('user-disconnected', userId)
// })
// })
// })
// server.listen(3000)
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 = {};
io.on('connection', socket => {
if (!users[socket.id]) {
users[socket.id] = socket.id;
}
socket.emit("yourID", socket.id);
io.sockets.emit("allUsers", users);
socket.on('disconnect', () => {
delete users[socket.id];
})
socket.on("callUser", (data) => {
io.to(data.userToCall).emit('hey', {signal: data.signalData, from: data.from});
})
socket.on("acceptCall", (data) => {
io.to(data.to).emit('callAccepted', data.signal);
})
});
// For some reason the console.log is not printed either
server.listen(3000, () => console.log('server is running on port 3000'));
This is my project file structure:
project name
.env
package.json
package-lock.json
.gitignore
server
server.js
client
public
react-images
src
pages
Room.js
App.js
index.js
App.css
App.test.js
serviceWorker.js
setupTests.js
.gitIgnore
package.json
package-lock.js
README.md
I was able to figure out my error and thought to post it here for any future people.
In my server.js
file I needed it to run on a different port so that my actual client side code use the server on a different port. To do this you just have to change this:
server.listen(3000, () => console.log('server is running on port 3000'));
to this:
server.listen(8000, () => console.log('server is running on port 8000'));
Changing that line means that your server will run on http://localhost:8000. Another one of my errors was that my client side code was not linked to the server, which means that all of the code I wrote in server.js
was irrelevant to the client side code.
To change this you have to add a line to the package.json
file in the client
folder. Instead of having this:
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"@apollo/react-hooks": "^4.0.0",
change it to this:
{
"name": "client",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:8000",
"dependencies": {
"@apollo/react-hooks": "^4.0.0",
Now your code should work! Good Luck!!!