forked from hastinbe/i3-volume
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvolume
executable file
·481 lines (424 loc) · 10.8 KB
/
volume
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
#!/bin/bash
#
# i3-volume
#
# Volume control and volume notifications for i3wm.
#
# Requires:
# alsa-utils or pulseaudio-utils
# awk (POSIX compatible)
#
# Optional:
# A libnotify compatible notification daemon such as notify-osd or dunst
# notify-send (libnotify) or dunstify (dunst)
#
# Copyright (c) 2016 Beau Hastings. All rights reserved.
# License: GNU General Public License v2
#
# Author: Beau Hastings <beausy@gmail.com>
# URL: https://github.com/hastinbe/i3-volume
# Get default sink name
get_default_sink_name() {
pacmd stat | awk -F": " '/^Default sink name: /{print $2}'
}
# Get the volume as a percentage.
get_volume() {
if $opt_use_amixer; then
get_volume_amixer $card
else
get_volume_pulseaudio $sink
fi
}
# Get the volume as a percentage.
#
# Arguments
# Sink name (string) Symbolic name of sink.
get_volume_pulseaudio() {
local sink="$1"
pacmd list-sinks |
awk -W posix '/^[ \t]+name: /{insink = $2 == "<'$sink'>"}
/^[ \t]+volume: / && insink {gsub("%", ""); print $5; exit}'
}
get_if_muted_pulseaudio() {
pacmd list-sinks $sink | grep muted | grep yes
}
# Get the volume as a percentage.
#
# Arguments
# Card (integer) Card number to control.
get_volume_amixer() {
local card="$1"
local volume
if [ -n "$card" ]; then
volume=$(amixer -c "$card" -- sget Master)
else
volume=$(amixer sget Master)
fi
echo $volume | awk -W posix -F'[][]' '/dB/ { gsub("%", ""); print $2 }'
}
# Increase volume relative to current volume.
#
# Arguments:
# Step (integer) Percentage to increase by.
raise_volume() {
if $opt_use_amixer; then
raise_volume_amixer "$card" "$1"
else
raise_volume_pulseaudio "$sink" "$1"
fi
}
# Increase volume relative to current volume using pulseaudio.
#
# Arguments:
# Sink name (string) Symbolic name of sink.
# Step (integer) Percentage to increase by.
raise_volume_pulseaudio() {
local sink="$1"
local step="${2:-5}"
set_volume_pulseaudio "$sink" "+${step}%"
}
# Increase volume relative to current volume using amixer.
#
# Arguments:
# Card (integer) Card number to control.
# Step (integer) Percentage to increase by.
raise_volume_amixer() {
local card="$1"
local step="${2:-5}"
set_volume_amixer "$card" "${step}%+"
}
# Decrease volume relative to current volume.
#
# Arguments:
# Step (integer) Percentage to decrease by.
lower_volume() {
if $opt_use_amixer; then
lower_volume_amixer "$card" "$1"
else
lower_volume_pulseaudio "$sink" "$1"
fi
}
# Decrease volume relative to current volume using pulseaudio.
#
# Arguments:
# Sink name (string) Symbolic name of sink.
# Step (integer) Percentage to decrease by.
lower_volume_pulseaudio() {
local sink="$1"
local step="${2:-5}"
set_volume_pulseaudio "$sink" "-${step}%"
}
# Decrease volume relative to current volume using amixer.
#
# Arguments:
# Card (integer) Card number to control.
# Step (integer) Percentage to decrease by.
lower_volume_amixer() {
local card="$1"
local step="${2:-5}"
set_volume_amixer "$card" "${step}%-"
}
# Set volume.
#
# Arguments:
# Step (integer) Percentage to decrease by.
set_volume() {
if $opt_use_amixer; then
set_volume_amixer "$card" "$1"
else
set_volume_pulseaudio "$sink" "$1"
fi
}
# Set volume using pulseaudio.
#
# Arguments:
# Sink name (string) Symbolic name of sink.
# Volume (integer|linear factor|percentage|decibel)
set_volume_pulseaudio() {
local sink="$1"
local vol="$2"
pactl set-sink-volume "$sink" "$vol" || pactl set-sink-volume "$sink" -- "$vol"
}
# Set volume using amixer.
#
# Arguments:
# Card (integer) Card number to control.
# Volume (integer|linear factor|percentage|decibel)
set_volume_amixer() {
local card="$1"
local vol="$2"
if [ -n "$card" ]; then
amixer -q -c "$card" -- set Master "$vol"
else
amixer -q set Master "$vol"
fi
}
# Toggle mute.
toggle_mute() {
if $opt_use_amixer; then
toggle_mute_amixer "$card"
else
toggle_mute_pulseaudio "$sink"
fi
}
# Toggle mute using pulseaudio.
#
# Arguments:
# Sink name (string) Symbolic name of sink.
toggle_mute_pulseaudio() {
local sink="$1"
pactl set-sink-mute "$sink" toggle
}
# Toggle mute using amixer.
#
# Arguments:
# Card (integer) Card number to control.
toggle_mute_amixer() {
local card="$1"
if [ -n "$card" ]; then
amixer -q -c "$card" -- set Master toggle
else
amixer -q set Master toggle
fi
}
# Check if muted.
is_muted() {
if $opt_use_amixer; then
return $(is_muted_amixer "$card")
else
return $(is_muted_pulseaudio "$sink")
fi
}
# Check if sink is muted.
#
# Arguments:
# Sink name (string) Symbolic name of sink.
#
# Returns:
# 0 when true, 1 when false.
is_muted_pulseaudio() {
local sink="$1"
muted=$(pacmd list-sinks |
awk -W posix '/^[ \t]+name: /{insink = $2 == "<'$sink'>"}
/^[ \t]+muted: / && insink {print $2; exit}')
[ "$muted" = "yes" ]
}
# Check if card is muted.
#
# Arguments:
# Card (integer) Card number to control.
#
# Returns:
# 0 when true, 1 when false.
is_muted_amixer() {
local card="$1"
local output
if [ -n "$card" ]; then
output=$(amixer -c "$card" -- sget Master)
else
output=$(amixer sget Master)
fi
status=$(echo $output | awk -W posix -F'[][]' '/dB/ { print $6 }')
[ "$status" = "off" ]
}
# Gets an icon for the provided volume.
#
# Arguments:
# Volume (integer) An integer indicating the volume.
#
# Returns:
# The volume icon name.
get_volume_icon() {
local vol="$1"
local icon
if [ "$vol" -ge 70 ]; then icon="audio-volume-high"
elif [ "$vol" -ge 40 ]; then icon="audio-volume-medium"
elif [ "$vol" -gt 0 ]; then icon="audio-volume-low"
else icon="audio-volume-low"
fi
echo "${icon}"
}
# Display a notification indicating the volume is muted.
notify_muted() {
if $opt_use_dunstify; then
dunstify -i audio-volume-muted -t $expires -h int:value:0 -h string:synchronous:volume "Volume muted" -r 1000
else
notify-send -i audio-volume-muted -t $expires -h int:value:0 -h string:synchronous:volume "Volume muted"
fi
}
# Display a notification indicating the current volume.
notify_volume() {
local vol=$(get_volume)
local icon=$(get_volume_icon "$vol")
local text="Volume ${vol}%"
if $opt_show_volume_progress; then
local progress=$(get_progress_bar "$vol")
text="$text $progress"
fi
if $opt_use_dunstify; then
dunstify -i "$icon" -t $expires -h int:value:"$vol" -h string:synchronous:volume "$text" -r 1000
else
notify-send -i "$icon" -t $expires -h int:value:"$vol" -h string:synchronous:volume "$text"
fi
}
# Updates the status line.
#
# Arguments:
# signal (string) The signal used to update the status line.
# proc (string) The name of the status line process.
update_statusline() {
local signal="$1"
local proc="$2"
pkill "-$signal" "$proc"
}
# Generates a progress bar for the provided value.
#
# Arguments:
# Percentage (integer) Percentage of progress.
# Maximum (integer) Maximum percentage. (default: 100)
# Divisor (integer) For calculating the ratio of blocks to progress (default: 5)
#
# Returns:
# The progress bar.
get_progress_bar() {
local percent="$1"
local max_percent=${2:-100}
local divisor=${3:-5}
local progress=$((($percent > $max_percent ? $max_percent : $percent) / $divisor))
printf '█%.0s' $(eval echo "{1..$progress}")
}
# Display program usage.
usage() {
echo "Usage: $0 [options]
Control volume and related notifications.
Options:
-a use alsa-utils instead of pulseaudio-utils for volume control
-c <card> card number to control (amixer only)
-d <amount> decrease volume
-e <expires> expiration time of notifications, in milliseconds
-i <amount> increase volume
-m toggle mute
-n show notifications
-p show text volume progress bar
-s <sink_name> symbolic name of sink (pulseaudio only)
-t <process_name> name of status line process. must be used with -u
-u <signal> update status line using signal. must be used with -t
-v <value> set volume
-y use dunstify instead of notify-send
-h display this help and exit
" 1>&2
exit 1
}
###########################################################
opt_decrease_volume=false
opt_increase_volume=false
opt_mute_volume=false
opt_notification=false
opt_set_volume=false
opt_show_volume_progress=false
opt_use_amixer=false
opt_use_dunstify=false
card=""
signal=""
sink=""
statusline=""
volume=5
expires="1500"
opt_get_volume=false
while getopts ":ac:d:e:hi:mnps:t:u:v:yg" o; do
case "$o" in
a)
opt_use_amixer=true
;;
c)
card="${OPTARG}"
;;
d)
opt_decrease_volume=true
volume="${OPTARG}"
;;
e)
expires="${OPTARG}"
;;
i)
opt_increase_volume=true
volume="${OPTARG}"
;;
m)
opt_mute_volume=true
;;
n)
opt_notification=true
;;
p)
opt_show_volume_progress=true
;;
s)
sink="${OPTARG}"
;;
t)
statusline="${OPTARG}"
;;
u)
signal="${OPTARG}"
;;
v)
opt_set_volume=true
volume="${OPTARG}"
;;
y)
opt_use_dunstify=true
;;
g)
opt_get_volume=true
;;
h | *)
usage
;;
esac
done
shift $((OPTIND-1)) # Shift off options and optional --
if ! $opt_use_amixer; then
if [ -z $sink ]; then
sink="$(get_default_sink_name)"
fi
fi
if ${opt_increase_volume}; then
raise_volume $volume
fi
if ${opt_decrease_volume}; then
lower_volume $volume
fi
if ${opt_set_volume}; then
set_volume $volume
fi
if ${opt_mute_volume}; then
toggle_mute $sink
fi
# The options below this line must be last
if ${opt_notification}; then
if is_muted; then
notify_muted
else
notify_volume
fi
fi
if ${opt_get_volume}; then
muted=$(get_if_muted_pulseaudio)
if [ -z "$muted" ]
then
echo $(get_volume)%
else
echo "MUTED"
fi
fi
if [ -n "${signal}" ]; then
if [ -z "${statusline}" ]; then
usage
fi
update_statusline "${signal}" "${statusline}"
else
if [ -n "${statusline}" ]; then
usage
fi
fi