You are not logged in.

#1 2008-02-22 11:39:34

HyperBaton
Member
From: Belgium
Registered: 2008-01-18
Posts: 207

How can I automate mpd ALSA outputs?

I'm using mpd + Sonata for my music collection (and loving it...). I also have 2 soundcards. One is the internal laptop soundcard and the other is an external USB soundcard. I want to automate mpd so that if the USB soundcard is plugged in, it only uses that output. If it's not plugged in, I want mpd to only use the internal soundcard. With the command-line client mpc you can enable/disable outputs, so is there some kind of script or something I can use to do this? These are my outputs:

[hb@hb-laptop .config]$ mpc outputs
Output 1 (Conectiv) is enabled
Output 2 (Intel) is enabled

Offline

#2 2008-02-22 16:36:04

fwojciec
Member
Registered: 2007-05-20
Posts: 1,411

Re: How can I automate mpd ALSA outputs?

Funny you should ask...  I just got a setup like this working.  Here is what I did.

1)  First of all you need to create a udev rule that will execute appropriate scripts when your USB soundcard is connect it.  You have to figure out what your USB soundcard shows up as under /dev when it is plugged in -- for me it is /dev/dsp2 ("dsp" is internal card and "dsp1" is the modem for some reason)... It's probably the highest "dsp*" entry in the /dev directory.

Once you know that you can create a udev rule.  My /etc/udev/rules.d/85-bithead.rules looks like this (the file name doesn't really matter as long as the path is correct):

KERNEL=="dsp2", ACTION=="add", SUBSYSTEM=="sound",\
RUN+="/home/filip/scripts/bithead-add.sh"
KERNEL=="dsp2", ACTION=="remove", SUBSYSTEM=="sound",\
RUN+="/home/filip/scripts/bithead-remove.sh"

2)  You need scripts that will do the actual output switching.  The general philosophy of my scripts is to edit mpd configuration file and then restart mpd -- you could rewrite the scripts to switch outputs using mpc (I didn't realize that was a possibility when I wrote these).  The config file that gets edited is ~/.mpdconf -- the file is also linked to /etc/mpd.conf (this is important).  You could probably just skip the home dir file completely and edit the /etc/mpd.conf directly -- there must be an /etc/mpd.conf file with the correct information in either case, just having a ".mpdconf" file in your home dir is not enough.  You will need to edit those scripts intelligently to make sure that mpd config file is edited correctly for your setup.  In my case the usb soundcard works as "hw:2,0" alsa output while the internal card is "hw:0,0" -- if this is different on your system you will need to adjust the scripts appropriately.  Anyways, these are the scripts for the udev rule.
bithead-add.sh:

#!/bin/sh

cat /home/filip/.mpdconf | grep -q "hw:0,0"

if [ "$?" -eq "0" ]
then
    sed -i 's/hw:0,0/hw:2,0/g' /home/filip/.mpdconf
fi

mpd --kill
/usr/bin/mpd /etc/mpd.conf &> /dev/null

and bithead-remove.sh:

#!/bin/sh

cat /home/filip/.mpdconf | grep -q "hw:2,0"

if [ "$?" -eq "0" ]
then
    sed -i 's/hw:2,0/hw:0,0/g' /home/filip/.mpdconf
fi
        
mpd --kill
/usr/bin/mpd /etc/mpd.conf &> /dev/null

3) You also probably want mpd to detect the usb soundcard correctly in case it is connected at boot.  What I did is I created a new daemon startup script called "mpd-multicard" that doesn't run mpd directly when started, but calls a script which first checks if my usb soundcard is connected and then edits mpd config file correctly before starting mpd.  I use "mpd-multicard" instead of regular "mpd" in my rc.conf file.  This is the /etc/rc.d/mpd-multicard file (it's basically a slightly modified version of the default mpd daemon startup script):

#!/bin/bash

. /etc/rc.conf
. /etc/rc.d/functions

case "$1" in
  start)
    stat_busy "Starting Music Player Daemon"
    /home/filip/scripts/mpd-multicard.sh
    if [ $? -gt 0 ]; then
      stat_fail
    else
      add_daemon mpd
      stat_done
    fi
    ;;
  stop)
    stat_busy "Stopping Music Player Daemon"
    /usr/bin/mpd --kill /etc/mpd.conf &> /dev/null
    if [ $? -gt 0 ]; then
      stat_fail
    else
      rm_daemon mpd
      stat_done
    fi
    ;;
  create-db)
    stat_busy "Creating mpd's database ..."
    logpath="/var/log/mpd/mpd.db-creation"
    /usr/bin/mpd --create-db /etc/mpd.conf > $logpath \
        && stat_busy "Output written to $logpath"
              stat_done
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  *)
    echo "usage: $0 {start|stop|restart|create-db}"
esac
exit 0

As you can see what this script does is call a script called mpd-multicard.sh instead of starting mpd directly.  Here is mpd-multicard.sh:

#!/bin/sh

lsusb | grep -q 08bb:2902
if [ "$?" -eq "0" ]
then
    cat /home/filip/.mpdconf | grep -q "hw:0,0"
    if [ "$?" -eq "0" ]
    then
        sed -i 's/hw:0,0/hw:2,0/g' /home/filip/.mpdconf
    fi
    /usr/bin/mpd /etc/mpd.conf &> /dev/null
else
    cat /home/filip/.mpdconf | grep -q "hw:2,0"
    if [ "$?" -eq "0" ]
    then
        sed -i 's/hw:2,0/hw:0,0/g' /home/filip/.mpdconf
    fi
    /usr/bin/mpd /etc/mpd.conf &> /dev/null
fi

You will need modify this script to use the correct xxxx:xxxx ID number for you USB soundcard -- my card is identified as "08bb:2902" -- you can get this number by using "lsusb" command when your usb soundcard is connected.  The previous qualifications about the alsa output names (hw:0,0 and hw:2,0) and mpd config file locations naturally apply as well.

4) Lastly, here is the script I use to switch outputs manually when both cards are connected .  Hopefully the logic here should be self-explanatory at this stage:

#!/bin/sh
# The scripts switches the soundcard currently used and restarts mpd
# It must be run as root.

# Check if user is root
if [ `whoami` != "root" ]
then
    echo "You need to be root!";
    exit 1
fi

lsusb | grep -q 08bb:2902
if [ "$?" -eq "0" ]
then
    cat /home/filip/.mpdconf | grep -q "hw:2,0"
    if [ "$?" -eq "0" ]
    then
        echo ":: Switching to the internal sound card..."
        sed -i 's/hw:2,0/hw:0,0/g' /home/filip/.mpdconf
        mpd --kill
        /usr/bin/mpd /etc/mpd.conf &> /dev/null
    else
        echo ":: Switching to Bithead..."
        sed -i 's/hw:0,0/hw:2,0/g' /home/filip/.mpdconf
        mpd --kill
        /usr/bin/mpd /etc/mpd.conf &> /dev/null
    fi
else
    echo "Bithead is not connected."
    cat /home/filip/.mpdconf | grep -q "hw:2,0"
    if [ "$?" -eq "0" ]
    then
        sed -i 's/hw:2,0/hw:0,0/g' /home/filip/.mpdconf
        mpd --kill
        /usr/bin/mpd /etc/mpd.conf &> /dev/null
    fi
fi

I have this in my .bashrc:

alias sound="sudo /home/filip/scripts/soundcard.sh"

And I have /home/filip/scripts/soundcard.sh specified in my sudoers file so it doesn't need a password.

Offline

#3 2008-02-22 21:51:06

HyperBaton
Member
From: Belgium
Registered: 2008-01-18
Posts: 207

Re: How can I automate mpd ALSA outputs?

Awesome tutorial, thank you very much! You've explained it very clearly and a non-programmer like me can actually see the logic in your scripts. I haven't got time to try this out tonight, but I'll get working on it tomorrow.

mpd --kill
/usr/bin/mpd /etc/mpd.conf &> /dev/null

Would this be replaceable by "/etc/rc.d/mpd-multicard restart"? And why is the "&> /dev/null" needed?

Offline

#4 2008-02-22 22:30:07

fwojciec
Member
Registered: 2007-05-20
Posts: 1,411

Re: How can I automate mpd ALSA outputs?

HyperBaton wrote:

Awesome tutorial, thank you very much! You've explained it very clearly and a non-programmer like me can actually see the logic in your scripts. I haven't got time to try this out tonight, but I'll get working on it tomorrow.

mpd --kill
/usr/bin/mpd /etc/mpd.conf &> /dev/null

Would this be replaceable by "/etc/rc.d/mpd-multicard restart"? And why is the "&> /dev/null" needed?

There were some problems when "/etc/rc.d/mpd-multicard restart" was called by HAL events -- for some reason using this command would result in the internal card being selected all the time.  The "&> /dev/null" makes sure that no output is printed when the command is executed -- I used it in my scripts, frankly, because I coped the entire command from the daemon startup script; I wanted to make sure that mpd was started in exactly the same way as it would be started if I used the daemon startup script.  You could probably get rid of it if you want, it shouldn't really make any difference one or the other way.

Offline

#5 2008-02-23 02:51:43

venox
Member
From: Curitiba, Brazil
Registered: 2003-08-23
Posts: 137
Website

Re: How can I automate mpd ALSA outputs?

Really awesome tutorial.
Could be a great page on the wiki smile

Offline

#6 2008-02-23 03:07:12

fwojciec
Member
Registered: 2007-05-20
Posts: 1,411

Re: How can I automate mpd ALSA outputs?

venox wrote:

Really awesome tutorial.
Could be a great page on the wiki smile

Thanks -- the wiki idea had occurred to me; I think I'll write something up eventually, but I think I'd like to rewrite the scripts a bit (to clean them up and make then easier to adapt for different setups) before I actually make a wiki article out of that.  Sometime in the next couple of weeks...

Offline

#7 2008-02-25 21:44:37

HyperBaton
Member
From: Belgium
Registered: 2008-01-18
Posts: 207

Re: How can I automate mpd ALSA outputs?

Well I got it working! I haven't implemented it all due to time constraints, but I will soon. I'm using the mpc enable/disable commands at the moment in the scripts, which is working great for me.

Offline

Board footer

Powered by FluxBB