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:
- Alice suggests a peer connection with Bob by creating an SDP Offer that the signaling server will deliver.
- Bob accepts the SDP Offer and responds by creating an SDP Answer that the signaling server will deliver.
- 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:
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:
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:
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:
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:
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:
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.