Example
Starting a call
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
In the above example, we create peer connection via createPeerConnection
method. Once the RTCPeerConnection has been created, we request access to the user's camera and microphone by calling MediaDevices.getUserMedia()
which is exposed to us through the MediaDevices.getUserMedia
property.
We attach the incoming stream to the local preview <video>
element by setting the element's srcObject property.
We then iterate over the tracks in the stream, calling addTrack()
to add each track to the RTCPeerConnection
. Even though the connection is not fully established yet, you can begin sending data when you feel it's appropriate to do so. Media received before the ICE negotiation is completed may be used to help ICE decide upon the best connectivity approach to take, thus aiding in the negotiation process.
Note that for native apps, such as a phone application, you should not begin sending until the connection has been accepted at both ends, at a minimum, to avoid inadvertently sending video and/or audio data when the user isn't prepared for it.
Creating the peer connection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
The createPeerConnection() function is used by both the caller and the callee to construct their RTCPeerConnection objects, their respective ends of the WebRTC connection.
When using the RTCPeerConnection() constructor, we will specify an RTCConfiguration-compliant object providing configuration parameters for the connection. This is an array of objects describing STUN and/or TURN servers for the ICE layer to use when attempting to establish a route between the caller and the callee.
After creating the RTCPeerConnection, we set up handlers for the events that matter to us. The first three of these event handlers are required; you have to handle them to do anything involving streamed media with WebRTC.
Starting negotiation
Once the caller has created its RTCPeerConnection
, created a media stream, and added its tracks to the connection, the browser will deliver a negotiationneeded
event to the RTCPeerConnection
to indicate that it's ready to begin negotiation with the other peer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
To start the negotiation process, we need to create and send an SDP offer to the peer we want to connect to. This offer includes a list of supported configurations for the connection, including information about the media stream we've added to the connection locally, and any ICE candidates gathered by the ICE layer already. We create this offer by calling myPeerConnection.createOffer()
.
When createOffer()
succeeds, we pass the created offer information into myPeerConnection.setLocalDescription()
, which configures the connection and media configuration state for the caller's end of the connection.
We know the description is valid, and has been set, this is when we send our offer to the other peer by creating a new "video-offer" message containing the local description, then sending it through our signaling server to the callee.
Handling the invitation
When the offer arrives, the callee's handleVideoOfferMsg()
function is called with the "video-offer" message that was received
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
This code is very similar to what we did in the invite()
function. It starts by creating and configuring an RTCPeerConnection using our createPeerConnection() function. Then it takes the SDP offer from the received "video-offer" message and uses it to create a new RTCSessionDescription object representing the caller's session description.
That session description is then passed into myPeerConnection.setRemoteDescription(). This establishes the received offer as the description of the remote (caller's) end of the connection.
Once the answer has been created using myPeerConnection.createAnswer(), the description of the local end of the connection is set to the answer's SDP by calling myPeerConnection.setLocalDescription(), then the answer is transmitted through the signaling server to the caller to let them know what the answer is.
Sending ICE candidates
The ICE negotiation process involves each peer sending candidates to the other, repeatedly, until it runs out of potential ways it can support the RTCPeerConnection
's media transport needs.
Once setLocalDescription()
's fulfillment handler has run, the ICE agent begins sending icecandidate
events to the RTCPeerConnection
one for each potential configuration it discovers.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Receiving ICE candidates
1 2 3 4 5 6 |
|
This function constructs an RTCIceCandidate
object by passing the received SDP into its constructor, then delivers the candidate to the ICE layer by passing it into myPeerConnection.addIceCandidate()
.
Receiving new streams
When new tracks are added to the RTCPeerConnection
— either by calling its addTrack()
method or because of renegotiation of the stream's format—a track event is set to the RTCPeerConnection
for each track added to the connection.
1 2 3 4 |
|
The incoming stream is attached to the "received_video" <video>
element.
Handling the removal of tracks
Your code receives a removetrack
event when the remote peer removes a track from the connection by calling RTCPeerConnection.removeTrack().
1 2 3 4 5 6 7 8 |
|
Ending the call
When the user clicks the "Hang Up" button to end the call, the hangUpCall() function is called:
1 2 3 4 5 6 7 8 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Dealing with state changes
ICE connection state
iceconnectionstatechange
events are sent to the RTCPeerConnection
by the ICE layer when the connection state changes (such as when the call is terminated from the other end).
1 2 3 4 5 6 7 8 |
|
ICE signaling state
1 2 3 4 5 6 7 |
|
ICE gathering state
icegatheringstatechange
events are used to let you know when the ICE candidate gathering process state changes
1 2 3 4 |
|