Linux Change alsa master volume with a remote control and give visual feedback
#1
This was born due to a lack to control volume when launching external program from within xbmc. The external program uses the alsa master volume and not the internal xbmc volume and if you have an xbmc appliance and you controls it just with a remote, this is a problem.

Prerequisite: aosd-cat and lirc

Code:
$ sudo apt-get install aosd-cat
$ sudo apt-get install lirc

for ubuntu systems.

The bash script:
Code:
#!/bin/bash
# parameter: <value>- or <value>+ or <value>
die () {
    echo >&2 "$@"
    exit 1
}

[ "$#" -eq 1 ] || die -e "\n1 argument required, $# provided.\n\nUsage:\n$0 1+     # increase alsa Master volume by 1 unit\n$0 2dB+   # increase alsa Master volume by 2 dB\n$0 10-    # decrease alsa Master volume by 10 units\n$0 50     # set alsa Master volume to 50\n"

u=1000
o=350
e=1
R=green
b=0
B=black
DISPLAY=:0.0 # primary display
AMIXER_CMD=/usr/bin/amixer
KILL_CMD=/usr/bin/killall

$AMIXER_CMD -q -c 0 sset Master,0 $1 2>/dev/null
$KILL_CMD aosd_cat &> /dev/null

CURR_VOLUME=`$AMIXER_CMD get Master 2>/dev/null | grep 'Mono:' | sed -e 's/^[^\[]*//' -e 's/^.//' -e 's/%.*$//'`

if [ "$CURR_VOLUME" != "0" ]
then
        echo $CURR_VOLUME |DISPLAY=$DISPLAY aosd_cat -n "Arial Black 18" -u $u -o $o -R $R -S none -f 0 -y -10 -e $e -b $b -B $B -t 0 -d 5 &
else
        echo "Mute" |DISPLAY=$DISPLAY aosd_cat -n "Arial Black 18" -u $u -o $o -R red -S none -f 0 -y -10 -e $e -b $b -B $B -d 5 -t 0&
fi

eventually made changes to fit your needs, save it into a new change_volume.sh file and make it executable:

Code:
$ chmod ugo+x ./change_volume.sh

To check that everything is going well, test the script with:

Code:
$ ./change_volume 10-

You should hear the sound lower down and its value on the screen (a very small and elegant bottom left corner green value).
Now edit your .lircrc and put this at bottom:

Code:
begin
        prog = irexec
        remote=devinput
        button = KEY_ZOOM
        config = ~/.xbmc/system/change_volume.sh 1+
        repeat = 1
end

begin
        prog = irexec
        remote=devinput
        button = KEY_MEDIA
        config = ~/.xbmc/system/change_volume.sh 1-
        repeat = 1
end

Where I've placed the change_volume.sh script into ~/.xbmc/system/ folder and mapped the actions to the lirc buttons KEY_ZOOM (volume up) and KEY_MEDIA (volume down).
Finally start irexec ad daemon:

Code:
$ irexec -d

to run the change_volume.sh script when the remote control buttons are pressed.

If you wants irexec at boot time, put this line inat the end of the /etc/rc.local file:
Code:
su xbmc -c "irexec -d > /dev/null 2>&1"

Hope this can be useful for someone.
Reply
#2
First i have to say Great code, its works very well.
I have done some changes because of some issues i having.

1- this code get every display in use and send osd to all
2- my amixer dont work without the -c0
3- my system wont unmute without the on off fix
4- the transparence set to 0 give me some artifacts
5- the kill -9 seens to make the screen freeze less
6- the mute stay on screen until unmuted

TODO:
Avoid toggle using set volume to 0 and them recover from a file
Stop all screen freeze
Add option to enable/disable volume as a bar

PS:
Use mudo as argument to mute and unmute

Code:
#!/bin/bash
# parameter: <value>- or <value>+ or <value>
#echo 2>&1 > ~/logvol.log

die () {
    echo >&2 "$@"
    exit 1
}

[ "$#" -eq 1 ] || die -e "\n1 argument required, $# provided.\n\nUsage:\n$0 1+     # increase alsa Master volume by 1 unit\n$0 2dB+   # increase alsa Master volume by 2 dB\n$0 10-    # decrease alsa Master volume by 10 units\n$0 50     # set alsa Master volume to 50\n"
u=1000
o=350
e=1
R=green
b=0
B=black
p=0
t=1
CONTROL=Master
DISPLAY=$(/bin/ps aux | grep xinit | egrep -ow ':[0-9] -auth|-- :[0-9]'| sed -e 's/ -auth//g'| sed -e 's/-- //g')
AMIXER_CMD=/usr/bin/amixer
AMIXER_PARAM=-c0
KILL_CMD=/bin/kill
PIDOF=/bin/pidof

if [ "$1" == "mudo" ]
then
$AMIXER_CMD $AMIXER_PARAM set $CONTROL toggle
$KILL_CMD -9 $($PIDOF aosd_cat) &> /dev/null
MUTESTATUS=$($AMIXER_CMD $AMIXER_PARAM get $CONTROL | egrep -w 'off|on' |  awk '{print $6}' | tr -d '[]')
if [ "$MUTESTATUS" == "off" ]
then
for i in $DISPLAY
do
echo "Mute" |DISPLAY=$i aosd_cat -n "Arial Black 23" -u $u -o 1234567890 -R red -S none -f 0 -y -10 -e $e -b $b -B $B -d 5 -t $t -p $p &
done
elif [ "$MUTESTATUS" = "on" ]
then
$AMIXER_CMD $AMIXER_PARAM set Speaker off
$AMIXER_CMD $AMIXER_PARAM set Speaker on
$AMIXER_CMD $AMIXER_PARAM set Headphone off
$AMIXER_CMD $AMIXER_PARAM set Headphone on
fi
else

$AMIXER_CMD -q $AMIXER_PARAM sset $CONTROL,0 $1 2>/dev/null
$KILL_CMD -9 $($PIDOF aosd_cat) &> /dev/null

CURR_VOLUME=`$AMIXER_CMD $AMIXER_PARAM get $CONTROL 2>/dev/null | grep 'Mono:' | sed -e 's/^[^\[]*//' -e 's/^.//' -e 's/%.*$//'`

if [ "$CURR_VOLUME" != "0" ]
then
for i in $DISPLAY
do
        echo $CURR_VOLUME |DISPLAY=$i aosd_cat -n "Arial Black 23" -u $u -o $o -R $R -S none -f 0 -y -10 -e $e -b $b -B $B -t $t -d 5 -p $p  &
done
else
for i in $DISPLAY
do
        echo "Mute" |DISPLAY=$i aosd_cat -n "Arial Black 23" -u $u -o $o -R red -S none -f 0 -y -10 -e $e -b $b -B $B -d 5 -t $t -p $p &
done
fi
fi
Reply
#3
some improvements

Code:
#!/bin/bash
# parameter: <value>- or <value>+ or <value>

#Script based on the code of joethefox http://forum.xbmc.org/archive/index.php/thread-125797.html
#Rewrited by ochiman
#PS: The code for the bar is lame, if someone know one good code please update this script

die () {
    echo >&2 "$@"
    exit 1
}

[ "$#" -eq 1 ] || die -e "\n1 argument required, $# provided.\n\nUsage:\n$0 1+     # increase alsa Master volume by 1 unit\n$0 2dB+   # increase alsa Master volume by 2 dB\n$0 10-    # decrease alsa Master volume by 10 units\n$0 50     # set alsa Master volume to 50\n$0 mudo   # set alsa Master to mute\n"

#AOSD_CAT Options, change whatever you want

FADEFULLOPACITY="1000"
FADEOUT="350"
SHADOWOFFSET="0"
FORECOLOR="green"
BACKGROUNDOPACITY="0"
BACKCOLOR="black"
POSITION="0"
POSITIONBAR="6"
TRANSPARENCE="0" # 0 to none | 1 to fake | 2 to composite
FONT="Arial Black 30"
FONTBAR="Arial Black 20"

#Mute options
FADEOUTMUTE="123456789"
FORECOLORMUTE="red"

#System Configuration
CONTROL="Master" # Can be used as PCM
AMIXER_PARAM="-c0" # Set to -D "your sound hardware" if you have some issue
BAR="1" #Active progress bar
TEXT="1" #Active Text mode

#For use of script, do not change unless you know what you are doing
DISPLAY=$(/bin/ps aux | egrep 'xinit|Xorg' | egrep -ow ':[0-9] -auth|-- :[0-9]|:0 -background'| sed -e 's/ -auth//g' -e 's/-- //g' -e 's/ -background//g') # Locate every open Display
MUTESTATUS=`amixer $AMIXER_PARAM get $CONTROL  | grep 'Mono:' | sed -e 's/^[^\[]*//' -e 's/^.//' -e 's/].*$//'` #Get the % to restore later


#Begin of code
    #Mute
if [ "$1" == "mudo" ]
then

    while [ "$(pidof aosd_cat)" != "" ] ; do #This is because i am neurotic
    kill -9 $(pidof aosd_cat)
    done

    if [ "$MUTESTATUS" != "0%" ]
    then

        amixer -q $AMIXER_PARAM sset $CONTROL,0 0
        echo $MUTESTATUS > ~/lastvol

            if [ "$TEXT" == "1" ]
            then
                for i in $DISPLAY
                do
                    echo "MUTE" | DISPLAY=$i /usr/bin/aosd_cat -n "$FONT" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5 -R $FORECOLORMUTE -o $FADEOUTMUTE -p $POSITION &
                    echo $AOSD
                done
            fi

            if [ "$BAR" == "1" ]
            then
                for i in $DISPLAY
                do
                    alvo="0"
                    z=""
                    while [ $alvo -lt "100" ]
                    do
                    z="$z-"
                    alvo=$[$alvo+1]
                    done
                    echo $z | DISPLAY=$i /usr/bin/aosd_cat -n "$FONTBAR" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5  -R $FORECOLORMUTE -o $FADEOUTMUTE -p $POSITIONBAR &    
                done            
            fi
        
    elif [ "$MUTESTATUS" == "0%" ]
    then

        file=$(ls ~/lastvol)
        if [ -f "$file" ]
        then

            LASTVOL=$(cat ~/lastvol)
            rm ~/lastvol
            amixer -q $AMIXER_PARAM sset $CONTROL,0 $LASTVOL
            CURR_VOLUME="$(echo $LASTVOL | sed -e 's/%//')"


                    if [ "$TEXT" == "1" ]
                    then
                        for i in $DISPLAY
                        do     
                            echo $CURR_VOLUME | DISPLAY=$i /usr/bin/aosd_cat -n "$FONT" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5 -R $FORECOLOR -o $FADEOUT -p $POSITION &
                        done
                    fi

                    if [ "$BAR" == "1" ]
                    then
                        for i in $DISPLAY
                        do                 
                            alvo=$CURR_VOLUME
                            z=""
                            l="0"
                            while [ $l -lt $alvo ]
                            do
                            z="$z+"
                            l=$[$l+1]
                            done
                            while [ $alvo -lt "100" ]
                            do
                            z="$z-"
                            alvo=$[$alvo+1]
                            done
                            echo $z | DISPLAY=$i /usr/bin/aosd_cat -n "$FONTBAR" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5 -p $POSITIONBAR &
                        done
                    fi
    
        fi
    fi

    #Volume Control
else
    #Check if is Muted and unmute before change volume
    file=$(ls ~/lastvol)
    if [ -s "$file" ]
    then
    LASTVOL=$(cat ~/lastvol)
    rm ~/lastvol
    amixer -q $AMIXER_PARAM sset $CONTROL,0 $LASTVOL
    fi

    amixer -q $AMIXER_PARAM sset $CONTROL,0 $1
    CURR_VOLUME=$(amixer $AMIXER_PARAM get $CONTROL  | grep 'Mono:' | sed -e 's/^[^\[]*//' -e 's/^.//' -e 's/%.*$//')

        while [ "$(pidof aosd_cat)" != "" ] ; do
        kill -9 $(pidof aosd_cat)
        done

    if [ "$CURR_VOLUME" != "0" ]
    then

            if [ "$TEXT" == "1" ]
            then
                for i in $DISPLAY
                do
                    echo $CURR_VOLUME | DISPLAY=$i /usr/bin/aosd_cat -n "$FONT" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5  -R $FORECOLOR -o $FADEOUT -p $POSITION &
                done
            fi

            if [ "$BAR" == "1" ]
            then
                for i in $DISPLAY
                do
                    alvo=$CURR_VOLUME
                    z=""
                    l="0"
                    while [ $l -lt $alvo ]
                    do
                    z="$z+"
                    l=$[$l+1]
                    done
                    while [ $alvo -lt "100" ]
                    do
                    z="$z-"
                    alvo=$[$alvo+1]
                    done
                    echo $z | DISPLAY=$i /usr/bin/aosd_cat -n "$FONTBAR" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5  -R $FORECOLOR -o $FADEOUT -p $POSITIONBAR &

                done
            fi


    fi

fi
Reply
#4
Everthing seens to be perfect
but the screen still freezes in fullscreen playback
if someone have a clue of why, please tell me
any help will be appreciated

Features:

-Displays volume bar and value simultaneous (or how user want)
-Send osd to every screen active
-Settings for volume bar and value separated
-Mute set the audio volume to 0, avoiding the issue of using toggle in some systems

PS: if you run emulator this is very useful, i put the every display for this reason.
Reply
#5
@ochiman, great work!!! I will try your improvements asap and will test the screen freezes in fullscreen playback issue.
Reply
#6
The issue appers to be because of this
Code:
22:44:51 T:140145185519360 WARNING: CRenderManager::FlipPage - timeout waiting for previous frame
22:45:02 T:140145185519360 WARNING: Previous line repeats 104 times.
22:45:02 T:140145185519360 WARNING: CRenderManager::FlipPage - timeout waiting for flip to complete
22:45:02 T:140145185519360 WARNING: CRenderManager::FlipPage - timeout waiting for previous frame
22:48:35 T:140145185519360 WARNING: Previous line repeats 97 times.
22:48:35 T:140145185519360 WARNING: CRenderManager::FlipPage - timeout waiting for flip to complete
22:48:35 T:140145185519360 WARNING: CRenderManager::FlipPage - timeout waiting for previous frame
22:48:43 T:140145185519360 WARNING: Previous line repeats 67 times.
22:48:43 T:140145185519360 WARNING: CRenderManager::FlipPage - timeout waiting for flip to complete
22:48:43 T:140145185519360 WARNING: CRenderManager::FlipPage - timeout waiting for previous frame

Fixed with a line in xorg.conf
Code:
Section "Device"
Identifier "nvidia"
...
        Option  "NoFlip"              "true"
...
EndSection

Now i think it is done
-when volume is 0 mute status shows up
-better characters for volume bar (in hex values)

Code:
#!/bin/bash
# parameter: <value>- or <value>+ or <value>

#Script based on the code of joethefox http://forum.xbmc.org/archive/index.php/thread-125797.html
#Rewrited by ochiman
#PS: The code for the bar is lame, if someone know one good code please update this script

die () {
    echo >&2 "$@"
    exit 1
}

[ "$#" -eq 1 ] || die -e "\n1 argument required, $# provided.\n\nUsage:\n$0 1+     # increase alsa Master volume by 1 unit\n$0 2dB+   # increase alsa Master volume by 2 dB\n$0 10-    # decrease alsa Master volume by 10 units\n$0 50     # set alsa Master volume to 50\n$0 mudo   # set alsa Master to mute\n"

#AOSD_CAT Options, change whatever you want

FADEFULLOPACITY="1000"
FADEOUT="350"
SHADOWOFFSET="0"
FORECOLOR="green"
BACKGROUNDOPACITY="0"
BACKCOLOR="black"
POSITION="0"
POSITIONBAR="6"
TRANSPARENCE="0" # 0 to none | 1 to fake | 2 to composite
FONT="Common 30"
FONTBAR="Common 11"

#Mute options
FADEOUTMUTE="123456789"
FORECOLORMUTE="red"

#System Configuration
CONTROL="Master" # Can be used as PCM
AMIXER_PARAM="-c0" # Set to -D your sound hardware if you have some issue
BAR="1" #Active progress bar
TEXT="1" #Active Text mode
BARFULL=$(echo -e "\\xe2\\x96\\x88\\x0a")
BAREMPTY=$(echo -e "\\xe2\\x96\\x81\\x0a")

#For use of script, do not change unless you know what you are doing
DISPLAY=$(/bin/ps aux | egrep 'xinit|Xorg' | egrep -ow ':[0-9] -auth|-- :[0-9]|:0 -background'| sed -e 's/ -auth//g' -e 's/-- //g' -e 's/ -background//g') # Locate every open Display
MUTESTATUS=`amixer $AMIXER_PARAM get $CONTROL  | grep 'Mono:' | sed -e 's/^[^\[]*//' -e 's/^.//' -e 's/].*$//'` #Get the % to restore later


#Begin of code
    #Mute
if [ "$1" == "mudo" ]
then

    while [ "$(pidof aosd_cat)" != "" ] ; do #This is because i am neurotic
    kill -9 $(pidof aosd_cat)
    done

    if [ "$MUTESTATUS" != "0%" ]
    then

        amixer -q $AMIXER_PARAM sset $CONTROL,0 0
        echo $MUTESTATUS > ~/lastvol

            if [ "$TEXT" == "1" ]
            then
                for i in $DISPLAY
                do
                    echo "MUTE" | DISPLAY=$i /usr/bin/aosd_cat -n "$FONT" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5 -R $FORECOLORMUTE -o $FADEOUTMUTE -p $POSITION &
                    echo $AOSD
                done
            fi

            if [ "$BAR" == "1" ]
            then
                for i in $DISPLAY
                do
                    alvo="0"
                    z=""
                    while [ $alvo -lt "100" ]
                    do
                    z="$z$BAREMPTY"
                    alvo=$[$alvo+1]
                    done
                    echo $z | DISPLAY=$i /usr/bin/aosd_cat -n "$FONTBAR" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5  -R $FORECOLORMUTE -o $FADEOUTMUTE -p $POSITIONBAR &
                done
            fi

    elif [ "$MUTESTATUS" == "0%" ]
    then

        file=$(echo ~/lastvol)
        if [ -f "$file" ]
        then

            LASTVOL=$(cat ~/lastvol)
            rm ~/lastvol
            amixer -q $AMIXER_PARAM sset $CONTROL,0 $LASTVOL
            CURR_VOLUME="$(echo $LASTVOL | sed -e 's/%//')"


                    if [ "$TEXT" == "1" ]
                    then
                        for i in $DISPLAY
                        do
                            echo $CURR_VOLUME | DISPLAY=$i /usr/bin/aosd_cat -n "$FONT" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5 -R $FORECOLOR -o $FADEOUT -p $POSITION &
                        done
                    fi

                    if [ "$BAR" == "1" ]
                    then
                        for i in $DISPLAY
                        do
                            alvo=$CURR_VOLUME
                            z=""
                            l="0"
                            while [ $l -lt $alvo ]
                            do
                            z="$z$BARFULL"
                            l=$[$l+1]
                            done
                            while [ $alvo -lt "100" ]
                            do
                            z="$z$BAREMPTY"
                            alvo=$[$alvo+1]
                            done
                            echo $z | DISPLAY=$i /usr/bin/aosd_cat -n "$FONTBAR" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5 -p $POSITIONBAR &
                        done
                    fi
        fi
    fi

    #Volume Control
else
    #Check if is Muted and unmute before change volume
    file=$(echo ~/lastvol)
    if [ -s "$file" ]
    then
    LASTVOL=$(cat ~/lastvol)
    rm ~/lastvol
    amixer -q $AMIXER_PARAM sset $CONTROL,0 $LASTVOL
    fi

    amixer -q $AMIXER_PARAM sset $CONTROL,0 $1
    CURR_VOLUME=$(amixer $AMIXER_PARAM get $CONTROL  | grep 'Mono:' | sed -e 's/^[^\[]*//' -e 's/^.//' -e 's/%.*$//')

        while [ "$(pidof aosd_cat)" != "" ] ; do
        kill -9 $(pidof aosd_cat)
        done


    if [ "$CURR_VOLUME" == "0" ]
    then

            if [ "$TEXT" == "1" ]
            then
                for i in $DISPLAY
                do
                    echo "MUTE" | DISPLAY=$i /usr/bin/aosd_cat -n "$FONT" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5 -R $FORECOLORMUTE -o $FADEOUTMUTE -p $POSITION &
                    echo $AOSD
                done
            fi

            if [ "$BAR" == "1" ]
            then
                for i in $DISPLAY
                do
                    alvo="0"
                    z=""
                    while [ $alvo -lt "100" ]
                    do
                    z="$z$BAREMPTY"
                    alvo=$[$alvo+1]
                    done
                    echo $z | DISPLAY=$i /usr/bin/aosd_cat -n "$FONTBAR" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5  -R $FORECOLORMUTE -o $FADEOUTMUTE -p $POSITIONBAR &
                done
            fi    

    elif [ "$CURR_VOLUME" != "0" ]
    then

            if [ "$TEXT" == "1" ]
            then
                for i in $DISPLAY
                do
                    echo $CURR_VOLUME | DISPLAY=$i /usr/bin/aosd_cat -n "$FONT" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5  -R $FORECOLOR -o $FADEOUT -p $POSITION &
                done
            fi

            if [ "$BAR" == "1" ]
            then
                for i in $DISPLAY
                do
                    alvo=$CURR_VOLUME
                    z=""
                    l="0"
                    while [ $l -lt $alvo ]
                    do
                    z="$z$BARFULL"
                    l=$[$l+1]
                    done
                    while [ $alvo -lt "100" ]
                    do
                    z="$z$BAREMPTY"
                    alvo=$[$alvo+1]
                    done
                    echo $z | DISPLAY=$i /usr/bin/aosd_cat -n "$FONTBAR" -u $FADEFULLOPACITY -S none -f 0 -y -10 -e $SHADOWOFFSET -b $BACKGROUNDOPACITY -B $BACKCOLOR -t $TRANSPARENCE -d 5  -R $FORECOLOR -o $FADEOUT -p $POSITIONBAR -e 0 &

                done
            fi


    fi

fi
thanks for the support
if you have some issue with the script, please let me know
Reply

Logout Mark Read Team Forum Stats Members Help
Change alsa master volume with a remote control and give visual feedback0