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
|
#!/usr/bin/awk -f
function get_parent(pid, cmd, ppid, arr) {
cmd = sprintf("/proc/%d/stat", pid)
ppid = ""
if ((getline line < cmd) > 0) {
split(line, arr)
ppid = arr[4]
}
close(cmd)
return ppid
}
function proc_clients(line, arr) {
if (match(line, /^Client #(.*)/, arr)) {
store_client()
client_index = arr[1]
return
}
else if (match(line, /^\s*application\.process\.id = "(.*)"/, arr)) {
process_id = arr[1]
return
}
else if (match(line, /^\s*application\.name = "(.*)"/, arr)) {
application_name = arr[1]
return
}
}
function store_client() {
if (client_index == "")
return
clients[client_index] = 1
clients[client_index, "pid"] = process_id
clients[client_index, "parent_pid"] = get_parent(process_id)
clients[client_index, "name"] = application_name
client_index = ""
process_id = ""
}
function proc_sink_inputs(line, arr) {
if (match(line, /^Sink Input #(.*)/, arr)) {
apply_sink_input()
sink_index = arr[1]
return
}
else if (match(line, /^\s*application\.process\.id = "(.*)"/, arr)) {
process_id = arr[1]
return
}
else if (match(line, /^\s*Client: (.*)/, arr)) {
client_index = arr[1]
return
}
else if (match(line, /^\s*Mute: (.*)/, arr)) {
muted = (arr[1] == "yes")
return
}
else if (match(line, /^\s*Volume:.* ([0-9]+)%/, arr)) {
volume = strtonum(arr[1])
return
}
}
function apply_sink_input( cmd, header, msg, inc) {
if (sink_index == "")
return
# Do stuff if PID matches
if (PID == clients[client_index, "pid"] || PID == clients[client_index, "parent_pid"]) {
switch (ACTION) {
case "-i":
case "-d":
inc = strtonum(ARG)
if (ACTION == "-i")
volume += inc
else
volume -= inc
volume = volume > 100 ? 100 : volume
volume = volume < 0 ? 0 : volume
cmd = sprintf("pactl set-sink-input-volume '%d' '%d'%", sink_index, volume)
system(cmd)
print cmd
break
case "-t":
muted = !muted
cmd = sprintf("pactl set-sink-input-mute '%d' '%s'", sink_index, muted ? "true" : "false")
system(cmd)
print cmd
break
}
# Display a "popup" with new volume
header = sprintf("Client Volume: %d%%%s", volume, muted ? " MUTED" : "")
msg = clients[client_index, "name"]
system(sprintf("notify-send -r 101 -u low -h 'int:value:%d' '%s' '%s'", volume, header, msg))
}
sink_index = ""
}
BEGIN {
# Get arguments
# ACTION: -d, -i or -t (like pamixer)
# ARG: num arg for -d or -i
ACTION = ARGV[1]
ARG = ARGV[2]
for (i = 1; i < ARGC; i++)
delete ARGV[i]
# Get client info
getline PID
getline TITLE # Not used
getline APPID # Not used
getline TAGS # Not used
getline GEOMETRY # Not used
if (PID == "")
exit 1
# Process PulseAudio clients list and store PIDs for each
cmd = "pactl list clients"
while ((cmd | getline line) > 0)
proc_clients(line)
close(cmd)
store_client()
# Process PulseAudio sink inputs list and run apply_sink_input() for each
cmd = "pactl list sink-inputs"
while ((cmd | getline line) > 0)
proc_sink_inputs(line)
close(cmd)
apply_sink_input()
}
|