# Vabu Media

Vabu Media is Vabu's own plane. Your encoder sends video to Vabu, Vabu makes a quality ladder from it, stores it, and serves it from the edge. You call the same Streams endpoints as on any other plane, and the `provider` field of a live stream says `vabu_media`.

Vabu sets the plane for your account. Test mode runs on the simulated plane and never reaches Vabu Media.

## What it can do

| Capability | Vabu Media |
|---|---|
| Live streaming (`live`) | Yes |
| Recordings of live streams (`vod`) | Yes |
| Audio-only live streams (`audio_only`) | Yes |
| SRT ingest (`srt_ingest`) | Yes |
| WHIP ingest from a browser (`whip_ingest`) | Yes |
| Signed playback (`signed_playback`) | Yes, always |
| Program date time in playlists (`program_date_time`) | Yes |
| Signing keys of your own (`delegated_signing`) | Dedicated environment only |
| Simulcast to other platforms (`simulcast`) | No |
| Low-latency HLS (`ll_hls`) | No |

A request this plane cannot do is refused with `422 provider_rejected` before anything is created.

## Going live

Create a live stream as usual. The response carries `stream_key` and `ingest`. Send RTMP to `ingest.rtmp_url` with the stream key, or use `ingest.srt_url` or `ingest.whip_url`. Send a keyframe every 2 seconds. Vabu builds the ladder from what you send: with the default `economy` ladder a 720p H.264 source plays as it is, next to a 360p picture and an audio-only rendition. The `standard` ladder adds 480p and 240p.

`reset_stream_key` gives a new key and disconnects the encoder that was using the old one. `disable` refuses the encoder and ends the broadcast.

## Playback

A playback grant returns one source. Its url looks like this:

```
https://media.vabu.live/t/<token>/<channel>/live/master.m3u8
```

The token is part of the path, so the segment and playlist addresses inside the playlists carry it without any change in your player. Play the url in any HLS player. A token that is wrong, expired or made for another stream is refused with `403`. A recording plays the same way, from a url that ends in `/recordings/<broadcast>/master.m3u8`.

A playback url is a bearer url: anyone who has it can play until the token expires, so do not post it. The viewer is not bound to the token.

Known limit: a token is made for a channel, not for one recording. A grant for a recording also plays that channel's live stream and its other recordings, because recordings share the live segments. If you sell recordings apart from the live event, do not rely on the token to keep them apart yet.

Tokens last as long as the viewer session plus a short grace period, and never more than 24 hours. The heartbeat of a viewer session keeps replacing them.

## Recordings

Every broadcast is recorded. When the encoder leaves and the last segments are stored, Vabu creates an asset with `source: "recording"`, `status: "ready"` and one signed playback id, and sends `streams.asset.created` and `streams.asset.ready`. A broadcast shorter than a second leaves no recording.

An encoder that drops and reconnects starts a new broadcast, so it makes a new recording.

## Where it differs

- **Always signed.** A live stream created with `playback_policy: public` answers `422 provider_rejected`.
- **One playback id per resource.** `POST /v1/streams/playback_ids` and `DELETE /v1/streams/playback_ids/{id}` answer `422 provider_rejected`. Playback is always signed.
- **No uploads or imports.** Assets on this plane are recordings. `POST /v1/streams/uploads` and `POST /v1/streams/assets` answer `422 provider_rejected`.
- **No clips yet.** `POST /v1/streams/assets/{id}/clips` answers `422 provider_rejected`.
- **Ladder.** The ladder is set for the account. It cannot be changed on a live stream that exists.
- **Ending a broadcast.** `complete` has no effect. The broadcast ends when the encoder leaves.
- **Deleting.** Deleting a live stream or an asset removes it from the API. The stored media stays in storage for now.

See [Delivery networks and capabilities](https://docs.vabu.live/concepts/delivery-networks.md) for how to write code that does not depend on the plane.
