diff options
Diffstat (limited to '.config/polybar/scripts/pulseaudio_control')
-rwxr-xr-x | .config/polybar/scripts/pulseaudio_control | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/.config/polybar/scripts/pulseaudio_control b/.config/polybar/scripts/pulseaudio_control new file mode 100755 index 0000000..7ba2c3f --- /dev/null +++ b/.config/polybar/scripts/pulseaudio_control | |||
@@ -0,0 +1,265 @@ | |||
1 | #!/usr/bin/env bash | ||
2 | |||
3 | ################################################################## | ||
4 | # Polybar Pulseaudio Control # | ||
5 | # https://github.com/marioortizmanero/polybar-pulseaudio-control # | ||
6 | ################################################################## | ||
7 | |||
8 | # Script configuration (more info in the README) | ||
9 | OSD="no" # On Screen Display message for KDE if enabled | ||
10 | INC=2 # Increment when lowering/rising the volume | ||
11 | MAX_VOL=100 # Maximum volume | ||
12 | AUTOSYNC="no" # All programs have the same volume if enabled | ||
13 | VOLUME_ICONS=( " " " " " " ) # Volume icons array, from lower volume to higher | ||
14 | MUTED_ICON=" " # Muted volume icon | ||
15 | MUTED_COLOR="%{F#A9AA83}" # Color when the audio is muted | ||
16 | DEFAULT_SINK_ICON="" # The default sink icon if a custom one isn't found | ||
17 | CUSTOM_SINK_ICONS=("" "") # Custom sink icons in index of sink order | ||
18 | NOTIFICATIONS="no" # Notifications when switching sinks if enabled | ||
19 | SINK_BLACKLIST=( ) # Index blacklist for sinks when switching between them | ||
20 | |||
21 | # Environment constants | ||
22 | LANGUAGE=en_US # Functions of this scripts depends on English outputs of pactl | ||
23 | |||
24 | # Global script variables | ||
25 | isMuted="no" | ||
26 | activeSink="" | ||
27 | endColor="%{F-}" | ||
28 | |||
29 | function getCurVol { | ||
30 | curVol=$(pacmd list-sinks | grep -A 15 'index: '"$activeSink"'' | grep 'volume:' | grep -E -v 'base volume:' | awk -F : '{print $3}' | grep -o -P '.{0,3}%'| sed s/.$// | tr -d ' ') | ||
31 | } | ||
32 | |||
33 | function getCurSink { | ||
34 | activeSink=$(pacmd list-sinks | awk '/* index:/{print $3}') | ||
35 | } | ||
36 | |||
37 | function volMuteStatus { | ||
38 | isMuted=$(pacmd list-sinks | grep -A 15 "index: $activeSink" | awk '/muted/{ print $2}') | ||
39 | } | ||
40 | |||
41 | function getSinkInputs { | ||
42 | inputArray=$(pacmd list-sink-inputs | grep -B 4 "sink: $1 " | awk '/index:/{print $2}') | ||
43 | } | ||
44 | |||
45 | function volUp { | ||
46 | getCurVol | ||
47 | maxLimit=$((MAX_VOL - INC)) | ||
48 | |||
49 | if [ "$curVol" -le "$MAX_VOL" ] && [ "$curVol" -ge "$maxLimit" ]; then | ||
50 | pactl set-sink-volume "$activeSink" "$MAX_VOL%" | ||
51 | elif [ "$curVol" -lt "$maxLimit" ]; then | ||
52 | pactl set-sink-volume "$activeSink" "+$INC%" | ||
53 | fi | ||
54 | |||
55 | getCurVol | ||
56 | |||
57 | if [ ${OSD} = "yes" ]; then | ||
58 | qdbus org.kde.kded /modules/kosd showVolume "$curVol" 0 | ||
59 | fi | ||
60 | |||
61 | if [ ${AUTOSYNC} = "yes" ]; then | ||
62 | volSync | ||
63 | fi | ||
64 | } | ||
65 | |||
66 | function volDown { | ||
67 | pactl set-sink-volume "$activeSink" "-$INC%" | ||
68 | getCurVol | ||
69 | |||
70 | if [ ${OSD} = "yes" ]; then | ||
71 | qdbus org.kde.kded /modules/kosd showVolume "$curVol" 0 | ||
72 | fi | ||
73 | |||
74 | if [ ${AUTOSYNC} = "yes" ]; then | ||
75 | volSync | ||
76 | fi | ||
77 | } | ||
78 | |||
79 | function volSync { | ||
80 | getSinkInputs "$activeSink" | ||
81 | getCurVol | ||
82 | |||
83 | for each in $inputArray; do | ||
84 | pactl set-sink-input-volume "$each" "$curVol%" | ||
85 | done | ||
86 | } | ||
87 | |||
88 | function volMute { | ||
89 | case "$1" in | ||
90 | mute) | ||
91 | pactl set-sink-mute "$activeSink" 1 | ||
92 | curVol=0 | ||
93 | status=1 | ||
94 | ;; | ||
95 | unmute) | ||
96 | pactl set-sink-mute "$activeSink" 0 | ||
97 | getCurVol | ||
98 | status=0 | ||
99 | ;; | ||
100 | esac | ||
101 | |||
102 | if [ ${OSD} = "yes" ]; then | ||
103 | qdbus org.kde.kded /modules/kosd showVolume ${curVol} ${status} | ||
104 | fi | ||
105 | |||
106 | } | ||
107 | |||
108 | function changeDevice { | ||
109 | # Treat pulseaudio sink list to avoid calling pacmd list-sinks twice | ||
110 | o_pulseaudio=$(pacmd list-sinks| grep -e 'index' -e 'device.description') | ||
111 | |||
112 | # Get all sink indices in a list | ||
113 | sinks=($(echo "$o_pulseaudio" | grep index | awk -F': ' '{print $2}')) | ||
114 | |||
115 | # Get present default sink index | ||
116 | activeSink=$(echo "$o_pulseaudio" | grep "\* index" | awk -F': ' '{print $2}') | ||
117 | |||
118 | # Set new sink index, checks that it's not in the blacklist | ||
119 | newSink=$activeSink | ||
120 | |||
121 | # Remove blacklist devices from the sink list | ||
122 | sinks=($(comm -23 <(echo "${sinks[@]}" | tr ' ' '\n' | sort) <(echo "${SINK_BLACKLIST[@]}" | tr ' ' '\n' | sort) | tr '\n' ' ')) | ||
123 | |||
124 | # If the resulting list is empty, do nothing | ||
125 | if [ -z "${sinks}" ]; then exit; fi | ||
126 | |||
127 | # If the current sink is greater or equal than last one, pick the first | ||
128 | # sink in the list. Otherwise just pick the next sink avaliable. | ||
129 | if [ "${activeSink}" -ge "${sinks[-1]}" ]; then | ||
130 | newSink=${sinks[0]} | ||
131 | else | ||
132 | for sink in "${sinks[@]}"; do | ||
133 | if [ "${activeSink}" -lt "${sink}" ]; then | ||
134 | newSink=$sink | ||
135 | break | ||
136 | fi | ||
137 | done | ||
138 | fi | ||
139 | |||
140 | # The new sink is set | ||
141 | pacmd set-default-sink "${newSink}" | ||
142 | |||
143 | # Move all audio threads to new sink | ||
144 | inputs=$(pactl list sink-inputs short | cut -f 1) | ||
145 | for i in $inputs; do | ||
146 | pacmd move-sink-input "$i" "$newSink" | ||
147 | done | ||
148 | |||
149 | if [ $NOTIFICATIONS = "yes" ]; then | ||
150 | sendNotification | ||
151 | fi | ||
152 | } | ||
153 | |||
154 | function sendNotification { | ||
155 | o_pulseaudio=$(pacmd list-sinks| grep -e 'index' -e 'device.description') | ||
156 | deviceName=$(echo "$o_pulseaudio" | sed -n '/* index/{n;p;}' | grep -o '".*"' | sed 's/"//g') | ||
157 | notify-send "Output cycle" "Changed output to ${deviceName}" --icon=audio-headphones-symbolic | ||
158 | } | ||
159 | |||
160 | function listen { | ||
161 | firstrun=0 | ||
162 | |||
163 | pactl subscribe 2>/dev/null | { | ||
164 | while true; do | ||
165 | { | ||
166 | # If this is the first time just continue | ||
167 | # and print the current state | ||
168 | # Otherwise wait for events | ||
169 | # This is to prevent the module being empty until | ||
170 | # an event occurs | ||
171 | if [ $firstrun -eq 0 ] | ||
172 | then | ||
173 | firstrun=1 | ||
174 | else | ||
175 | read -r event || break | ||
176 | if ! echo "$event" | grep -e "on card" -e "on sink" -e "on server" | ||
177 | then | ||
178 | # Avoid double events | ||
179 | continue | ||
180 | fi | ||
181 | fi | ||
182 | } &>/dev/null | ||
183 | output | ||
184 | done | ||
185 | } | ||
186 | } | ||
187 | |||
188 | function output() { | ||
189 | if [ -z "$(pgrep pulseaudio)" ]; then echo "Pulseaudio not running"; return 1; fi | ||
190 | |||
191 | getCurSink | ||
192 | getCurVol | ||
193 | volMuteStatus | ||
194 | |||
195 | # Fixed volume icons over max volume | ||
196 | iconsLen="${#VOLUME_ICONS[@]}" | ||
197 | if [ "$iconsLen" -ne 0 ]; then | ||
198 | volSplit=$(( MAX_VOL / iconsLen )) | ||
199 | for (( i=1; i<=iconsLen; i++ )); do | ||
200 | if (( i*volSplit >= curVol )); then | ||
201 | volIcon="${VOLUME_ICONS[$((i-1))]}" | ||
202 | break | ||
203 | fi | ||
204 | done | ||
205 | else | ||
206 | volIcon="" | ||
207 | fi | ||
208 | |||
209 | # Uses custom sink icon if the array contains one | ||
210 | sinksLen=${#CUSTOM_SINK_ICONS[@]} | ||
211 | if [ "$activeSink" -le "$((sinksLen - 1))" ]; then | ||
212 | sinkIcon=${CUSTOM_SINK_ICONS[$activeSink]} | ||
213 | else | ||
214 | sinkIcon=$DEFAULT_SINK_ICON | ||
215 | fi | ||
216 | |||
217 | # Showing the formatted message | ||
218 | if [ "${isMuted}" = "yes" ]; then | ||
219 | echo "${MUTED_COLOR}${MUTED_ICON}${curVol}% ${sinkIcon} ${activeSink}${endColor}" | ||
220 | else | ||
221 | echo "${volIcon}${curVol}% ${sinkIcon} ${activeSink}" | ||
222 | fi | ||
223 | } | ||
224 | |||
225 | |||
226 | getCurSink | ||
227 | case "$1" in | ||
228 | --up) | ||
229 | volUp | ||
230 | ;; | ||
231 | --down) | ||
232 | volDown | ||
233 | ;; | ||
234 | --togmute) | ||
235 | volMuteStatus | ||
236 | if [ "$isMuted" = "yes" ] | ||
237 | then | ||
238 | volMute unmute | ||
239 | else | ||
240 | volMute mute | ||
241 | fi | ||
242 | ;; | ||
243 | --mute) | ||
244 | volMute mute | ||
245 | ;; | ||
246 | --unmute) | ||
247 | volMute unmute | ||
248 | ;; | ||
249 | --sync) | ||
250 | volSync | ||
251 | ;; | ||
252 | --listen) | ||
253 | # Listen for changes and immediately create new output for the bar | ||
254 | # This is faster than having the script on an interval | ||
255 | listen | ||
256 | ;; | ||
257 | --change) | ||
258 | # Changes the audio device | ||
259 | changeDevice | ||
260 | ;; | ||
261 | *) | ||
262 | # By default print output for bar | ||
263 | output | ||
264 | ;; | ||
265 | esac | ||