Want to build your own peer-to-peer video chat app? WebRTC is a technology that creates a realtime connection between browsers where users can exchange audio/video streams https://fireship.io/lessons/webrtc-firebase-video-chat/

00:00 WebRTC Explained
02:01 Build your own Video Chat
3:37 Code setup
04:34 Peer Connection & Webcam
06:49 Offer Signaling
09:45 Answer Signaling

Source Code

https://github.com/fireship-io/webrtc-firebase-demo

Useful Resources

WebRTC Docs https://webrtc.org/
Codelab https://webrtc.org/getting-started/firebase-rtc-codelab 
Signaling https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Signaling_and_video_calling

#webdev #js #100SecondsOfCode

Install the quiz app 🤓

iOS https://itunes.apple.com/us/app/fireship/id1462592372?mt=8
Android https://play.google.com/store/apps/details?id=io.fireship.quizapp

Upgrade to Fireship PRO at https://fireship.io/pro
Use code lORhwXd2 for 25% off your first payment. 

My VS Code Theme

- Atom One Dark 
- vscode-icons
- Fira Code Font
2024-02-04T14:15:03.802Z
nova-2
2-general-nova
2024-01-09.29447
30089e05-99d1-4376-b32e-c263170674af
50800cdc-965a-4731-94a6-6d87a46046e4
94477b5d489c64b0a56e2db5505af7c8eb5df521d0cd5d0fffa0113e91c17b1a
67875a7f-c9c4-48a0-aa55-5bdb8a91c34a
deprecated
WebRTC.
Exchange real time audio video streams with your friends entirely in the browser.
I'm here live.
It's not I'm not a cat.
If you wanna build your own video conferencing app to capitalize on the work from home boom, then WebRTC is the API you're looking for Because it allows you to establish a peer to peer connection between 2 or more browsers where they can exchange audio video media directly Without the need for a third party server or native app, it works like this.
The first peer will create an offer asking for another peer to connect to them.
This will in an SDP object or session description protocol, which contains information describing the peer to peer connection, like the video codec, timing, and so on.
The Data will then be saved in a server where it can then be read by another peer to answer the call, which is achieved by creating an STP answer and writing that to the server.
This process Is known as signaling, and it's handled by a third party server.
The signaling server allows the 2 parties to securely exchange connection data, never touches the media that's actually transmitted between the peers.
But here's where things get tricky.
Most devices in the real world sit behind firewalls and IP addresses constantly change thanks to network address translation.
This makes peer to peer connection complicated from a networking standpoint.
But luckily, there's a standard called Active Connectivity Establishment or ICE, which helps clients coordinate the discovery of their public facing IP addresses.
Now both peers We'll generate a list of ICE candidates, which contain an IP address and port that peer 1 can use to connect to peer 2.
In the background, WebRTC will do this By making a series of requests to a stun server.
A stun server is not something you need to set up on your own because there are many free options out there from reliable sources like Google.
Each peer will save their ICE candidates in the database where they can then be read by the other peer.
The algorithm will then automatically determine which candidate is best, at which point real time media can begin flowing between the two peers.
This has been WebRTC in 100 seconds.
If you wanna see more short videos like this, make sure to hit the like button, then stay tuned because now we're going to build our own Video chat app from scratch.
That may sound pretty complicated, but the WebRTC API allows all this stuff to magically happen in the background.
Over the few minutes, you'll build a peer to peer video calling app from scratch using nothing but vanilla JavaScript and Firebase as the signaling server.
By the end of this tutorial, You'll know how to implement real time features that cater to the needs of the new work from home paradigm that we live in.
In addition to this video, you can also reference the Full article on Fireship IO and the source code on GitHub.
Let's start by taking a look at the demo.
We have the local user's video feed on the left side and the Remote video on the right side.
The local user will first grant permission for the app to access the webcam.
That user can then create a call, which will write a document to Firestore with the offer details.
At the same time, we'll create a peer connection instance in the browser, which handles the WebRTC negotiation process.
The offer will have a unique ID that can then be accessed by another user somewhere else in the world.
That user will then join the call with the unique ID, Then establish their own peer connection and write the answer details to the same document.
Then both peers will write their ICE candidates To the database, we have one sub collection for offer candidates and another for answer candidates.
This data model will allow signaling to take place between the two peers.
The data itself looks like a bunch of nonsense, but what it contains is an IP address port pair that allows the 2 peers to establish a connection.
Now both users can listen to this data in real time Then use the WebRTC API in the browser to establish the connection, giving us a one to one video chat feature.
And now we're ready to jump into our JavaScript code.
I started by creating a vanilla JavaScript project using a tool called Vite, which is a very simple build tool developed by the Vue JS guy.
We can initialize a new project by running npm initvjs/app from the command line.
Basically, it gives us a web project where we can install dependencies without having to worry about things like webpack.
After initializing the project, we need to install Firebase.
Firebase contains the Firestore database, which we can use as our back end server.
Firebase is an exceptional choice for a signaling server because it's easy to listen to updates to the database in real time.
If we were working with a traditional database, we'd likely have to implement something like WebSockets to make that possible and this video would be a crazy 20 minutes long or something.
From the Firebase console, initialize Firestore in test mode, then create a web project from the settings panel and grab your project credentials.
We can then go into the main JS file, import Firebase, And initialize the app with our Firebase config.
Now that we have Firebase set up, we're going to initialize 3 pieces of global state.
These are values you would likely want to share between multiple components if you're using a UI framework like React or Angular.
The first and most important Value is the rtc pure connection.
This object is where all of the action happens.
It emits a bunch of different events that we Listen to to update the database and to add media streams to the connection itself.
One very important thing it does is generate the ICE candidates, But in order to do that, it needs to know which STUN servers to use.
There are many different options out there, but we're just going to use the free ones from Google.
From there, we have values for local stream and remote stream, which are the video streams from the webcams of each user.
Now because we're working with vanilla JS, we need to use Imperative Dom APIs.
We're using document get element by ID to grab a bunch of elements from the HTML, like video elements to Show the actual video feeds along with buttons that provide different interaction in the UI.
The first thing the user will do is click a button to open up their webcam.
We'll We'll go ahead and register an event handler for the click event on the webcam button.
Obtaining a stream from the user's webcam is very easy.
We just await the navigator mediatevices Is get user media method and will set video and audio to true.
That'll bring up a dialogue in the browser asking the user for permission to access the webcam.
That's complete, the promise will resolve to a media stream object.
Once we have access to the webcam, we can also go ahead and set up the remote stream here, which itself will just be an empty media stream.
Now from here, we need to take our 2 streams and make them available on the peer connection and show them on Video elements in the DOM.
The local stream is already running here in the browser, so we can get its tracks and then loop over them.
And for each track, we'll call peer connection add track with that track in the local stream.
Now the remote stream is currently empty and it will be updated by the Pure connection itself.
So what we can do is listen to the on track event on the Pure connection, then get the tracks from the stream, Loop over them and add them to the remote stream when they come in.
Now, the final step for managing our streams is to apply them To video elements in the DOM.
We can do that by simply calling the video element source object and setting it equal to the stream.
At this point, we have a way to manage a local and remote stream through the peer connection.
But in order to make that happen, we need to do some signaling with Firestore.
The user who starts a call is the one who makes an offer.
We have a call button in the DOM to handle that functionality inside this async function here.
We have a call document, which is used to manage the answer and offer from both users.
Then we have offer candidates and answer candidates, which are subcollections under that document that contain all the candidates for each of those users.
When we reference a document without an ID, Firebase will automatically generate a random ID for us.
So we'll go ahead and use that to populate an input in the UI, which can then be used in another browser tab or by another user somewhere else in the world to answer the call.
Now we're ready to create an offer and save it to the database.
The first thing we'll do is await the peer connection create offer method, which will return with an offer description.
We'll then set it as the local description on the Pure connection.
Most importantly, this object contains an SDP value, Which stands for Session Description Protocol.
That's the value we want to save to the database, so we'll go ahead and convert it to a plain JavaScript object, Then write it to the database by calling await call document set with that data.
Now what's inside the SDP object isn't really important, but it contains information about the Video codec along with a bunch of other stuff to negotiate the connection.
Now one really important thing to point out here is that when we called set local description, it automatically started generating the ICE candidates.
An ICE candidate contains a potential IP address and port pair that can be used to establish the actual peer to peer connection.
Need to be listening to the ICE candidates, so it's important that we have a listener established before we make that call that listens to the on ICE candidate event.
When the event is fired, we'll make sure that a candidate exists, then write the data as JSON to the offer candidate's collection.
So at this point, as the caller making the offer, We are saving all of our data to the database, but now we need to also be listening for the answer from the user on the other end.
The way we do that is by listening to changes to the called document in Firestore.
The on snapshot method will fire a callback anytime the document in the database changes.
If our peer connection doesn't have a remote description and the data has an answer, then we'll go ahead and set an answer description on our peer connection here locally.
In other words, we're listening to our database for an answer and when that answer is received, we update it on our peer connection.
That negotiates the initial connection, But we also need to listen for ICE candidates from the answering user.
We do that by listening to updates to the answer candidates collection.
Firestore has a cool little feature where you can listen to only the documents that have been added to the collection, which is handled with the doc changes method on the query.
So every time we have a new document added, we can then create a new ICE candidate with the document data and then add that candidate to our peer connection.
At this point, we're listening to updates from the answer side, but we still need to give the answering user a way to actually answer the call.
Answering a call is very similar to initiating a call.
The main difference is that we're going to listen to a document in Firestore with the same document ID that was created by the caller.
We'll make a reference to that document as well as the answer candidate's collection, then listen to the ICE candidate event on the peer connection to update the answer The candidate's collection whenever a new candidate is generated.
From there, we can fetch the call document from the database and grab its data.
It contains the offer data, Which we can use to set a remote description on the peer connection.
After that, we can then generate an answer locally, then set the local description as the answer.
Now just like we did with the offer in the previous function, we'll set it up as a plain object and then update it on the call document so that the other user can listen to the answer.
In addition, we'll set up a listener on the offer candidates collection, and whenever a new ICE candidate is added to that collection, then we'll go ahead and create an ICE candidate here locally.
And that's all it takes to build a video chat feature With WebRTC, the vast majority of the work is just signaling data between the two users.
WebRTC handles all the complicated peer to peer networking and media streaming under the hood.
I'm gonna go ahead and wrap things up there.
If this video helped you, please like and subscribe.
And if you wanna learn more advanced concepts about the web and Firebase, consider becoming a pro member atfireship io.
Thanks for watching, and I will see you in the next one.

Speaker 0: WebRTC. Exchange real time audio video streams with your friends entirely in the browser. I'm here live. It's not I'm not a cat. If you wanna build your own video conferencing app to capitalize on the work from home boom, then WebRTC is the API you're looking for Because it allows you to establish a peer to peer connection between 2 or more browsers where they can exchange audio video media directly Without the need for a third party server or native app, it works like this.

The first peer will create an offer asking for another peer to connect to them. This will in an SDP object or session description protocol, which contains information describing the peer to peer connection, like the video codec, timing, and so on. The Data will then be saved in a server where it can then be read by another peer to answer the call, which is achieved by creating an STP answer and writing that to the server. This process Is known as signaling, and it's handled by a third party server. The signaling server allows the 2 parties to securely exchange connection data, never touches the media that's actually transmitted between the peers.

But here's where things get tricky. Most devices in the real world sit behind firewalls and IP addresses constantly change thanks to network address translation. This makes peer to peer connection complicated from a networking standpoint. But luckily, there's a standard called Active Connectivity Establishment or ICE, which helps clients coordinate the discovery of their public facing IP addresses. Now both peers We'll generate a list of ICE candidates, which contain an IP address and port that peer 1 can use to connect to peer 2.

In the background, WebRTC will do this By making a series of requests to a stun server. A stun server is not something you need to set up on your own because there are many free options out there from reliable sources like Google. Each peer will save their ICE candidates in the database where they can then be read by the other peer. The algorithm will then automatically determine which candidate is best, at which point real time media can begin flowing between the two peers. This has been WebRTC in 100 seconds.

If you wanna see more short videos like this, make sure to hit the like button, then stay tuned because now we're going to build our own Video chat app from scratch. That may sound pretty complicated, but the WebRTC API allows all this stuff to magically happen in the background. Over the few minutes, you'll build a peer to peer video calling app from scratch using nothing but vanilla JavaScript and Firebase as the signaling server. By the end of this tutorial, You'll know how to implement real time features that cater to the needs of the new work from home paradigm that we live in. In addition to this video, you can also reference the Full article on Fireship IO and the source code on GitHub.

Let's start by taking a look at the demo. We have the local user's video feed on the left side and the Remote video on the right side. The local user will first grant permission for the app to access the webcam. That user can then create a call, which will write a document to Firestore with the offer details. At the same time, we'll create a peer connection instance in the browser, which handles the WebRTC negotiation process.

The offer will have a unique ID that can then be accessed by another user somewhere else in the world. That user will then join the call with the unique ID, Then establish their own peer connection and write the answer details to the same document. Then both peers will write their ICE candidates To the database, we have one sub collection for offer candidates and another for answer candidates. This data model will allow signaling to take place between the two peers. The data itself looks like a bunch of nonsense, but what it contains is an IP address port pair that allows the 2 peers to establish a connection.

Now both users can listen to this data in real time Then use the WebRTC API in the browser to establish the connection, giving us a one to one video chat feature. And now we're ready to jump into our JavaScript code. I started by creating a vanilla JavaScript project using a tool called Vite, which is a very simple build tool developed by the Vue JS guy. We can initialize a new project by running npm initvjs/app from the command line. Basically, it gives us a web project where we can install dependencies without having to worry about things like webpack.

After initializing the project, we need to install Firebase. Firebase contains the Firestore database, which we can use as our back end server. Firebase is an exceptional choice for a signaling server because it's easy to listen to updates to the database in real time. If we were working with a traditional database, we'd likely have to implement something like WebSockets to make that possible and this video would be a crazy 20 minutes long or something. From the Firebase console, initialize Firestore in test mode, then create a web project from the settings panel and grab your project credentials.

We can then go into the main JS file, import Firebase, And initialize the app with our Firebase config. Now that we have Firebase set up, we're going to initialize 3 pieces of global state. These are values you would likely want to share between multiple components if you're using a UI framework like React or Angular. The first and most important Value is the rtc pure connection. This object is where all of the action happens.

It emits a bunch of different events that we Listen to to update the database and to add media streams to the connection itself. One very important thing it does is generate the ICE candidates, But in order to do that, it needs to know which STUN servers to use. There are many different options out there, but we're just going to use the free ones from Google. From there, we have values for local stream and remote stream, which are the video streams from the webcams of each user. Now because we're working with vanilla JS, we need to use Imperative Dom APIs.

We're using document get element by ID to grab a bunch of elements from the HTML, like video elements to Show the actual video feeds along with buttons that provide different interaction in the UI. The first thing the user will do is click a button to open up their webcam. We'll We'll go ahead and register an event handler for the click event on the webcam button. Obtaining a stream from the user's webcam is very easy. We just await the navigator mediatevices Is get user media method and will set video and audio to true.

That'll bring up a dialogue in the browser asking the user for permission to access the webcam. That's complete, the promise will resolve to a media stream object. Once we have access to the webcam, we can also go ahead and set up the remote stream here, which itself will just be an empty media stream. Now from here, we need to take our 2 streams and make them available on the peer connection and show them on Video elements in the DOM. The local stream is already running here in the browser, so we can get its tracks and then loop over them.

And for each track, we'll call peer connection add track with that track in the local stream. Now the remote stream is currently empty and it will be updated by the Pure connection itself. So what we can do is listen to the on track event on the Pure connection, then get the tracks from the stream, Loop over them and add them to the remote stream when they come in. Now, the final step for managing our streams is to apply them To video elements in the DOM. We can do that by simply calling the video element source object and setting it equal to the stream.

At this point, we have a way to manage a local and remote stream through the peer connection. But in order to make that happen, we need to do some signaling with Firestore. The user who starts a call is the one who makes an offer. We have a call button in the DOM to handle that functionality inside this async function here. We have a call document, which is used to manage the answer and offer from both users.

Then we have offer candidates and answer candidates, which are subcollections under that document that contain all the candidates for each of those users. When we reference a document without an ID, Firebase will automatically generate a random ID for us. So we'll go ahead and use that to populate an input in the UI, which can then be used in another browser tab or by another user somewhere else in the world to answer the call. Now we're ready to create an offer and save it to the database. The first thing we'll do is await the peer connection create offer method, which will return with an offer description.

We'll then set it as the local description on the Pure connection. Most importantly, this object contains an SDP value, Which stands for Session Description Protocol. That's the value we want to save to the database, so we'll go ahead and convert it to a plain JavaScript object, Then write it to the database by calling await call document set with that data. Now what's inside the SDP object isn't really important, but it contains information about the Video codec along with a bunch of other stuff to negotiate the connection. Now one really important thing to point out here is that when we called set local description, it automatically started generating the ICE candidates.

An ICE candidate contains a potential IP address and port pair that can be used to establish the actual peer to peer connection. Need to be listening to the ICE candidates, so it's important that we have a listener established before we make that call that listens to the on ICE candidate event. When the event is fired, we'll make sure that a candidate exists, then write the data as JSON to the offer candidate's collection. So at this point, as the caller making the offer, We are saving all of our data to the database, but now we need to also be listening for the answer from the user on the other end. The way we do that is by listening to changes to the called document in Firestore.

The on snapshot method will fire a callback anytime the document in the database changes. If our peer connection doesn't have a remote description and the data has an answer, then we'll go ahead and set an answer description on our peer connection here locally. In other words, we're listening to our database for an answer and when that answer is received, we update it on our peer connection. That negotiates the initial connection, But we also need to listen for ICE candidates from the answering user. We do that by listening to updates to the answer candidates collection.

Firestore has a cool little feature where you can listen to only the documents that have been added to the collection, which is handled with the doc changes method on the query. So every time we have a new document added, we can then create a new ICE candidate with the document data and then add that candidate to our peer connection. At this point, we're listening to updates from the answer side, but we still need to give the answering user a way to actually answer the call. Answering a call is very similar to initiating a call. The main difference is that we're going to listen to a document in Firestore with the same document ID that was created by the caller.

We'll make a reference to that document as well as the answer candidate's collection, then listen to the ICE candidate event on the peer connection to update the answer The candidate's collection whenever a new candidate is generated. From there, we can fetch the call document from the database and grab its data. It contains the offer data, Which we can use to set a remote description on the peer connection. After that, we can then generate an answer locally, then set the local description as the answer. Now just like we did with the offer in the previous function, we'll set it up as a plain object and then update it on the call document so that the other user can listen to the answer.

In addition, we'll set up a listener on the offer candidates collection, and whenever a new ICE candidate is added to that collection, then we'll go ahead and create an ICE candidate here locally. And that's all it takes to build a video chat feature With WebRTC, the vast majority of the work is just signaling data between the two users. WebRTC handles all the complicated peer to peer networking and media streaming under the hood. I'm gonna go ahead and wrap things up there. If this video helped you, please like and subscribe.

And if you wanna learn more advanced concepts about the web and Firebase, consider becoming a pro member atfireship io. Thanks for watching, and I will see you in the next one.
WebRTC. Exchange real time audio video streams with your friends entirely in the browser. I'm here live. It's not I'm not a cat. If you wanna build your own video conferencing app to capitalize on the work from home boom, then WebRTC is the API you're looking for Because it allows you to establish a peer to peer connection between 2 or more browsers where they can exchange audio video media directly Without the need for a third party server or native app, it works like this. The first peer will create an offer asking for another peer to connect to them. This will in an SDP object or session description protocol, which contains information describing the peer to peer connection, like the video codec, timing, and so on. The Data will then be saved in a server where it can then be read by another peer to answer the call, which is achieved by creating an STP answer and writing that to the server.
video gaming
multimedia
streaming
networking
youtube
internet
This process Is known as signaling, and it's handled by a third party server. The signaling server allows the 2 parties to securely exchange connection data, never touches the media that's actually transmitted between the peers. But here's where things get tricky. Most devices in the real world sit behind firewalls and IP addresses constantly change thanks to network address translation. This makes peer to peer connection complicated from a networking standpoint. But luckily, there's a standard called Active Connectivity Establishment or ICE, which helps clients coordinate the discovery of their public facing IP addresses. Now both peers We'll generate a list of ICE candidates, which contain an IP address and port that peer 1 can use to connect to peer 2.
networking
internet
telecommunications
social media
infrastructure
phones
In the background, WebRTC will do this By making a series of requests to a stun server. A stun server is not something you need to set up on your own because there are many free options out there from reliable sources like Google.
Each peer will save their ICE candidates in the database where they can then be read by the other peer. The algorithm will then automatically determine which candidate is best, at which point real time media can begin flowing between the two peers. This has been WebRTC in 100 seconds. If you wanna see more short videos like this, make sure to hit the like button, then stay tuned because now we're going to build our own Video chat app from scratch. That may sound pretty complicated, but the WebRTC API allows all this stuff to magically happen in the background. Over the few minutes, you'll build a peer to peer video calling app from scratch using nothing but vanilla JavaScript and Firebase as the signaling server. By the end of this tutorial, You'll know how to implement real time features that cater to the needs of the new work from home paradigm that we live in. In addition to this video, you can also reference the Full article on Fireship IO and the source code on GitHub. Let's start by taking a look at the demo. We have the local user's video feed on the left side and the Remote video on the right side. The local user will first grant permission for the app to access the webcam. That user can then create a call, which will write a document to Firestore with the offer details.
home improvement
youtube
streaming
documentary
video gaming
data
multimedia
media
databases
customer support
social media
At the same time, we'll create a peer connection instance in the browser, which handles the WebRTC negotiation process. The offer will have a unique ID that can then be accessed by another user somewhere else in the world. That user will then join the call with the unique ID, Then establish their own peer connection and write the answer details to the same document.
Then both peers will write their ICE candidates To the database, we have one sub collection for offer candidates and another for answer candidates. This data model will allow signaling to take place between the two peers. The data itself looks like a bunch of nonsense, but what it contains is an IP address port pair that allows the 2 peers to establish a connection. Now both users can listen to this data in real time Then use the WebRTC API in the browser to establish the connection, giving us a one to one video chat feature. And now we're ready to jump into our JavaScript code. I started by creating a vanilla JavaScript project using a tool called Vite, which is a very simple build tool developed by the Vue JS guy.
data
databases
networking
data analysis
data management
video gaming
internet
telecommunications
We can initialize a new project by running npm initvjs/app from the command line. Basically, it gives us a web project where we can install dependencies without having to worry about things like webpack. After initializing the project, we need to install Firebase. Firebase contains the Firestore database, which we can use as our back end server. Firebase is an exceptional choice for a signaling server because it's easy to listen to updates to the database in real time.
If we were working with a traditional database, we'd likely have to implement something like WebSockets to make that possible and this video would be a crazy 20 minutes long or something. From the Firebase console, initialize Firestore in test mode, then create a web project from the settings panel and grab your project credentials.
video gaming
We can then go into the main JS file, import Firebase, And initialize the app with our Firebase config. Now that we have Firebase set up, we're going to initialize 3 pieces of global state. These are values you would likely want to share between multiple components if you're using a UI framework like React or Angular.
The first and most important Value is the rtc pure connection. This object is where all of the action happens. It emits a bunch of different events that we Listen to to update the database and to add media streams to the connection itself. One very important thing it does is generate the ICE candidates, But in order to do that, it needs to know which STUN servers to use.
data
networking
internet
telecommunications
There are many different options out there, but we're just going to use the free ones from Google. From there, we have values for local stream and remote stream, which are the video streams from the webcams of each user. Now because we're working with vanilla JS, we need to use Imperative Dom APIs.
streaming
youtube
We're using document get element by ID to grab a bunch of elements from the HTML, like video elements to Show the actual video feeds along with buttons that provide different interaction in the UI. The first thing the user will do is click a button to open up their webcam. We'll We'll go ahead and register an event handler for the click event on the webcam button.
Obtaining a stream from the user's webcam is very easy. We just await the navigator mediatevices Is get user media method and will set video and audio to true. That'll bring up a dialogue in the browser asking the user for permission to access the webcam. That's complete, the promise will resolve to a media stream object. Once we have access to the webcam, we can also go ahead and set up the remote stream here, which itself will just be an empty media stream. Now from here, we need to take our 2 streams and make them available on the peer connection and show them on Video elements in the DOM. The local stream is already running here in the browser, so we can get its tracks and then loop over them. And for each track, we'll call peer connection add track with that track in the local stream. Now the remote stream is currently empty and it will be updated by the Pure connection itself. So what we can do is listen to the on track event on the Pure connection, then get the tracks from the stream, Loop over them and add them to the remote stream when they come in. Now, the final step for managing our streams is to apply them To video elements in the DOM. We can do that by simply calling the video element source object and setting it equal to the stream. At this point, we have a way to manage a local and remote stream through the peer connection.
streaming
multimedia
youtube
video gaming
But in order to make that happen, we need to do some signaling with Firestore. The user who starts a call is the one who makes an offer. We have a call button in the DOM to handle that functionality inside this async function here. We have a call document, which is used to manage the answer and offer from both users. Then we have offer candidates and answer candidates, which are subcollections under that document that contain all the candidates for each of those users. When we reference a document without an ID, Firebase will automatically generate a random ID for us. So we'll go ahead and use that to populate an input in the UI, which can then be used in another browser tab or by another user somewhere else in the world to answer the call.
Now we're ready to create an offer and save it to the database. The first thing we'll do is await the peer connection create offer method, which will return with an offer description. We'll then set it as the local description on the Pure connection. Most importantly, this object contains an SDP value, Which stands for Session Description Protocol.
networking
customer support
databases
That's the value we want to save to the database, so we'll go ahead and convert it to a plain JavaScript object, Then write it to the database by calling await call document set with that data. Now what's inside the SDP object isn't really important, but it contains information about the Video codec along with a bunch of other stuff to negotiate the connection.
databases
data management
Now one really important thing to point out here is that when we called set local description, it automatically started generating the ICE candidates. An ICE candidate contains a potential IP address and port pair that can be used to establish the actual peer to peer connection. Need to be listening to the ICE candidates, so it's important that we have a listener established before we make that call that listens to the on ICE candidate event.
When the event is fired, we'll make sure that a candidate exists, then write the data as JSON to the offer candidate's collection. So at this point, as the caller making the offer, We are saving all of our data to the database, but now we need to also be listening for the answer from the user on the other end.
data
databases
data management
The way we do that is by listening to changes to the called document in Firestore. The on snapshot method will fire a callback anytime the document in the database changes.
If our peer connection doesn't have a remote description and the data has an answer, then we'll go ahead and set an answer description on our peer connection here locally. In other words, we're listening to our database for an answer and when that answer is received, we update it on our peer connection. That negotiates the initial connection, But we also need to listen for ICE candidates from the answering user. We do that by listening to updates to the answer candidates collection. Firestore has a cool little feature where you can listen to only the documents that have been added to the collection, which is handled with the doc changes method on the query. So every time we have a new document added, we can then create a new ICE candidate with the document data and then add that candidate to our peer connection.
networking
databases
publishing
At this point, we're listening to updates from the answer side, but we still need to give the answering user a way to actually answer the call. Answering a call is very similar to initiating a call. The main difference is that we're going to listen to a document in Firestore with the same document ID that was created by the caller.
We'll make a reference to that document as well as the answer candidate's collection, then listen to the ICE candidate event on the peer connection to update the answer The candidate's collection whenever a new candidate is generated. From there, we can fetch the call document from the database and grab its data. It contains the offer data, Which we can use to set a remote description on the peer connection. After that, we can then generate an answer locally, then set the local description as the answer. Now just like we did with the offer in the previous function, we'll set it up as a plain object and then update it on the call document so that the other user can listen to the answer.
databases
programming
data
elections
voting
In addition, we'll set up a listener on the offer candidates collection, and whenever a new ICE candidate is added to that collection, then we'll go ahead and create an ICE candidate here locally.
And that's all it takes to build a video chat feature With WebRTC, the vast majority of the work is just signaling data between the two users. WebRTC handles all the complicated peer to peer networking and media streaming under the hood. I'm gonna go ahead and wrap things up there. If this video helped you, please like and subscribe. And if you wanna learn more advanced concepts about the web and Firebase, consider becoming a pro member atfireship io.
streaming
networking
social media
internet
websites
Thanks for watching, and I will see you in the next one.
WebRTC. Exchange real time audio video streams with your friends entirely in the browser. I'm here live. It's not I'm not a cat. If you wanna build your own video conferencing app to capitalize on the work from home boom, then WebRTC is the API you're looking for Because it allows you to establish a peer to peer connection between 2 or more browsers where they can exchange audio video media directly Without the need for a third party server or native app, it works like this. The first peer will create an offer asking for another peer to connect to them. This will in an SDP object or session description protocol, which contains information describing the peer to peer connection, like the video codec, timing, and so on. The Data will then be saved in a server where it can then be read by another peer to answer the call, which is achieved by creating an STP answer and writing that to the server. This process Is known as signaling, and it's handled by a third party server. The signaling server allows the 2 parties to securely exchange connection data, never touches the media that's actually transmitted between the peers. But here's where things get tricky. Most devices in the real world sit behind firewalls and IP addresses constantly change thanks to network address translation. This makes peer to peer connection complicated from a networking standpoint. But luckily, there's a standard called Active Connectivity Establishment or ICE, which helps clients coordinate the discovery of their public facing IP addresses. Now both peers We'll generate a list of ICE candidates, which contain an IP address and port that peer 1 can use to connect to peer 2. In the background, WebRTC will do this By making a series of requests to a stun server. A stun server is not something you need to set up on your own because there are many free options out there from reliable sources like Google. Each peer will save their ICE candidates in the database where they can then be read by the other peer. The algorithm will then automatically determine which candidate is best, at which point real time media can begin flowing between the two peers. This has been WebRTC in 100 seconds. If you wanna see more short videos like this, make sure to hit the like button, then stay tuned because now we're going to build our own Video chat app from scratch. That may sound pretty complicated, but the WebRTC API allows all this stuff to magically happen in the background. Over the few minutes, you'll build a peer to peer video calling app from scratch using nothing but vanilla JavaScript and Firebase as the signaling server. By the end of this tutorial, You'll know how to implement real time features that cater to the needs of the new work from home paradigm that we live in. In addition to this video, you can also reference the Full article on Fireship IO and the source code on GitHub. Let's start by taking a look at the demo. We have the local user's video feed on the left side and the Remote video on the right side. The local user will first grant permission for the app to access the webcam. That user can then create a call, which will write a document to Firestore with the offer details. At the same time, we'll create a peer connection instance in the browser, which handles the WebRTC negotiation process. The offer will have a unique ID that can then be accessed by another user somewhere else in the world. That user will then join the call with the unique ID, Then establish their own peer connection and write the answer details to the same document. Then both peers will write their ICE candidates To the database, we have one sub collection for offer candidates and another for answer candidates. This data model will allow signaling to take place between the two peers. The data itself looks like a bunch of nonsense, but what it contains is an IP address port pair that allows the 2 peers to establish a connection. Now both users can listen to this data in real time Then use the WebRTC API in the browser to establish the connection, giving us a one to one video chat feature. And now we're ready to jump into our JavaScript code. I started by creating a vanilla JavaScript project using a tool called Vite, which is a very simple build tool developed by the Vue JS guy. We can initialize a new project by running npm initvjs/app from the command line. Basically, it gives us a web project where we can install dependencies without having to worry about things like webpack. After initializing the project, we need to install Firebase. Firebase contains the Firestore database, which we can use as our back end server. Firebase is an exceptional choice for a signaling server because it's easy to listen to updates to the database in real time. If we were working with a traditional database, we'd likely have to implement something like WebSockets to make that possible and this video would be a crazy 20 minutes long or something. From the Firebase console, initialize Firestore in test mode, then create a web project from the settings panel and grab your project credentials. We can then go into the main JS file, import Firebase, And initialize the app with our Firebase config. Now that we have Firebase set up, we're going to initialize 3 pieces of global state. These are values you would likely want to share between multiple components if you're using a UI framework like React or Angular. The first and most important Value is the rtc pure connection. This object is where all of the action happens. It emits a bunch of different events that we Listen to to update the database and to add media streams to the connection itself. One very important thing it does is generate the ICE candidates, But in order to do that, it needs to know which STUN servers to use. There are many different options out there, but we're just going to use the free ones from Google. From there, we have values for local stream and remote stream, which are the video streams from the webcams of each user. Now because we're working with vanilla JS, we need to use Imperative Dom APIs. We're using document get element by ID to grab a bunch of elements from the HTML, like video elements to Show the actual video feeds along with buttons that provide different interaction in the UI. The first thing the user will do is click a button to open up their webcam. We'll We'll go ahead and register an event handler for the click event on the webcam button. Obtaining a stream from the user's webcam is very easy. We just await the navigator mediatevices Is get user media method and will set video and audio to true. That'll bring up a dialogue in the browser asking the user for permission to access the webcam. That's complete, the promise will resolve to a media stream object. Once we have access to the webcam, we can also go ahead and set up the remote stream here, which itself will just be an empty media stream. Now from here, we need to take our 2 streams and make them available on the peer connection and show them on Video elements in the DOM. The local stream is already running here in the browser, so we can get its tracks and then loop over them. And for each track, we'll call peer connection add track with that track in the local stream. Now the remote stream is currently empty and it will be updated by the Pure connection itself. So what we can do is listen to the on track event on the Pure connection, then get the tracks from the stream, Loop over them and add them to the remote stream when they come in. Now, the final step for managing our streams is to apply them To video elements in the DOM. We can do that by simply calling the video element source object and setting it equal to the stream. At this point, we have a way to manage a local and remote stream through the peer connection. But in order to make that happen, we need to do some signaling with Firestore. The user who starts a call is the one who makes an offer. We have a call button in the DOM to handle that functionality inside this async function here. We have a call document, which is used to manage the answer and offer from both users. Then we have offer candidates and answer candidates, which are subcollections under that document that contain all the candidates for each of those users. When we reference a document without an ID, Firebase will automatically generate a random ID for us. So we'll go ahead and use that to populate an input in the UI, which can then be used in another browser tab or by another user somewhere else in the world to answer the call. Now we're ready to create an offer and save it to the database. The first thing we'll do is await the peer connection create offer method, which will return with an offer description. We'll then set it as the local description on the Pure connection. Most importantly, this object contains an SDP value, Which stands for Session Description Protocol. That's the value we want to save to the database, so we'll go ahead and convert it to a plain JavaScript object, Then write it to the database by calling await call document set with that data. Now what's inside the SDP object isn't really important, but it contains information about the Video codec along with a bunch of other stuff to negotiate the connection. Now one really important thing to point out here is that when we called set local description, it automatically started generating the ICE candidates. An ICE candidate contains a potential IP address and port pair that can be used to establish the actual peer to peer connection. Need to be listening to the ICE candidates, so it's important that we have a listener established before we make that call that listens to the on ICE candidate event. When the event is fired, we'll make sure that a candidate exists, then write the data as JSON to the offer candidate's collection. So at this point, as the caller making the offer, We are saving all of our data to the database, but now we need to also be listening for the answer from the user on the other end. The way we do that is by listening to changes to the called document in Firestore. The on snapshot method will fire a callback anytime the document in the database changes. If our peer connection doesn't have a remote description and the data has an answer, then we'll go ahead and set an answer description on our peer connection here locally. In other words, we're listening to our database for an answer and when that answer is received, we update it on our peer connection. That negotiates the initial connection, But we also need to listen for ICE candidates from the answering user. We do that by listening to updates to the answer candidates collection. Firestore has a cool little feature where you can listen to only the documents that have been added to the collection, which is handled with the doc changes method on the query. So every time we have a new document added, we can then create a new ICE candidate with the document data and then add that candidate to our peer connection. At this point, we're listening to updates from the answer side, but we still need to give the answering user a way to actually answer the call. Answering a call is very similar to initiating a call. The main difference is that we're going to listen to a document in Firestore with the same document ID that was created by the caller. We'll make a reference to that document as well as the answer candidate's collection, then listen to the ICE candidate event on the peer connection to update the answer The candidate's collection whenever a new candidate is generated. From there, we can fetch the call document from the database and grab its data. It contains the offer data, Which we can use to set a remote description on the peer connection. After that, we can then generate an answer locally, then set the local description as the answer. Now just like we did with the offer in the previous function, we'll set it up as a plain object and then update it on the call document so that the other user can listen to the answer. In addition, we'll set up a listener on the offer candidates collection, and whenever a new ICE candidate is added to that collection, then we'll go ahead and create an ICE candidate here locally. And that's all it takes to build a video chat feature With WebRTC, the vast majority of the work is just signaling data between the two users. WebRTC handles all the complicated peer to peer networking and media streaming under the hood. I'm gonna go ahead and wrap things up there. If this video helped you, please like and subscribe. And if you wanna learn more advanced concepts about the web and Firebase, consider becoming a pro member atfireship io. Thanks for watching, and I will see you in the next one.
WebRTC.
webrtc
Exchange
exchange
real
real
time
time
audio
audio
video
video
streams
streams
with
with
your
your
friends
friends
entirely
entirely
in
in
the
the
browser.
browser
I'm
i'm
here
here
live.
live
It's
it's
not
not
I'm
i'm
not
not
a
a
cat.
cat
If
if
you
you
wanna
wanna
build
build
your
your
own
own
video
video
conferencing
conferencing
app
app
to
to
capitalize
capitalize
on
on
the
the
work
work
from
from
home
home
boom,
boom
then
then
WebRTC
webrtc
is
is
the
the
API
api
you're
you're
looking
looking
for
for
Because
because
it
it
allows
allows
you
you
to
to
establish
establish
a
a
peer
peer
to
to
peer
peer
connection
connection
between
between
2
2
or
or
more
more
browsers
browsers
where
where
they
they
can
can
exchange
exchange
audio
audio
video
video
media
media
directly
directly
Without
without
the
the
need
need
for
for
a
a
third
third
party
party
server
server
or
or
native
native
app,
app
it
it
works
works
like
like
this.
this
The
the
first
first
peer
peer
will
will
create
create
an
an
offer
offer
asking
asking
for
for
another
another
peer
peer
to
to
connect
connect
to
to
them.
them
This
this
will
will
in
in
an
an
SDP
sdp
object
object
or
or
session
session
description
description
protocol,
protocol
which
which
contains
contains
information
information
describing
describing
the
the
peer
peer
to
to
peer
peer
connection,
connection
like
like
the
the
video
video
codec,
codec
timing,
timing
and
and
so
so
on.
on
The
the
Data
data
will
will
then
then
be
be
saved
saved
in
in
a
a
server
server
where
where
it
it
can
can
then
then
be
be
read
read
by
by
another
another
peer
peer
to
to
answer
answer
the
the
call,
call
which
which
is
is
achieved
achieved
by
by
creating
creating
an
an
STP
stp
answer
answer
and
and
writing
writing
that
that
to
to
the
the
server.
server
This
this
process
process
Is
is
known
known
as
as
signaling,
signaling
and
and
it's
it's
handled
handled
by
by
a
a
third
third
party
party
server.
server
The
the
signaling
signaling
server
server
allows
allows
the
the
2
2
parties
parties
to
to
securely
securely
exchange
exchange
connection
connection
data,
data
never
never
touches
touches
the
the
media
media
that's
that's
actually
actually
transmitted
transmitted
between
between
the
the
peers.
peers
But
but
here's
here's
where
where
things
things
get
get
tricky.
tricky
Most
most
devices
devices
in
in
the
the
real
real
world
world
sit
sit
behind
behind
firewalls
firewalls
and
and
IP
ip
addresses
addresses
constantly
constantly
change
change
thanks
thanks
to
to
network
network
address
address
translation.
translation
This
this
makes
makes
peer
peer
to
to
peer
peer
connection
connection
complicated
complicated
from
from
a
a
networking
networking
standpoint.
standpoint
But
but
luckily,
luckily
there's
there's
a
a
standard
standard
called
called
Active
active
Connectivity
connectivity
Establishment
establishment
or
or
ICE,
ice
which
which
helps
helps
clients
clients
coordinate
coordinate
the
the
discovery
discovery
of
of
their
their
public
public
facing
facing
IP
ip
addresses.
addresses
Now
now
both
both
peers
peers
We'll
we'll
generate
generate
a
a
list
list
of
of
ICE
ice
candidates,
candidates
which
which
contain
contain
an
an
IP
ip
address
address
and
and
port
port
that
that
peer
peer
1
1
can
can
use
use
to
to
connect
connect
to
to
peer
peer
2.
2
In
in
the
the
background,
background
WebRTC
webrtc
will
will
do
do
this
this
By
by
making
making
a
a
series
series
of
of
requests
requests
to
to
a
a
stun
stun
server.
server
A
a
stun
stun
server
server
is
is
not
not
something
something
you
you
need
need
to
to
set
set
up
up
on
on
your
your
own
own
because
because
there
there
are
are
many
many
free
free
options
options
out
out
there
there
from
from
reliable
reliable
sources
sources
like
like
Google.
google
Each
each
peer
peer
will
will
save
save
their
their
ICE
ice
candidates
candidates
in
in
the
the
database
database
where
where
they
they
can
can
then
then
be
be
read
read
by
by
the
the
other
other
peer.
peer
The
the
algorithm
algorithm
will
will
then
then
automatically
automatically
determine
determine
which
which
candidate
candidate
is
is
best,
best
at
at
which
which
point
point
real
real
time
time
media
media
can
can
begin
begin
flowing
flowing
between
between
the
the
two
two
peers.
peers
This
this
has
has
been
been
WebRTC
webrtc
in
in
100
100
seconds.
seconds
If
if
you
you
wanna
wanna
see
see
more
more
short
short
videos
videos
like
like
this,
this
make
make
sure
sure
to
to
hit
hit
the
the
like
like
button,
button
then
then
stay
stay
tuned
tuned
because
because
now
now
we're
we're
going
going
to
to
build
build
our
our
own
own
Video
video
chat
chat
app
app
from
from
scratch.
scratch
That
that
may
may
sound
sound
pretty
pretty
complicated,
complicated
but
but
the
the
WebRTC
webrtc
API
api
allows
allows
all
all
this
this
stuff
stuff
to
to
magically
magically
happen
happen
in
in
the
the
background.
background
Over
over
the
the
few
few
minutes,
minutes
you'll
you'll
build
build
a
a
peer
peer
to
to
peer
peer
video
video
calling
calling
app
app
from
from
scratch
scratch
using
using
nothing
nothing
but
but
vanilla
vanilla
JavaScript
javascript
and
and
Firebase
firebase
as
as
the
the
signaling
signaling
server.
server
By
by
the
the
end
end
of
of
this
this
tutorial,
tutorial
You'll
you'll
know
know
how
how
to
to
implement
implement
real
real
time
time
features
features
that
that
cater
cater
to
to
the
the
needs
needs
of
of
the
the
new
new
work
work
from
from
home
home
paradigm
paradigm
that
that
we
we
live
live
in.
in
In
in
addition
addition
to
to
this
this
video,
video
you
you
can
can
also
also
reference
reference
the
the
Full
full
article
article
on
on
Fireship
fireship
IO
io
and
and
the
the
source
source
code
code
on
on
GitHub.
github
Let's
let's
start
start
by
by
taking
taking
a
a
look
look
at
at
the
the
demo.
demo
We
we
have
have
the
the
local
local
user's
user's
video
video
feed
feed
on
on
the
the
left
left
side
side
and
and
the
the
Remote
remote
video
video
on
on
the
the
right
right
side.
side
The
the
local
local
user
user
will
will
first
first
grant
grant
permission
permission
for
for
the
the
app
app
to
to
access
access
the
the
webcam.
webcam
That
that
user
user
can
can
then
then
create
create
a
a
call,
call
which
which
will
will
write
write
a
a
document
document
to
to
Firestore
firestore
with
with
the
the
offer
offer
details.
details
At
at
the
the
same
same
time,
time
we'll
we'll
create
create
a
a
peer
peer
connection
connection
instance
instance
in
in
the
the
browser,
browser
which
which
handles
handles
the
the
WebRTC
webrtc
negotiation
negotiation
process.
process
The
the
offer
offer
will
will
have
have
a
a
unique
unique
ID
id
that
that
can
can
then
then
be
be
accessed
accessed
by
by
another
another
user
user
somewhere
somewhere
else
else
in
in
the
the
world.
world
That
that
user
user
will
will
then
then
join
join
the
the
call
call
with
with
the
the
unique
unique
ID,
id
Then
then
establish
establish
their
their
own
own
peer
peer
connection
connection
and
and
write
write
the
the
answer
answer
details
details
to
to
the
the
same
same
document.
document
Then
then
both
both
peers
peers
will
will
write
write
their
their
ICE
ice
candidates
candidates
To
to
the
the
database,
database
we
we
have
have
one
one
sub
sub
collection
collection
for
for
offer
offer
candidates
candidates
and
and
another
another
for
for
answer
answer
candidates.
candidates
This
this
data
data
model
model
will
will
allow
allow
signaling
signaling
to
to
take
take
place
place
between
between
the
the
two
two
peers.
peers
The
the
data
data
itself
itself
looks
looks
like
like
a
a
bunch
bunch
of
of
nonsense,
nonsense
but
but
what
what
it
it
contains
contains
is
is
an
an
IP
ip
address
address
port
port
pair
pair
that
that
allows
allows
the
the
2
2
peers
peers
to
to
establish
establish
a
a
connection.
connection
Now
now
both
both
users
users
can
can
listen
listen
to
to
this
this
data
data
in
in
real
real
time
time
Then
then
use
use
the
the
WebRTC
webrtc
API
api
in
in
the
the
browser
browser
to
to
establish
establish
the
the
connection,
connection
giving
giving
us
us
a
a
one
one
to
to
one
one
video
video
chat
chat
feature.
feature
And
and
now
now
we're
we're
ready
ready
to
to
jump
jump
into
into
our
our
JavaScript
javascript
code.
code
I
i
started
started
by
by
creating
creating
a
a
vanilla
vanilla
JavaScript
javascript
project
project
using
using
a
a
tool
tool
called
called
Vite,
vite
which
which
is
is
a
a
very
very
simple
simple
build
build
tool
tool
developed
developed
by
by
the
the
Vue
vue
JS
js
guy.
guy
We
we
can
can
initialize
initialize
a
a
new
new
project
project
by
by
running
running
npm
npm
initvjs/app
initvjs/app
from
from
the
the
command
command
line.
line
Basically,
basically
it
it
gives
gives
us
us
a
a
web
web
project
project
where
where
we
we
can
can
install
install
dependencies
dependencies
without
without
having
having
to
to
worry
worry
about
about
things
things
like
like
webpack.
webpack
After
after
initializing
initializing
the
the
project,
project
we
we
need
need
to
to
install
install
Firebase.
firebase
Firebase
firebase
contains
contains
the
the
Firestore
firestore
database,
database
which
which
we
we
can
can
use
use
as
as
our
our
back
back
end
end
server.
server
Firebase
firebase
is
is
an
an
exceptional
exceptional
choice
choice
for
for
a
a
signaling
signaling
server
server
because
because
it's
it's
easy
easy
to
to
listen
listen
to
to
updates
updates
to
to
the
the
database
database
in
in
real
real
time.
time
If
if
we
we
were
were
working
working
with
with
a
a
traditional
traditional
database,
database
we'd
we'd
likely
likely
have
have
to
to
implement
implement
something
something
like
like
WebSockets
websockets
to
to
make
make
that
that
possible
possible
and
and
this
this
video
video
would
would
be
be
a
a
crazy
crazy
20
20
minutes
minutes
long
long
or
or
something.
something
From
from
the
the
Firebase
firebase
console,
console
initialize
initialize
Firestore
firestore
in
in
test
test
mode,
mode
then
then
create
create
a
a
web
web
project
project
from
from
the
the
settings
settings
panel
panel
and
and
grab
grab
your
your
project
project
credentials.
credentials
We
we
can
can
then
then
go
go
into
into
the
the
main
main
JS
js
file,
file
import
import
Firebase,
firebase
And
and
initialize
initialize
the
the
app
app
with
with
our
our
Firebase
firebase
config.
config
Now
now
that
that
we
we
have
have
Firebase
firebase
set
set
up,
up
we're
we're
going
going
to
to
initialize
initialize
3
3
pieces
pieces
of
of
global
global
state.
state
These
these
are
are
values
values
you
you
would
would
likely
likely
want
want
to
to
share
share
between
between
multiple
multiple
components
components
if
if
you're
you're
using
using
a
a
UI
ui
framework
framework
like
like
React
react
or
or
Angular.
angular
The
the
first
first
and
and
most
most
important
important
Value
value
is
is
the
the
rtc
rtc
pure
pure
connection.
connection
This
this
object
object
is
is
where
where
all
all
of
of
the
the
action
action
happens.
happens
It
it
emits
emits
a
a
bunch
bunch
of
of
different
different
events
events
that
that
we
we
Listen
listen
to
to
to
to
update
update
the
the
database
database
and
and
to
to
add
add
media
media
streams
streams
to
to
the
the
connection
connection
itself.
itself
One
one
very
very
important
important
thing
thing
it
it
does
does
is
is
generate
generate
the
the
ICE
ice
candidates,
candidates
But
but
in
in
order
order
to
to
do
do
that,
that
it
it
needs
needs
to
to
know
know
which
which
STUN
stun
servers
servers
to
to
use.
use
There
there
are
are
many
many
different
different
options
options
out
out
there,
there
but
but
we're
we're
just
just
going
going
to
to
use
use
the
the
free
free
ones
ones
from
from
Google.
google
From
from
there,
there
we
we
have
have
values
values
for
for
local
local
stream
stream
and
and
remote
remote
stream,
stream
which
which
are
are
the
the
video
video
streams
streams
from
from
the
the
webcams
webcams
of
of
each
each
user.
user
Now
now
because
because
we're
we're
working
working
with
with
vanilla
vanilla
JS,
js
we
we
need
need
to
to
use
use
Imperative
imperative
Dom
dom
APIs.
apis
We're
we're
using
using
document
document
get
get
element
element
by
by
ID
id
to
to
grab
grab
a
a
bunch
bunch
of
of
elements
elements
from
from
the
the
HTML,
html
like
like
video
video
elements
elements
to
to
Show
show
the
the
actual
actual
video
video
feeds
feeds
along
along
with
with
buttons
buttons
that
that
provide
provide
different
different
interaction
interaction
in
in
the
the
UI.
ui
The
the
first
first
thing
thing
the
the
user
user
will
will
do
do
is
is
click
click
a
a
button
button
to
to
open
open
up
up
their
their
webcam.
webcam
We'll
we'll
We'll
we'll
go
go
ahead
ahead
and
and
register
register
an
an
event
event
handler
handler
for
for
the
the
click
click
event
event
on
on
the
the
webcam
webcam
button.
button
Obtaining
obtaining
a
a
stream
stream
from
from
the
the
user's
user's
webcam
webcam
is
is
very
very
easy.
easy
We
we
just
just
await
await
the
the
navigator
navigator
mediatevices
mediatevices
Is
is
get
get
user
user
media
media
method
method
and
and
will
will
set
set
video
video
and
and
audio
audio
to
to
true.
true
That'll
that'll
bring
bring
up
up
a
a
dialogue
dialogue
in
in
the
the
browser
browser
asking
asking
the
the
user
user
for
for
permission
permission
to
to
access
access
the
the
webcam.
webcam
That's
that's
complete,
complete
the
the
promise
promise
will
will
resolve
resolve
to
to
a
a
media
media
stream
stream
object.
object
Once
once
we
we
have
have
access
access
to
to
the
the
webcam,
webcam
we
we
can
can
also
also
go
go
ahead
ahead
and
and
set
set
up
up
the
the
remote
remote
stream
stream
here,
here
which
which
itself
itself
will
will
just
just
be
be
an
an
empty
empty
media
media
stream.
stream
Now
now
from
from
here,
here
we
we
need
need
to
to
take
take
our
our
2
2
streams
streams
and
and
make
make
them
them
available
available
on
on
the
the
peer
peer
connection
connection
and
and
show
show
them
them
on
on
Video
video
elements
elements
in
in
the
the
DOM.
dom
The
the
local
local
stream
stream
is
is
already
already
running
running
here
here
in
in
the
the
browser,
browser
so
so
we
we
can
can
get
get
its
its
tracks
tracks
and
and
then
then
loop
loop
over
over
them.
them
And
and
for
for
each
each
track,
track
we'll
we'll
call
call
peer
peer
connection
connection
add
add
track
track
with
with
that
that
track
track
in
in
the
the
local
local
stream.
stream
Now
now
the
the
remote
remote
stream
stream
is
is
currently
currently
empty
empty
and
and
it
it
will
will
be
be
updated
updated
by
by
the
the
Pure
pure
connection
connection
itself.
itself
So
so
what
what
we
we
can
can
do
do
is
is
listen
listen
to
to
the
the
on
on
track
track
event
event
on
on
the
the
Pure
pure
connection,
connection
then
then
get
get
the
the
tracks
tracks
from
from
the
the
stream,
stream
Loop
loop
over
over
them
them
and
and
add
add
them
them
to
to
the
the
remote
remote
stream
stream
when
when
they
they
come
come
in.
in
Now,
now
the
the
final
final
step
step
for
for
managing
managing
our
our
streams
streams
is
is
to
to
apply
apply
them
them
To
to
video
video
elements
elements
in
in
the
the
DOM.
dom
We
we
can
can
do
do
that
that
by
by
simply
simply
calling
calling
the
the
video
video
element
element
source
source
object
object
and
and
setting
setting
it
it
equal
equal
to
to
the
the
stream.
stream
At
at
this
this
point,
point
we
we
have
have
a
a
way
way
to
to
manage
manage
a
a
local
local
and
and
remote
remote
stream
stream
through
through
the
the
peer
peer
connection.
connection
But
but
in
in
order
order
to
to
make
make
that
that
happen,
happen
we
we
need
need
to
to
do
do
some
some
signaling
signaling
with
with
Firestore.
firestore
The
the
user
user
who
who
starts
starts
a
a
call
call
is
is
the
the
one
one
who
who
makes
makes
an
an
offer.
offer
We
we
have
have
a
a
call
call
button
button
in
in
the
the
DOM
dom
to
to
handle
handle
that
that
functionality
functionality
inside
inside
this
this
async
async
function
function
here.
here
We
we
have
have
a
a
call
call
document,
document
which
which
is
is
used
used
to
to
manage
manage
the
the
answer
answer
and
and
offer
offer
from
from
both
both
users.
users
Then
then
we
we
have
have
offer
offer
candidates
candidates
and
and
answer
answer
candidates,
candidates
which
which
are
are
subcollections
subcollections
under
under
that
that
document
document
that
that
contain
contain
all
all
the
the
candidates
candidates
for
for
each
each
of
of
those
those
users.
users
When
when
we
we
reference
reference
a
a
document
document
without
without
an
an
ID,
id
Firebase
firebase
will
will
automatically
automatically
generate
generate
a
a
random
random
ID
id
for
for
us.
us
So
so
we'll
we'll
go
go
ahead
ahead
and
and
use
use
that
that
to
to
populate
populate
an
an
input
input
in
in
the
the
UI,
ui
which
which
can
can
then
then
be
be
used
used
in
in
another
another
browser
browser
tab
tab
or
or
by
by
another
another
user
user
somewhere
somewhere
else
else
in
in
the
the
world
world
to
to
answer
answer
the
the
call.
call
Now
now
we're
we're
ready
ready
to
to
create
create
an
an
offer
offer
and
and
save
save
it
it
to
to
the
the
database.
database
The
the
first
first
thing
thing
we'll
we'll
do
do
is
is
await
await
the
the
peer
peer
connection
connection
create
create
offer
offer
method,
method
which
which
will
will
return
return
with
with
an
an
offer
offer
description.
description
We'll
we'll
then
then
set
set
it
it
as
as
the
the
local
local
description
description
on
on
the
the
Pure
pure
connection.
connection
Most
most
importantly,
importantly
this
this
object
object
contains
contains
an
an
SDP
sdp
value,
value
Which
which
stands
stands
for
for
Session
session
Description
description
Protocol.
protocol
That's
that's
the
the
value
value
we
we
want
want
to
to
save
save
to
to
the
the
database,
database
so
so
we'll
we'll
go
go
ahead
ahead
and
and
convert
convert
it
it
to
to
a
a
plain
plain
JavaScript
javascript
object,
object
Then
then
write
write
it
it
to
to
the
the
database
database
by
by
calling
calling
await
await
call
call
document
document
set
set
with
with
that
that
data.
data
Now
now
what's
what's
inside
inside
the
the
SDP
sdp
object
object
isn't
isn't
really
really
important,
important
but
but
it
it
contains
contains
information
information
about
about
the
the
Video
video
codec
codec
along
along
with
with
a
a
bunch
bunch
of
of
other
other
stuff
stuff
to
to
negotiate
negotiate
the
the
connection.
connection
Now
now
one
one
really
really
important
important
thing
thing
to
to
point
point
out
out
here
here
is
is
that
that
when
when
we
we
called
called
set
set
local
local
description,
description
it
it
automatically
automatically
started
started
generating
generating
the
the
ICE
ice
candidates.
candidates
An
an
ICE
ice
candidate
candidate
contains
contains
a
a
potential
potential
IP
ip
address
address
and
and
port
port
pair
pair
that
that
can
can
be
be
used
used
to
to
establish
establish
the
the
actual
actual
peer
peer
to
to
peer
peer
connection.
connection
Need
need
to
to
be
be
listening
listening
to
to
the
the
ICE
ice
candidates,
candidates
so
so
it's
it's
important
important
that
that
we
we
have
have
a
a
listener
listener
established
established
before
before
we
we
make
make
that
that
call
call
that
that
listens
listens
to
to
the
the
on
on
ICE
ice
candidate
candidate
event.
event
When
when
the
the
event
event
is
is
fired,
fired
we'll
we'll
make
make
sure
sure
that
that
a
a
candidate
candidate
exists,
exists
then
then
write
write
the
the
data
data
as
as
JSON
json
to
to
the
the
offer
offer
candidate's
candidate's
collection.
collection
So
so
at
at
this
this
point,
point
as
as
the
the
caller
caller
making
making
the
the
offer,
offer
We
we
are
are
saving
saving
all
all
of
of
our
our
data
data
to
to
the
the
database,
database
but
but
now
now
we
we
need
need
to
to
also
also
be
be
listening
listening
for
for
the
the
answer
answer
from
from
the
the
user
user
on
on
the
the
other
other
end.
end
The
the
way
way
we
we
do
do
that
that
is
is
by
by
listening
listening
to
to
changes
changes
to
to
the
the
called
called
document
document
in
in
Firestore.
firestore
The
the
on
on
snapshot
snapshot
method
method
will
will
fire
fire
a
a
callback
callback
anytime
anytime
the
the
document
document
in
in
the
the
database
database
changes.
changes
If
if
our
our
peer
peer
connection
connection
doesn't
doesn't
have
have
a
a
remote
remote
description
description
and
and
the
the
data
data
has
has
an
an
answer,
answer
then
then
we'll
we'll
go
go
ahead
ahead
and
and
set
set
an
an
answer
answer
description
description
on
on
our
our
peer
peer
connection
connection
here
here
locally.
locally
In
in
other
other
words,
words
we're
we're
listening
listening
to
to
our
our
database
database
for
for
an
an
answer
answer
and
and
when
when
that
that
answer
answer
is
is
received,
received
we
we
update
update
it
it
on
on
our
our
peer
peer
connection.
connection
That
that
negotiates
negotiates
the
the
initial
initial
connection,
connection
But
but
we
we
also
also
need
need
to
to
listen
listen
for
for
ICE
ice
candidates
candidates
from
from
the
the
answering
answering
user.
user
We
we
do
do
that
that
by
by
listening
listening
to
to
updates
updates
to
to
the
the
answer
answer
candidates
candidates
collection.
collection
Firestore
firestore
has
has
a
a
cool
cool
little
little
feature
feature
where
where
you
you
can
can
listen
listen
to
to
only
only
the
the
documents
documents
that
that
have
have
been
been
added
added
to
to
the
the
collection,
collection
which
which
is
is
handled
handled
with
with
the
the
doc
doc
changes
changes
method
method
on
on
the
the
query.
query
So
so
every
every
time
time
we
we
have
have
a
a
new
new
document
document
added,
added
we
we
can
can
then
then
create
create
a
a
new
new
ICE
ice
candidate
candidate
with
with
the
the
document
document
data
data
and
and
then
then
add
add
that
that
candidate
candidate
to
to
our
our
peer
peer
connection.
connection
At
at
this
this
point,
point
we're
we're
listening
listening
to
to
updates
updates
from
from
the
the
answer
answer
side,
side
but
but
we
we
still
still
need
need
to
to
give
give
the
the
answering
answering
user
user
a
a
way
way
to
to
actually
actually
answer
answer
the
the
call.
call
Answering
answering
a
a
call
call
is
is
very
very
similar
similar
to
to
initiating
initiating
a
a
call.
call
The
the
main
main
difference
difference
is
is
that
that
we're
we're
going
going
to
to
listen
listen
to
to
a
a
document
document
in
in
Firestore
firestore
with
with
the
the
same
same
document
document
ID
id
that
that
was
was
created
created
by
by
the
the
caller.
caller
We'll
we'll
make
make
a
a
reference
reference
to
to
that
that
document
document
as
as
well
well
as
as
the
the
answer
answer
candidate's
candidate's
collection,
collection
then
then
listen
listen
to
to
the
the
ICE
ice
candidate
candidate
event
event
on
on
the
the
peer
peer
connection
connection
to
to
update
update
the
the
answer
answer
The
the
candidate's
candidate's
collection
collection
whenever
whenever
a
a
new
new
candidate
candidate
is
is
generated.
generated
From
from
there,
there
we
we
can
can
fetch
fetch
the
the
call
call
document
document
from
from
the
the
database
database
and
and
grab
grab
its
its
data.
data
It
it
contains
contains
the
the
offer
offer
data,
data
Which
which
we
we
can
can
use
use
to
to
set
set
a
a
remote
remote
description
description
on
on
the
the
peer
peer
connection.
connection
After
after
that,
that
we
we
can
can
then
then
generate
generate
an
an
answer
answer
locally,
locally
then
then
set
set
the
the
local
local
description
description
as
as
the
the
answer.
answer
Now
now
just
just
like
like
we
we
did
did
with
with
the
the
offer
offer
in
in
the
the
previous
previous
function,
function
we'll
we'll
set
set
it
it
up
up
as
as
a
a
plain
plain
object
object
and
and
then
then
update
update
it
it
on
on
the
the
call
call
document
document
so
so
that
that
the
the
other
other
user
user
can
can
listen
listen
to
to
the
the
answer.
answer
In
in
addition,
addition
we'll
we'll
set
set
up
up
a
a
listener
listener
on
on
the
the
offer
offer
candidates
candidates
collection,
collection
and
and
whenever
whenever
a
a
new
new
ICE
ice
candidate
candidate
is
is
added
added
to
to
that
that
collection,
collection
then
then
we'll
we'll
go
go
ahead
ahead
and
and
create
create
an
an
ICE
ice
candidate
candidate
here
here
locally.
locally
And
and
that's
that's
all
all
it
it
takes
takes
to
to
build
build
a
a
video
video
chat
chat
feature
feature
With
with
WebRTC,
webrtc
the
the
vast
vast
majority
majority
of
of
the
the
work
work
is
is
just
just
signaling
signaling
data
data
between
between
the
the
two
two
users.
users
WebRTC
webrtc
handles
handles
all
all
the
the
complicated
complicated
peer
peer
to
to
peer
peer
networking
networking
and
and
media
media
streaming
streaming
under
under
the
the
hood.
hood
I'm
i'm
gonna
gonna
go
go
ahead
ahead
and
and
wrap
wrap
things
things
up
up
there.
there
If
if
this
this
video
video
helped
helped
you,
you
please
please
like
like
and
and
subscribe.
subscribe
And
and
if
if
you
you
wanna
wanna
learn
learn
more
more
advanced
advanced
concepts
concepts
about
about
the
the
web
web
and
and
Firebase,
firebase
consider
consider
becoming
becoming
a
a
pro
pro
member
member
atfireship
atfireship
io.
io
Thanks
thanks
for
for
watching,
watching
and
and
I
i
will
will
see
see
you
you
in
in
the
the
next
next
one.
one
success
The speakers discuss the use of WebRTC for video conferencing and the challenges of peer-to-peer connections. They also explain the process of creating a vanilla JavaScript project using Vite and the use of APIs for streaming video streams. The speakers then give a tutorial on creating a vanilla JavaScript project using the Vite tool and the SDP object, explaining how to handle streaming media streams and set up remote streams through the peer connection. They also discuss managing video and audio streams and setting up a listener on the offer candidates collection and generate an answer locally. WebRTC handles all of the complicated peer to peer networking and media streaming.
WebRTC in 100 Seconds // Build a Video Chat app from Scratch
WebRTC. Exchange real time audio video streams with your friends entirely in the browser. I'm here live. It's not I'm not a cat. If you wanna build your own video conferencing app to capitalize on the work from home boom, then WebRTC is the API you're looking for Because it allows you to establish a peer to peer connection between 2 or more browsers where they can exchange audio video media directly Without the need for a third party server or native app, it works like this. The first peer will create an offer asking for another peer to connect to them. This will in an SDP object or session description protocol, which contains information describing the peer to peer connection, like the video codec, timing, and so on. The Data will then be saved in a server where it can then be read by another peer to answer the call, which is achieved by creating an STP answer and writing that to the server. This process Is known as signaling, and it's handled by a third party server. The signaling server allows the 2 parties to securely exchange connection data, never touches the media that's actually transmitted between the peers. But here's where things get tricky. Most devices in the real world sit behind firewalls and IP addresses constantly change thanks to network address translation. This makes peer to peer connection complicated from a networking standpoint. But luckily, there's a standard called Active Connectivity Establishment or ICE, which helps clients coordinate the discovery of their public facing IP addresses. Now both peers We'll generate a list of ICE candidates, which contain an IP address and port that peer 1 can use to connect to peer 2. In the background, WebRTC will do this By making a series of requests to a stun server. A stun server is not something you need to set up on your own because there are many free options out there from reliable sources like Google. Each peer will save their ICE candidates in the database where they can then be read by the other peer. The algorithm will then automatically determine which candidate is best, at which point real time media can begin flowing between the two peers. This has been WebRTC in 100 seconds. If you wanna see more short videos like this, make sure to hit the like button, then stay tuned because now we're going to build our own Video chat app from scratch. That may sound pretty complicated, but the WebRTC API allows all this stuff to magically happen in the background. Over the few minutes, you'll build a peer to peer video calling app from scratch using nothing but vanilla JavaScript and Firebase as the signaling server. By the end of this tutorial, You'll know how to implement real time features that cater to the needs of the new work from home paradigm that we live in. In addition to this video, you can also reference the Full article on Fireship IO and the source code on GitHub. Let's start by taking a look at the demo. We have the local user's video feed on the left side and the Remote video on the right side. The local user will first grant permission for the app to access the webcam. That user can then create a call, which will write a document to Firestore with the offer details. At the same time, we'll create a peer connection instance in the browser, which handles the WebRTC negotiation process. The offer will have a unique ID that can then be accessed by another user somewhere else in the world. That user will then join the call with the unique ID, Then establish their own peer connection and write the answer details to the same document. Then both peers will write their ICE candidates To the database, we have one sub collection for offer candidates and another for answer candidates. This data model will allow signaling to take place between the two peers. The data itself looks like a bunch of nonsense, but what it contains is an IP address port pair that allows the 2 peers to establish a connection. Now both users can listen to this data in real time Then use the WebRTC API in the browser to establish the connection, giving us a one to one video chat feature. And now we're ready to jump into our JavaScript code. I started by creating a vanilla JavaScript project using a tool called Vite, which is a very simple build tool developed by the Vue JS guy. We can initialize a new project by running npm initvjs/app from the command line. Basically, it gives us a web project where we can install dependencies without having to worry about things like webpack. After initializing the project, we need to install Firebase. Firebase contains the Firestore database, which we can use as our back end server. Firebase is an exceptional choice for a signaling server because it's easy to listen to updates to the database in real time. If we were working with a traditional database, we'd likely have to implement something like WebSockets to make that possible and this video would be a crazy 20 minutes long or something. From the Firebase console, initialize Firestore in test mode, then create a web project from the settings panel and grab your project credentials. We can then go into the main JS file, import Firebase, And initialize the app with our Firebase config. Now that we have Firebase set up, we're going to initialize 3 pieces of global state. These are values you would likely want to share between multiple components if you're using a UI framework like React or Angular. The first and most important Value is the rtc pure connection. This object is where all of the action happens. It emits a bunch of different events that we Listen to to update the database and to add media streams to the connection itself. One very important thing it does is generate the ICE candidates, But in order to do that, it needs to know which STUN servers to use. There are many different options out there, but we're just going to use the free ones from Google. From there, we have values for local stream and remote stream, which are the video streams from the webcams of each user. Now because we're working with vanilla JS, we need to use Imperative Dom APIs. We're using document get element by ID to grab a bunch of elements from the HTML, like video elements to Show the actual video feeds along with buttons that provide different interaction in the UI. The first thing the user will do is click a button to open up their webcam. We'll We'll go ahead and register an event handler for the click event on the webcam button. Obtaining a stream from the user's webcam is very easy. We just await the navigator mediatevices Is get user media method and will set video and audio to true. That'll bring up a dialogue in the browser asking the user for permission to access the webcam. That's complete, the promise will resolve to a media stream object. Once we have access to the webcam, we can also go ahead and set up the remote stream here, which itself will just be an empty media stream. Now from here, we need to take our 2 streams and make them available on the peer connection and show them on Video elements in the DOM. The local stream is already running here in the browser, so we can get its tracks and then loop over them. And for each track, we'll call peer connection add track with that track in the local stream. Now the remote stream is currently empty and it will be updated by the Pure connection itself. So what we can do is listen to the on track event on the Pure connection, then get the tracks from the stream, Loop over them and add them to the remote stream when they come in. Now, the final step for managing our streams is to apply them To video elements in the DOM. We can do that by simply calling the video element source object and setting it equal to the stream. At this point, we have a way to manage a local and remote stream through the peer connection. But in order to make that happen, we need to do some signaling with Firestore. The user who starts a call is the one who makes an offer. We have a call button in the DOM to handle that functionality inside this async function here. We have a call document, which is used to manage the answer and offer from both users. Then we have offer candidates and answer candidates, which are subcollections under that document that contain all the candidates for each of those users. When we reference a document without an ID, Firebase will automatically generate a random ID for us. So we'll go ahead and use that to populate an input in the UI, which can then be used in another browser tab or by another user somewhere else in the world to answer the call. Now we're ready to create an offer and save it to the database. The first thing we'll do is await the peer connection create offer method, which will return with an offer description. We'll then set it as the local description on the Pure connection. Most importantly, this object contains an SDP value, Which stands for Session Description Protocol. That's the value we want to save to the database, so we'll go ahead and convert it to a plain JavaScript object, Then write it to the database by calling await call document set with that data. Now what's inside the SDP object isn't really important, but it contains information about the Video codec along with a bunch of other stuff to negotiate the connection. Now one really important thing to point out here is that when we called set local description, it automatically started generating the ICE candidates. An ICE candidate contains a potential IP address and port pair that can be used to establish the actual peer to peer connection. Need to be listening to the ICE candidates, so it's important that we have a listener established before we make that call that listens to the on ICE candidate event. When the event is fired, we'll make sure that a candidate exists, then write the data as JSON to the offer candidate's collection. So at this point, as the caller making the offer, We are saving all of our data to the database, but now we need to also be listening for the answer from the user on the other end. The way we do that is by listening to changes to the called document in Firestore. The on snapshot method will fire a callback anytime the document in the database changes. If our peer connection doesn't have a remote description and the data has an answer, then we'll go ahead and set an answer description on our peer connection here locally. In other words, we're listening to our database for an answer and when that answer is received, we update it on our peer connection. That negotiates the initial connection, But we also need to listen for ICE candidates from the answering user. We do that by listening to updates to the answer candidates collection. Firestore has a cool little feature where you can listen to only the documents that have been added to the collection, which is handled with the doc changes method on the query. So every time we have a new document added, we can then create a new ICE candidate with the document data and then add that candidate to our peer connection. At this point, we're listening to updates from the answer side, but we still need to give the answering user a way to actually answer the call. Answering a call is very similar to initiating a call. The main difference is that we're going to listen to a document in Firestore with the same document ID that was created by the caller. We'll make a reference to that document as well as the answer candidate's collection, then listen to the ICE candidate event on the peer connection to update the answer The candidate's collection whenever a new candidate is generated. From there, we can fetch the call document from the database and grab its data. It contains the offer data, Which we can use to set a remote description on the peer connection. After that, we can then generate an answer locally, then set the local description as the answer. Now just like we did with the offer in the previous function, we'll set it up as a plain object and then update it on the call document so that the other user can listen to the answer. In addition, we'll set up a listener on the offer candidates collection, and whenever a new ICE candidate is added to that collection, then we'll go ahead and create an ICE candidate here locally. And that's all it takes to build a video chat feature With WebRTC, the vast majority of the work is just signaling data between the two users. WebRTC handles all the complicated peer to peer networking and media streaming under the hood. I'm gonna go ahead and wrap things up there. If this video helped you, please like and subscribe. And if you wanna learn more advanced concepts about the web and Firebase, consider becoming a pro member atfireship io. Thanks for watching, and I will see you in the next one.
The speakers discuss the use of WebRTC for video conferencing and the challenges of peer-to-peer connections. They also explain the process of creating a vanilla JavaScript project using Vite and the use of APIs for streaming video streams. The speakers then give a tutorial on creating a vanilla JavaScript project using the Vite tool and the SDP object, explaining how to handle streaming media streams and set up remote streams through the peer connection. They also discuss managing video and audio streams and setting up a listener on the offer candidates collection and generate an answer locally. WebRTC handles all of the complicated peer to peer networking and media streaming.