Setting up sound on multiseat

In todays computers, 5.1 sound card is almost a standard. But if you are not watching a movie, you rarely fully use all 5 channels – in most cases you use only two of them. That brings up a question whether it would be possible to (via some software) pretend, that we have two stereo sound cards and each user could use one of the outputs.

With Linux – precisely with ALSA – it is not a problem. Splitting rear and front output is described at ALSA wiki. However, I have to use a bit different setup, because this solution does not deal well when two different users want to access the same device.

Futhermore, I have to save this settings as global into /etc/alsa/ (this location could vary by distribution you use). To separate multiseat settings from the normal ones, I inserted it into standalone file (/etc/alsa/mul­tiseat.alsa.con­f) and load this file into main ALSA configuration file (/etc/alsa/al­sa.conf) – in my distribution (Fedora) the only thing to do is to add a path to function load, which is right on top of this file. I added also loading of user configuration file ~/.asound.mseat (about that bit later):

#
#  ALSA library configuration file
#

# pre-load the configuration files

@hooks [
        {
                func load
                files [
                        "/etc/alsa/multiseat.alsa.conf"
                        "/etc/asound.conf"
                        "~/.asoundrc"
                        "~/.asound.mseat"
                ]
                errors false
        }
]

...

a this is how looks already mentioned multiseat.alsa­.conf (notice adding rights to the device – that allows more users to use the same device simultaneously):

pcm.dshare {
    type dmix
    ipc_key 2049
    ipc_key_add_uid false
    ipc_perm 0666
    slave {
        pcm "hw:0"
        rate 44100
        period_time 0
        period_size 1024
        buffer_size 8192
        channels 4
    }
    bindings {
        0 0
        1 1
        2 2
        3 3
    }
}
pcm.frontx {
    type plug
    slave {
        pcm "dshare"
        channels 4
    }
    ttable.0.0 1
    ttable.1.1 1
}
pcm.rearx {
    type plug
    slave {
        pcm "dshare"
        channels 4
    }
    ttable.0.2 1
    ttable.1.3 1
}

pcm.!default {
        type copy
        slave.pcm "frontx"
}

Setting up programs (players etc.)

Allright, now we splitted the output of the sound card, but still we have to tell the programs about it. Some of them allows to select audio output through GUI (e.g. audacity), others via options of command line – for example mplayer will send its output to rearx after supllying -ao alsa:device=rearx. This looks good except that average user will not use command line. Luckily, we can specify the default audio output – this can be seen at the last block above – starting with pcm.!default. All we have to do now is to copy this part to files ~/.asoundrc for each user (and change frontx for rearx in some of them) and all is done. Well, almost.

I found out, that I often need to switch between these two options – when I am alone, I rather send the music to loadspeakers (that are connected to frontx), in case it would disturb someone, I send it to headphones (that I more easily connect to rearx). I can't say that I would stand against hand-editing of configuration file, but it is easier to run one command or even click some icon to do this (not talking about users that do not use command line at all).

So I wrote a small shell script that switches the default output device and – as I bonus – search through GNOME panel and sets up volume control to point to this output. For this reason, it stores its current configuration into ~/.mseat and by reading this file changes ALSA configuration file ~/.asound.mseat. (Yes, I know, that one file should be enought but this way the script was much easier to write).

Because I use GNOME I have no reason to find out, if a similar thing would be able to do for other environments – if you manage to do this, send me an e-mail and I will place the updated script here. Thanks.

#!/bin/sh

# changes default ALSA output according to user current
# settings

# Available outputs
#  format: alsaname,Human-readable name,GNOME volume applet device name;alsaname2,...
ALSAOUTPUTS=";rearx,Rear,Surround;frontx,Front,Front";

# Configuration file locations
USERALSACONFIG="${HOME}/.asound.mseat";
USERCONFIG="${HOME}/.mseat";

# osd_cat font settings
OSDFONT='-adobe-helvetica-bold-r-*-*-34-*-*-*-*-*-*-*';


#############
# Lines below this typically do not have to be changed
#

usage() {
cat <<EOF_USAGE
Redirection of default ALSA output
Usage:
  $0 [-ovg] [--osd] [--verbose] [--gnome]
    -o  --osd      Display OSD-message after redirection
    -v  --verbose  Be verbose
    -g  --gnome    Change device in GNOME volume applet

EOF_USAGE
exit 1
}


# CL options
changeGnome=0;
ECHO=":";
osd=0;

opts="-o o,v,g -l osd,verbose,gnome";
getopt -Qq $opts -- "$@" || usage;
eval set -- `getopt -q $opts -- "$@"`;

while [ $# -gt 1 ]; do
    case $1 in
        -o|--osd) osd=1;;
        -v|--verbose) ECHO="echo";;
        -g|--gnome) changeGnome=1;;
        *) usage;;
    esac
    shift
done

# Easier searching
ALSAOUTPUTS=`echo "$ALSAOUTPUTS" | sed -e '/^;/!s#.#;&#;/;$/!s#.*#&;#'`

# Find current settings
[ -e "$USERCONFIG" ] && current=`sed -n '/^alsaredirect=/{s/[^=]*=\(.*\)/\1/;p;q}' <$USERCONFIG`;
if [ -z "$current" ]; then
    current=`echo "$ALSAOUTPUTS" | cut '-d;' -f 2 | cut '-d,' -f 1`;
    # to prevent failure when editing
    echo "alsaredirect=blabla" >> $USERCONFIG
fi

$ECHO "Current output is ${current}...";

# Find next in the list
new=`echo $ALSAOUTPUTS | sed 's#.*;'"$current"',[^;]*;\([^;]*\).*#\1#'`;
[ -z "$new" ] && new=`echo "$ALSAOUTPUTS" | cut '-d;' -f 2`;

# Get the names of the devices
deviceAlsa=`echo $new | cut '-d,' -f 1`;
deviceName=`echo $new | cut '-d,' -f 2`;
deviceGnome=`echo $new | cut '-d,' -f 3`;

$ECHO "Switching output to $deviceName [$deviceAlsa,$deviceGnome]";


# Save changes
printf 'pcm.!default {\n    type copy\n    slave.pcm "%s"\n   }\n\n' "$deviceAlsa" >$USERALSACONFIG
printf '/^alsaredirect=/\ns/=.*/=%s/\nw\nq\n' "$deviceAlsa" | ed $USERCONFIG &>/dev/null


# Change GNOME applet default device
[ $changeGnome -eq 1 ] && (
    $ECHO -n "About to change GNOME applet device...";
    for applet in `gconftool-2 --all-dirs '/apps/panel/applets'`; do
        iid=`gconftool-2 -g "$applet/bonobo_iid" 2>/dev/null`;
        if [ "$iid" = "OAFIID:GNOME_MixerApplet" ]; then
            # Found him (if it has inside a prefs dir)
            track=`gconftool-2 -g "$applet/prefs/active-track" 2>/dev/null`;
            if [ -n "$track" ]; then
                gconftool-2 --set "$applet/prefs/active-track" --type string "$deviceGnome" 2>/dev/null;
                $ECHO -n " ok";
            fi
        fi
    done
    $ECHO " ";
) &


# Here goes other applets changing (run them in background to
# enable possible parallelism)

wait


[ $osd -eq 1 ] && \
    printf "Default audio output redirected to %s\n" "$deviceName" | \
        osd_cat "--font=$OSDFONT" -c white -O 1 -u black \
        -p bottom -A center -d 5 &
exit

Page was last changed on March 28, 2008 at 9:06 pm

Created by Vojtech HorkyXHTML & CSS valid •