On this pageOPENCLOSE
SDP without the fog
Read a real session description line by line: m-lines, codecs, directions, ICE credentials, and fingerprints.
Goal
- 01Read an SDP offer well enough to know what is being proposed and what will break.
- 02Understand m-lines, direction attributes, codecs, ICE credentials, and fingerprints.
- 03Recognize when a change needs renegotiation instead of a track replacement.
The concept, plainly
is a text description of a session. The browser generates it from the peer connection's transceivers, codecs, and transport state. An offer proposes a session; an answer accepts or narrows it. The signaling channel carries these descriptions, but SDP does not itself create a network path. That is ICE's job.
An `m=` line defines one media section, in order. The order matters because `sdpMLineIndex` and the transceiver list refer to it. A typical offer has `m=audio` and `m=video`. Each section contains a payload type list, direction, codec parameters, and possibly ICE credentials and a DTLS fingerprint. Bundling commonly puts all media on one transport, but the m-lines still exist.
Direction attributes explain who sends what: `sendrecv`, `sendonly`, `recvonly`, or `inactive`. A video element can be black even though the connection is connected if the negotiated direction is `recvonly` on both sides or `inactive`. When you add a track after an offer, the existing transceiver direction may need to change, which requires negotiation.
Codec lines use `a=rtpmap:<payload> <name>/<clock>/<channels>` and `a=fmtp` for parameters. Browsers offer multiple codecs and choose based on the answer and `setCodecPreferences`. Do not assume the first payload type is the one selected. For debugging, look at the actual `RTCRtpSender.getParameters()` and the receiver's stats, not only the SDP text.
ICE credentials (`a=ice-ufrag`, `a=ice-pwd`) and the DTLS fingerprint (`a=fingerprint`) bind the signaling description to the transport that will be built. The fingerprint is how the peer verifies the certificate presented during the DTLS handshake. If an intermediary rewrites SDP fingerprints, the handshake fails even though the network path is fine.
Renegotiation is needed when the session shape changes: adding a track where no suitable transceiver exists, changing direction, adding a data channel after the initial negotiation, or restarting ICE. Replacing a live track of the same kind usually does not need it. SDP gets long, but the subset that matters for most incidents is small: m-lines, directions, codecs, ICE, and fingerprint.
See it move
Interactive diagram
Reading an offer from the outside in
Session lines establish context
The v= line is the version, o= identifies the session origin, and s= is a name. Browser SDP mostly hides these details from you, but they are the header before the meaningful media sections.
Start with the m-lines and directions, then inspect codecs and transport credentials. The order is the contract.
Behind the scenes
Transceivers generate SDP
A transceiver is a sender/receiver pair with a direction and a mid. addTrack can reuse a compatible transceiver or create a new one depending on the connection state. When SDP is generated, each transceiver becomes an m-line. That is why a track added after negotiation may need a new offer: the contract has to be reissued with the new section or direction.
The answer is not a mirror
Browsers offer many codecs and several RTP header extensions. The answer selects what the responder supports and may choose a lower-cost codec. It can also reject a section or mark it inactive. If you compare offers by string equality, you will misread a perfectly valid answer.
SDP and ICE candidates are separate
A non-trickle exchange waits for gathering and puts candidates into the SDP. A trickle exchange sends them as separate signaling messages and may leave the initial SDP with no candidates. Both are valid. The mistake is assuming an SDP with no candidate lines has failed; it may simply be trickling.
Code walkthrough
You rarely need a full SDP parser. Extract the m-lines, directions, codecs, and transport facts for diagnostics.
export function summarizeSdp(sdp: string) {const lines = sdp.split(/\r?\n/);const sections = [] as Array<{kind: string;direction: string;codecs: string[];mid?: string;}>;let current: (typeof sections)[number] | undefined;for (const line of lines) {if (line.startsWith("m=")) {const [kind, , , ...payloads] = line.slice(2).split(" ");current = { kind: kind ?? "unknown", direction: "sendrecv", codecs: payloads };sections.push(current);} else if (current && line.startsWith("a=mid:")) {current.mid = line.slice(6);} else if (current && /^a=(sendrecv|sendonly|recvonly|inactive)$/.test(line)) {current.direction = line.slice(2);} else if (current && line.startsWith("a=rtpmap:")) {current.codecs.push(line.slice(9));}}return {sections,iceUfrag: lines.find((line) => line.startsWith("a=ice-ufrag:"))?.slice(12),fingerprint: lines.find((line) => line.startsWith("a=fingerprint:"))?.slice(14),candidates: lines.filter((line) => line.startsWith("a=candidate:")).length,};}
Do and don't
Do
Check directions before codecs
If both sides are recvonly or a section is inactive, no codec change will produce media. Read the direction first.
Keep the complete SDP
Do not trim lines you do not recognize when relaying manually. Fingerprints, ICE credentials, and extensions are all load-bearing.
Log the negotiated sections
A compact summary of m-lines, mids, directions, and candidate counts makes signaling logs diagnosable.
Don't
Don't hand-edit SDP without a reason
Removing a fingerprint or changing a payload type can break the transport or produce silent media. Use browser APIs for preferences first.
Don't assume offer order equals track order
The mids and transceiver mapping are authoritative. A renegotiation can add or recycle sections.
Don't treat an answer as a failed offer
An answer with fewer codecs or an inactive section may be correct. Validate the session, not string equality.
Practice
Hands-on lab
Read your own offer
Open manual signaling in the 1:1 lab and create an offer bundle. Inspect the SDP in the textarea or copy it into a scratch file.
- 1Count the m= lines. Which one is audio, video, or application?
- 2Find each a=mid, direction, ice-ufrag, and fingerprint.
- 3List the rtpmap codecs offered for video and compare them with what the answer keeps.
- 4Reload and repeat. Notice which lines change every session and which stay stable.
Solo? Loopback generates a live SDP internally; the lab's peer-event log shows when the offer and answer are created.
Quick quiz
Knowledge check
0 of 4 answered
- 01
What does one m= line represent?
- 02
A connection is connected but the remote video is black. Which SDP attribute should you inspect first?
- 03
What is the DTLS fingerprint in SDP used for?
- 04
When is renegotiation required?
Key takeaways
- SDP is a contract: m-lines, directions, codecs, ICE credentials, and fingerprints are the parts that matter.01
- The answer can narrow or reject an offer; string equality is the wrong test.02
- Connected plus no video is often a direction or track problem, not a codec problem.03
- Renegotiation is for shape changes; replaceTrack handles same-kind source swaps.04
Common errors and fixes
Terms in this lesson
Done with this lesson?
Mark it complete, then keep the thread.