Skip to content

Communication HLS

pschatzmann edited this page Oct 22, 2026 · 1 revision

HTTP Live Streaming (HLS) is how many radio stations and TV broadcasters provide their streams today: instead of one endless HTTP stream, the server provides a playlist (.m3u8) that lists short segments (a few seconds each), and the client downloads and plays them one after the other, reloading the playlist to learn about new segments. See HTTP Client for plain HTTP streams and Communication for the general considerations.

The HLSStream class

HLSStream (AudioTools/Communication/HLSStream.h) does all of this for you: begin(url) loads the playlist (following master playlists to a media playlist), and readBytes() delivers the data of the segments as one continuous stream. It is a URLStream like the others, based on the Arduino network API; HLSStreamESP32 (HLSStreamESP32.h) uses the ESP-IDF HTTP client instead.

Method Description
HLSStream(ssid, password) connects to WiFi
begin(url) loads the playlist and starts reading
readBytes(), available() the audio data
codec(), contentType() the codec from the playlist, and the content type of the segments - use it to select the decoder
setBufferSize(size, count) buffer for the segment data
setCACert(cert), setPowerSave(bool), setAgent(agent) HTTPS certificate, WiFi power save, User-Agent

Example

From hls-i2s.ino: a MultiDecoder selects the decoder from the content type that HLSStream reports:

#include "AudioTools.h"
#include "AudioTools/Communication/HLSStream.h"
#include "AudioTools/AudioCodecs/CodecHelix.h"  // https://github.com/pschatzmann/codec-helix

I2SStream out;
HLSStream hls_stream("ssid", "password");
MP3DecoderHelix mp3;
AACDecoderHelix aac;
MultiDecoder multi(hls_stream);  // uses the mime type of hls_stream
EncodedAudioOutput dec(&out, &multi);
StreamCopy copier(dec, hls_stream);

void setup(void) {
  if (!hls_stream.begin("https://streams.radiomast.io/ref-128k-mp3-stereo/hls.m3u8"))
    stop();
  multi.addDecoder(mp3, "audio/mpeg");
  multi.addDecoder(aac, "audio/aac");
  auto cfg = out.defaultConfig(TX_MODE);
  out.begin(cfg);
  dec.begin();
}

void loop() { copier.copy(); }

Many HLS streams put their audio into MPEG transport stream segments (video/mp2t): add an MTSDecoder (AudioTools/AudioCodecs/CodecMTS.h) wrapping the AAC decoder for them, as in hls-buffer-i2s.ino:

MTSDecoder mts(aac);
multi.addDecoder(mts, "video/mp2t");

Buffering

Between two segments the client has to open a new HTTP connection, and from time to time it reloads the playlist: without a buffer, the playback pauses each time. hls-buffer-i2s.ino therefore copies the stream in a separate task into a thread-safe queue (BufferRTOS + QueueStream), from which the main loop decodes and plays:

BufferRTOS<uint8_t> buffer(0);
QueueStream<uint8_t> queue(buffer);
StreamCopy copier_play(dec, queue);               // loop(): queue -> decoder
StreamCopy copier_write_queue(queue, hls_stream);  // task: HLS -> queue
Task writeTask("write", 1024 * 8, 10, 0);
...
buffer.resize(10 * 1024);  // more with PSRAM
queue.begin(100);          // start reading when the queue is 100% full
writeTask.begin([]() { copier_write_queue.copy(); });

Things to consider

  • Test streams: the radiomast reference streams provide MP3, AAC-LC and HE-AAC via HLS.
  • HE-AAC needs a decoder that supports it (e.g. AACDecoderHelix supports HE-AAC v1).
  • Memory: HTTPS and the segment buffers need a lot of RAM - use an ESP32, preferably with PSRAM.

Clone this wiki locally