As I started to use the i3 window manager I wanted to have a visual feedback on sound volume change events. Usually it's done by a daemon that binds to specific keyboard combinations to adjust volume and to send notifications to a notify daemon. In xfce this is done by the xfce4-volumed. I should also point here to other lightweight volume daemons like volnoti or pa-applet. Without a dedicated daemon it is also pretty much simple to handle sound volume keys by a simple bash script which is bind to specific keyboard combinations.
I've seen several examples of such a script the only problem with them was that notify-send command used to send notifications still does not return an id of a notification shown which results in several notification popups floating at the same time. As it's described here one could patch notify-send command so that it will return an id if asked but I came up with an easier solution using python-notify lib. Until patched notify-send is available in an official repository one could use this pynotify workaround. Here is an example of pynotify usage in a script to adjust sound volume:
$ cat bin/volume_notify.sh #!/bin/bash # $0 - icon_name, $2 - volume, $3 - id print_cmd() { cat <<HEREDOC import pynotify pynotify.init("volume_notif.py") notif=pynotify.Notification("Volume", "", "$1") notif.set_hint_int32("value",$2) notif.set_property("id", $3) notif.show() print notif.get_property("id") HEREDOC } step=5 id_file="/tmp/notify_volume.id" icon_high="/usr/share/icons/elementary-xfce/notifications/48/audio-volume-high.png" icon_low="/usr/share/icons/elementary-xfce/notifications/48/audio-volume-low.png" icon_medium="/usr/share/icons/elementary-xfce/notifications/48/audio-volume-medium.png" icon_muted="/usr/share/icons/elementary-xfce/notifications/48/audio-volume-muted.png" icon_off="/usr/share/icons/elementary-xfce/notifications/48/audio-volume-off.png" case $1 in up) amixer -q set Master $step+ ;; down) amixer -q set Master $step- ;; toggle) #pactl list sinks|grep -q Mute:.yes;pactl set-sink-mute 0 ${PIPESTATUS[1]} ;; # amixer needs -D pulse switch as a workaround for the pulseaudio # check http://goo.gl/4z4U6R amixer -q -D pulse set Master toggle ;; *) echo "Usage: $0 up/down/toggle" exit 1 ;; esac muted=$(amixer get Master | tail -n1 | sed -nr 's/.*\[([a-z]+)\].*/\1/p') volume=$(amixer get Master | tail -n1 | sed -nr 's/[^\[]*.([^%]*).*/\1/p') if ((volume==0)); then icon=$icon_off elif ((volume<34)); then icon=$icon_low elif ((volume<67)); then icon=$icon_medium else icon=$icon_high fi if [[ $muted == "off" ]]; then icon=$icon_muted fi id=$(cat $id_file 2>/dev/null);id=${id:-0} idn=$(python -c "$(print_cmd $icon $volume $id)") (($idn != $id)) && echo "$idn" > "$id_file" exit 0Here pynotify module is used to send a notification and return its id. This id is stored in a temp file defined by id_file variable so that it can be accessed by another script process.
ps: lines 42-43 could be optimized to this:
val=$(amixer get Master | tail -n1 | sed -nr 'h;s/[^\[]*.([^%]*).*/\1/p;g;s/.*\[([a-z]+)\].*/\1/p') muted=${val#*$'\n'} volume=${val%$'\n'*}This reduces number of created subprocesses two times
Edit 2020.11:
The script above uses older python lib which isn't available any longer. Additionally it controls amixer but pulseaudio should be used instead. Here is an updated version:
$ cat bin/volume_notify_pa.sh #!/bin/bash # this script requires python3-notify2 lib to be installed first STEP='5%' # some sound cards could have different MIN/MAX values # this isn't implemented yet as I can't test it MIN_VOLUME=0 MAX_VOLUME=65536 # file where notification ids are stored ID_FILE="/tmp/notify_volume.id" # $1 - icon_name, $2 - volume, $3 - id print_cmd() { cat <<HEREDOC import notify2 notify2.init("volume_notify.py") notif=notify2.Notification("Volume", "", "$1") notif.set_hint_int32("value",$2) notif.id = $3 notif.show() print(notif.id) HEREDOC } # input parameters are: $1 - volume, $3 - muted status send_notification() { local icon id idn local volume_raw=$1 local muted=$2 local volume=$(( (100*(volume_raw-MIN_VOLUME))/(MAX_VOLUME-MIN_VOLUME) )) if ((volume==0)); then icon=$icon_off elif ((volume<34)); then icon=$icon_low elif ((volume<67)); then icon=$icon_medium else icon=$icon_high fi if [[ "$muted" == "yes" ]]; then icon=$icon_muted fi id=$(cat $ID_FILE 2>/dev/null);id=${id:-0} idn=$(python3 -c "$(print_cmd "$icon" "$volume" "$id")") (("$idn" != "$id")) && echo "$idn" > "$ID_FILE" } get_volume() { local VOLHEX=$(pacmd dump | awk '/^set-sink-volume/{printf("%s", $3)}') [ -n "$VOLHEX" ] || { echo "$MIN_VOLUME" return } printf '%d' $VOLHEX } # returns 'yes' or 'no' get_muted() { MUTED=$(pacmd dump | awk '/set-sink-mute/{print $3}') printf "%s" "$MUTED" } icon_high="audio-volume-high" icon_low="audio-volume-low" icon_medium="audio-volume-medium" icon_muted="audio-volume-muted" icon_off="audio-volume-off" SINK=$(pactl info | awk '/Default Sink/{print $3}') [ -n "$SINK" ] || exit 1 case $1 in up) pactl set-sink-volume "$SINK" "+$STEP" [ "$(get_volume)" -gt $MAX_VOLUME ] && pactl set-sink-volume "$SINK" "$MAX_VOLUME" ;; down) pactl set-sink-volume "$SINK" "-$STEP" [ "$(get_volume)" -le $MIN_VOLUME ] && pactl set-sink-volume "$SINK" "$MIN_VOLUME" ;; toggle) MUTED=$(pacmd dump | awk '/set-sink-mute/{print $3}') if [ "yes" = "$MUTED" ]; then pactl set-sink-mute "$SINK" 0 else pactl set-sink-mute "$SINK" 1 fi ;; *) echo "Usage: $0 up/down/toggle" exit 1 ;; esac send_notification "$(get_volume)" "$(get_muted)" exit 0
1 comment:
Thank you!!
Here is a modded version that worked for me..
$ cat volume.sh
#!/bin/bash
# $0 - icon_name, $2 - volume, $3 - id
print_cmd()
{
cat </dev/null);id=${id:-0}
idn=$(python2 -c "$(print_cmd $icon $volume $id)")
(($idn != $id)) && echo "$idn" > "$id_file"
exit 0
Post a Comment