Please note that this situation with different function names is temporary, and after WebRTC is standardized, every browser will support the standard WebRTC API function names. Thus, the WebRTC adapter that we're developing here will probably not be necessary in the future.
Developing a WebRTC API wrapper
It is useful to develop a little WebRTC API wrapper library to use it in your application.
Create a file and name it www/myrtclib.js
.
First of all, we need to define several variables to control WebRTC entities and use the API. We make them equal to null
. However, using our adapter that we developed previously, these variables will refer to appropriate API functions:
Here, we keep the virtual room number:
The initiator
variable keeps the initiator state that tells us whether we are calling our peer or are waiting for a call:
The following two variables keep the references to local and remote media streams:
We need the pc
variable to control a peer connection:
As we discussed previously, we need a signaling mechanism to make our connection work. The following variable will store the URL that will point to our signaling server:
The following variables keep the HTML video entities: local and remote. They are just IDs of video
HTML tags:
We want to know whether our signaling channel is ready for operation, and we need a variable to control it:
Here, we define two STUN servers to support the NAT traversal functionality:
We also need to define constraints. Using this, we tell a web browser whether we want to use just audio for our conference, or video, or both:
Next, we define several wrapping/helping functions to make our code more universal and reusable.
This is our initialization function. It gets a signaling server's URL and references to local and remote video HTML entities.
Here, we perform the initialization of our API adapter that we developed earlier; after this, we will have universal API function names that we can use under any web browser that supports WebRTC.
After the adapter is initialized, we call the openChannel
function that we use to initiate a connection to our signaling server:
The openChannel
function opens a connection to our signaling server. Here, we use WebSockets as a transport layer, but it is not mandatory. You can create your own implementation using Ajax, for example, or any other suitable technology that you like the most:
This callback function will be called if our signaling connection has been established successfully. We can't continue if the signaling channel has not been opened:
When our peer sends a message during the process of establishing the peer connection, the onChannelMessage
callback function will be called and we will be able to react on it:
If the signaling channel has been closed due to some reason (our peer closed its browser or the signaling sever has been powered down), we will get a notification from the onChannelClosed
function and react on these two event: show a message to the user or try to re-establish a connection:
We will get here after the signaling channel has been opened successfully and we can continue and start our conference:
First of all, we need to indicate that the signaling channel is opened and alive:
Here, we try to understand whether we're calling to our peer or we're waiting for a call from it.
We take the URL of our location and try to find the room
word inside of it. If there is no such word, then we're going to create a virtual room and act passively, waiting for a call from someone.
If we find the room
word, it means that someone has already created a virtual room and we want to enter it; we're in a calling state and should behave actively, trying to initiate a connection to our peer in the room.
We use the sendMessage
function to send messages to our signaling server. If the virtual room has not been created yet, then the signaling server will create it and return its room number back to us. In case we have a virtual room number, we ask the signaling server to enter us in to the room; it will parse our message and send it to our peer to initiate the establishment of a direct connection:
We solved our questions with the virtual room; now, we need to ask the browser to give us access to the browser's media resources, video (web camera), and audio (mic):
The following function is called when we get a message from our signaling server. Here, we can add some logging or any additional logic but for now, we just need to process the message and react on it:
The onChannelClosed
function will be called when the signaling server becomes unavailable (a dropped connection) or if the remote peer has closed the connection (the remote customer has closed its web browser, for example).
In this function, you can also show an appropriate message to your customer or implement any other additional logic.
In the following function, we just indicate that the channel has been closed, and we don't want to transfer any messages to our signaling server:
To communicate with the signaling server, we use the sendMessage
function. It gets a message as a JSON object, makes a string from it, and just transfers it to the signaling server.
When debugging, it is usually helpful to add some kind of message-logging functionality here:
We need to parse messages from the signaling server and react on them, respectively:
If we get an offer
message, then it means that someone is calling us and we need to answer the call:
If we get an answer
message from the signaling server, it means that we just tried to call someone and it replied with the answer
message, confirming that it is ready to establish a direct connection:
When a remote peer sends a list of candidates to communicate with, we get this type of message from the signaling server. After we get this message, we add candidates to the peer connection:
If we asked the signaling server to create a virtual room, it will send a GETROOM
message with the created room's number. We need to store the number to use it later:
The OnRoomReceived
function is called to implement an additional functionality. Here, we can perform some UI-related actions, such as showing the room's URL to the customers so that they can share it with their friends:
If we get an URL from our friend that asks us to enter a virtual room but the room number is wrong or outdated, we will get the WRONGROOM
message from the signaling server. If so, we are just moving to the index page:
Here, we're asking the web browser to get us access to the microphone and web camera.
Chrome will show a pop-up window to the user that will ask the user whether he/she wants to provide access or not. So, you will not get access until the user decides. Chrome will ask this every time the user opens your application page. To avoid this and make Chrome remember your choice, you should use the HTTPS connection with the SSL/TLS certificate properly configured in the web server that you're using. Please note that the certificate either needs to be signed by a public CA (Certificate Authority), or by a private CA whose identity has been configured in the browser/client computer. If the browser doesn't trust the certificate automatically and prompts the user to indicate an exception, then your choice will not be remembered by Chrome.
Firefox won't remember the choice, but this behavior can be changed in future:
We ask the WebRTC API to call our callback function, onUserMediaSuccess
, if we have got the access rights from the user:
If we didn't get the access rights, we'll get an exception. Here, you probably want to add some logging and UI logic to inform your customer that something is wrong and we can't continue:
We will get trapped here if we get the access rights to reach the web camera and microphone via the web browser:
We get a video stream from a local web camera and we want to show it on the page, so we're attaching the stream to the video
tag:
Store the stream in a variable because we want to refer to it later:
Now we're ready to create a direct connection to our peer:
After the peer connection is created, we put our local video stream into it to make the remote peer see us:
Check whether we're waiting for a call or we're the caller. If we're the initiator, we call the doCall
function to initiate an establishment to a direct connection:
The following function will try to create a peer connection—a direct connection between peers:
To improve the security of the connection, we ask the browser to switch on the DTLS-SRTP option. It enables the exchange of the cryptographic parameters and derives the keying material. The key exchange takes place in the media plane and is multiplexed on the same ports as the media itself.
This option was disabled in Chrome by default, but it has been enabled from Version 31 onwards. Nevertheless, we don't want to check the version of a browser used by our customer, so we can't rely on the default settings of the browser:
Create a peer connection using the WebRTC API function call. We pass a predefined list of STUN servers and connection configurations to the function:
Here, we define a callback function to be called when we have to send the ICE candidates to the remote part:
When the connection is established, the remote side will add its media stream to the connection. Here, we want to be informed of such an event in order to be able to show the remote video on our web page:
If the establishment of the connection fails, we will get an exception. Here, you can add debug console logging and UI improvements to inform the customer that something is wrong:
When we have ICE candidates from the WebRTC API, we want to send them to the remote peer in order to establish a connection:
We will get trapped into this function when a direct connection has been established and a remote peer has added its media stream to the connection. We want to show a remote video so, here, we're attaching a remote video to the video
tag on the web page:
We also want to store a reference to the remote stream in order to use it later:
The following function is called by us when we're joining a virtual room and initiating a call to the remote peer:
We don't want to use the data channel yet (as it will be introduced in the next chapter). It is enabled in Firefox by default so here, we're asking Firefox to disable it:
Check whether we're running this execution under Chrome and if so, remove the unnecessary options that are preconfigured to run under Firefox:
Merge browser options with the whole constraints
entity, and call the createOffer
function in order to initiate a peer connection. In case of a success, we will get into the setLocalAndSendMessage
function:
If we're waiting for a call and have got an offer from a remote peer, we need to answer the call in order to establish a connection and begin the conference.
Here is the function that will be used to answer a call. As is the case with doAnswer
, we will get into the setLocalAndSendMessage
function in case of a success:
The preceding callback function is used during the process of establishing a connection by the WebRTC API. We receive a session description entity, and then we need to set up a local description and send an SDP object to the remote peer via a signaling server:
The following is a simple helper that merges the constraints: