/
mic_over_mumble
executable file
·229 lines (192 loc) · 5.43 KB
/
mic_over_mumble
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
#!/bin/bash
# https://github.com/pzmarzly/mic_over_mumble
set -euo pipefail
# To debug, uncomment the following line:
# set -x
# PAID = PulseAudio ID
# ID = PID / process ID
main () {
set_up
echo "Press Return to shut down..."
read -n1 -s -r
shut_down
}
prepare_env () {
if [ ! -e ~/.mic_over_Mumble ]; then
mkdir ~/.mic_over_Mumble
fi
cd ~/.mic_over_Mumble
echo "bonjour=true" > murmur.ini
echo "bandwidth=130000" >> murmur.ini
if [ ! -e ./initdone ]; then
run_mumble_client_wizard
touch ./initdone
fi
}
run_mumble_client_wizard () {
echo "You will need to configure Mumble client to use the lowest possible latency."
echo "We will start Mumble now. Please complete setup wizard and go to settings to increase quality and decrease latency."
echo "Also, mute your microphone (if you have one) in Mumble."
echo "Then exit Mumble."
mumble >/dev/null 2>&1
}
set_up () {
prepare_env
start_mumble_server
start_mumble_client
change_pa_config
echo "Done. Please use pavucontrol to ensure everything works."
print_ip
}
shut_down () {
echo "Shutting down..."
stop_murmur_client
stop_murmur_server
restore_pa_config
}
start_mumble_client () {
echo "Starting Mumble client (a window should appear in a moment)..."
mumble "mumble://localhost" >/dev/null 2>&1 &
MUMBLE_CLIENT_ID=$!
# FIXME: I don't remember why I thought this
# was necessary.
disown
# Mumble is slow to launch, and the
# user may need to click on OK button.
# FIXME: probe PulseAudio server to see if
# Mumble has connected.
sleep 15
}
stop_murmur_client () {
echo "Stopping Mumble client..."
kill -KILL "$MUMBLE_CLIENT_ID" || true
sleep 2
}
start_mumble_server () {
echo "Starting Mumble server (murmurd)..."
murmurd -ini ./murmur.ini &
# Murmur forks, so the PID acquired by `$!`
# wouldn't help us much.
sleep 5
}
stop_murmur_server () {
echo "Stopping Mumble server..."
# FIXME: find a better way to kill Murmur.
pkill murmurd || true
}
change_pa_config () {
echo "Changing PulseAudio configuration..."
add_sink
move_mumble_to_sink
add_source
set_default_source
}
restore_pa_config () {
echo "Restoring PulseAudio configuration..."
remove_source
remove_sink
}
# PA utilities.
add_sink () {
echo "Adding sink..."
SINK_MODULE_PAID=$(pactl load-module \
module-null-sink \
sink_name=Loopback_of_Mumble \
sink_properties=device.description=Loopback_of_Mumble)
sleep 1
SINK_PAID=$(get_sink_paid)
}
remove_sink () {
pactl unload-module "$SINK_MODULE_PAID"
}
add_source () {
echo "Adding a virtual microphone..."
SOURCE_MODULE_PAID=$(pactl load-module \
module-virtual-source \
source_name=VirtualMic \
master=Loopback_of_Mumble.monitor \
source_properties=device.description=VirtualMic)
}
remove_source () {
pactl unload-module "$SOURCE_MODULE_PAID"
}
move_mumble_to_sink () {
MUMBLE_CLIENT_PAID=$(get_mumble_client_paid)
pacmd move-sink-input "$MUMBLE_CLIENT_PAID" "$SINK_PAID"
}
set_default_source () {
pactl set-default-source VirtualMic
}
# Data fetching & parsing.
get_mumble_client_paid () {
result=$(pacmd list-sink-inputs |
grep -F -e "index: " -e "media.name = " |
cut_every_second_newline |
grep -F -e "Mumble" |
take_second_column)
if [ -z "$result" ]; then
echo "Error: Mumble client did not connect to PulseAudio (yet?)." 2>&1
print_how_to_restart 2>&1
exit 1
fi
if [ "$(echo "$result" | wc -l)" != "1" ]; then
echo "Error: Multiple Mumble instances found." 2>&1
print_how_to_restart 2>&1
exit 1
fi
echo "$result"
}
get_sink_paid () {
result=$(pacmd list-sinks |
grep -F -e "index: " -e "name: " |
cut_every_second_newline |
grep -F -e "Loopback" |
cut_active_device_indicator |
take_second_column)
if [ -z "$result" ]; then
echo "Error: Failed to find the device the script should have added." 2>&1
print_how_to_restart 2>&1
exit 1
fi
if [ "$(echo "$result" | wc -l)" != "1" ]; then
echo "Error: Multiple virtual devices found." 2>&1
print_how_to_restart 2>&1
exit 1
fi
echo "$result"
}
# https://serverfault.com/a/375098/449626
cut_every_second_newline () {
awk 'ORS=NR%2?" ":"\n"'
}
take_second_column () {
awk '{print $2}'
}
# See https://github.com/pzmarzly/mic_over_mumble/issues/5 .
# The initial whitespace may contain an asterisk if the current
# device is the default one.
cut_active_device_indicator () {
cut -c 5-
}
print_ip () {
if ! [ -x "$(command -v ip)" ]; then
echo "Skipping IP printing: ip command not found..."
return
fi
if ! [ -x "$(command -v jq)" ]; then
echo "Skipping IP printing: jq command not found..."
return
fi
echo "Your IP addresses:"
set +e
ip -j addr | jq -r ".[] | .addr_info | .[] | select(.family==\"inet\") | select(.local != \"127.0.0.1\") | .local"
set -e
}
# Errors
print_how_to_restart () {
echo "Please find the reason why this happened, try fixing it"
echo "(\`pacmd list-sink-inputs\` and \`pacmd list-sinks\` may be"
echo "useful), then kill mumble and murmurd, restart PulseAudio via"
echo "\`pulseaudio -k\`, and finally, restart the script."
}
main