# `XMediaLib.SDP.Parser.Helpers`
[🔗](https://github.com/Lazarus404/xmedialib/blob/main/lib/sdp/parser/helpers.ex#L26)

Field parsers for individual SDP line values.

## What problem this solves

Full SDP documents are long, but tests and tools often need to parse one `a=`
or `c=` value in isolation. Each helper maps the payload after a line prefix
into a typed struct or attribute tuple used by `XMediaLib.SDP.Parser`. Keeping
them separate avoids duplicating grammar rules across session and media
sections.

These pure functions turn the payload *after* the line prefix (`o=`, `c=`,
`m=`, or the value portion of `a=`) into typed structs or attribute tuples.
`XMediaLib.SDP.Parser` calls them while walking a full session description;
tests and tools may call them directly when only one line needs parsing.

Promoted WebRTC attributes (ICE, fingerprint, rtpmap, etc.) update
`%XMediaLib.SDP.Media{}` fields. Unrecognized media attributes accumulate in
`:attributes` as `{name, value}` or `{name, true}`.

## RFCs

* [RFC 8866](https://www.rfc-editor.org/rfc/rfc8866) - SDP line formats
* [RFC 8445](https://www.rfc-editor.org/rfc/rfc8445) - ICE candidate syntax
* [RFC 8122](https://www.rfc-editor.org/rfc/rfc8122) - DTLS fingerprint/setup
* [RFC 8841](https://www.rfc-editor.org/rfc/rfc8841) - SCTP/data channel attributes

# `parse_candidate`

```elixir
@spec parse_candidate(String.t()) :: XMediaLib.SDP.Candidate.t()
```

Parses an ICE `candidate` attribute value into `%XMediaLib.SDP.Candidate{}`.

## Examples

    iex> cand = "1 1 udp 2130706431 192.0.2.1 5000 typ host"
    iex> XMediaLib.SDP.Parser.Helpers.parse_candidate(cand)
    %XMediaLib.SDP.Candidate{foundation: "1", component_id: 1, transport: "udp",
      priority: 2130706431, ip: "192.0.2.1", port: 5000, type: "host", rest: nil}

# `parse_connection`

```elixir
@spec parse_connection(String.t()) :: XMediaLib.SDP.Connection.t()
```

Parses a `c=` value (without the `c=` prefix) into `%XMediaLib.SDP.Connection{}`.

## Examples

    iex> XMediaLib.SDP.Parser.Helpers.parse_connection("IN IP4 192.0.2.1")
    %XMediaLib.SDP.Connection{net_type: "IN", addr_type: "IP4", address: "192.0.2.1"}

# `parse_group`

```elixir
@spec parse_group(String.t()) :: XMediaLib.SDP.Group.t()
```

Parses an `a=group:` value (after `group:`) into `%XMediaLib.SDP.Group{}`.

## Examples

    iex> XMediaLib.SDP.Parser.Helpers.parse_group("BUNDLE 0 1")
    %XMediaLib.SDP.Group{semantics: "BUNDLE", mids: ["0", "1"]}

# `parse_media_attribute`

```elixir
@spec parse_media_attribute(String.t(), XMediaLib.SDP.Media.t()) ::
  XMediaLib.SDP.Media.t()
```

Applies one media-level `a=` attribute to `%XMediaLib.SDP.Media{}`.

`attr_line` is the full attribute body after `a=` (e.g. `mid:0` or
`candidate:...`). Known attributes update typed fields; others append to
`:attributes`.

## Examples

    iex> media = %XMediaLib.SDP.Media{type: :audio, port: 9}
    iex> updated = XMediaLib.SDP.Parser.Helpers.parse_media_attribute("mid:0", media)
    iex> updated.mid
    "0"

# `parse_media_header`

```elixir
@spec parse_media_header(String.t()) :: XMediaLib.SDP.Media.t()
```

Parses an `m=` value (without the `m=` prefix) into a new `%XMediaLib.SDP.Media{}`.

Known media types and transports are normalized to atoms; others remain strings.

## Examples

    iex> media = XMediaLib.SDP.Parser.Helpers.parse_media_header("audio 9 UDP/TLS/RTP/SAVPF 111")
    iex> {media.type, media.port, media.protocol, media.formats}
    {:audio, 9, :UDP_TLS_RTP_SAVPF, ["111"]}

# `parse_origin`

```elixir
@spec parse_origin(String.t()) :: XMediaLib.SDP.Origin.t()
```

Parses an `o=` value (without the `o=` prefix) into `%XMediaLib.SDP.Origin{}`.

## Examples

    iex> XMediaLib.SDP.Parser.Helpers.parse_origin("- 0 0 IN IP4 127.0.0.1")
    %XMediaLib.SDP.Origin{username: "-", session_id: "0", session_version: "0",
      net_type: "IN", addr_type: "IP4", unicast_address: "127.0.0.1"}

# `parse_session_attribute`

```elixir
@spec parse_session_attribute(String.t()) :: {String.t(), String.t() | true}
```

Parses a session-level `a=` attribute into `{name, value}`.

Flag attributes without a colon value return `{name, true}`.

## Examples

    iex> XMediaLib.SDP.Parser.Helpers.parse_session_attribute("ice-lite")
    {"ice-lite", true}

    iex> XMediaLib.SDP.Parser.Helpers.parse_session_attribute("msid-semantic: WMS stream")
    {"msid-semantic", " WMS stream"}

# `parse_time`

```elixir
@spec parse_time(String.t()) :: XMediaLib.SDP.Time.t()
```

Parses a `t=` value (without the `t=` prefix) into `%XMediaLib.SDP.Time{}`.

## Examples

    iex> XMediaLib.SDP.Parser.Helpers.parse_time("0 0")
    %XMediaLib.SDP.Time{start: 0, stop: 0}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
