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.
The general principle is that the Icecast server
mountpoint is fed by liquidsoap, which plays a mix of:
- random music
- live audio from Icecast or RTP (so MPD, live recording, etc)
The full configuration is in anaradio.liq.
I had to figure out a few sticky problems to make this somehow work.
I just load all the files on startup - it can take around 3-4 minutes, so that isn't so bad. It also notices all new files automatically.
# 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])
Right now, I use a small collection of jingles:
# 3. jingles playlist jingles = playlist('/srv/playlists/jingles.m3u')
Those are mostly samples I found in my various travels on the internet and elsewhere.
Tricks to create the jingles are explained below.
I have recorded 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 text doesn't match the current recording however, so 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
/usr/share/icecast2/web). The encoding of the jingle needs to match
the encoding from the stream (e.g. Vorbis or MP3) otherwise it will not work!
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])
Update: this was completely disabled following a catastrophic failure where the audio output was enabled before I left for a weekend with disastrous results on my neighborhood relations. Besides, I had to disable the pulseaudio output for Liquidsoap to start at all so there is not even an RTP output.
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.
To tap into the home radio or live broadcast, I am again using the fallback feature of the stream:
# we replace that with an RTP multicast listener based on gstreamer # 126.96.36.199 is the MPD multicast stream, which uses the default # Pulseaudio multicast address, which seems to be wrongly in the # zeroconfaddr multicast range (188.8.131.52-184.108.40.206) # # we use a different IP for our outgoing stream to avoid loops livertp = input.gstreamer.audio(pipeline="udpsrc multicast-group=220.127.116.11 port=5004 caps=\"application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10\" ! rtpL16depay") livecast = input.http("http://localhost:8000/live.ogg") live = fallback(track_sensitive=false, [livertp, livecast]) # time-configurable crossfade def crossfade(t,a,b) add(normalize=false, [ sequence([ blank(duration=t/2.), fade.initial(duration=t,b) ]), fade.final(duration=t,a) ]) end # final output # output live if available, fallback on radio # we crossfade between the two, we could add jingles when switching, see also # http://liquidsoap.fm/doc-svn/cookbook.html final = fallback(track_sensitive=true, transitions=[crossfade(5.),crossfade(3.)], [live,radio])
Phew! That is quite a mouthful! Taking this apart, the key components are:
livecast = input.http("http://localhost:8000/live.ogg") live = fallback(track_sensitive=false, [livertp, livecast])
... and this:
final = fallback(track_sensitive=true, transitions=[crossfade(5.),crossfade(3.)], [live,radio])
Combines the live stream with the shuffle previously crafted. Whenever a live feed comes in, it overrides the radio tracks. Notice how it is "track-sensitive", so it will actually wait for the song to complete before going live.
To go live, I have had trouble with darkice: it wouldn't start at all, and I filed bug #821040 about it. I ended up testing with ices2, which seemed to work better (it didn't crash) but i will need further test to see if that all works correctly. Here's the config file I used:
<?xml version="1.0"?> <ices> <!-- run in background --> <background>0</background> <!-- where logs go. --> <logpath>/home/anarcat</logpath> <logfile>.ices.log</logfile> <!-- size in kilobytes --> <logsize>2048</logsize> <!-- 1=error, 2=warn, 3=infoa ,4=debug --> <loglevel>4</loglevel> <!-- logfile is ignored if this is set to 1 --> <consolelog>0</consolelog> <!-- optional filename to write process id to --> <!-- <pidfile>/home/ices/ices.pid</pidfile> --> <stream> <!-- metadata used for stream listing --> <metadata> <name>Live audio stream</name> <genre></genre> <description>Live stream straight from the mike</description> <url>http://radio.anarc.at/</url> </metadata> <!-- Input module. This example uses the 'alsa' module. It takes input from the ALSA audio device (e.g. line-in), and processes it for live encoding. --> <input> <module>alsa</module> <param name="rate">44100</param> <param name="channels">2</param> <param name="device">default</param> <!-- Read metadata (from stdin by default, or --> <!-- filename defined below (if the latter, only on SIGUSR1) --> <param name="metadata">0</param> <param name="metadatafilename">test</param> </input> <!-- Stream instance. You may have one or more instances here. This allows you to send the same input data to one or more servers (or to different mountpoints on the same server). Each of them can have different parameters. This is primarily useful for a) relaying to multiple independent servers, and b) encoding/reencoding to multiple bitrates. If one instance fails (for example, the associated server goes down, etc), the others will continue to function correctly. This example defines a single instance doing live encoding at low bitrate. --> <instance> <!-- Server details. You define hostname and port for the server here, along with the source password and mountpoint. --> <hostname>radio.anarc.at</hostname> <port>8000</port> <password>hackme</password> <!-- right... --> <mount>/live.ogg</mount> <yp>0</yp> <!-- allow stream to be advertised on YP, default 0 --> <!-- Live encoding/reencoding: channels and samplerate currently MUST match the channels and samplerate given in the parameters to the alsa input module above or the remsaple/downmix section below. --> <encode> <quality>6</quality> <samplerate>44100</samplerate> <channels>2</channels> </encode> <!-- stereo->mono downmixing, enabled by setting this to 1 --> <downmix>0</downmix> <!-- resampling. Set to the frequency (in Hz) you wish to resample to, <resample> <in-rate>44100</in-rate> <out-rate>22050</out-rate> </resample> --> </instance> </stream> </ices>
Other interesting software also include idjc, which looks like a more complete DJ solution, but is a little too hard to configure for my small needs. ezstream was ignored because it doesn't stream from the microphone directly, although something could be used to encode such a stream and pipe it through it. It does involve messing around with an XML config file as well, so its value over ices2 is limited. oggfwd is also a similar tool which does only piping from stdin, and has the advantage of not requiring any config file.
Update: this is not really in use anymore. I use Icecast to stream live stuff into Liquidsoap now, but maybe the RTP stream still works.
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=18.104.22.168 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=22.214.171.124 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://126.96.36.199: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.
Tout ce qui suit se passe dans un terminal.
Pour convertir un vidéo youtube en musique, d'abord, on veut télécharger le vidéo:
sudo apt-get install youtube-dl
télécharger le vidéo dont tu veux extraire la musique:
les guillemets sont importants, et je recommende fortement le copier-coller! dans le terminal, le "coller" est dans le menu "Éditer" en haut.
le vidéo devrait être maintenant dans ton répertoire personnel, essaie de le trouver dans le navigateur de fichiers et double-clique dessus, tu devrais voir le vidéo (hehehe)
Maintenant, tu as une copie du vidéo! Youpi! Peut-être que ça va être suffisant et que tu peux juste mettre ça sur ton téléphone.
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.
Note: nowadays, you can just use the
youtube-dlinstead of all this! This is useful if you want to extract audio from an existing movie, for example.
To extract the audio, install ffmpeg or libav and run:
sudo apt-get install libav-tools 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.
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.
- 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
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 #109this actually works now! 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 herePA worked, again
- liquidsoap can't reload its config file without restarting
at least in Debian 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 #109now this works!
- liquidsoap crashes after 3 days, see Debian bug #727307 -
remains to be testedit 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: [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.
make a nice diagram explaining all flowsdone
- start from the top again and document everything (merging blogs in here)
- split technical (english) and user (french) documentation
- make a new blog post summarising this
- file a bug about the opus plugin, see this post
- make a schedule to play specific streams at specific times:
- radio canada during specific times:
- X:00 - X:05 at every hour
- except at 9, 12 and 17, where we play for 10 minutes
- années lumières
- la sphère?
- democracy now
- stream url?
- CKUT news?