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.
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.
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: [pulseaudio] module-combine-sink.c: Invalid slave sink 'alsa_output.pci-0000_00_1b.0.analog-stereo' mars 29 12:37:16 marcos pulseaudio: [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: [pulseaudio] main.c: Module load failed. mars 29 12:37:16 marcos pulseaudio: [pulseaudio] main.c: Failed to initialize daemon. mars 29 12:37:16 marcos pulseaudio: [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.
The general principle is that the Icecast server
mountpoint is fed by liquidsoap, which plays a mix of
The icecast server, in turn, will fallback on the
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.
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=188.8.131.52 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=184.108.40.206 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.
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).
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.
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://220.127.116.11: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:
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.
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
<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
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])
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])
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
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.
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
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.