Pages

15/04/2018

Using darkcast and icecast to stream audio from a Linux ALSA audio interface on Debian

This is a quick and dirty guide to streaming audio from a sound card, physical or otherwise to the internet as an MP3 stream. I am using a new, stock Debian 9 installation and the ALSA audio driver.

Darkice captures from the sound card and pushes it to Icecast. Icecast then streams the audio to connected clients. I am also using nginx to prevent users accessing the admin interface, for a layer of security.

As this is a quick and dirty guide, its assumed you have some Linux experience. If you get stuck, feel free to leave a comment.



Warning: In order to stream audio to the public internet, you will need to expose your system to the public internet, possibly by port forwarding if you're behind NAT. 

You will need to ensure your system is suitably secured, which is not covered in full in this guide. 

As a minimum, I'd suggest using iptables to prevent users accessing services they shouldn't. The native Icecast port 8000 should be blocked, ensuring that users only connect to the stream via NGINX.


Installation


First of all change to the root user:
sudo su

And install some dependencies:
apt-get install libxslt-dev libvorbis-ocaml libvorbis-ocaml-dev pkg-config nginx

Then install the lame MP3 Library. Check the website for the latest version and update accordingly. The following commands should be run sequentially:
cd /usr/src
curl -O -J -L https://sourceforge.net/projects/lame/files/latest/download?source=files
tar -xvf lame-3.100.tar.gz
cd lame-3.100
./configure --with-fileio=lame --disable-gtktest --enable-expopt=full --prefix=/usr
make
make install

Then install darkice. Check the website for the latest version and update accordingly:
cd /usr/src
curl -O -J -L http://sourceforge.net/projects/darkice/files/darkice/1.3/darkice-1.3.tar.gz/download
tar -xvf darkice-1.3.tar.gz
cd darkice-1.3
./configure --with-alsa
make
make install

Then install icecast. Check the website for the latest version and update accordingly:
cd /usr/src
curl -O -J -L http://downloads.xiph.org/releases/icecast/icecast-2.4.3.tar.gz
tar -xvf icecast-2.4.3.tar.gz
cd icecast-2.4.3
./configure
make
make install

Configuration


Create the user, and setup directories and permissions. Run the following commands sequentially:
groupadd icecast
useradd -d /var/log/icecast -m -g icecast -s /bin/false icecast
mkdir -p /var/run/icecast
chown -R icecast:icecast /var/run/icecast

Create a config file for icecast:
vim /etc/icecast.xml

And use the following example as a guide. Refer to the icecast documentation for more complex setups:
<icecast>

    <location>[YOUR LOCATION]</location>
    <admin>[Your Email Address]</admin>

    <limits>
        <clients>100</clients>
        <sources>2</sources>
        <queue-size>524288</queue-size>
        <client-timeout>30</client-timeout>
        <header-timeout>15</header-timeout>
        <source-timeout>10</source-timeout>
        <burst-on-connect>1</burst-on-connect>
        <burst-size>65535</burst-size>
    </limits>

    <authentication>
        <source-password>[PASSWORD]</source-password>
        <admin-user>admin</admin-user>
        <admin-password>[PASSWORD]</admin-password>
    </authentication>

    <hostname>
    [HOSTNAME OF SERVER]
    </hostname>

    <listen-socket>
       <port>8000</port>
    </listen-socket>

    <fileserve>1</fileserve>

    <http-headers>
        <header name="Access-Control-Allow-Origin" value="*" />
    </http-headers>

    <paths>
        <logdir>/usr/local/var/log/icecast</logdir>
        <webroot>/usr/local/share/icecast/web</webroot>
        <adminroot>/usr/local/share/icecast/admin</adminroot>
        <logdir>/var/log/icecast</logdir>
        <pidfile>/var/run/icecast/icecast.pid</pidfile>
        <alias source="/" dest="/status.xsl"/>
    </paths>

    <logging>
       <accesslog>access.log</accesslog>
       <errorlog>error.log</errorlog>
       <playlistlog>playlist.log</playlistlog>
       <loglevel>1</loglevel>
       <logsize>10000</logsize>
       <logarchive>1</logarchive>
    </logging>

    <security>
       <chroot>0</chroot>
    </security>

</icecast>

Then create the Darkice configuration file:
/etc/darkice.conf

And enter your configuration, using the following as a template:
[general]
duration        = 0                  # duration of encoding, in seconds. 0 means forever
bufferSecs      = 5                  # size of internal slip buffer, in seconds
reconnect       = yes                # reconnect to the server(s) if disconnected
realtime        = yes                # run the encoder with POSIX realtime priority
rtprio          = 3                  # scheduling priority for the realtime threads
[input]
device          = dsnoop:D1,DEV=1    # Soundcard device for the audio input
sampleRate      = 48000              # sample rate in Hz. try 11025, 22050, 44100 or 48000
bitsPerSample   = 16                 # bits per sample. try 16
channel         = 2                  # channels. 1 = mono, 2 = stereo
[icecast2-0]
bitrateMode     = cbr                # average bit rate
format          = mp3                # format of the stream: ogg vorbis
bitrate         = 64                 # bitrate of the stream sent to the server
server          = [SERVER IP]        # host name of the server
port            = [SERVER PORT]      # port of the IceCast2 server, usually 8000
password        = [SERVER PASSWORD]  # source password to the IceCast2 server
mountPoint      = [MOUNT POINT]      # mount point of this stream. I suggest suffixing with .mp3
name            = [NAME]             # name of the stream
description     = [DESCRIPTION]      # description of the stream
url             = [YOUR URL]         # URL related to the stream
genre           = [GENRE]            # genre of the stream
public          = yes                # advertise this stream?
#localDumpFile   = dump.mp3          # Dump the stream to a local file (optional)

Edit the nginx config file:
vim /etc/nginx/sites-available/default

Enter the following, ensuring you update it with your details. The rewrite will redirect anyone thats not specified a stream to another URL of your choice.
server {
        listen 80 default_server;
        root /var/www/html;

        # Add index.php to the list if you are using PHP
        index index.html index.htm index.nginx-debian.html;

        server_name [YOUR FQDN];

        location = / {
            rewrite ^ [URL of home page] redirect;
        }

        location = /[YOUR MOUNTPOINT] {
            proxy_pass http://127.0.0.1:8000/[YOUR MOUNTPOINT];
        }

        location ~ / {
            deny all;
            return 403;
        }
}

Reload nginx so the settings take affect:
systemctl reload nginx

Securing the system with iptables


Editing firewall rules can potentially lock you out the system if you get it wrong. Be careful. The following is some 'inspiration' but you will need to edit the rules if you're hosting other services on the same system. Additionally, this only covers IPv4, as I don't have an IPv6 address on this system. If you're using IPv6, you will need to also secure traffic to the IPv6 address.

Create a rules file:
vim /etc/iptables.rules

Enter the following. If you're running other services, remember to add the relevant rules. Also note the following rules will allow anyone to connect to your  MP3 stream and attempt to SSH into your system:
*filter
:INPUT DROP
:FORWARD ACCEPT
:OUTPUT ACCEPT

# Allow Loopback traffic
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

# Allow establised connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow SSH (You should really be using ssh keys and/or fail2ban)
-A INPUT -p tcp --dport 22 -m state --state NEW -s 0.0.0.0/0 -j ACCEPT

# Allow HTTP to NGINX
-A INPUT -p tcp --dport 80 -m state --state NEW -s 0.0.0.0/0 -j ACCEPT

# Allow ICMP
-A INPUT -p ICMP --icmp-type 8 -s 0.0.0.0/0 -j ACCEPT
-A INPUT -p ICMP --icmp-type 11 -s 0.0.0.0/0 -j ACCEPT

COMMIT

Apply the rules:
iptables-restore /etc/iptables.rules

I suggest you then disconnect from the SSH session and attempt to re-connect. Remember to sudo su again. If you're unable to connect, something has gone wrong. But don't panic! Rebooting the system will remove the rules, and you can fix the issue.

If you can successfully reconnect, then configure the interface to load the rules before it initialises: 
vim /etc/network/if-pre-up.d/iptables

Enter the following:
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.rules

And make it executable:

chmod +x /etc/network/if-pre-up.d/iptables

Starting services on boot


Create a service to ensure Icecast starts up on boot:
vim /lib/systemd/system/icecast.service

Add the following:
[Unit]
Description=Icecast live audio streamer
After=network-online.target
Wants=network-online.target

[Service]
Restart=always
RestartSec=3
ExecStart=/usr/local/bin/icecast -c /etc/icecast.xml
ExecStop=/usr/bin/pkill icecast
User=icecast
Group=icecast

[Install]
WantedBy=multi-user.target

Then create a service to ensure Darkice starts up on boot, after Icecast has started:
vim /lib/systemd/system/darkice.service

Add the following. The CPUScheduling sections help to minimise dropped audio if they system is under load.
[Unit]
Description=DarkIce live audio streamer
After=icecast.service
Wants=icecast.service

[Service]
Restart=always
RestartSec=3
ExecStart=/usr/local/bin/darkice -c /etc/darkice.conf
ExecStop=/usr/bin/pkill darkice

CPUSchedulingPolicy=fifo
CPUSchedulingPriority=4

[Install]
WantedBy=multi-user.target

Next reboot the server:
reboot

Accessing the stream


If everything is setup correctly, you should now be able to access the stream. Access the URL in the following format should load up a audio player in your browser, and you can listen to the stream:
http://[YOUR FQDN]/[YOUR MOUNTPOINT]

You should see a player similar to below:


No comments:

Post a Comment