Part 2: How to implement WebRTC using JavaScript and Node.js in the Backend
Tutorials in this Series
- Understanding WebRTC
- Implementing WebRTC in code (this tutorial)
In the previous tutorial, we learned about the fundamentals of WebRTC.
In this tutorial, we will learn how to implement those concepts in code and create a website for online video-conferencing.
Live Demo
You can see and use the website live in action at the link mentioned below. You just have to enter the room name to create/join a room.
WebTutsPlus Webcon
Note:-
- The website currently supports only 2 persons per room.
Video
You can also watch the following video to see how to use this website.
Requirements
If you have not read the previous tutorial, it is highly recommended that you read it before you begin this tutorial.
We will use the following:-
- Node.Js (version 12.14.1) — Runtime Env for JS
- Socket.IO (version 1.2.0) — for signaling in WebRTC
- Express.Js: (version 4.17.1) — BackEnd Framework
- Code Editor (Microsoft Visual Studio Code recommended)
- A Good Browser (Google Chrome Recommended)
We will use Node.Js with Express.Js Framework for the backend. If you are not familiar with Node.Js and Express.Js but you know any other MVC framework, DON’T WORRY. We have tried to explain in such a way that you should be able to understand even if you have never worked with Node.Js & Express.Js
Step 1. Setting up the Project
Let’s begin with setting up the project.
Step 1.1. Download Node.Js
- You can download Node.Js for your platform by clicking on this link. Downloading Node.Js will automatically install NPM (Node Package Manager) on your PC. NPM is the default Package Manager for Node.Js
Step 1.2. Create a node project
- Create a New Folder. This folder will be the root directory for our project.
- Open terminal/CMD in this folder and run the command npm init .
- Press the Enter Key continuosly to skip the additional configurations for the project and write YES when prompted.
- This will create a file package.json in the root directory of the project. This file will contain all the necessary information regarding our project like project dependencies.
Step 1.3. Installing dependencies
- In the terminal, run the following command. It will install the dependencies — Express.JS and socket.IO in our project.
npm install express@4.17.1 socket.io@1.2.0 --save
- The flag
--save
will save the name and versions of these dependencies inpackage.json
for future reference. - After the above command has finished execution, you will see a folder
node_modules
created in the root directory of the project. This folder contains the dependencies that we have just installed.
Now we have finished setting up the project. The following is the project structure at this stage.
Step 2. Creating The BackEnd
Let us now begin writing the code for the backend. Before we begin, let’s revise a few points from the previous tutorial.
- We need a backend server for signaling.
- Certain information — Candidate (network) information & Media Codecs must be exchanged between the two peers before a direct connection can be made between them using WebRTC.
- Signaling refers to the mechanism using which two peers exchange this information
The above points tell us that we have to implement a mechanism using which two clients (browsers) can send messages to each other. We will use Socket.IO for this purpose. Socket.IO is suited to learning about WebRTC signaling because of its built-in concept of ‘rooms’. Let’s first discuss what is Socket.IO
Socket.IO
- Socket.IO consists of two parts—
client Library
&server Library
. Obviously, theclient library
is used on the client-side &server library
is used on the server-side. - Socket.IO helps in implementing the following — Let’s say four clients are connected to the server. When the server receives a new message from one client, it should notify all the other clients and also forward this message to the other client. It is similar to a group chat.
- In Socket.IO, each message, that is sent to the server or received from the server, is associated with an event. So, if a client sends a message to the server on a particular event, the server will forward this message to only those clients that are listening to this corresponding event.
- There are some reserved events. However, we can also define custom events. To know about the reserved events, you can visit this link.
- Also, the clients can join a room and ask the server to send the message to only those clients that have joined a particular room.
Now that we have discussed Socket.IO, we can begin implementing the backend server
Step 2.1. Create a file index.js
- In the Express framework,
index.js
is the starting point for our server by default. So create a file index.js at the root level of our project.
Step 2.2. Create a Public folder and a views folder
- Create the following folders at the root level of our project
-
public
— contains the static files like CSS and JS files for the frontend -
views
— contains the views for the frontend
-
Our website will only contain one page. Inside the views folder, create a file index.ejs that will contain the HTML code for the frontend. Expresses uses ejs as the templating engine.
The project structure will now look like the following
Step 2.3. Initialize Express and an HTTP Server-
Now, we must initialize Express, HTTP server, and Socket.IO for our backend. To do this, paste the following code in the
index.js
located at the root level of the project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters'use strict'; //Loading dependencies & initializing express var os = require('os'); //for operating system-related utility methods and properties var express = require('express'); var app = express(); var http = require('http');//for creating http server //For signalling in WebRTC var socketIO = require('socket.io'); //Define the folder which contains the CSS and JS for the fontend app.use(express.static('public')) //Define a route app.get("/", function(req, res){ //Render a view (located in the directory views/) on this route res.render("index.ejs"); }); //Initialize http server and associate it with express var server = http.createServer(app); //Ports on which server should listen - 8000 or the one provided by the environment server.listen(process.env.PORT || 8000); //Initialize socket.io var io = socketIO(server); - Now, it is time to implement Socket.IO in the backend.
- Paste the following code in
index.js
fileThis file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters//Initializing Express and other dependencies ... ... var io = socketIO(server); //Implementing Socket.io //connection is a synonym of reserved event connect //connection event is fired as soon as a client connects to this socket. io.sockets.on('connection', function(socket) { // Convenience function to log server messages on the client. // Arguments is an array like object which contains all the arguments of log(). // To push all the arguments of log() in array, we have to use apply(). function log() { var array = ['Message from server:']; array.push.apply(array, arguments); socket.emit('log', array); } //Defining Server behavious on Socket Events socket.on('message', function(message, room) { log('Client said: ', message); //server should send the receive only in room socket.in(room).emit('message', message, room); }); //Event for joining/creating room socket.on('create or join', function(room) { log('Received request to create or join room ' + room); //Finding clients in the current room var clientsInRoom = io.sockets.adapter.rooms[room]; var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0; log('Room ' + room + ' now has ' + numClients + ' client(s)'); //If no client is in the room, create a room and add the current client if (numClients === 0) { socket.join(room); log('Client ID ' + socket.id + ' created room ' + room); socket.emit('created', room, socket.id); } //If one client is already in the room, add this client in the room else if (numClients === 1) { log('Client ID ' + socket.id + ' joined room ' + room); io.sockets.in(room).emit('join', room); socket.join(room); socket.emit('joined', room, socket.id); io.sockets.in(room).emit('ready'); } //If two clients are already present in the room, do not add the current client in the room else { // max two clients socket.emit('full', room); } }); //Utility event socket.on('ipaddr', function() { var ifaces = os.networkInterfaces(); for (var dev in ifaces) { ifaces[dev].forEach(function(details) { if (details.family === 'IPv4' && details.address !== '127.0.0.1') { socket.emit('ipaddr', details.address); } }); } }); //Event for notifying other clients when a client leaves the room socket.on('bye', function(){ console.log('received bye'); }); }); index.js
.This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters'use strict'; //Loading dependencies & initializing express var os = require('os'); var express = require('express'); var app = express(); var http = require('http'); //For signalling in WebRTC var socketIO = require('socket.io'); app.use(express.static('public')) app.get("/", function(req, res){ res.render("index.ejs"); }); var server = http.createServer(app); server.listen(process.env.PORT || 8000); var io = socketIO(server); io.sockets.on('connection', function(socket) { // Convenience function to log server messages on the client. // Arguments is an array like object which contains all the arguments of log(). // To push all the arguments of log() in array, we have to use apply(). function log() { var array = ['Message from server:']; array.push.apply(array, arguments); socket.emit('log', array); } //Defining Socket Connections socket.on('message', function(message, room) { log('Client said: ', message); // for a real app, would be room-only (not broadcast) socket.in(room).emit('message', message, room); }); socket.on('create or join', function(room) { log('Received request to create or join room ' + room); var clientsInRoom = io.sockets.adapter.rooms[room]; var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0; log('Room ' + room + ' now has ' + numClients + ' client(s)'); if (numClients === 0) { socket.join(room); log('Client ID ' + socket.id + ' created room ' + room); socket.emit('created', room, socket.id); } else if (numClients === 1) { log('Client ID ' + socket.id + ' joined room ' + room); io.sockets.in(room).emit('join', room); socket.join(room); socket.emit('joined', room, socket.id); io.sockets.in(room).emit('ready'); } else { // max two clients socket.emit('full', room); } }); socket.on('ipaddr', function() { var ifaces = os.networkInterfaces(); for (var dev in ifaces) { ifaces[dev].forEach(function(details) { if (details.family === 'IPv4' && details.address !== '127.0.0.1') { socket.emit('ipaddr', details.address); } }); } }); socket.on('bye', function(){ console.log('received bye'); }); });
Now, let’s create the frontend of our website
Step 3.1. Create the HTML file
- Let’s create the HTML file for our frontend.
- We will define the CSS and Javascript for the front-end in
public/css/styles.css
andpublic/js/main.js
respectively. Hence, we must import those files. In the backend, we explicitly setpublic
it as the default directory for serving static files. Hence, we will import the files fromcss/styles.css
&js/main.js
in HTML. - We will also import the client library for
socket.io
. - We will also import
adapter.js
for WebRTC because implementations of WebRTC are still evolving, and because each browser has different levels of support for codecs and WebRTC features. The adapter is a JavaScript shim that lets your code be written to the specification so that it will “just work” in all browsers with WebRTC support. - We discussed STURN/TURN servers in the previous tutorials. We will import the TURN/STUN URLs from
public/js/config.js
. We will create this file later in this tutorial. -
Paste the following code in
views/index.ejs
.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters<!DOCTYPE html> <html> <head> <title>WebTutsPlus WebCon</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Import Google Fonts --> <link href="https://fonts.googleapis.com/css2?family=Baloo+Tamma+2:wght@400;500;600&family=Josefin+Slab&display=swap" rel="stylesheet"> <!-- Import CSS file --> <link rel="stylesheet" href="/css/styles.css"> <!-- <link rel="stylesheet" href="/css/main.css" /> --> </head> <body class="h-100"> <div class="h-100" id="video_display"> <div id ="video_container" class="align-items-center" style="margin-top: 10%;"> <div class="local_div" id="div1" style=""> <!-- For playing local video --> <video id="localVideo" class="" autoplay muted playsinline></video> </div> <div class="remote_div" id="div2"> <!-- For playing local audio --> <video id="remoteVideo" class="" autoplay playsinline></video> </div> </div> </div> <!-- Import SocketIO for signalling --> <script src="/socket.io/socket.io.js"></script> <!-- Import WebRTC adapter for compatibility with all the browsers --> <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script> <!-- Import TURN config --> <script src="js\config.js"></script> <!-- Import script containing WebRTC related functions --> <script src="js\main.js"></script> </body> </html> - We are not explaining the CSS code.
- Paste the following code in public/css/styles.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
*, ::after, ::before { box-sizing: border-box; } html { display: block; line-height: 1.15; } div { display: block; } body { margin: 0; line-height: 1.5; color: #212529; text-align: left; display: block; background-color: #0080AD; font-family: 'Baloo Tamma 2', cursive; } .h-100 { height: 100%!important; } .row { display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; } .ml-auto, .mx-auto { margin-left: auto!important; } .mr-auto, .mx-auto { margin-right: auto!important; } .font-weight-bold { font-weight: 600!important; } .text-center { text-align: center!important; } .jumbotron { background-color: #e9ecef; } .align-items-center { -ms-flex-align: center!important; align-items: center!important; } .container { margin-right: auto; margin-left: auto; } /* For Desktop */ .col-12 { position: relative; width: 40%; } .jumbotron { padding: 2rem 1rem; margin-bottom: 2rem; border-radius: .3rem; } #h1 { font-size: 1.5rem; font-weight: 300; line-height: 1.2; margin-bottom: 1rem!important; margin-top: 0px!important; } @media (orientation: landscape) { .btn-danger { display:block; font-size : 15px; margin:auto; width: 15%; height: 25px; color: #fff; background-color: #25274d; border-color: #25274d; } .btn { display:block; font-size : 15px; margin:auto; margin-right:0px; width: 15%; height: 25px; color: #fff; background-color: #25274d; border-color: #25274d; } .btn_option { display:block; font-size : 15px; margin:auto; width: 50%; height: 25px; color: #fff; background-color: #25274d; border-color: #25274d; } #room_value { margin-left: 20px; } .local_div { width:33%; float:left } .remote_div { width:33%; float:left } .remote2_div { width:33%; float:left } #video_container { display: flex; width: 85%; margin: auto; height: 80% } video { width:100%; } } /* For Mobile */ @media (orientation: portrait) { .row { margin-right: -15px; margin-left: -15px; } .col-12 { padding-right: 15px; padding-left: 15px; position: relative; width: 100%; } .container { max-width: 310px; padding-right: 5px; padding-left: 5px; } .jumbotron { /* padding: 0.02rem 2rem; */ padding: 2rem 1rem; margin-bottom: 2rem; border-radius: .3rem; } #h1 { font-size: 1.5rem; font-weight: 300; line-height: 1.2; margin-bottom: 1rem!important; margin-top: 0px!important; } #label_name { font-size: 17px; width: 100%; } .form-group { margin-bottom: 1rem; } .form-control { height:35px; font-size:20px; display: block; width: 100%; padding: .375rem .75rem; font-weight: 400; line-height: 1.5; color: #495057; background-color: #fff; background-clip: padding-box; border: 1px solid #ced4da; border-radius: .25rem; transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; } .btn { font-size : 16px; width: 100%; height: 35px; color: #fff; background-color: #25274d; border-color: #25274d; } .local_div { display: flex ; width: 100%; position:relative; overflow:hidden; z-index:-1; } .remote_div { width: 120px; display: block; position:absolute; top:0px; right:0px; z-index:1; } .remote2_div { width: 120px; display: block; position:absolute; top:95px; right:0px; z-index:1; } #video_container { height: 80%; position:relative; display:flex; flex-wrap:wrap } .remote_div video { -ms-flex: 0 0 100%; flex: 0 0 100%; max-width: 100%; } .remote2_div video { -ms-flex: 0 0 100%; flex: 0 0 100%; max-width: 100%; } .btn-danger { font-size : 16px; width: 100%; height: 35px; color: #fff; background-color: #25274d; border-color: #25274d; } }
Now, let’s add javascript to our frontend. We had already the file
public/js/main.js
inindex.ejs
. It is in this file, we will implement the various methods for usingWebRTC and client library of Socket.IO
A lot of messages will be exchanged between the two clients before a direct connection is created between them. We saw this in details in the previous tutorial when we gave the example of Amy and Bernadette. It is highly recommended that you read that example. We have simply implemented each step mentioned in that article using Socket.IO
-
Paste the following code in
public/js/main.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters'use strict'; //Defining some global utility variables var isChannelReady = false; var isInitiator = false; var isStarted = false; var localStream; var pc; var remoteStream; var turnReady; //Initialize turn/stun server here //turnconfig will be defined in public/js/config.js var pcConfig = turnConfig; //Set local stream constraints var localStreamConstraints = { audio: true, video: true }; // Prompting for room name: var room = prompt('Enter room name:'); //Initializing socket.io var socket = io.connect(); //Ask server to add in the room if room name is provided by the user if (room !== '') { socket.emit('create or join', room); console.log('Attempted to create or join room', room); } //Defining socket events //Event - Client has created the room i.e. is the first member of the room socket.on('created', function(room) { console.log('Created room ' + room); isInitiator = true; }); //Event - Room is full socket.on('full', function(room) { console.log('Room ' + room + ' is full'); }); //Event - Another client tries to join room socket.on('join', function (room){ console.log('Another peer made a request to join room ' + room); console.log('This peer is the initiator of room ' + room + '!'); isChannelReady = true; }); //Event - Client has joined the room socket.on('joined', function(room) { console.log('joined: ' + room); isChannelReady = true; }); //Event - server asks to log a message socket.on('log', function(array) { console.log.apply(console, array); }); //Event - for sending meta for establishing a direct connection using WebRTC //The Driver code socket.on('message', function(message, room) { console.log('Client received message:', message, room); if (message === 'got user media') { maybeStart(); } else if (message.type === 'offer') { if (!isInitiator && !isStarted) { maybeStart(); } pc.setRemoteDescription(new RTCSessionDescription(message)); doAnswer(); } else if (message.type === 'answer' && isStarted) { pc.setRemoteDescription(new RTCSessionDescription(message)); } else if (message.type === 'candidate' && isStarted) { var candidate = new RTCIceCandidate({ sdpMLineIndex: message.label, candidate: message.candidate }); pc.addIceCandidate(candidate); } else if (message === 'bye' && isStarted) { handleRemoteHangup(); } }); //Function to send message in a room function sendMessage(message, room) { console.log('Client sending message: ', message, room); socket.emit('message', message, room); } //Displaying Local Stream and Remote Stream on webpage var localVideo = document.querySelector('#localVideo'); var remoteVideo = document.querySelector('#remoteVideo'); console.log("Going to find Local media"); navigator.mediaDevices.getUserMedia(localStreamConstraints) .then(gotStream) .catch(function(e) { alert('getUserMedia() error: ' + e.name); }); //If found local stream function gotStream(stream) { console.log('Adding local stream.'); localStream = stream; localVideo.srcObject = stream; sendMessage('got user media', room); if (isInitiator) { maybeStart(); } } console.log('Getting user media with constraints', localStreamConstraints); //If initiator, create the peer connection function maybeStart() { console.log('>>>>>>> maybeStart() ', isStarted, localStream, isChannelReady); if (!isStarted && typeof localStream !== 'undefined' && isChannelReady) { console.log('>>>>>> creating peer connection'); createPeerConnection(); pc.addStream(localStream); isStarted = true; console.log('isInitiator', isInitiator); if (isInitiator) { doCall(); } } } //Sending bye if user closes the window window.onbeforeunload = function() { sendMessage('bye', room); }; //Creating peer connection function createPeerConnection() { try { pc = new RTCPeerConnection(pcConfig); pc.onicecandidate = handleIceCandidate; pc.onaddstream = handleRemoteStreamAdded; pc.onremovestream = handleRemoteStreamRemoved; console.log('Created RTCPeerConnnection'); } catch (e) { console.log('Failed to create PeerConnection, exception: ' + e.message); alert('Cannot create RTCPeerConnection object.'); return; } } //Function to handle Ice candidates generated by the browser function handleIceCandidate(event) { console.log('icecandidate event: ', event); if (event.candidate) { sendMessage({ type: 'candidate', label: event.candidate.sdpMLineIndex, id: event.candidate.sdpMid, candidate: event.candidate.candidate }, room); } else { console.log('End of candidates.'); } } function handleCreateOfferError(event) { console.log('createOffer() error: ', event); } //Function to create offer function doCall() { console.log('Sending offer to peer'); pc.createOffer(setLocalAndSendMessage, handleCreateOfferError); } //Function to create answer for the received offer function doAnswer() { console.log('Sending answer to peer.'); pc.createAnswer().then( setLocalAndSendMessage, onCreateSessionDescriptionError ); } //Function to set description of local media function setLocalAndSendMessage(sessionDescription) { pc.setLocalDescription(sessionDescription); console.log('setLocalAndSendMessage sending message', sessionDescription); sendMessage(sessionDescription, room); } function onCreateSessionDescriptionError(error) { trace('Failed to create session description: ' + error.toString()); } //Function to play remote stream as soon as this client receives it function handleRemoteStreamAdded(event) { console.log('Remote stream added.'); remoteStream = event.stream; remoteVideo.srcObject = remoteStream; } function handleRemoteStreamRemoved(event) { console.log('Remote stream removed. Event: ', event); } function hangup() { console.log('Hanging up.'); stop(); sendMessage('bye',room); } function handleRemoteHangup() { console.log('Session terminated.'); stop(); isInitiator = false; } function stop() { isStarted = false; pc.close(); pc = null; }
Step 3.4. Add the STUN/TURN URLs in config.js To make this website in the real world, we must specify TURN/STUN configuration to
RTCPeerConnection()
. There are a lot of companies that provide free STUN/TURN servers. We will use the servers offered by XirSys.Steps to obtain the TURN/STUN URLs from XirSys are mentioned in this README file
Paste the obtained configurations in
public/js/config.js
-
Following is how
config.js
will look. (The urls will be differentThis file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersturnConfig = { iceServers: [ { urls: [ "stun:bn-turn1.xirsys.com" ] }, { username: "0kYXFmQL9xojOrUy4VFemlTnNPVFZpp7jfPjpB3AjxahuRe4QWrCs6Ll1vDc7TTjAAAAAGAG2whXZWJUdXRzUGx1cw==", credential: "285ff060-5a58-11eb-b269-0242ac140004", urls: [ "turn:bn-turn1.xirsys.com:80?transport=udp", "turn:bn-turn1.xirsys.com:3478?transport=udp", "turn:bn-turn1.xirsys.com:80?transport=tcp", "turn:bn-turn1.xirsys.com:3478?transport=tcp", "turns:bn-turn1.xirsys.com:443?transport=tcp", "turns:bn-turn1.xirsys.com:5349?transport=tcp" ] } ] }
Congratulations!
You have now created a web-conferencing website. To deploy your website on localhost and test it, follow these steps
- Open a terminal in the root directory of our project.
- Run the following command — node
index.js
. - Open Google Chrome and visit
localhost:8000
. Enter a room name (say foo). You should see your video. - Open a new tab and visit
localhost:8000
. Enter the same room name (foo). You should now see two video elements.
You can find the complete code in this GitHub Repo
Top comments (10)
In my maltop, I reach the "enter room name" and then I get a blue background screen with nothing...
But if I'll do the same in my mobile, in the console node.js I get this error:
/var/www/vhosts/guvavet.com/app.guvavet.com/videochat/index.js:47
var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
^
TypeError: Cannot convert undefined or null to object
at Function.keys ()
at Socket. (/var/www/vhosts/guvavet.com/app.guvavet.com/videochat/index.js:47:44)
at Socket.emit (events.js:315:20)
at Socket.onevent (/var/www/vhosts/guvavet.com/app.guvavet.com/videochat/node_modules/socket.io/lib/socket.js:327:8)
at Socket.onpacket (/var/www/vhosts/guvavet.com/app.guvavet.com/videochat/node_modules/socket.io/lib/socket.js:287:12)
at Client.ondecoded (/var/www/vhosts/guvavet.com/app.guvavet.com/videochat/node_modules/socket.io/lib/client.js:185:14)
at Decoder.Emitter.emit (/var/www/vhosts/guvavet.com/app.guvavet.com/videochat/node_modules/component-emitter/index.js:134:20)
at Decoder.add (/var/www/vhosts/guvavet.com/app.guvavet.com/videochat/node_modules/socket.io-parser/index.js:247:12)
at Client.ondata (/var/www/vhosts/guvavet.com/app.guvavet.com/videochat/node_modules/socket.io/lib/client.js:170:16)
at Socket.emit (events.js:315:20)
Any idea?
Thanks !!!
I found it. I had the same error.
line 47, index.js:
var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
change it to:
var numClients = clientsInRoom ? Object.keys(clientsInRoom).length : 0;
the first time there is no room, and the object is made bij 'join' with teh name of the room. When the second user joins, the room object is made but:
'sockets' appears not to be a property,and gives 'undefined'. so leave it out.
It probably has to to with different versions of socket.io. It took a couple of hours to find this out.
@xgubianas , This is Shivam. @nilmadhabmondal informed me that you wanted to integrate WEBRTC with your veterinary project. Please DM me on Dev.to
Hi,
Great tutorial, but i have issues to make it work..
It only displays the local stream, i can't find out why..
The remote stream seems to connect, but it does not trigger the handleRemoteStreamAdded function ?
I've just made a few changes (the correction below for the var numClients, and the deprecated "onaddstream" replaces by "ontrack"
I'm not really used to js development (PHP mostly) so debugging is not easy !
A little help/advices would be much appreciated !
Here is my console log :
Attempted to create or join room foo main.js:32:11
Going to find Local media main.js:105:9
Getting user media with constraints
Object { audio: true, video: true }
main.js:124:9
Message from server: Received request to create or join room foo main.js:63:15
Message from server: Room foo now has 0 client(s) main.js:63:15
Message from server: Client ID z-44yxk-0TY0syYKAAAF joined room foo main.js:63:15
joined: foo main.js:57:11
Adding local stream. main.js:114:11
Client sending message: got user media foo main.js:96:11
Message from server: Client said: got user media main.js:63:15
Client received message: bye foo main.js:70:13
Another peer made a request to join room foo main.js:50:11
This peer is the initiator of room foo! main.js:51:11
Client received message: got user media foo main.js:70:13
Thanks for any help
Need this to join in my app, we have a tuition center, around 15 teachers and 400 students.
If anyone can help us host this or similar script, you are welcome to work with us.
Please call +919216142737
Nice article, about how to create web conferencing. For TURN server you can consider the openrelayproject.org/
which provides free public turn server.
If some one is looking for a paid TURN service than Metered TURN servers are a good alternative
It works
thanks for this
Going to try it out
I will revert back on how it goes
this works like a charm! Is there a reason why you capped it to max two users? I removed the ifelse statement on the server, but still a third user doesn't join the video. any clue why?
Great tutorial, but please check if code still works for socket.io 1.2 or higher versions. I installed 1.2.0 but had compatibility issues.