XMediaLib.SDP (xmedialib v0.3.0)

Copy Markdown View Source

Session Description Protocol (SDP) parse and encode for real-time sessions.

What problem this solves

Before RTP flows, peers exchange SDP text listing codecs, ICE candidates, DTLS fingerprints, and SCTP data channels. Browsers and SIP endpoints emit slightly different attribute lines. This module is the public parse/encode entry point so XMediaLib callers can inspect or rewrite offers and answers without hand-rolling line parsers.

SDP is a line-oriented text format that describes a multimedia session: who created it, when it is valid, and which media streams (audio, video, SCTP data channels) are offered with what codecs, transports, and network hints. In WebRTC, two endpoints exchange SDP in an offer/answer handshake (often together with ICE candidates) so each peer knows how to send and receive encrypted RTP or SCTP traffic.

This module is the public API. parse/1 turns SDP wire text into %XMediaLib.SDP{}; encode/1 serializes that struct back to wire bytes with CRLF line endings. Session-level fields live on the root struct; each m= media block becomes %XMediaLib.SDP.Media{}. Lower-level parsing and field helpers live in XMediaLib.SDP.Parser and XMediaLib.SDP.Encoder.

RFCs

  • RFC 4566 - SDP (obsoleted by RFC 8866)
  • RFC 8866 - SDP (current)
  • RFC 8829 - JSEP (browser offer/answer usage)
  • RFC 8445 - ICE (a=ice-ufrag, a=ice-pwd, a=candidate)
  • RFC 8122 - DTLS fingerprint (a=fingerprint, a=setup)
  • RFC 8841 - SCTP data channels (a=sctp-port, a=dcmap)

Summary

Types

Generic session- or media-level attribute as {name, value}.

t()

Parsed session description.

Functions

Encodes %XMediaLib.SDP{} to an RFC-oriented binary with \r\n line endings.

Parses an SDP binary into %XMediaLib.SDP{}.

Parses an SDP binary with options.

Types

attribute()

@type attribute() :: {String.t(), String.t() | true}

Generic session- or media-level attribute as {name, value}.

Flag attributes (no colon value on the wire) decode as {name, true}.

t()

@type t() :: %XMediaLib.SDP{
  attributes: [attribute()],
  connection: XMediaLib.SDP.Connection.t() | nil,
  groups: [XMediaLib.SDP.Group.t()],
  media: [XMediaLib.SDP.Media.t()],
  origin: XMediaLib.SDP.Origin.t() | nil,
  session_name: String.t(),
  time: [XMediaLib.SDP.Time.t()],
  version: non_neg_integer()
}

Parsed session description.

Fields

  • :version - SDP version from v= (always 0 on the wire today)
  • :origin - session creator from o= (%XMediaLib.SDP.Origin{})
  • :session_name - human-readable title from s=
  • :connection - default connection address from session-level c=
  • :time - active intervals from t= lines
  • :groups - BUNDLE and other grouping from a=group:
  • :attributes - other session-level a= lines not promoted to structs
  • :media - ordered list of %XMediaLib.SDP.Media{} from m= sections

Functions

encode(sdp)

@spec encode(t()) :: {:ok, binary()} | {:error, term()}

Encodes %XMediaLib.SDP{} to an RFC-oriented binary with \r\n line endings.

Session-level t= defaults to t=0 0 when the list is empty. A missing o= line is emitted as o=- 0 0 IN IP4 127.0.0.1.

Examples

iex> sdp = %XMediaLib.SDP{version: 0, session_name: "-", time: [%XMediaLib.SDP.Time{}]}
iex> {:ok, bin} = XMediaLib.SDP.encode(sdp)
iex> String.starts_with?(bin, "v=0")
true

parse(raw)

@spec parse(binary()) :: {:ok, t()} | {:error, term()}

Parses an SDP binary into %XMediaLib.SDP{}.

Unknown non-a= lines are skipped unless parse/2 is called with strict: true. Malformed input returns {:error, :parse_failed}.

Examples

iex> {:ok, sdp} = XMediaLib.SDP.parse("v=0\r\no=- 0 0 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\n")
iex> sdp.version
0

parse(raw, opts)

@spec parse(
  binary(),
  keyword()
) :: {:ok, t()} | {:error, term()}

Parses an SDP binary with options.

Supported options:

  • :strict - when true, unsupported non-attribute lines return {:error, {:unsupported_line, line}} instead of being skipped

Examples

iex> raw = "v=0\r\no=- 0 0 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\nz=bad\r\n"
iex> {:error, {:unsupported_line, "z=bad"}} = XMediaLib.SDP.parse(raw, strict: true)