
This course includes our updated coding exercises so you can practice your skills as you learn.
See a demo
To understand why WebRTC was created, you need to understand the traditional flow of data over the wire using HTTP. Because remember, WebRTC does not use HTTP. That's right, WebRTC dances to its own tune, and has its own set of protocols and rules that tell us (developers) how to send data from one peer to another peer.
In this lecture I'll show you how we would go about building a simple HTTP chat app. I'm sure you'll quickly see the limitations.
WebRTC uses the RTCPeerConnection interface and dances to its own tune - it does NOT use the HTTP protocol. This lecture will expose you to how WebRTC works, and you may be surprised to learn a few things you didn't know before.
WebRTC is a client-side (browser) API, and therefore to access it, you need to know how to use and write JavaScript.
Most developers think that WebRTC is a new technology that was introuced in 2021.
But you are not like most other developers.
Let me show you that WebRTC was used WAYYYYY back in the old days, before it became officially recommended by the W3C.
WebRTC differs from protocols like HTTP/2 or HTTP/3, which are governed by a single comprehensive specification. Instead, WebRTC is defined across numerous documents, including W3C specifications and various RFCs, totaling over 50. This decentralized approach allows for flexibility and modularity, encompassing multiple aspects such as media transport, security, and connection establishment, which are detailed in separate specifications rather than a single document.
I know most of you think that WebRTC is used for video conferencing ... but did you know there are many other uses across various industries? I'll show you a multiplayer game that used WebSockets all the way back in 2013, and i'll show you some other use cases that you may not have thought of before.
Have you ever wondered what language WebRTC itself was written in?
In this fun lecture I'll show you what the RTCPeerConnection constructor function looks like, and also explain why you have to use the "new" keyword in order to invoke the function.
Next, before a WebRTC connection can be established, you need to understand two key aspects of WebRTC - the data that is being sent/received and ... drumroll ... the actual peer-to-peer connection setup itself.
I really can't wait to get into the nitty gritty, in the next section!
Just for fun, lets use getUserMedia() method (which is part of the entire WebRTC API) that allows web applications to access the user's camera and microphone. When invoked, it prompts the user for permission to use these media inputs. If granted, it returns a promise that resolves to a MediaStream, which contains audio and/or video tracks.
The MediaDevices.enumerateDevices() method retrieves a list of available media input and output devices, such as microphones and cameras. It returns a Promise that resolves with an array of MediaDeviceInfo objects, each containing details about the devices. This method is essential for applications that require user media, allowing developers to present options for device selection.
Great Clyde, we have the video stream ... but how do we see it?
To display a media stream in a <video> tag using WebRTC, utilize the getUserMedia() API to capture video from the user's camera. This media stream is then assigned to the srcObject property of the <video> element.
In the olden days, we used to create a URL object that points to a blob that contains the stream. But today I'll show you that this method is deprecated.
WebRTC requires the identification of computers to establish secure peer-to-peer connections. This process is facilitated by Interactive Connectivity Establishment (ICE) servers, which help in NAT traversal and connection setup. However, for manual identification, tools like ipconfig, netstat, and services like whatismyipaddress.com can be used to retrieve local and public IP addresses.
Before we move on, I want to clarify that just because I could see my public routers login page, this does not mean that it will be the case for you.
Network Address Translation (NAT) is a technique that allows multiple devices on a local network to share a single public IP address by modifying the IP header of packets as they pass through a router. In the context of WebRTC, NAT poses challenges for peer-to-peer connections, as it can block direct communication between devices. To overcome this, WebRTC employs protocols like STUN and TURN to facilitate connectivity by discovering public addresses and relaying traffic when direct connections are not possible
I would like to provide a high-level overview of what is required for two devices to establish a connection. Understanding this concept is crucial, as it applies not only to WebRTC but also to any connection made between two devices, such as your PC connecting with Udemy. Spoiler alert ?: every connection is uniquely identified and managed through a process known as a 5-tuple.
Before diving into the ICE Framework, it’s helpful to understand the entire workflow from User 1's perspective when setting up a WebRTC connection.
While there are many steps involved, grasping the logic behind each one makes the process intuitive and straightforward.
The very first step in establishing a successful WebRTC connection is to create the "object" that manages the entire process. As I mentioned in Section 1, this is done by invoking the RTCPeerConnection() constructor function.
Next, you need to communicate to the other peer what types of data you are willing to send and receive. This step is crucial because, before you can calculate the various paths or candidates that the other side can use to connect with you, you must first clarify the types of data involved in the communication. After that, you'll send your available routes (candidates) to the other peer.
Finally, you must wait for the other peer to send you important information as well. Once all these steps are completed, a successful WebRTC connection can be established.
This overview covers the essential aspects of the process, though there is more to explore beyond this initial understanding, which I'll do later.
ICE servers play a crucial role in WebRTC by facilitating peer-to-peer connections, especially when devices are behind NATs or firewalls. They gather potential connection paths, known as ICE candidates, using STUN and TURN protocols.
The ICE (Interactive Connectivity Establishment) Framework is a crucial component of WebRTC that facilitates connections between devices, especially when navigating network obstacles like NATs and firewalls.
The ICE Agent is responsible for managing this process, gathering potential network addresses (ICE candidates) and determining the best path for establishing a reliable connection. But don't stress - an "Ice Agent" is just a piece of code within the browser that handles this process.
In this lecture, we will examine the RTCPeerConnection object, which we will store in a variable called "pc."
I have already highlighted the most important properties of this object, including localDescription and remoteDescription. However, it's also essential to note some valuable read-only properties such as connectionState, signalingState, iceGatheringState, and iceConnectionState. These properties provide crucial insights into the status and behavior of the connection throughout the WebRTC process.
Oh and I almost forgot - lets also set up a icegatheringstatechange event listener too :)
In this lecture, I'll show you how you can examine a WebRTC session within a browser. In other words, using tools given to us by a browser.
The most common is Chrome's chrome://webrtc-internals tool.
But did you know that Firefox also has one: about:webrtc.
These tools can be used for debugging WebRTC connections.
DID YOU KNOW?
The URLs chrome://webrtc-internals and about:webrtc are not traditional URLs that use standard web protocols like HTTP or HTTPS. Instead, they are special internal URLs (often referred to as "chrome URLs" or "about pages") used by web browsers to access built-in features or settings directly.
Most developers I know, only think that Chrome and Firefox have internal methods to view WebRTC connections. This is not true.
The onicecandidate event is fired when the local ICE agent finds a new candidate that can be used to connect to the remote peer. This could include candidates from different network interfaces (e.g., local IP addresses, public IPs obtained via STUN servers).
When this event occurs, it is necessary to send the gathered ICE candidate to the remote peer through a signaling server. This allows both peers to have the necessary information to establish a connection.
Creating a WebRTC offer involves using the RTCPeerConnection.createOffer() method, which generates an SDP (Session Description Protocol) offer to initiate a connection with a remote peer.
Once the offer is created, it is set as the local description using setLocalDescription(), and then sent through a signaling server to the remote peer. The remote peer will subsequently set this offer as its remote description and respond with an answer, completing the connection negotiation process
With all this talk of "offers", "answers" etc, it can be tricky to conceptualize it. In this short lecture I'll explain in my own words how you should think about an WebRTC offer.
In JavaScript, there are two primary ways to handle asynchronous operations: using .then() and .catch() versus async and await.
.then() and .catch(): This method chains callbacks for resolved and rejected promises, allowing for clear handling of success and error cases.
async/await: Introduced in ES7, this syntax allows writing asynchronous code in a more synchronous style. Functions marked with async return promises, and await pauses execution until the promise resolves, simplifying error handling with try...catch.
Additionally, functions can be defined using the function keyword or arrow syntax with const.
Confused much?
Don't stress, I'll explain everything in this lecture.
WebRTC manages connections using local and remote session descriptions, which are key components of the signaling process. The local session description is created by the initiating peer, typically via the setLocalDescription() method, and contains details about its media capabilities. This description is sent to the remote peer. Conversely, the remote session description is set using setRemoteDescription(), which incorporates the received offer or answer from the other peer, allowing both sides to agree on compatible media parameters.
The remote session description in WebRTC is a crucial component that defines the media properties and configuration of the remote peer in a connection. It is represented by an RTCSessionDescription object, which is set using the RTCPeerConnection.setRemoteDescription() method after receiving an offer or answer from another peer. This description includes details such as media formats and transport protocols, allowing both peers to negotiate and agree on the parameters necessary for effective communication. If not yet set, the remote session description will return as null.
For a WebRTC connection to be successfully established, both the localDescription and remoteDescription properties must be set appropriately.
You are learning tons!
In this lecture, I'll introduce you to the JavaScript Session Establishment Protocol (JSEP), outlined in RFC 9429, that governs the formatting of the the signaling process in WebRTC by managing the exchange of session descriptions and ICE candidates. During the WebRTC connection process, peers format their offers and answers using SDP to specify media capabilities and transport configurations. Additionally, JSEP handles the rules governing the Interactive Connectivity Establishment (ICE) state machine.
It really is a pitty that so many developers skip learning about this.
To add media to a WebRTC peer connection, you can use the getTracks() method to retrieve individual tracks from a media stream obtained via getUserMedia(). Each track can then be added to the RTCPeerConnection using the addTrack() method.
The process typically involves creating an RTCPeerConnection, retrieving tracks from the local media stream, and iterating through them to call addTrack(track, localStream) for each track. This setup usually happens before the connection is established, ensuring immediate availability of media streams for transmission.
In this lecture, the focus is on utilizing the getStats() method in WebRTC to access and display connection statistics. By invoking getStats() on an RTCPeerConnection, developers can retrieve real-time data about media streams, including metrics like packet loss and video quality. The statistics are returned as an array of reports, which can be iterated through using a loop. Each report can be formatted and displayed in the console or on a webpage, providing insights into the performance of the WebRTC connection and enabling effective monitoring and troubleshooting of communication sessions.
In this lecture, we will explore how an OFFER in WebRTC defines the media types and capabilities the initiating peer is willing to send and receive. By default, this is indicated by the a=sendrecv flag in the Session Description Protocol (SDP). However, you can modify the SDP to change this behavior. For instance, by setting the a=recvonly flag, a peer can specify that it is only willing to receive media but not send any. This flexibility is particularly useful in scenarios like one-way video streaming or when a peer needs to conserve bandwidth. By customizing the SDP, developers can tailor their WebRTC connections to meet specific application requirements, enhancing control over media transmission and reception. This capability showcases the power of WebRTC in enabling dynamic and adaptable communication setups.
In this lecture, I will demonstrate how to generate HOST ICE candidates in WebRTC. Since we haven't configured any STUN servers for our RTCPeerConnection object, only host candidates will be returned. Host candidates are created by binding to the client's locally assigned IP addresses and ports, allowing direct connections within a local network.
The onnegotiationneeded event in the RTCPeerConnection interface is triggered when a change occurs that requires session negotiation, such as adding a new media track. This event signals that the connection needs to be negotiated (or renegotiated), and it should be handled by the offerer. The event handler typically creates an offer using createOffer() and sets it as the local description with setLocalDescription(), allowing for updated session parameters to be communicated to the remote peer.
The RTCIceCandidate interface represents a candidate for establishing a WebRTC connection. Key properties include:
candidate: A string detailing the candidate's network information, formatted according to the SDP specification.
sdpMid: Identifies the media stream associated with the candidate, linking it to a specific media description in the SDP.
sdpMLineIndex: Indicates the index of the media line in the SDP where this candidate is defined, helping to correlate candidates with their respective media types.
A STUN server helps devices figure out their public IP address and public port when they’re behind a router or firewall. This is important for apps like video calls or online games that need devices to connect directly to each other. By asking the STUN server, a device learns how it appears on the internet, making it easier to set up a smooth connection without complicated setups.
A few fun facts about STUN.
In this lecture I'll show you how to find free STUN servers, and then how to add those servers to your configuration options when creating your peer connection object.
This is a big milestone because it's telling the ice agent that you want it to find out what your IP configurations are from the public's perspective.
I want to use a packet sniffer like WireShark to show you how to view a binding STUN request from your server and to view a binding STUN response from a server.
The point of this is to solidify what you've learnt and to also show you that the concepts you are learning in this course are very real and very PRACTICAL.
STUN can fail to traverse NAT in certain scenarios, primarily due to the limitations of NAT types and network configurations:
Symmetric NAT: STUN struggles with symmetric NATs, where the NAT device assigns a unique mapping for each external connection. This makes it difficult for peers to establish direct communication without additional help, as the mappings are inconsistent and unpredictable.
Firewalls and Security Policies: Some firewalls block UDP traffic or enforce strict rules, preventing STUN from functioning properly.
Multiple NAT Layers: Networks with multiple NAT devices or complex configurations can disrupt STUN's ability to establish connections.
In such cases, TURN servers act as relays to ensure communication.
A TURN server (Traversal Using Relays around NAT) is a network service that relays data between devices when they cannot connect directly due to NAT or firewall restrictions. It acts as an intermediary, receiving data from one client and forwarding it to another, ensuring communication in scenarios where direct peer-to-peer connections fail.
The WebRTC suite of APIs and protocols do not tell us how to exchange important connection information between two peers. That gives u a lot of freedom.
It means you can build a WebRTC signaling server in a way that suits you and makes you feel most comfortable.
Different types include:
SIP (Session Initiation Protocol): Used for initiating and managing communication sessions.
XMPP (Extensible Messaging and Presence Protocol): An XML-based protocol for instant messaging and presence.
WebSockets: Enables full-duplex communication over a single TCP connection.
AJAX: Allows asynchronous data exchange, often used for real-time updates.
Developers often have the tendency to overcomplicate code.
Its time to get serious, and to show you for the first time the entire WebRTC connection process.
As you'll soon discover, there are a lot of moving parts.
However, each part on its own makes sense, and is relatively simple.
In WebRTC, the final step of the ICE process involves connectivity checks. This critical phase tests all gathered ICE candidates by attempting to send media packets across various address pairs. The goal is to identify a successful path for media transmission between peers, ensuring effective communication.
I've attached the coding files to this lecture just in case you get stuck.
This section is not mandatory for WebRTC
This lecture will introduce you to our HTML and CSS files, and how I have laid out the project. As I'll explain, I will not be coding up HTML and CSS with you, as I want the focus of this course to be on the more (complicated) heavy application logic side.
I want to structure our files better. It's good practice to separate your public files (those accessible by the browser ... in other words, your frontend code) from your server files. Therefore, I'll set up a PUBLIC folder that contains our frontend code.
But I want you to be a grandmaster, so for that reason i'll also insert a MODULES folder that will contain all of our modules. I'll be using the latest ES Module syntax in this course, so get ready for some awesome knowledge.
Finally, we can calcualate the userId and display that to the user using template literals.
Managing state is crucial, and its for this reason that I want to show you how to create a state.js module that will manage our users state for their entire WebRTC session. I'll also show you how to use spread operators to define a generic setter function so we can set various properties on our state object later in this section.
Now that we have set up our file directors and modules, why don't we add logic inside of our uiUtils.js file to enable the modal to work correctly.
I gave you a challenge at the end of the previous lecture to allow the user to click anywhere outside of the modal content box to trigger an event on the window object that will execute the closeModal() function.
I will use the target property to make this work.
I want to improve our code slightly by removing the hidden class entirely (indeed you would have noticed that we have a .hide class so having a hidden class makes this redundant).
Exciting times, because now we're going to turn our attention to setting up our backend server. I will show you how to initiate a Node.js project. I'll also show you:
how to tell Node to use ES Module syntax
how to install express and the ws module (for our WebSocket server)
how to install the native http module
We do a ton in this lecture, such as:
starting an express application
creating a HTTP server using Node's http module
attaching our express application to the http server
using middleware to tell Node to look in the "public" directory for static files
define a PORT for testing and production
spin up our server
I'll show you why many developers use Nodemon for testing purposes.
I'll also show you why developers usually set up a "start" script within their node application.
Just in case you are wondering .... here are some benefits of a "start" script:
Simplicity: Instead of typing long commands in the console every time you want to start your application, you can simply run npm start. This reduces the chance of errors and makes it easier to remember the command.
Consistency: By defining a standard command in your package.json, all team members can use the same command to start the project, ensuring consistency across different development environments.
Customization: You can customize the "start" script to include additional commands or environment variables, making it adaptable to various scenarios (e.g., development vs. production).
This lecture covers the process of listening for an incoming WebSocket connection request. We will be using the "ws" module on the server side to do this, which is a low-level library that is close to raw WebSockets. Many developers will use socket.io but I want you to truly understand whats happening behind the scenes.
I will also use the URLSearchParams object in Node to extract the userId from the query string.
This lecture focuses on managing user states within a WebSocket application. We will define a global connections object of type Array, that will contain an object for each user connected.
In this lecture we'll use the native WebSocket API that the browser makes available to initiate a WebSocket connection from the client.
This lecture addresses server-side logic for handling client disconnections and setting up a function for incoming messages.
Do you remember that on the client-side, we have a state.js file that manages our user's state? Well, I want to now set up a websocket connection object and attach it to this state. I also want to set up our code to listen for the other 3 WebSocket events on the client side - the message, close and error events.
In this lecture, you'll learn how to create a custom logging mechanism on the client side for monitoring all of our interactions (including for WebRTC later). The lecture emphasizes the importance of logging for debugging and performance tracking, providing insights into client-server communication and application behavior.
This lecture focuses on organizing code by defining a constants.js file that holds reusable values for our WebRTC application. Of course, let's not forget about the custom logger we created in the previous lecture, so we will test that everything works as expected.
This lecture covers how to set up event listeners for handling various WebSocket events on the client side. You'll learn about different types of events, such as onopen, onmessage, and onclose, which are crucial for managing interactions and ensuring smooth communication between clients and servers.
Well done for completing this section. Seriously. It was tough!
But keep going.
This section is not mandatory.
In this lecture let's set up a click event listener on the create button so that we can then send an AJAX request to our server to perform business logic on the room.
I will also set up a new ajax.js module that will handle all of our ajax related code.
In this lecture let's access the Fetch API to send a POST ajax request to our server.
Why a POST request? Well, we have to send the server data (the userId and the roomName) so that the server can manage room state and perform certain checks.
As you'll see, Fetch is Promised based, therefore we have to catch the result of the Promise in a .then() statement. We will use the json() method to wait for the browser to process the response stream which again is in a Promise.
If you are uncertain at all about Fetch and AJAX, please check out my AJAX course. It's EPIC.
Node is powerful, and one of its best features is the ability to process streams of data in the form of chunks.
In this lecture I'll show you how to use an express middleware (express.json()) which basically does the same thing as the browser's .json() method.
However, I will go further and actually remove this middleware and show you to process the raw chunks directly. Why? Because I want you to become a true coding Grandmaster.
After performing checks, I want to to send back a response to the client that will either be a success or failure.
I want to implement logic that tests for the response cases from the server, and update our state object and UI accordingly.
In this lecture we will complete the UI component - that is, when a user creates a room successfully, they need to enter the room.
If the user types in a channel name and hits the "return" or "enter" key, I want to trigger the click() event on our create button. This makes for a better user experience.
JavaScript is very finnicky about syntax. We are using the arrow syntax to loop through our array of rooms, and I totally forgot to include the "return" keyword. This causes issue as the "find" method needs to know what expression to test for and that's done by using the return keyword.
Let's write the logic on the frontend to send an AJAX request (using Fetch) to destroy a room. Why am I using AJAX and not WebSockets?
Well, remember that at this stage there is no other peer inside of this room. This means there is nothing we need to "push" to peer2 and thus we can handle all logic using AJAX. In other words, why complicate our code when we don't have to?
In this lecture let's hop back into our app.js (server) file and write the logic required to destroy a room. We will use the findIndex() method and slice() methods to do so.
Let's get crackin'
We can now finally finish off our code and test that all of our logic works.
In the previous lecture I noticed a bug. If the user (a) creates a room and (b) then disconnects for example by navigating away from the page, then the server does not remove the room from its state. This means if that user (or any other user) later attempts to create the same name room, an error will be thrown.
We don't want this.
Let's fix it.
Before we get onto the joining room logic, let's fix some errors. Firstly we are using the wrong method to remove an item from an array - I want to use splice, but instead I used slice.
Web browsers automatically send an HTTP request for a favicon (usually favicon.ico) upon loading a webpage. This request occurs if no favicon is specified in the HTML. If the favicon is missing, the browser will attempt to fetch it, leading to unnecessary 404 errors and additional overhead on page load.
In this lecture I'll show you how to fix that issue by using the data URI scheme.
Its now time to think about how we can write logic that will allow a second user to join a room.
I'll explain why I have decided to use our WebSocket server for this functionality.
Unlike a normal HTTP request (where we can route different types of requests to different URLs), WebSockets are always listening on the same url endpoint. This means we need to use "flags" of some sort to allow the WebSocket server to understand what logic that particular request relates to.
We will use JavaScript's switch() statement to make this task a lot more streamlined and easier to read.
Before a user can join a room, we need to check whether someone connected with our server has indeed created that particular room.
This is a timeout lecture where we can define a generic WebSocket send function that will allow us to easily specify which userId we want to send a message to.
This will come in handy as we have to send WebSocket responses to various users throughout our session.
The final check we have to perform is whether the room that a user wants to join is already occupier by other peers. Remember, we only want to limit the room to 2 peers.
We can easily do this by checking whether peer1 and peer2 properties are not null.
At this point in our code, we know that the room both exists and it is available (there are not already 2 users joined in the room).
This means that our server must perform two very important tasks:
send a successful response to the user requesting to join the room
notify the other user that a second peer has joined their room
Now that we have received a response from the server, the next step is to listen for incoming WebSocket messages from the server on the client side.
We will set up switch() statements to check and route different messages to the appropriate code blocks.
In this lecture we will deal with the successful case of a user requesting to join a room. We will have to update the global state object, redirect the user to the correct room, and finish off all logic on the frontend to set the scene for WebRTC.
The second function our server did was to send a notification to the creator of the room that a second peer has entered the room.
Logically, in this lecture we have to define code that listens for this incoming notification and then perform logic accordingly.
We encountered an error in the previous lecture which I want to address now.
While we are at it, let's also update our message container to make it clear that once two users have joined the room, they have now initiated a WebRTC process request.
Last but not least, we have to allow a user to exit a room.
The first step is to listen for a 'click' event on the exit button, and then to send the WebSocket server with the information required for the server to remove that user from the room.
We have to now handle the server-side code necessary to deal with an exit request.
In the previous lecture, the server sent a notification message to the person still in the room. The logic next step is for us to have code on the frontend that listens for a message of this type, so that we can indeed notify the remaining user that the other peer has left the room.
Proof is in the pudding as the old saying goes.
In this lecture let's test our application logic.
I noticed that if a user disconnects from our WebSocket server, that we are not notifying the other user that is still in the room.
In this lecture let's set up the server-side code that handles this logic.
The final piece of the puzzle is to listen on the frontend for a disconnection notification and then notify the user that the other peer in the room has somehow lost a connection.
A quick reminder about what is required for a WebRTC connection. I have also provided you with a markdown file that outlines the steps required. We may amend this file as we progress in the course.
Before we can create our WebRTC connection object, the very first step is to configure our STUN servers that will be used to establish routes (ice candidates).
We need this configuration object to pass into the RTCPeerConnection() constructor function.
But who am I kidding ... you already know all of this.
Let's get crackin'
The user who joins a room receives a sucessfull message from our WebSocket server. It is now that I want this user to initiate a WebRTC connection.
For learning purposes, I want to show the offeror (the user who is creating a WebRTC offer) all the buttons we'll be using throughout the course.
As you know, WebRTC is not possible without some 'object' managing the session. This 'object' is the peer connection object.
So without further ado, let's instantiate the RTCPeerConnection() constructor function, passing into it our STUN configurations.
In WebRTC, the connectionstatechange and signalingstatechange events help track what's happening with the connection between two devices. The connectionstatechange event tells you if the connection is working, disconnected, or trying to reconnect. The signalingstatechange event lets you know how the setup process for the connection is going, like when both devices are exchanging information to connect. These events help developers manage and troubleshoot live communication smoothly.
Now that you know what the connectionstatechange and signalingstatechange event listeners are, let's complete the logic for them in our WebRTC application.
After a user clicks a WebRTC button, I want to update the UI of the button to indicate its been clicked on. Not only this, but I also want us to define a custom handler function to take in a message argument, so that we can update the button, and log a custom message to our custom logger ALL IN ONE.
I can't wait.
Before we go further, let's test our code thus far.
I want to set up a click event listener on the next button and set up the function that will handle our logic of creating a data channel.
I want you to become a grandmaster coder, and for that I want to take this lecture to dig a little deeper into what a WebRTC data channel is. For example, it uses the SCTP protocol to transfer data, and only PEER1 has to create a Data Channel.
What?
Don't worry, after you view this lecture it'll all make sense.
While we are dealing with our data channel logic, I will create two separate pieces of code that will either create a new data channel (if PEER1) or register an event listener on the pc object for the creation of a data channel (if PEER2).
This is a great achievement and milestone.
(p.s. I will also add configurations to the data channel object, by converting it to allow unordered messaging, thus mimicking UDP).
I want to test our code up to this point, and also view the WebRTC connection in Chrome's webrtc-internals GUI.
Now that we have configured our peer connection object, passed in STUN servers, registered our data channel to our pc object, we can now (finally) create an offer. This offer will contain SDP information, as well as a type property to indicate its an offer.
Creating a WebRTC offer is only one piece of the puzzle. It's not enough. If you do nothing with the offer, it just floats around in space.
In this lecture we will formally register that offer with our pc object, and as soon as we do this we know that the browser's ice agent will automatically start gathering ice candidates. We will listen for the event that fires on our pc object when an ice candidate has been gathered, and log them to the console.
Before we continue, let's test our code and see if ice candidates are being generated, as expected.
We are now at the point where we have to write code to allow PEER1 to send its WebRTC offer to PEER2.
This is a huge milestone, as now we are sending the offer to our signaling server with all the required information (the offer and PEER2's id) so that our signaling server knows who to send the offer to.
Remember that I've split the entire WebRTC process into 5 high level stages. After this lecture is complete, this marks the end of Stage 1.
Let's get crackin'
Stage 2 could not be more simple.
All our signaling server has to do is receive the offer sent to it by PEER1, and send that same data object (that contains the offer) to PEER2.
That's it.
Nothing more.
Nothing less.
We have now reached the point where PEER2 will receive the offer originally sent by PEER1.
How exciting?
Let's fix a small bug, and then test our application by checking whether PEER2 has received the offer from PEER1.
You know the drill.
Now that we know that PEER2 has received the offer, we can show PEER2 the process buttons.
As you know, only the offeror (the user initiating a WebRTC connection) needs to create a Data Channel. Peer2 merely has to listen for the "datachannel" event on its pc object and then take the event object inside of that event to set to its data channel object.
The peer connection object has various properties and methods. In this lecture I'll show that the ondatachannel property is auto-populated with the event listener we have defined in our code.
From the perspective of PEER2, remember that PEER1 is the "remote" side. Therefore PEER2 needs to set its remote session description information (relating to PEER1) with PEER1's offer it received earlier.
We are almost done.
PEER2 is now in the position that they can create their own offer ... which we call "answer" and then update their own local session description.
A few grammar mistakes I want to fix in this lecture.
I also want you to visualize that each peer has their own instance of a peer connection, and each peer connection has session information related to its own peer (the local session description) and the remote peer (the remote session description).
Now that PEER2 has generated their answer, they need to get this to PEER1.
This, as you know, is managed by our signaling server.
Well done! You've come a long way and in this lecture we can finally send the ice candidates to the signaling server.
At this point in time, PEER2 has done everything it needs to do (in terms of signaling) in order to establish a real WebRTC connection.
We are getting so close to finishing the course project.
By the way, I've attached the course files to this lecture, so you can start Stage 4 with a bang!
The WebSocket signaling server has a very simple task - relay information received to the other peer. That's it!
Nothing more!
Nothing less!
There is no reason why we can't create one generic function that does this, instead of having 3 similar functions that do the same thing
A quick recommendation to remove the console logs.
We are at the point in the course where PEER1 has now received the WebRTC answer created by PEER2, and also the ice candidates.
Let's set up listening functions for these incoming events on the client-side, and then we can complete the logic in the next few lectures.
I can't wait!
Let's take a quick timeout to test our code thus far.
Before we go further, why doesn't PEER1 send PEER2 its ice candidates?
So far in the course, we have not defined any handler function that deals with incoming ice candidates.
In this lecture we will deal with what happens when a PEER's websocket connection sends an ICE_CANDIDATE message.
It is a little more tricky that first meets the eye, because a peer can only add ice candidates to their pc object when they have set their remoteDescription property.
For this reason I will set up a temporary buffer to handle the case where a peer receives ice candidates but has not yet set its remote description.
If you took nothing away from the previous lecture, other than what I'm about to show you now, then I've done my job :)
Now that PEER1 has received the answer from PEER2, they can add that answer to their remoteDescription property. Of course, as soon as this is done, don't forget that we need to take all ice candidates inside of the temporary buffer and now call the pc.addIceCandidate() method to add them to the remote description.
This is going to be a huge milestone in the course - because as soon as PEER1 has set its remote description and added ice candidates to its remote Description property, a successfully WebRTC connection is established.
Are we done?
not quite. Although we have a successful connection, we need to update the UI to allow users to exchange (and view) messages they send each other. I also want to update our exit button functionality to cater for closing a pc connection and also a data channel.
Now that we have a successful WebRTC connection, we are at the point where we can remove the learning buttons and show the message input element so that the users can now start typing and sending messages "DIRECTLY" to each other.
How exciting!
Before we send a message over a data channel, let's add a message that a user types to their own message container.
Let's define a function that takes in a string argument, and sends that string over the Data Channel to the other peer. As I mentioned in the previous section, a data channel has 2 methods, send() and close(). We will use the send() method to send our message over the dataChannel object to the other peer.
Every WebRT dataChannel has events we can listen for, one the one relevant to this lecture is the "onmessage" event. We will use this event to listen for an incoming message received on the data channel. This will throw an event object, which we will use to access the message and then finally display that message to the user.
There is a little more logic we need to implement before we can finish off the project, and that is, we need to write logic that closes the peer connection and data channel if a user decides to exit a room.
You are going to now see what happens when a user closes their side of the peer connection by calling pc.close().
what is surprising is that by calling this close() method, the other peer does not get notified of the closure in an easy way. By "easy" I mean there is no "onclose" event that the other peer can listen for to indicate that the other peer has closed the connection.
You'll often see developers set the data channel and peer connection objects to null after they have been closed. But why?
Data Channel Closure:
dataChannel.close() triggers the onclose event on both peers' data channels.
Both peers are notified that the data channel has been closed.
Well done for sticking with me to this point - you've covered a lot.
I want to get to the point just before a peer closes their peer connection. Let's use webrtc internals to view the webrtc process.
Although peer1 has closed their peer connection object and set it to null, the remaining peer still has a peer connection object that is in the 'disconnected' state.
In this lecture I'll show you a few ways you can deal with this issue.
Closing a peer connection by calling pc.close() is not as intuitive as it first seems. It is not the same as calling dataChannel.close() which (as you know) notified the other peer by emitting a close event. This necessitates the need to come up with 'creative' solutions to handle a closure manually.
As you know, once a WebRTC connection is established between two peers, there is no longer any need for a server to transmit data sent/received between them.
But you know me ... proof is in the pudding.
A serer should always be used, even once a WebRTC connection has been established.
In this lecture we will view network traffic involved on our localhost loopback traffic using Wireshark, a free packet sniffer.
It's going to be very interesting because you'll see:
how our server handles AJAX requests
how our server handles WebSocket signaling
that once a WebRTC connection is established, DTLS is negotiated between the two browsers and all messages sent between the peers are encrypted.
that local (peer-to-peer) STUN requests are used to establish a connection and also keep the connection alive
A quick word about the certificate generation you were seeing.
I touched on the sctp property earlier on in this course, and I promised to come back to it later. Well, "later is now" and so I just want to give you some insight into this property.
Well done.
Where to next?
*** BEST WEBRTC COURSE ***
WebRTC allows web browsers and apps to connect directly to each other for video calls, voice chats, or sharing files in real time. It works without needing extra software or servers.
Pure WebRTC: forget libraries. I want you to learn pure native WebRTC.
Real-Time Communication: Build apps with instant video, audio, and data exchange.
Become a Sought-After Developer: Employers want WebRTC expertise.
Peer-to-Peer Connectivity: Use WebRTC to build direct peer-to-peer connections, WITHOUT A SERVER.
Versatile Applications: From conferencing, video calls, chat applications to gaming, endless possibilities.
Cross-Platform Compatibility: Works in all major browsers, seamlessly.
Future-Proof Skills: Essential for modern, real-time web development.
Stand Out from the Crowd: Showcase your real-time communication skills.
Are you ready?
The WebRTC API is complex and verbose, and this course will simplify it and demystify all the complexity behind WebRTC.
Dive into the world of WebRTC and unlock the power of real-time communication on the web! This course takes you beyond basic tutorials, providing a comprehensive understanding of WebRTC from the ground up.
Forget relying solely on libraries – you'll learn to harness the raw power of WebRTC to build dynamic, interactive applications.
Imagine building video conferencing platforms, collaborative workspaces, and interactive gaming experiences directly within a browser or device. This course makes that dream a reality.
Unlike traditional request-response models (where client sends a request to a server, and the server responds), WebRTC enables persistent, peer-to-peer connections WITHOUT A SERVER allowing for seamless data exchange without constant polling. In a world demanding real-time experiences, understanding WebRTC is no longer optional. It's essential.
This course focuses on the pure WebRTC protocol, providing you with in-depth knowledge and practical skills to build cutting-edge real-time applications.
Why WebRTC is a Game Changer:
Real-Time Communication: Build applications that send and receive video, audio, and data instantly, creating engaging user experiences.
Peer-to-Peer Connectivity: Understand the power of direct peer-to-peer connections WITHOUT A SERVER, reducing latency and improving performance.
Versatile Applications: Create a wide range of applications, from video conferencing and live streaming to online gaming and collaborative tools.
Cross-Platform Compatibility: WebRTC is supported by all major browsers, ensuring your applications work seamlessly across different platforms and devices.
Future-Proof Skills: Master a technology that is essential for modern web development and will continue to be relevant as real-time applications (and yes, AI) become more prevalent.
What You Will Learn:
WebRTC Fundamentals: Discover what WebRTC is, its origins, and its role in revolutionizing real-time communication on the web.
Underlying Protocols: Deep dive into the protocols that make WebRTC work, including SDP, ICE, STUN, and TURN. Learn how these protocols enable peer-to-peer connections and handle NAT traversal.
Real-World Applications: Explore various real-world applications of WebRTC, including video conferencing, live streaming, online gaming (I even show you a first-shooter game that uses WebRTC), and collaborative tools. Get inspired to build your own innovative WebRTC applications
WebRTC APIs: Get hands-on experience with the WebRTC APIs, including getUserMedia, RTCPeerConnection, and RTCDataChannel. Learn how to access media devices, establish peer connections, and send data between peers.
Understanding NAT: Gain insights into Network Address Translation (NAT) and its role in peer-to-peer communication. Learn how NAT affects connectivity and how WebRTC overcomes these challenges to establish seamless connections (spoiler alert: this is where STUN and TURN come into the picture).
Signaling: Understand the importance of signaling in WebRTC, why its needed and learn how to implement a signaling server using WebSockets. No libraries. No SocketIO.
Data Channels: Learn how to use WebRTC data channels to send arbitrary data between peers. This opens up possibilities for building collaborative applications, file sharing tools, CDNs, and more.
Media Streams: Explore how to capture and stream audio and video using WebRTC.
Building a Node Server: Get hands-on experience by building a Node.js server using native WebSockets (without Socket IO). Understand the server-side architecture necessary to support your WebRTC applications.
COURSE PROJECT: WebRTC Chat Application: Put your knowledge into practice by developing a fully functional chat application using WebRTC and data channels. This project will solidify your understanding of real-time communication and give you a tangible product to showcase your skills.
Why You Need This WebRTC Course:
Here's why learning about WebRTC is crucial for any aspiring web developer:
Build Engaging Applications: Create dynamic, interactive experiences that captivate users and keep them coming back for more.
Unlock New Possibilities: Explore a wide range of real-time applications and discover innovative ways to leverage WebRTC technology.
Stand Out from the Crowd: Showcase your skills and creativity by building standout projects that demonstrate your expertise in real-time communication.
Become a Sought-After Developer: Employers are looking for developers who can create modern, interactive applications, and WebRTC skills are highly valued.
Join a Thriving Community: Connect with other WebRTC developers, share ideas, and stay inspired as you explore new ways to push the boundaries of web technology.
Your Instructor: Clyde
Clyde is a coding enthusiast who has been immersed in the world of computers since the age of 7.
With years of experience in web development and a passion for teaching, Clyde brings a wealth of knowledge and practical insights to the course. His engaging teaching style and real-world examples will make complex concepts accessible and enjoyable.
You might wonder, is he an AI bot? Nope. He's a real person, and he's with you every step of the way, right beside you through every single lecture. Together, you'll navigate the challenges, celebrate the breakthroughs, and make complex concepts feel clear and achievable. This course isn’t just a series of lessons; it’s a journey you take together, with Clyde as your dedicated guide, your companion in learning until you master the skills you seek.
Why AI Won't Replace WebRTC Developers
While AI can automate certain coding tasks, it can't replicate the creativity, problem-solving skills, and deep understanding of network protocols required to build robust WebRTC applications. AI can assist with code generation, but it can't replace the human expertise needed to design, implement, and maintain complex real-time communication systems.
Enroll Now
Don’t miss this opportunity to elevate your web development skills and unlock the potential of real-time communication with WebRTC.
Right this second, your competitors are learning how to become better web developers.
Web development is a blazing hot topic at the moment.
But you have a distinct advantage. This course offers memorable learning topics, actionable tactics and real-world examples. Get ready to transform your projects into interactive experiences that captivate users and make you money!
Let's get crackin'!