How to create own Video Stream Platform using “webRTC” React with Simple-peer & socket.io & express nodejs?

Savindu Pasintha
4 min readJun 11, 2021

create New-Folder → Inside Create Frontend-Folder & Backend-Folder.

Frontend Folder Inside Create new React-js app

npx create-react-app “name_website”

Now we should install necessary npm modules.

  • npm i socket.io-client — save

socket.io use to Real time commiunication between the frontend and backend.

  • npm i react-copy-to-clipboard — save

easier to text copy paste.

  • npm i @material-ui/core — save
  • npm i @material-ui/icons — save

material ui use web-UI styling.

+ — Now You can Copy paste App.js File to That codes. — +

import Button from “@material-ui/core/Button”;

import IconButton from “@material-ui/core/IconButton”;

import TextField from “@material-ui/core/TextField”;

import AssignmentIcon from “@material-ui/icons/Assignment”;

import PhoneIcon from “@material-ui/icons/Phone”;

import React, { useEffect, useRef, useState } from “react”;

import { CopyToClipboard } from “react-copy-to-clipboard”;

import Peer from “simple-peer”;

import io from “socket.io-client”;

import “./AudioTransmit.css”;

const socket = io.connect(‘http://localhost:5000')

const App = () => {

const [me, setMe] = useState(“”)

const [stream, setStream] = useState();

const [receivingCall, setReceivingCall] = useState(false);

const [caller, setCaller] = useState(“”);

const [callerSignal, setCallerSignal] = useState();

const [callAccepted, setCallAccepted] = useState(false);

const [idToCall, setIdToCall] = useState(“”);

const [callEnded, setCallEnded] = useState(false);

const [name, setName] = useState(“”);

const myVideo = useRef();

const userVideo = useRef();

const myAudio = useRef();

const userAudio = useRef();

const connectionRef = useRef();

useEffect(() => {

navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then((stream) => {

setStream(stream)

myVideo.current.srcObject = stream;

myAudio.current.srcObject = stream;

})

//emit() used to send data to front end or url

/* endpoint paths in url access back end

https:/3000/me

https:/3000/disconnect

https:/3000/callUser

https:/3000/answerCall

https:/3000/callAccepted

*/

socket.on(“me”, (id) => {

setMe(id);

})

socket.on(“callUser”, (data) => {

setReceivingCall(true)

setCaller(data.from)

setName(data.name)

setCallerSignal(data.signal)

})

}, [])

const callUser = (id) => {

const peer = new Peer({

initiator: true,

trickle: false,

stream: stream

})

peer.on(“signal”, (data) => {

socket.emit(“callUser”, {

userToCall: id,

signalData: data,

from: me,

name: name

})

})

peer.on(“stream”, (stream) => {

userVideo.current.srcObject = stream;

userAudio.current.srcObject = stream;

})

socket.on(“callAccepted”, (signal) => {

setCallAccepted(true)

peer.signal(signal)

})

connectionRef.current = peer;

}

const answerCall = () => {

setCallAccepted(true)

const peer = new Peer({

initiator: false,

trickle: false,

stream: stream

})

peer.on(“signal”, (data) => {

socket.emit(“answerCall”, { signal: data, to: caller })

})

peer.on(“stream”, (stream) => {

userVideo.current.srcObject = stream;

userAudio.current.srcObject = stream;

})

peer.signal(callerSignal);

connectionRef.current = peer;

}

const leaveCall = () => {

setCallEnded(true);

connectionRef.current.destroy();

}

return (

<div>

<h1 style={{ textAlign: “center”, color: ‘#fff’ }}>savindupasingtha@gmail.com with chat</h1>

<p>1-copy uour id 2- paste your friend textbox 3- call 4- answer button click</p>

<div className=”row”>

<div className=”col-6">

<p>You</p>

{stream &&

<audio id=”myaudio” controls ref={myAudio} />

}

</div>

<div className=”col-6">

<p>Friend</p>

{callAccepted && !callEnded ?

<audio id=”friendAudio” controls ref={userAudio} />

: null}

</div>

</div>

<div className=”container”>

<div className=”video-container”>

<div className=”video”>

{stream && <video ref={myVideo} playsInline muted autoPlay controls style={{ width: “300px” }} />}

</div>

<div className=”video”>

{callAccepted && !callEnded ?

<video controls ref={userVideo} playsInline muted autoPlay controls style={{ width: “300px” }} /> :

null}

</div>

</div>

<div className=”myId”>

<TextField

id=”filled-basic”

label=”Name”

variant=”filled”

value={name}

onChange={(e) => setName(e.target.value)}

style={{ marginBottom: “20px” }}

/>

<CopyToClipboard text={me} style={{ marginBottom: “2rem” }}>

<Button variant=”contained” color=”primary” startIcon={<AssignmentIcon fontSize=”large” />}>

Copy ID

</Button>

</CopyToClipboard>

<TextField

id=”filled-basic”

label=”ID to call”

variant=”filled”

value={idToCall}

onChange={(e) => setIdToCall(e.target.value)}

/>

<div className=”call-button”>

{callAccepted && !callEnded ? (

<Button variant=”contained” color=”secondary” onClick={leaveCall}>

End Call

</Button>

) : (

<IconButton color=”primary” aria-label=”call” onClick={() => callUser(idToCall)}>

<PhoneIcon fontSize=”large” />

</IconButton>

)}

{idToCall}

</div>

</div>

<div>

{receivingCall && !callAccepted ? (

<div className=”caller”>

<h1 >{name} is calling…</h1>

<Button variant=”contained” color=”primary” onClick={answerCall}>

Answer

</Button>

</div>

) : null}

</div>

</div>

</div>

);

};

export default App;

Now App.css file to Copy this codes

.container {

display: grid;

grid-template-columns: 7fr 3fr;

}

.myId {

margin-right: 5rem;

border-radius: 5px;

background: #c9d6ff; /* fallback for old browsers */

background: -webkit-linear-gradient(to right, #e2e2e2, #c9d6ff); /* Chrome 10–25, Safari 5.1–6 */

background: linear-gradient(

to right,

#e2e2e2,

#c9d6ff

); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */

padding: 2rem;

display: grid;

justify-content: center;

align-content: center;

}

.call-button {

text-align: center;

margin-top: 2rem;

}

.video-container {

display: grid;

grid-template-columns: 1fr 1fr;

justify-content: center;

align-content: center;

margin-top: 10rem;

margin-left: 10rem;

}

.caller {

text-align: center;

color: #fff;

}

body {

background: #4776e6; /* fallback for old browsers */

background: -webkit-linear-gradient(to right, #8e54e9, #4776e6); /* Chrome 10–25, Safari 5.1–6 */

background: linear-gradient(

to right,

#8e54e9,

#4776e6

); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */

}

Backend Folder now we can start to code.

create package.json file in the root of the tis folder.

npm install express socket.io nodemon cors http — save

  • express is node js framework
  • socket.io used to Real Time Data Commiunication
  • cors — cross origin server Error handle
  • nodemone use to server Real time run without the server close.

edit your package.json file Like this.

create a server.js file root of the back end folder.

copy paste that codes inside to the server.js file.

const express = require(“express”);

const http = require(“http”);

const app = express();

const server = http.createServer(app);

const io = require(“socket.io”)(server, {

cors: {

origin: “http://localhost:3000",

methods: [ “GET”, “POST” ]

}

});

io.on(“connection”, (socket) => {

//emit() used to send data to front end or url

/* endpoint paths in url

https:/5000/me

https:/5000/disconnect

https:/5000/callUser

https:/5000/answerCall

https:/5000/callAccepted

*/

socket.emit(“me”, socket.id);

socket.on(“disconnect”, () => {socket.broadcast.emit(“callEnded”);});

socket.on(“callUser”, (data) => {

io.to(data.userToCall).emit(“callUser”, { signal: data.signalData, from: data.from, name: data.name });

})

socket.on(“answerCall”, (data) => {

io.to(data.to).emit(“callAccepted”, data.signal)

})

})

server.listen(5000, () => console.log(“server is running on port 5000”))

Now you can run your App.

Run React App — npm start

Back end run — node server.js

--

--