Skip to content

Playback & distribution

Get playback URLs and the full playlist, choose the right credential, and understand how on-demand channels start and stop.

Updated View as Markdown

After you configure a channel, two questions remain: which URL should the player open, and which credential should it use? The sections below cover every playback endpoint.

Playback URLs

Each channel has exactly one entry point. Everything else is generated by the playlist, so you never assemble these by hand:

  • /v1/play/{id}/index.m3u8: the entry point. HLS channels get the rewritten upstream playlist; DASH channels get the repackaged master playlist.
  • /v1/play/{id}/live/{file}: media playlists, segments, init segments, and subtitles produced locally by the DASH repackaging path.
  • /v1/play/{id}/u/{upstream}: the same-origin fetch proxy for HLS channels. {upstream} is the encoded upstream address and carries a ?sig= signature; the target host must also be within the allowed set. Failing either check is rejected outright.

Each DASH restart produces a new publication generation, carried as ?g= on the URL. Media playlist requests are redirected with 307 to the current generation, and a request for a generation that is already gone returns 410 with Retry-After: 1. Players roll onto the new generation on their own, with no manual refresh needed.

Segments and init segments carry long-lived cache headers; playlists are always no-store.

Authentication

Playback routes require a credential by default, governed by security.play_require_auth. The two ways to pass one are exactly equivalent, with the query parameter taking precedence:

curl -s "http://127.0.0.1:8080/v1/play/hls-demo/index.m3u8?token=$TOKEN"
curl -s http://127.0.0.1:8080/v1/play/hls-demo/index.m3u8 -H "authorization: Bearer $TOKEN"

The query parameter exists to accommodate players: most IPTV clients will not attach custom headers to segment requests, so playlist URLs consistently carry ?token=.

A non-admin session scoped to a channel subset can only play channels in that subset; anything else returns 403.

The full playlist

GET /v1/playlist.m3u returns an M3U of every enabled channel and accepts a login session only. An admin API token is rejected here, because this route is not registered among the routes a token can reach.

What it does:

  • The credential used for the request is embedded verbatim as ?token= on every playback URL, so the playlist stays valid exactly as long as the session token does.
  • A session scoped to a channel subset only receives that subset.
  • When the guide is enabled, the #EXTM3U line carries x-tvg-url pointing at Kiln’s own EPG endpoint.
  • Disabled channels are omitted.

When you need a playlist that outlives a session and can be handed to a player long-term, use a playback key instead.

Path-based playback keys

A playback key lives in the URL path rather than a query parameter, so the whole link can be distributed as one string and usage can be attributed by key prefix in the logs.

  • /p/{token}/playlist.m3u: the playlist within that key’s scope.
  • /p/{token}/play/{id}/index.m3u8: the entry point.
  • /p/{token}/play/{id}/live/{file}: locally produced media.
  • /p/{token}/play/{id}/u/{upstream}: the same-origin fetch proxy.

Playlists served under this prefix carry no ?token=; every entry stays inside /p/.

Creating and managing keys

Create and maintain keys under Playback Access Control in the admin console, or through the /v1/admin/access-tokens endpoints.

  • Shown once: the plaintext is returned only at creation. The server keeps a SHA-256 digest and the first ten characters as a prefix, so a lost key can only be replaced.
  • Scopable: a key covers every channel by default, or a chosen subset. Channels outside the scope return 403 and never appear in that key’s playlist.
  • Optional expiration: an expiration date invalidates the key automatically.
  • Revocable: revoking or disabling takes effect immediately, with no restart.
  • Auditable: every use writes a playback access log entry.

Playback access log

Each use records the key prefix, channel, status code, client IP, and request path, and failed authentication attempts are recorded too. The logged path is redacted down to the key prefix, so a complete key never reaches the log.

Entries are retained by day count, 30 days by default and adjustable in settings. The console filters by key and by channel, which is what answers “who used this link, and when”.

On-demand start and reclaim

From a viewer’s point of view, the full lifecycle of an on_demand channel looks like this:

The first viewer triggers the start

Kiln only begins pulling the upstream when an index.m3u8 request arrives with no session running. Concurrent first requests for the same channel trigger exactly one start and the rest wait on that same result, so the upstream never sees duplicate connections.

Waiting for the first playlist

An HLS channel fetches the upstream playlist as soon as it has a session. A DASH channel has to wait for the packager to produce its first playlist, and returns 502 with playlist not ready until then, which players simply retry. To remove that wait, prewarm the channel with Start now in the console, or set it to prewarm at startup.

Playback keeps the lease alive

Every playlist or segment fetch afterwards refreshes the session’s activity timestamp. As long as someone is watching, the session is never reclaimed.

Reclaimed once nobody watches

The reaper sweeps every 5 seconds. An on_demand channel idle for longer than idle_timeout_sec (90 seconds by default) has its session stopped, its upstream connection dropped, and its working directory cleaned up. The next viewer starts the whole sequence again.

A channel with on_demand off and autostart on is never reclaimed and holds its upstream connection permanently, at the cost of resident memory and bandwidth. That suits frequently watched channels; leave everything else on demand.

Channels with max_viewers set get one more layer: the entry request is redirected with 307 to add a signed viewer= lease, the lease expires if it is not renewed within a minute, and viewers beyond the ceiling receive 429.

Playlist rewriting

An HLS channel’s upstream playlist is rewritten before it reaches the player: relative references are resolved to absolute addresses, and entries that must be fetched through Kiln are pointed at /v1/play/{id}/u/... with a signature attached. Whether an entry is rewritten is decided by the playlist_policy outbound setting, rewrite by default; channels with max_viewers set are rewritten unconditionally, since viewer counting is impossible otherwise. Policy values and host-based routing rules are covered in Outbound proxying.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close