Webradio
Intro
I was struggling to fit some requirements:
- I ripped all my CDs on the HD attached to the slug
- I wanted my Philips Streamium (which is not UPnP) to be able to play whatever I want
- Streamium is not UPnP
- Streamium doesn't understand Ogg format
- Streamium has a very poor UI
- I wanted to be able to control the playlist from any other computer in the house
- Why not extending those possibilities from anywhere on the Net?
Resources
- madplay/libmad (fixed point mp3 player)
- In terms of codecs this is the only fixed-point lib available for the slug and it allows only mp3 playback.
- musicdp, aka mpd (its faq)
- That's THE solution to manage the playlists, now we need to cope with its playing capabilities...
- http://www.nslu2-linux.org/wiki/HowTo/SlugAsAudioPlayer
- With mpd and libmad, good idea but is using the slug soundcard (if you add one), not icecast
- icecast2
- The solution for streaming, if we find the right way to add a mp3 source to it.
- mpd + icecast2
- 2 problems: only streaming in Ogg and needs to reencode the stream, too much without a fixed point encoder!
- oggfwd
- Would solve one problem: does not reencode, but, as the name tells you, only Ogg.
- EzStream
- Good candidate, feeds icecast with mp3 without reencoding, but needs to be hooked to mpd
- Ices and especially the versions 0.x
- Same as for EzStream
- Jinzora
- To be explored... but requires php/mysql, maybe too much for the slug
- Hack mpd with ices client
- That's the best I could find: a Perl script as scriptable playlist for ices fetches the songs from mpd playlist ans streams them to icecast2
- Ices in its basic configuration doesn't perform any reencoding
- Note that the old version of ices is required as the new one supports only Ogg
Let's go
mpd
apt-get install mpd mpc
- Edit /etc/mpd.conf
- point music_directory to your mp2s or make a symlink from /var/lib/mpd/music
- define password for clients if you want
- On the slug there is by default no soundcard but mpd cannot start without at least one output, we'll give it a dummy soundcard:
echo snd-dummy >> /etc/modules modprobe snd-dummy
- Generate DB
/etc/init.d/mpd stop mpd --create-db
- Launch mpd
/etc/init.d/mpd start mpc stop
(Remember that we don't use mpd to play music but only to handle playlists)
- When need to update the DB:
- There are plenty of tools to tune id3 tags, mp3info is one of them and by default allows to change one item without touching the other id3 infos.
- It could happen that you got some mp3 tagged with ID3 tags v2 too, in that case mpd will use that info so you need to deal with them. To modify them, you can use id3v2 (id3v2 -d will delete v2 tags and let v1 tags in place).
- Then update the DB or the dirs you touched/added
mpc update [relative path]
- gmpc can display content in UTF-8 but depending on the locales of your platform, encoding done by mpd could be wrong, in that case you need to add to /etc/mpd.conf sth like this and recreate the db
filesystem_charset "UTF-8" id3v1_encoding "UTF-8"
mpd --create-db
icecast2
apt-get install icecast2
- Edit /etc/icecast2/icecast.xml
- Change passwords in <authentication>
- Change <hostname> if it's relevant
- You can add clients authentication as well:
<mount> <mount-name>/mymountpoint</mount-name> <authentication type="htpasswd"> <option name="filename" value="/etc/icecast2/authusers"/> <option name="allow_duplicate_users" value="0"/> </authentication> </mount> touch /etc/icecast2/authusers chown icecast2 /etc/icecast2/authusers chmod 700 /etc/icecast2/authusers
Note that my streamium cannot handle basic authentication, the only way would then be based on IP, with URL auth in icecast2 or simply through iptables.
- Edit /etc/default/icecast2
- ENABLE=true
/etc/init.d/icecast2 start
- Then to manage users, go to the admin page http://myserver:port/admin/ -> Manage authentication of that source
- Stream playing can be achieved with sth like
xmms http://user:pwd@myserver:port/mymountpoint vlc http://user:pwd@myserver:port/mymountpoint.m3u
ices as glue
- Debian features only ices2 so we've to compile the old version ourselves
apt-get install libshout3-dev libperl-dev libmp3-info-perl wget http://downloads.us.xiph.org/releases/ices/ices-0.4.tar.gz tar xzf ices-0.4.tar.gz cd ices-0.4 ./configure --with-perl make cp src/ices /usr/local/bin cp conf/ices.conf.dist /etc/ices.conf
- Copy script from http://mpd.wikia.com/wiki/Hack:ices-client
wget -q -O - http://mpd.wikia.com/wiki/Hack:ices-client | awk '/<pre/,/<\/pre/'|html2text -width 200 > mpdplaylist.pm
- Edit mpdplaylist.pm
- my $mediaroot: points to your mp3 directory, must be identical to music_directory in /etc/mpd.conf but with trailing /
- my $playlistdir: points to your playlists dir, must be identical to playlist_directory in /etc/mpd.conf (default is /var/lib/mpd/playlists) but with trailing /
- Add the following lines to use authentication for musicp clients (cf password in /etc/mpd.conf) or to connect to a remote mpd or a non default port
$ENV{'MPD_HOST'} = 'mypassword@localhost'; $ENV{'MPD_PORT'} = '6600';
- Edit /etc/ices.conf
<Playlist> <Type>perl</Type> <Module>mpdplaylist</Module> </Playlist>
Maybe you need to adapt also <Mountpoint>, <Password> to match the icecast2 source pwd and the <Bitrate> but that's just for info as we won't recode the stream anyway, and once everything is running properly, set <Background> to 1.
- Run
rm /tmp/ices.log ices -c /etc/ices.conf # or as icecast2 user: su icecast2 -m /bin/bash -c "ices -c /etc/ices.conf"
- Fallback playlist: prepare the playlist in mpd then
mpc save fallbackplaylist
- To get the playlist shuffled differently everytime, change in mpdplaylist.pm
system("mpc load $playlistname"); -> system("mpc load $playlistname && mpc shuffle");
- To let mpd playing the songs at the same time, only for sync display of the playing song in mpd clients, you can edit mpdplaylist.pm by moving the "mpc del 1" call to the begin of ices_get_next() and adding a call to play the current top song when fetching it, as shown below.
if (length($playlist) > 0) { system("mpc stop && mpc play 1");
phpMp2
- Download phpMp2
- Extract into a directory on your webserver
- Change $mpd_host and $mpd_port in config.php
- Surf to the location of the phpMp2 directory on your webserver
- If you use password with mpd, several ways: add it to config.php:
"password" => "mypass",
- Or use auth.php but be careful "http://" is hardcoded and probably needs to be adapted to "https://" in your case. Anyway, remember, password won't fly in clear between client and phpMp2 but could well between phpMp2 and a remote mpd!
- As mpd is here only for playlist management we don't need the control panel, we can remove it by removing the following from the layout, e.g. layouts/classic/right.php (once we have a correct way to sent SIGUSR1 to ices we could add it here)
<?php include("control.php") ?>
- Fix: I got sometimes (when using find) errors because phpMp2 sent a command with protected quotes (\"), maybe because of magic_quoting being active. I solved it by modifying functions.php:
function do_mpd_command($conn, $command, $varname = null, $return_array = false) { //Phil: fix magic quoting breaking mpd msgs $command = str_replace('\"', '"', $command);
Other (good) clients of mpd
- mpc (CLI)
- gmpc (Gnome GUI)
Media Players That Support Icecast Streaming
- cf http://www.icecast.org/3rdparty.php -> Media Players That Support Icecast Streaming
- Windows Media Player on Windows: File->Open URL
- Winamp: open Winamp, hit Ctrl-L to display the "Open URL" box
- Realplayer: File -> Open
- XMMS: Ctrl-L to display the "Open URL" box
- iTunes: open ITunes, use menu item Advanced -> Open Stream
- quick time player seems not robust at all
Icecast relay
Icecast allows listener authentication but as streamium does not understand http auth_basic we cannot use it on the slug.
One solution is to install an icecast relay on a remote server (this will also help if we want more than one remote listener) and use iptables on the slug to allow only local access and access from the relay.
Then on the relay we can use authentication.
Note that in the following setup we have both access controlled mountpoint and free but hidden mountpoint just in case a listener software doesn't support authentication...
Specific Mountpoint Relay with icecast2 is very easy to achieve, cf http://www.icecast.org/docs/icecast-2.3.1/icecast2_config_file.html#relay
For private use it's probably a very good idea to set it in a "on-demand" mode so that upstream will be sucked only if there is at least one listener.
In that case the mountpoint doesn't appear in the admin interface unless it is used
One possible setup:
- A first relay, htpasswd protected, relaying the original stream
- A second loopback relay, without authentication (as some clients don't support it) but hidden (!)
<relay> <server>original icecast server</server> <port>8000</port> <mount>/original_mountpoint</mount> <local-mount>/local_mountpoint</local-mount> <on-demand>1</on-demand> <relay-shoutcast-metadata>0</relay-shoutcast-metadata> </relay> <relay> <server>ourselves</server> <port>8000</port> <mount>/local_mountpoint</mount> <username>localuser</username> <password>localpasswd</password> <local-mount>/local_mountpoint_free_access</local-mount> <on-demand>1</on-demand> <relay-shoutcast-metadata>0</relay-shoutcast-metadata> </relay> <mount> <mount-name>/local_mountpoint</mount-name> <no-yp>1</no-yp> <authentication type="htpasswd"> <option name="filename" value="/etc/icecast2/authusers"/> <option name="allow_duplicate_users" value="0"/> </authentication> </mount> <mount> <mount-name>/local_mountpoint_free_access</mount-name> <no-yp>1</no-yp> <hidden>1</hidden> </mount>
And don't forget to create the local user for the second relay!
TODO
- From phpMp2?
- auto upload of ripped CDs?
- mpc update
- next song: killall -s USR1 ices
- ices:
- ices crossfade?
- when using "mpc play" to sync display of played song, we consume a few CPU (about 7% on boosted slug, so probably about 14% on regular slug) just to play mp3 through a dummy sound card.
we could try to do a dummy libmad!
- renice? When on heavy load, the slug is not quick enough between songs ans the Streamium gets out of buffer.