services » radio

Une radio Icecast est disponible à l'addresse http://radio.anarc.at/. Le stream est de basse qualité (64kbps) pour éviter de prendre toute la bande passante. Je permets aussi seulement 5 accès simultanés.

Une radio RTP est également disponible localement, voir cet article pour plus de détails.

La radio devrait être disponible de façon continue, grâce à Liquidsoap. Ce logiciel fait office de DJ automatique, en mettant en évidence mes chansons favorites, mais en permettant aussi à l'auditoire d'écouter la grande variété du répertoire, tout en insérant des petits "jingles" à intervalles réguliers (à chaque 15 chansons).

Les détails de la configuration technique sont ci-bas.

  1. Overall design
  2. Problèmes restants
  3. Remaining todo
  4. Liquidsoap configuration
    1. tap in home radio
    2. Other RTP streaming attempts
    3. jingles
    4. weighting
    5. random playlist
    6. Playing on the sound card
  5. Audio mastering tips
    1. Extracting and splitting audio from video files

Overall design

Problèmes restants

  1. no desktop integration: metadata isn't showed on the desktop for automatic choices done by liquidsoap, and all the cool features like album/artist art and lyrics from MPD is not available - there's the liguidsoap UI, which connects only on the insecure telnet port, but at least it can tell us which file is playing on the shuffle
  2. liquidsoap doesn't generate an RTP stream, so I don't get music by default in the other players in the house, see liquidsoap bug #109 this actually works now!
  3. liquidsoap doesn't play on the sound card out of the box, i need to start something to listen to the stream, which is silly, but then i don't want to hardcode an output by default, because i am not sure how to remove it. again, PA may be a solution here PA worked, again
  4. liquidsoap can't reload its config file without restarting at least in Debian
  5. liquidsoap can't listen to the RTP stream so I have to decode data twice when listening to a custom playlist with MPD, see below for details and liquidsoap bug #109 now this works!
  6. liquidsoap crashes after 3 days, see Debian bug #727307 - remains to be tested it still crashes, but after a while longer... when it crashes, pulseaudio just hangs there

To recover from the hang, I need to do this:

sudo -u liquidsoap -s
rm -rf .pulse.old
mv .pulse .pulse.old
cp .pulse.old/default.pa .pulse
exit
sudo service liquidsoap restart

Make sure the audio device is free when started, otherwise I get:

mars 29 12:37:16 marcos pulseaudio[26115]: [pulseaudio] module-combine-sink.c: Invalid slave sink 'alsa_output.pci-0000_00_1b.0.analog-stereo'
mars 29 12:37:16 marcos pulseaudio[26115]: [pulseaudio] module.c: Failed to load module "module-combine-sink" (argument: "sink_name=combined slaves=alsa_output.pci-0000_00_1b.0.analog-stereo,rtp"): initialization failed.
mars 29 12:37:16 marcos pulseaudio[26115]: [pulseaudio] main.c: Module load failed.
mars 29 12:37:16 marcos pulseaudio[26115]: [pulseaudio] main.c: Failed to initialize daemon.
mars 29 12:37:16 marcos pulseaudio[26111]: [pulseaudio] main.c: Daemon startup failed.

A potential solution for #2 problem would be to embrace Pulseaudio even further, by making Liquidsoap tap into MPD as a PA RTP source, and in turn generate RTP on output. See this issue for details.

Another idea would be to tap into MPD further for metadata, see this issue to try to figure out how this can be integrated.

Finally, this tutorial has tons more ideas.

Remaining todo

Liquidsoap configuration

The general principle is that the Icecast server random.ogg mountpoint is fed by liquidsoap, which plays a mix of

The icecast server, in turn, will fallback on the random.ogg radio if the regular radio is not playing, that is, if no playlist is playing on the regular mpd media player.

The full configuration is in anaradio.liq.

I had to figure out a few sticky problems to make this somehow work.

tap in home radio

To tap into the home radio, I originally thought I would make liquidsoap listen for traffic over the RTP port, so that when I listen to music, liquidsoap does the same. Liquidsoap, in turns, would rule the icecast server. This would have the advantage of having only a single decoder running at the same time: if mpd is running, it's the one decoding the media files, and liquidsoap is just passing bits to the icecast server.

Unfortunately, I couldn't figure out how to make liquidsoap play RTP at all. First, I tried gstreamer. I found the proper pipeline, to make it work:

gst-launch udpsrc multicast-group=224.0.0.56 port=5004 ! "application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10" ! rtpL16depay ! audioconvert ! alsasink

Phew. That was a pain to find! but it works, on the commandline. Liquidsoap is supposed to have a gstreamer plugin, but it was broken (Debian bug #727044) in Debian Wheezy, I'll have to test this again:

liquidsoap 'out(input.gstreamer.audio(pipeline="udpsrc multicast-group=224.0.0.56 port=5004 ! \"application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10\" ! rtpL16depay ! audioconvert ! alsasink sync=false"))'

But now it works! See liquidsoap bug #109 for all the details.

One thing that *still* doesn't work is that the `udpsink` doesn't send proper SDP announcements, so VLC complains. We need to setup a proper RTSP server for that in our pipeline... We are pretty much stuck at the same place as [this guy](http://stackoverflow.com/questions/21258574/get-rtp-stream-media-capabilities-without-sdp-file-gstreamer). [Those people](http://stackoverflow.com/questions/13154983/gstreamer-rtp-stream-to-vlc) used a `.sdp` file, but we'd like to avoid that. This is also the approached used [here](https://developer.ridgerun.com/wiki/index.php/Introduction_to_network_streaming_using_GStreamer#Generating_a_SDP_file_from_a_streaming_pipeline). I'm getting the same error as [this question](http://stackoverflow.com/questions/17307210/c-rtp-multicast-of-a-ts-file-with-sdp-error):
SDP required: A description in SDP format is required to receive the RTP stream. Note that rtp:// URIs cannot work with dynamic RTP payload format (77).
The [rtpbin](http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gst-plugins-good-plugins/html/gst-plugins-good-plugins-rtpbin.html) may be the solution. See also [this simpler script](http://cgit.freedesktop.org/gstreamer/gst-plugins-good/tree/tests/examples/rtp/server-alsasrc-PCMA.sh).

Pulseaudio does all that for us, so maybe that would be simpler (again), than using gstreamer. Unfortunately, we can't select the sink from the liquidsoap manifest, see liquidsoap issue #154. That doesn't matter - we set the default sink and we're done with it.

RTP streaming works.

Other RTP streaming attempts

I have tried all sorts of other tortuous ways of making that work - the external method works:

liquidsoap 'out(input.external("mplayer -demuxer rawaudio -rawaudio format=0x20776172  -ao pcm:file=/dev/stdout -vc null -vo null rtp://224.0.0.56:5004"))'

.. but liquidsoap doesn't kill mplayer correctly, so it hangs there. I also doubt it will detect it properly. I also tried to make liquidsoap talk to pulseaudio to listen to its stream, that also failed:

liquidsoap 'out(input.udp(host="224.0.0.56",port=5004,"audio/wav"))'

I am guessing this doesn't support multicast (for one) and two, that it won't guess the proper audio file format - in any case it just fails.

jingles

Right now, I use a small collection of jingles:

# 3. jingles playlist
jingles = playlist('/srv/playlists/jingles.m3u')

# 3.1 strangelove
jingles = rotate(weights = [1, 10], [playlist('/srv/playlists/strangelove.m3u'), jingles])

A mix of Dr. Strangelove clips and an arbitrary jingles list. I really need to record my own...

Tricks to create the jingles are explained below.

I have a fallback jingle that is started from Icecast when everything fails. Here's the text:

You are listening to anarcat radio, and I fucked up, so the stream is down. Try to connect gain to see if it's back, otherwise i'll leave you with this bumbling along for ever, and ever, and ever, and ever...

Vous écoutez radio anarcat, et je me suis planté, donc le stream est down. Essayez de vous reconnecter pour voir si c'est de retour, sinon je vous laisser avec ce bomblage qui se répète pour toujouuuuuurs....

That's not the current recording however, I need to redo them. The trick for the fallback is to have the following in icecast.xml:

<mount>
    <mount-name>/radio.ogg</mount-name>
    <fallback-mount>/fallback-jingle.ogg</fallback-mount>
    <fallback-override>1</fallback-override>
    <!-- ... -->
</mount>

And then put a file named fallback-jingle.ogg in the webroot (/usr/share/icecast2/web).

weighting

turns out documentation isn't quite clear about the difference between rotate() and random(): i was told that the rotate() really chooses deterministically, while random() is just random. So I use rotate().

# play favorites roughly half the time, and jingles every 15 songs
radio = rotate(weights = [5, 10, 1], [favorites, shuffle, jingles])

random playlist

I just load all the files on startup - it takes around 3-4 minutes, so that isn't so bad, plus it makes all new files appear magically.

# 2. random playlist
shuffle = playlist('/srv/mp3')

# 2.1 incoming random playlist
incoming = playlist('/srv/incoming')

# play incoming one out of 15 times
shuffle = rotate(weights = [1, 15], [incoming, shuffle])

Playing on the sound card

For liquidsoap to play both on the RTP stream and the sound card, well, i got confused and again went only with Pulseaudio. First, we create a combined stream:

load-module module-combine-sink sink_name=combined slaves=alsa_output.pci-0000_00_1b.0.analog-stereo,rtp
set-default-sink combined

This means, by default, that output.pulseaudio() will now play on both the stream and the sound card. This is no big deal because we can still mute the soundcard and PA will keep state (i think?). To toggle the mute, I use the following incantation:

sudo -u liquidsoap pactl set-sink-mute alsa_output.pci-0000_00_1b.0.analog-stereo toggle

Then we just need to make sure we don't get prompted for this crap, with the following entry in /etc/sudoers.d/liquidsoap:

anarcat ALL = (liquidsoap) NOPASSWD: /usr/bin/pactl

Then I bind this to my music key in my window manager, using xev to figure out the proper keycode and everything.

Audio mastering tips

Back when I used to do HDR recording, I was using Ardour. Nowadays for small tasks I try to use Audacity.

Extracting and splitting audio from video files

I often have to do this weird task of extracting audio from a video file, often to save data from Youtube or similarly weird websites.

To extract the audio, install ffmpeg or libav and run:

avconv -i foo.webm -vn -acodec copy foo.mp3

This will split the audio into the foo.mp3 file, assuming the audio is mp3 (just change the extension accordingly).

To take a fragment out of that, use mp3cut (from poc-streamer):

mp3cut  -t 29:48-30:49+750 foo.mp3

This will take an excerpt (from 29 minutes and 48 seconds to 30 minutes, 49 seconds and 750 miliseconds) from foo.mp3 and will write it into foo.out.mp3. mp3cut splits the files on MP3 frames to ensure best quality, so you may have to fiddle around those timings to get them just right.

Then use exfalso to tag that new file properly.

Audio can be extracted directly with avconv as well:

avconv -i example.avi -ss 1458 -t 50  -vn -acodec flac example.flac

This will take 50 seconds from position 1458 (seconds) into the AVI file and re-encode the audio in FLAC.