Prologue -------- If you were waiting for the next installment of the TTY office series, I got a bit sidetracked. A few weeks ago, Rogers Communications shut down six radio stations across Canada. Two were in Vancouver. One was a 24-hour news station (CKWX) and the other was a sports talk station (CISL, better known as "Sportsnet 650"). These were AM stations. I tended to listen online during the day and over the air at night, due to my distance from the transmitters. After they shut down, I decided to set up my own streaming sports talk station. My setup makes use of ezstream and icecast2, both of which are available in the Debian repositories. Here's a flowchart to outline how these pieces of software function together: ezstream icecast2 various (streaming -----> (streaming -----> receiving client) server) clients The streaming client sends the stream to the streaming server, which then relays it to receiving clients. The streaming client and server may be on different machines. Mine are. I have ezstream installed on my laptop at home. It sends the stream to icecast2 on my vps in Toronto. For clients, I use Transistor to listen on my Android phone and gst123 to listen on my laptop. Configuration ------------- Here are my configuration files for ezstream and icecast2: I called my ezstream configuration file ez-config.xml. It can be placed in any convenient directory. I've used "password_one" as the password in this file so you can connect it to the correct password in the icecast.xml file. If you have icecast on the same device as ezstream, substitute 127.0.0.1 for your.server.com in this file. your.server.com 8000 password_one /stream.ogg Ogg AM 750 CSPO BC's Sports Talk Connection! stdin The icecast.xml configuration file is at /etc/icecast2/icecast.xml. It's a long file and you only need to make a few changes. Here are the changed sections of mine, separated by ellipses. In this file, "password_one" should be the same password you used in the ezstream configuration file. You use "password_three" to log in as administrator in icecast's web portal, which you'll find by visiting "your.server.com:8000" with your web browser. Unless you're dealing with multiple icecast instances, you'll probably never use "password_two". These particular passwords are used for illustrative purposes. Change them to something more difficult to guess! password_one password_two ArthurCarlson password_three ... your.server.com 8000 ... /stream.ogg 14400 /static.ogg 1 1 The fallback mount, static.ogg, is actually just a file placed in the /usr/share/icecast2/web/ directory. It plays a one-minute recording of radio static when the station is offline (when I'm not relaying any streams through ezstream). Each time icecast2 concludes playing the file, it will check to see if I'm streaming again and will attempt to switch listeners over to the main stream ("stream.ogg"). The switch-over only seems to work with well-behaved clients. For the fallback stream, you can use any file you like, but make it short, since it doesn't appear to try to hand clients back to the main stream until the file finishes playing. If you read up further about icecast2, you'll find that you can actually set up multiple "mounts" (to which clients can send streams) and prioritize among them by setting up chains of fallbacks. You can also use "liquidsoap" to do this kind of thing in a more professional way, but I haven't tried it. To start icecast2: $ systemctl start icecast2.service To autostart icecast2 each time you start the server: $ systemctl enable icecast2.service You will listen to your station at: your.server.com:8000/stream.ogg But first, you have to send it a stream. Streaming "Recipes" ------------------- Okay, here comes the fun part! Here are some one-line recipes you can use to stream from various sources to your station. In several of these recipes, I use yt-dlp to stream from YouTube and pipe the output through ffmpeg and ezstream. Since I'm the only person using this station, I'm not really concerned about copyright. It's best to download the yt-dlp binary directly from their releases on Github (https://github.com/yt-dlp/yt-dlp). Place it in a directory in your path. I've renamed it from "yt-dlp_linux" to "yt-dlp". If you leave it as yt-dlp_linux, just substitute that name in the commands below. Once installed, you can update yt-dlp to the latest version by typing "yt-dlp -U" without the quotation marks. You'll also need ffmpeg. It's in the Debian repos. Here are the recipes: # Send a local file to your station at 64k (stereo): ffmpeg -i path/to/file.mp3 -b:a 64k -f opus - | ezstream -c /path/to/ez-config.xml # Relay another audio or video stream to your station as 16k mono audio: ffmpeg -i https://rogers-hls.leanstream.co/rogers/tor590.stream/playlist.m3u8 -b:a 16k -f opus -ac 1 - | ezstream -c /path/to/ez-config.xml # Relay a YouTube stream to your station at 64k (stereo): yt-dlp -f wa* https://www.youtube.com/watch?v=6gtQck24Nf8 -o - | ffmpeg -i pipe: -b:a 64k -f opus - | ezstream -c /path/to/ez-config.xml # Relay and record a YouTube stream simultaneously in 16k mono: yt-dlp -f wa* https://www.youtube.com/watch?v=DbO0t3c5ukk -o - | ffmpeg -i pipe: -b:a 16k -f opus -ac 1 - | tee testfile.ogg | ezstream -c /path/to/ez-config.xml # Relay a YouTube livestream to your station at 16k mono (with some # sound modifications to make it sound like an AM station). See the # switch explanations below. timeout 120m yt-dlp --wait-for-video 30-60 -f wa* https://www.youtube.com/@SekeresPrice/live -o - | ffmpeg -i pipe: -b:a 16k -f opus -af "asubboost=boost=2.0:cutoff=60,equalizer=f=1500:width_type=h:width=200:g=1.2,lowpass=f=6000,volume=0.8" -ac 1 - | ezstream -c /path/to/ez-config.xml What do the various switches and commands mean? ffmpeg -i input file (or stream or pipe) -b:a 64k bitrate audio (set to 64k) -f opus encode audio as opus (the format used inside ogg containers) -ac 1 audio channel 1 (mono rather than stereo) - output to stdout, so you can pipe it to the next application -af audio filter yt-dlp --wait-for-video 30-60 wait for the livestream to start. Wait at least 30 seconds and at most 60 seconds between retries. -f wa* get the worst quality audio-only (preferred) or audio-video stream from YouTube -o - output to stdout ezstream -c location of configuration file tee adds a "tee" into your pipe: testfile.ogg ^ yt-dlp > ffmpeg > ezstream timeout 120m kill the command if it's still running after 120 minutes Here's one final recipe. It's a bit more complicated to set up. This one relays the sound from your device (any application playing sound from any source) to ezstream and on to your icecast station. So you can just play something using an audio player, your browser, etc., and you'll hear the sound on your icecast station.[1] ffmpeg -f pulse -i