Having things my way

Most laptops have at least two ways of letting sound out - via built in speakers and via a headphone jack. On my old and now retired Thinkpad, this duality was a frequent source of frustration. You see, to hear anything on the built-in speakers, I would have to turn the volume all the way up. Then some time later, I’d attach my headphones and play some movie or song, having forgotten that the volume is set to max. Result: irreparable ear damage.

My current laptop, a Dell Inspiron 700m, has a neat solution to this problem. The audio chipset on this machine allows me to change the volume of the headphone’s output independent of the speaker volume! This lets me set the main speaker volume high (and usually muted) while leaving the headphone volume at a more reasonable level.

kmix

I am happy with this but not happy enough. Like most laptops, the Dell also has some Fn shortcut keys to control the system volume: Fn + F6 decreases the volume, Fn + F7 increases it while Fn + F5 toggles mute. Unfortunately, these control the Master channel (i.e. speakers) and have no effect on the headphone channel! So I lose the convenience of having these shortcut keys anytime I am using the headphones, which is most of the time.

Could this be remedied? This Dell’s keyboard has the Win key next to the Fn key and so I figured that setting up Win + F5 etc., as shortcuts to control the headphone channel just like the master channel would be a good solution. Thankfully, DCOP makes it easy. A bit of experimentation revealed that dcop kmix Mixer0 provides all the functions I need to increase, decrease and mute the headphone channel. So a quick visit to KHotkeys and I’ve got global shortcuts for Win + F? to trigger the appropriate DCOP calls.

Could this be improved? One of the nice things about the Fn + F? triggers is that calling them provides visual feedback about what’s going on. So pressing Fn + F6 shows a passive overlay window with the current volume. I could do the same for my Win + F? triggers by using kdialog to provide feedback via a passive window. To do that, I wrote a simple shell script around the dcop and kdialog calls and then mapped the Win + F? shortcuts to trigger the script with the appropriate parameters. I submit the script herewith for your kind perusal:

#!/bin/sh

# functions
usage() {
    echo "Usage: $0 (less|more|mute)"
}

popup() {
#     echo "$*"
    # display popup with 1 second delay. Also, background the process so that
    # script doesn't block. This lets us invoke the script in quick succession.
    kdialog --title "Headphone" --passivepopup "$*" 1 &
}

currentVol() {
    current_vol=`$app absoluteVolume $dev`
    return $(($current_vol*100/$max_vol))
}

# Usage check
if [ $# -ne 1 ]; then
    usage
    exit
fi

if [ ! `dcop | grep -m 1 ^kmix` ]; then
    popup "kmix not found"
    exit
fi

app="dcop kmix `dcop kmix | grep ^Mixer`"
dev=2 # The headphone is device index 2 on my system
max_vol=`$app absoluteVolumeMax $dev`

if [ "$1" = "less" ]; then
    $app decreaseVolume $dev
    currentVol
    popup "Volume is $?%"
elif [ "$1" = "more" ]; then
    $app increaseVolume $dev
    currentVol
    popup "Volume is $?%"
elif [ "$1" = "mute" ]; then
    $app toggleMute $dev
    if [ `$app mute $dev` = "true" ]; then
        popup "mute enabled"
    else
        popup "mute disabled"
    fi
else
    usage
fi

Although this script is functionally complete, I am still not happy with the look of the passive popup that kdialog displays. The notification shows up as a bubble on the top left of the screen even though my systray is on the bottom right of the screen. Further, I’d like to display the volume percentage as a progress bar instead of plain text. However, kdialog doesn’t support passive progress dialogs.

Oh well, I can’t have everything my way.