Did you know? All Video & Audio API plans include a $100 free usage credit each month so you can build and test risk-free. View Plans ->

WebRTC For The Brave

Working With SDP Messages

In this part, you'll how to create a peer connection for a multimedia call by exchanging SDP messages.

SDP Message Overview

After creating a peer connection, you should exchange SDP (Session Description Protocol), which is a standard format for describing multimedia communication sessions for a peer-to-peer connection.

The SDP includes essential information for making a peer connection, such as Codec, source address, media types of audio and video, and other associated properties, as you can see in the SDP message below:

v=0
o=- 5168502270746789779 2 IN IP4 127.0.0.1
s=
c=IN IP4 0.0.0.0
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000
m=video 51372 RTP/AVP 31
a=rtpmap:31 H261/90000
m=video 53000 RTP/AVP 32
a=rtpmap:32 MPV/90000

Each peer can figure out what types of Codec or media will be delivered by exchanging SDP messages. Let’s see a scenario that Alice and Bob want to connect on a video call:

  1. Alice suggests a peer connection with Bob by creating an SDP Offer that the signaling server will deliver.
  2. Bob accepts the SDP Offer and responds by creating an SDP Answer that the signaling server will deliver.
  3. Alice accepts the SDP Answer, and they will prepare to establish a connection between them.

The steps above can be drawn like the figure below:

The local peer (Alice) sends a SDP Offer and the remote peer (Bob) return a SDP Answer, and then ****it’s ready for establishing a peer connection.

Create an SDP Offer

The SDP offer contains everything peers need to connect, such as MediaStreamTrack, Codec, and other associated properties, as we’ve discussed before. You can create an SDK offer with the RTCPeerConnection.createOffer() method, which initiates the creation of an SDP offer to start a new WebRTC connection to a remote peer:

javascript
            const offerOptions = {
    iceRestart: true,
    offerToReceiveAudio: true,
    offerToReceiveVideo: true
};

const offer = await localPeerConnection.createOffer(offerOptions);
        

As you can see in the code above, you can give an offerOptions parameter to the createOffer method. The offerOptions provides offerToReceiveAudio and offerToReceiveVideo options, providing additional control over audio and video\'s directionality.

After creating the SDP offer, you should set the message to the peer connection as a local description and make it clear that your local peer connection initiates the WebRTC connection to a remote peer:

javascript
            await localPeerConnection.setLocalDescription(offer);
        

Let’s assume the remote peer received an SDP offer from a signaling server. Then the remote peer connection should set the SDP offer message as a remote description and make it clear that the remote peer connection received the SDK offer message:

javascript
            await remotePeerConnection.setRemoteDescription(offer);
        

Create an SDP Answer

After receiving the SDP offer message from the local peer, the remote peer should return an SDP answer message to the local peer. You can create an SDP answer with the RTCPeerConnection.createAnswer() method, which contains information about media sessions, codecs and options supported by browser to reply to the local peer:

javascript
            const answer = await remotePeerConnection.createAnswer();
        

Now let’s assume the local peer received an SDP answer from a signaling server. Then the local peer connection should set the SDP answer message as a remote description and make it clear the peer connection has established:

javascript
            await localPeerConnection.setRemoteDescription(desc);
        

Exchange SDP Messages

Now let’s combine all the concepts above and establish a peer connection by exchanging SDP messages between a local peer (p1) and a remote peer (p2), and each peer wants to establish a peer-to-peer connection by exchanging SDP messages:

javascript
            let localStream, pc1, pc2;

async function attachLocalMedia() {
    callPc1Button.disabled = true;
    try {
        const stream = await navigator.mediaDevices.getUserMedia(videoConstraints);
        localVideo.srcObject = stream;
        localStream = stream;
        callPc2Button.disabled = false;
    } catch (e) {
        onCatch(e)
    }
}

async function peerConnection() {
    callPc2Button.disabled = true;
    disconnectButton.disabled = false;

    pc1 = new RTCPeerConnection(rtcConfig);
    pc2 = new RTCPeerConnection(rtcConfig);

    localStream.getTracks().forEach(track => pc1.addTrack(track, localStream));

    try {
        console.log('pc1 createOffer start');
        const offer = await pc1.createOffer({
            iceRestart: true,
            offerToReceiveAudio: true,
            offerToReceiveVideo: true
        });
        await onCreateOfferSuccess(offer);
    } catch (e) {
        onCatch(e);
    }
}

async function onCreateOfferSuccess(desc) {
    console.log(`Offer from pc1\nsdp: ${desc.sdp}`);
    try {
        await pc1.setLocalDescription(desc);
    } catch (e) {
        onCatch(e)
    }

    try {
        await pc2.setRemoteDescription(desc);
    } catch (e) {
        onCatch(e)
    }

    try {
        const answer = await pc2.createAnswer();
        await onCreateAnswerSuccess(answer);
    } catch (e) {
        onCatch(e);
    }
}

function gotRemoteStream(e) {
    if (remoteVideo.srcObject !== e.streams[0]) {
        remoteVideo.srcObject = e.streams[0];
    }
}

async function onCreateAnswerSuccess(desc) {
    try {
        await pc2.setLocalDescription(desc);
    } catch (e) {
        onCatch(e)
    }

    try {
        await pc1.setRemoteDescription(desc);
    } catch (e) {
        onCatch(e)
    }
}

function getName(pc) {
  return (pc === pc1) ? 'pc1' : 'pc2';
}

function getOtherPc(pc) {
  return (pc === pc1) ? pc2 : pc1;
}
        

The local peer (p1) initiates the creation of an SDP offer to start a new WebRTC connection to a remote peer (p2), and the remote peer (p2) returns an SDP answer to finalize a peer connection to the local peer (p1).

Typically, this process should be done by a signaling server responsible for resolving connectivity problems and establishing a connection between peers by exposing minimized private information. But in this tutorial, we don’t use a signaling server and set up a connection between two RTCPeerConnection objects (known as peers) on the same page with each peer to help you better grasp how SDP messages are exchanged.

Now, you should do one more setup for establishing peer connections ultimately. The code above will not work now because peers don’t know how to reach each other behind a NAT/Firewall in their local network. For this, you need to set up ICE candidates.