I’ve been trying different ways to stream DJ sets from MIXXX and found this method that works providing a lossless FLAC ogg stream to icecast2, with an update of what track is playing.
I’m using Xubuntu 16.04 for this.
It took me a while to get this combination of software working, so I thought I’d post the recipe as a set of rough scripts to show the approach
As the built in MIXXX broadcasting options don’t support this, I set up the “booth” output to go to an ALSA loopback audio device.
I then use arecord piped into aviconv to stream the audio as an Icecast flac stream to the ICECAST2 server. I’m piping from arecord as I couldn’t figure out how to record from the Loopback device direct with aviconv.
I’m using arecord “raw” as arecord defaults to recording WAV which has a max size of 2GB, even when piped.
As this loses the metadata, I use an sqlite3 command to extract the “now playing” info and display it on a web page.
The below two shell fragments can be made into scripts and left running in a screen session on the PC running mixxx.
Broadcast script:
# very simple loop, needs
# sudo modprobe snd-aloop
# run to have the loopback audio set (or set it up in /etc/ ..)
#
# then set hw:Loopback,0 as the BOOTH output in MIXXX
# you may need to increase the latency to reduce glitching with the additional output.
#
# set s16 to s32 for 24 bit flac, but thats overkill...
#
cd /tmp
while true
do
date
arecord -D hw:Loopback,1,0 -f FLOAT_LE -c 2 -r 44100 -t raw | \
avconv -report \
-f f32le -sample_rate 44100 -ac 2 -sample_fmt f32le \
-i pipe: \
-ar 44100 -ac 2 -b:a 420000 -sample_fmt s16 \
-bufsize 20480k \
-c:a flac -compression_level 10 -f ogg \
-ice_name 'MY RADIO LOSSLESS FLAC STREAM' \
-ice_description 'Describe my stream' \
-ice_url 'https://www.website.net.au/' \
-ice_public 1 \
-content_type application/ogg \
icecast://source:password@icecast.website.net.au:8000/source
sleep 1
As it has lost the metadata during this process, update a now playing text file on the web site by grabbing that info from the MIXXX database…
touch /tmp/nowplaying.txt-prev /tmp/nowplaying.txt
while true
do
sqlite3 /home/dj/.mixxx/mixxxdb.sqlite -column -header "select library.artist, library.title, library.album, library.year from library where library.id = (select PlaylistTracks.track_id from PlaylistTracks where id = (select max(id) from PlaylistTracks));" > /tmp/nowplaying.txt
if ! diff /tmp/nowplaying.txt /tmp/nowplaying.txt-prev > /dev/null
then
echo track has changed
cat /tmp/nowplaying.txt
date >> /tmp/radio.log
cat /tmp/nowplaying.txt >> /tmp/radio.log
scp -q /tmp/nowplaying.txt user@website.net.au:site/nowplaying.txt
cp /tmp/nowplaying.txt /tmp/nowplaying.txt-prev
fi
sleep 10
done
Web page that will display an inline player for the above code:
<!DOCTYPE html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />
<script type="text/javascript">
function refresh() {
var req = new XMLHttpRequest();
console.log("Grabbing Value");
req.onreadystatechange = function () {
if (req.readyState == 4 && req.status == 200) {
document.getElementById('NowPlayingElement').innerText = req.responseText;
}
}
req.open("GET", 'https://static.website.net.au/nowplaying.txt', true);
req.send(null);
}
function init() {
refresh()
var int = self.setInterval(function () {
refresh()
}, 2000);
}
</script>
</head>
<body onload="init()">
<div id="main">
<div id="updateMe">
<b>MY RADIO Track Now Playing is:</b>
<pre><p id="NowPlayingElement"></pre>
</div>
<p><audio controls="controls" preload="none"><source src="https://icecast.website.net.au:8443/source" type="audio/ogg" />Your browser does not support the audio element.</audio> <!-- END OF THE RADIO HTML5 PLAYER EMBEDDING --></p>
</div>
</body>
</html>
Running example (if the entry level cloud ICECAST2 server doesn’t fall over is here: zog.net.au/experimental-zog … ation.html