Skip to content

HLS for browsers and apps ​

HLS (HTTP Live Streaming) splits audio into small files plus a playlist. Browsers and phone apps handle it well, and it passes through CDNs and strict networks that block long-lived connections. Your normal mount stream keeps working alongside it.

Looking to relay someone else's HLS stream?

This page is about serving HLS from Quikcast. To pull an existing HLS station into one of your mounts as a normal stream, see Relay an HLS stream.

HLS needs a producer

Quikcast serves HLS, but it does not create it. Something else (FFmpeg plus a small script, or your own application) must encode the segments and upload them through Quikcast's private ingest API. Quikcast validates what you upload, stores it in memory, writes the playlists, and serves everything to players. It never re-encodes anything.

1. Turn HLS on ​

toml
[hls]
username = "hls"
secret_file = "secrets/hls-ingest"
cors_origin = "https://player.example.com"
  • The ingest password must be different from every mount password.
  • cors_origin lets a website on that exact origin play your HLS in a browser. Leave it out if you only serve apps.

Everything else has defaults. See [hls] in the reference for capacity settings.

2. Publish a stream ​

A producer does the following. Every call uses HTTP Basic authentication with the HLS username and password, and goes to the private admin address (admin_listen, default 127.0.0.1:9090) under /internal/v1/hls/. Players, on the other hand, use the public address. That means your producer should run on the same machine as Quikcast, or reach the admin port through an SSH tunnel; the admin port is never exposed to the internet.

StepRequest
Create the streamPUT /internal/v1/hls/streams/radio
Create a rendition (one quality level)PUT /internal/v1/hls/streams/radio/renditions/aac with a JSON description
Upload each segmentPUT .../renditions/aac/segments/0, .../1, and so on
Publish the playlistPUT .../renditions/aac/publication
Publish the master playlistPUT /internal/v1/hls/streams/radio/master

A complete example you can run ​

This script creates three 2-second AAC segments with FFmpeg, uploads them and publishes the playlists. It uses bash and curl.

sh
HLS=http://127.0.0.1:9090/internal/v1/hls/streams
PW=$(cat secrets/hls-ingest)
c() { curl -s -u "hls:$PW" "$@"; }                       # authenticated curl
gen() { sed -E 's/.*"generation":"([0-9]+)".*/\1/'; }     # pull the generation out of a reply

# Make three test segments (replace with your real encoder output)
for n in 0 1 2; do
  ffmpeg -loglevel error -y -f lavfi -i "sine=frequency=$((440 + n * 220)):duration=2" \
    -c:a aac -b:a 128k -f mpegts seg$n.ts
done

# 1. Create the stream. Keep the generation it returns.
SG=$(c -X PUT $HLS/radio | gen)

# 2. Create a rendition (one quality level).
RG=$(c -X PUT $HLS/radio/renditions/aac \
  -H 'Content-Type: application/json' -H "X-HLS-Generation: $SG" \
  -d '{"target_duration":2,"window_segments":6,"bandwidth":128000,"codecs":"mp4a.40.2"}' | gen)

# 3. Upload the segments.
for n in 0 1 2; do
  c -X PUT $HLS/radio/renditions/aac/segments/$n \
    -H "X-HLS-Generation: $SG" -H "X-HLS-Rendition-Generation: $RG" \
    -H "X-HLS-Duration-Ms: 2000" -H "Content-Type: video/mp2t" --data-binary @seg$n.ts
done

# 4. Publish the media playlist, then the master playlist.
c -X PUT $HLS/radio/renditions/aac/publication \
  -H 'Content-Type: application/json' -H "X-HLS-Generation: $SG" -H "X-HLS-Rendition-Generation: $RG" \
  -d '{"expected_revision":0,"segments":[{"sequence":0,"duration_ms":2000},{"sequence":1,"duration_ms":2000},{"sequence":2,"duration_ms":2000}],"end":false}'

c -X PUT $HLS/radio/master \
  -H 'Content-Type: application/json' -H "X-HLS-Generation: $SG" \
  -d '{"expected_revision":0,"renditions":["aac"]}'

Generations are numbers Quikcast gives you

Creating a stream or rendition returns a long number such as 7832260401770470567. Send it back unchanged on later calls. It proves you are talking to the stream you created, not an older one with the same name.

A real producer keeps uploading new segments and publishing a sliding window (for example the latest six). Every call, header and error is documented in the HLS ingest API reference.

3. Play it ​

text
http://your-server:8000/hls/radio/master.m3u8

Open it in Safari, VLC, or a web player such as hls.js.

Supported formats ​

FormatSegmentsTypical codecs
MPEG-TS with AAC.tsmp4a.40.2
Packed AAC-LC.aacmp4a.40.2
Packed MP3.mp3mp4a.40.34
Fragmented MP4 with AAC-LC.m4s plus an init .mp4mp4a.40.2
Fragmented MP4 with FLAC.m4s plus an init .mp4fLaC

Not supported: Ogg or native FLAC in HLS, encryption, video, low-latency HLS and DASH.

Good to know ​

  • It lives in memory. Restarting Quikcast clears all HLS content. Your producer must register and upload again.
  • Public URLs are generated for you. Players only need the master playlist address. Everything else comes from it.
  • Protect a stream with signed links if it should not be public.
  • Caching is already tuned. Playlists are served no-cache; segments are immutable and cached for a year, which is what CDNs want.
  • Range requests work. Single byte ranges return 206, which players use when seeking.

Documentation for Quikcast.