Without Streaming stopped being a player and became a radio station
When I wrote the first posts about Without Streaming, the word “radio” was more of a descriptive form.
Back then each person was effectively running their own player. The browser got a playlist from Telegram, chose the track sequence itself, managed transitions, and the two knobs Jazz ⇄ Hip-hop and Drifting ⇄ Driving let everyone assemble their own version of the stream.
It worked, but real radio has one fundamental property: at any moment there is one broadcast for everyone.
That’s exactly what I eventually rebuilt completely.
Now a person who opens Without Streaming doesn’t get their own queue and doesn’t start a track from the beginning. They connect to the point that is on air right now.
Inside, the architecture now looks roughly like this:
Telegram local media library Python Liquidsoap AAC-LC HLS Caddy one shared live broadcast
In the simplest words:
Liquidsoap is the radio engine. It continuously plays the selected tracks, makes transitions between them and forms the very signal that’s actually on air at that moment.
AAC-LC is an audio codec: it compresses this signal into a format that can be sent to listeners over the internet economically enough.
HLS is a way of delivering a live stream. Instead of one endless connection, the broadcast is constantly cut into short segments, and the browser fetches them in sequence and so can connect to the current moment of the broadcast.
Caddy is the web server at the end of this chain. It serves HLS, the site and other public files to listeners.
The most important change here isn’t even related to Liquidsoap or HLS but to the separation of responsibility.
Python decides what should sound next.
Liquidsoap is the actual point of broadcast.
The browser no longer programmes anything, it only listens.
Previously, during Play, a track was requested directly from Telegram and streamed to the browser. Now the whole usable library is mirrored locally and can keep playing regardless of whether Telegram is available.
So Telegram gradually turned from:
CMS + file server + runtime dependency
into:
CMS + source of publication and of the material’s origin.
The client changed too.
Instead of a browser audio engine there’s now one permanent <audio> connected to HLS.
After a pause, Play now returns the listener not to the old position but back to the current broadcast.
Visuals exist separately from the music programme. They’re prepared locally, served as static MP4 and rotate independently for each listener.
That’s why the old Jazz / Hip-hop and Drifting / Driving knobs disappeared from the interface, and not by accident. The idea isn’t discarded, but control of the music logic is gradually moving to where it now belongs: into server-side programming of the shared broadcast rather than each listener’s personal player.
In parallel the radio got a separate operational layer. Now I can see how many people are on the site, how many are really listening to HLS, the daily number of listening sessions and the peak.
The next stage for me now isn’t about new buttons. I’m bringing the system to a state where it recovers on its own after process crashes, network loss and reboot, then I’ll measure the real throughput of the home server, and only after that continue building the Programming Engine.
And then begins perhaps the most interesting part of Without Streaming’s development. The music programme will gradually become much more complex, and things will appear on air that have never been in the project before. But that’s for another time.
The result is a little paradoxical: the more complex Without Streaming gets inside, the fewer actions remain for the listener outside :)