---
title: "Add an audio stream to a live call"
method: POST
path: "/legs/{id}/streams"
tags: ["Legs"]
---

# Add an audio stream to a live call

`POST /legs/{id}/streams`

Negotiates an additional m=audio section with a re-INVITE (RFC 3264 §8.1). The new section is appended below the existing ones and binds its own RTP port. Use it to carry a second independent audio stream — a translated feed, for example — alongside the original. Set `content` to "alt" and `lang` to the feed's language so the peer can tell them apart. A peer that answers the new section with port 0 leaves the call untouched and this returns 409.

## Request body

- AddLegStreamRequest
  - `direction` 'sendrecv' | 'sendonly' | 'recvonly' | 'inactive' — Media direction for the new stream, from this server's point of view. Defaults to sendrecv.
  - `lang` string — BCP 47 language tag advertised as a=lang (RFC 8866), e.g. "es-ES" for a Spanish translation feed.
  - `content` 'main' | 'alt' | 'speaker' | 'slides' | 'sl' — Value advertised as a=content (RFC 4796). Use "main" for original audio and "alt" for an alternative feed such as a translation.
  - `label` string — Value advertised as a=label (RFC 4574), for correlating the stream with external metadata.
  - `room_id` string — If set, attach the new stream to this room once it is negotiated.
  - `role` string — Routing role to apply when room_id is set.

## Response `201`

Stream negotiated

- LegStreamView
  - `id` string, required — Stream identifier, stable for the life of the dialog. The primary stream is always "0".
  - `mid` string — The stream's SDP a=mid token (RFC 5888), used to correlate it across offer/answer.
  - `index` integer, required — Position of the stream's m= line in the SDP. Fixed for the life of the dialog (RFC 3264 §8).
  - `primary` boolean, required — True for the call's main bidirectional audio stream, which cannot be removed or attached to a room independently.
  - `state` 'pending' | 'active' | 'removed', required — Negotiation state.
  - `direction` 'sendrecv' | 'sendonly' | 'recvonly' | 'inactive', required — Negotiated media direction from this server's point of view.
  - `desired_direction` 'sendrecv' | 'sendonly' | 'recvonly' | 'inactive' — Direction requested by the application. Survives hold/unhold, unlike the negotiated direction.
  - `codec` string — Codec negotiated for this stream. Streams on one leg may use different codecs.
  - `sample_rate` integer — Native sample rate of the stream's codec, in Hz.
  - `local_port` integer — Local RTP port. Each stream binds its own port; a shared transport is undefined without BUNDLE (RFC 9143).
  - `remote_addr` string — Remote RTP address media is currently sent to.
  - `label` string — The stream's a=label value (RFC 4574), for correlating it with external metadata.
  - `content` string — The stream's a=content value (RFC 4796), e.g. "main" for original audio and "alt" for a translated feed.
  - `lang` string — The stream's a=lang value (RFC 8866): a BCP 47 language tag such as "en" or "es-ES".
  - `room_id` string — Room this stream's audio is mixed into. A secondary stream may sit in a different room than its leg.
  - `role` string — Routing role of this stream within its room. Streams carry their own role, independent of their leg's.

## Other responses

- `400` — Invalid JSON or not a SIP leg
- `404` — Leg or room not found
- `409` — Leg has no negotiated media yet, or the peer rejected the stream

---

[API](https://skmtc.net/voiceblender/apis/voiceblender-api.md) · [All operations](https://skmtc.net/voiceblender/apis/voiceblender-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/voiceblender/voiceblender-api/versions/ad30827d3b57/schema)
