blob: d14aaae1d1e891d3b560a98da322db4e21660081 [file] [log] [blame]
Copybara botca5ce642024-11-08 17:38:08 +01001#!/bin/bash
2# Displays the default device, volume, and mute status for i3blocks
3
4set -a
5
6AUDIO_HIGH_SYMBOL=${AUDIO_HIGH_SYMBOL:-' '}
7
8AUDIO_MED_THRESH=${AUDIO_MED_THRESH:-50}
9AUDIO_MED_SYMBOL=${AUDIO_MED_SYMBOL:-' '}
10
11AUDIO_LOW_THRESH=${AUDIO_LOW_THRESH:-0}
12AUDIO_LOW_SYMBOL=${AUDIO_LOW_SYMBOL:-' '}
13
14AUDIO_MUTED_SYMBOL=${AUDIO_MUTED_SYMBOL:-' '}
15
16AUDIO_DELTA=${AUDIO_DELTA:-5}
17
18DEFAULT_COLOR=${DEFAULT_COLOR:-"#ffffff"}
19MUTED_COLOR=${MUTED_COLOR:-"#a0a0a0"}
20
21LONG_FORMAT=${LONG_FORMAT:-'${SYMB} ${VOL}% [${INDEX}:${NAME}]'}
22SHORT_FORMAT=${SHORT_FORMAT:-'${SYMB} ${VOL}% [${INDEX}]'}
23USE_ALSA_NAME=${USE_ALSA_NAME:-0}
24USE_DESCRIPTION=${USE_DESCRIPTION:-0}
25
26SUBSCRIBE=${SUBSCRIBE:-0}
27
28MIXER=${MIXER:-""}
29SCONTROL=${SCONTROL:-""}
30
31while getopts F:Sf:adH:M:L:X:T:t:C:c:i:m:s:h opt; do
32 case "$opt" in
33 S) SUBSCRIBE=1 ;;
34 F) LONG_FORMAT="$OPTARG" ;;
35 f) SHORT_FORMAT="$OPTARG" ;;
36 a) USE_ALSA_NAME=1 ;;
37 d) USE_DESCRIPTION=1 ;;
38 H) AUDIO_HIGH_SYMBOL="$OPTARG" ;;
39 M) AUDIO_MED_SYMBOL="$OPTARG" ;;
40 L) AUDIO_LOW_SYMBOL="$OPTARG" ;;
41 X) AUDIO_MUTED_SYMBOL="$OPTARG" ;;
42 T) AUDIO_MED_THRESH="$OPTARG" ;;
43 t) AUDIO_LOW_THRESH="$OPTARG" ;;
44 C) DEFAULT_COLOR="$OPTARG" ;;
45 c) MUTED_COLOR="$OPTARG" ;;
46 i) AUDIO_INTERVAL="$OPTARG" ;;
47 m) MIXER="$OPTARG" ;;
48 s) SCONTROL="$OPTARG" ;;
49 h) printf \
50"Usage: volume-pulseaudio [-S] [-F format] [-f format] [-p] [-a|-d] [-H symb] [-M symb]
51 [-L symb] [-X symb] [-T thresh] [-t thresh] [-C color] [-c color] [-i inter]
52 [-m mixer] [-s scontrol] [-h]
53Options:
54-F, -f\tOutput format (-F long format, -f short format) to use, with exposed variables:
55\${SYMB}, \${VOL}, \${INDEX}, \${NAME}
56-S\tSubscribe to volume events (requires persistent block, always uses long format)
57-a\tUse ALSA name if possible
58-d\tUse device description instead of name if possible
59-H\tSymbol to use when audio level is high. Default: '$AUDIO_HIGH_SYMBOL'
60-M\tSymbol to use when audio level is medium. Default: '$AUDIO_MED_SYMBOL'
61-L\tSymbol to use when audio level is low. Default: '$AUDIO_LOW_SYMBOL'
62-X\tSymbol to use when audio is muted. Default: '$AUDIO_MUTED_SYMBOL'
63-T\tThreshold for medium audio level. Default: $AUDIO_MED_THRESH
64-t\tThreshold for low audio level. Default: $AUDIO_LOW_THRESH
65-C\tColor for non-muted audio. Default: $DEFAULT_COLOR
66-c\tColor for muted audio. Default: $MUTED_COLOR
67-i\tInterval size of volume increase/decrease. Default: $AUDIO_DELTA
68-m\tUse the given mixer.
69-s\tUse the given scontrol.
70-h\tShow this help text
71" && exit 0;;
72 esac
73done
74
75if [[ -z "$MIXER" ]] ; then
76 MIXER="default"
77 if amixer -D pulse info >/dev/null 2>&1 ; then
78 MIXER="pulse"
79 fi
80fi
81
82if [[ -z "$SCONTROL" ]] ; then
83 SCONTROL=$(amixer -D "$MIXER" scontrols | sed -n "s/Simple mixer control '\([^']*\)',0/\1/p" | head -n1)
84fi
85
86CAPABILITY=$(amixer -D $MIXER get $SCONTROL | sed -n "s/ Capabilities:.*cvolume.*/Capture/p")
87
88
89function move_sinks_to_new_default {
90 DEFAULT_SINK=$1
91 pactl list sink-inputs | grep 'Sink Input #' | grep -o '[0-9]\+' | while read SINK
92 do
93 pactl move-sink-input $SINK $DEFAULT_SINK
94 done
95}
96
97function set_default_playback_device_next {
98 inc=${1:-1}
99 num_devices=$(pactl list sinks | grep -c Name:)
100 sink_arr=($(pactl list sinks | grep Name: | sed -r 's/\s+Name: (.+)/\1/'))
101 default_sink=$(pactl get-default-sink)
102 default_sink_index=$(for i in "${!sink_arr[@]}"; do if [[ "$default_sink" = "${sink_arr[$i]}" ]]; then echo "$i"; fi done)
103 default_sink_index=$(( ($default_sink_index + $num_devices + $inc) % $num_devices ))
104 default_sink=${sink_arr[$default_sink_index]}
105 pactl set-default-sink $default_sink
106 move_sinks_to_new_default $default_sink
107}
108
109case "$BLOCK_BUTTON" in
110 1) set_default_playback_device_next ;;
111 2) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY toggle ;;
112 3) set_default_playback_device_next -1 ;;
113 4) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY $AUDIO_DELTA%+ ;;
114 5) amixer -q -D $MIXER sset $SCONTROL $CAPABILITY $AUDIO_DELTA%- ;;
115esac
116
117function print_format {
118 echo "$1" | envsubst '${SYMB}${VOL}${INDEX}${NAME}'
119}
120
121function print_block {
122 ACTIVE="$(pactl list sinks | grep "State\: RUNNING" -B4 -A55)"
123 if [[ $ACTIVE = "" ]] ; then
124 ACTIVE="$(pactl list sinks | grep "$(pactl get-default-sink)" -B4 -A55)"
125 fi
126 ACTIVE="$(echo "$ACTIVE" | grep "Name:\|Volume: \(front-left\|mono\)\|Mute:\|api.alsa.pcm.card = \|node.nick = ")"
127 for Name in NAME MUTED VOL INDEX NICK; do
128 read $Name
129 done < <(echo "$ACTIVE")
130 INDEX=$(echo "$INDEX" | grep -o '".*"' | sed 's/"//g')
131 VOL=$(echo "$VOL" | grep -o "[0-9]*%" | head -1 )
132 VOL="${VOL%?}"
133 NAME=$(echo "$NICK" | grep -o '".*"' | sed 's/"//g')
134
135 if [[ $USE_ALSA_NAME == 1 ]] ; then
136 ALSA_NAME=$(pactl list sinks |\
137awk '/^\s*\*/{f=1}/^\s*index:/{f=0}f' |\
138grep "alsa.name\|alsa.mixer_name" |\
139head -n1 |\
140sed 's/.*= "\(.*\)".*/\1/')
141 NAME=${ALSA_NAME:-$NAME}
142 elif [[ $USE_DESCRIPTION == 1 ]] ; then
143 DESCRIPTION=$(pactl list sinks | grep "State\: RUNNING" -B4 -A55 | grep 'Description: ' | sed 's/^.*: //')
144 NAME=${DESCRIPTION:-$NAME}
145 fi
146
147 if [[ $MUTED =~ "no" ]] ; then
148 SYMB=$AUDIO_HIGH_SYMBOL
149 [[ $VOL -le $AUDIO_MED_THRESH ]] && SYMB=$AUDIO_MED_SYMBOL
150 [[ $VOL -le $AUDIO_LOW_THRESH ]] && SYMB=$AUDIO_LOW_SYMBOL
151 COLOR=$DEFAULT_COLOR
152 else
153 SYMB=$AUDIO_MUTED_SYMBOL
154 COLOR=$MUTED_COLOR
155 fi
156
157 if [[ $ACTIVE = "" ]] ; then
158 echo "Sound inactive"
159 COLOR='#222225'
160 fi
161
162 if [[ $SUBSCRIBE == 1 ]] ; then
163 print_format "$LONG_FORMAT"
164 else
165 print_format "$LONG_FORMAT"
166 print_format "$SHORT_FORMAT"
167 echo "$COLOR"
168 fi
169}
170
171print_block
172if [[ $SUBSCRIBE == 1 ]] ; then
173 while read -r EVENT; do
174 print_block
175 done < <(pactl subscribe | stdbuf -oL grep change)
176fi