summaryrefslogtreecommitdiffstats
path: root/.config/polybar/scripts/pulseaudio_control
diff options
context:
space:
mode:
Diffstat (limited to '.config/polybar/scripts/pulseaudio_control')
-rwxr-xr-x.config/polybar/scripts/pulseaudio_control265
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)
9OSD="no" # On Screen Display message for KDE if enabled
10INC=2 # Increment when lowering/rising the volume
11MAX_VOL=100 # Maximum volume
12AUTOSYNC="no" # All programs have the same volume if enabled
13VOLUME_ICONS=( " " " " " " ) # Volume icons array, from lower volume to higher
14MUTED_ICON=" " # Muted volume icon
15MUTED_COLOR="%{F#A9AA83}" # Color when the audio is muted
16DEFAULT_SINK_ICON="" # The default sink icon if a custom one isn't found
17CUSTOM_SINK_ICONS=("" "") # Custom sink icons in index of sink order
18NOTIFICATIONS="no" # Notifications when switching sinks if enabled
19SINK_BLACKLIST=( ) # Index blacklist for sinks when switching between them
20
21# Environment constants
22LANGUAGE=en_US # Functions of this scripts depends on English outputs of pactl
23
24# Global script variables
25isMuted="no"
26activeSink=""
27endColor="%{F-}"
28
29function 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
33function getCurSink {
34 activeSink=$(pacmd list-sinks | awk '/* index:/{print $3}')
35}
36
37function volMuteStatus {
38 isMuted=$(pacmd list-sinks | grep -A 15 "index: $activeSink" | awk '/muted/{ print $2}')
39}
40
41function getSinkInputs {
42 inputArray=$(pacmd list-sink-inputs | grep -B 4 "sink: $1 " | awk '/index:/{print $2}')
43}
44
45function 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
66function 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
79function 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
88function 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
108function 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
154function 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
160function 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
188function 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
226getCurSink
227case "$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 ;;
265esac