Appearance
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_originlets 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.
| Step | Request |
|---|---|
| Create the stream | PUT /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 segment | PUT .../renditions/aac/segments/0, .../1, and so on |
| Publish the playlist | PUT .../renditions/aac/publication |
| Publish the master playlist | PUT /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.m3u8Open it in Safari, VLC, or a web player such as hls.js.
Supported formats
| Format | Segments | Typical codecs |
|---|---|---|
| MPEG-TS with AAC | .ts | mp4a.40.2 |
| Packed AAC-LC | .aac | mp4a.40.2 |
| Packed MP3 | .mp3 | mp4a.40.34 |
| Fragmented MP4 with AAC-LC | .m4s plus an init .mp4 | mp4a.40.2 |
| Fragmented MP4 with FLAC | .m4s plus an init .mp4 | fLaC |
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.