Skip to content

Commit 3016450

Browse files
committed
small enhancements to bluetooth/pulseaudio control tools
1 parent c508264 commit 3016450

File tree

2 files changed

+112
-16
lines changed

2 files changed

+112
-16
lines changed

bin/bluectrl

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#!/bin/bash
22
set -eu -o pipefail
33

4+
###############################################################################
5+
# script for doing stuff with bluetooth
6+
# simplifies the process of connecting and disconnected bluetooth devices
7+
###############################################################################
8+
49
SCRIPTNAME=$(basename $0)
510

611
SCANFILE=$(mktemp --tmpdir bluescanXXXXX)
@@ -20,6 +25,7 @@ function printusage {
2025
echo " con|connect pair/connect a device"
2126
echo " dis|disconnect disconnect a connected device"
2227
echo " disall|disconnectall disconnect all connected devices"
28+
echo " reset reset bluetooth kernel module"
2329
echo ""
2430
echo "options:"
2531
echo " --scan [n] do a scan for n seconds (deafult 4) for devices"
@@ -31,15 +37,15 @@ function check_connected {
3137
local sleep_time="0.3"
3238
local err=1
3339
while [[ $tries -lt $max_tries ]]; do
34-
sleep
3540
if bluetoothctl info $1 | grep 'Connected: yes' > /dev/null; then
3641
err=0
3742
break
3843
fi
3944
tries=$((${tries}+1))
40-
sleep 0.5
45+
echo -n "."
46+
sleep 1
4147
done
42-
return err
48+
return $err
4349
}
4450

4551
set -- `getopt -n$0 -u -a --longoptions="scan help" "h" "$@"`
@@ -150,22 +156,22 @@ elif [[ "$1" == "con" ]] || [[ "$1" == "connect" ]]; then
150156
echo -n "already paired. connecting ${DEVICE}..."
151157
if ! bluetoothctl connect $chosen_id > /dev/null; then
152158
# sometimes connecting reports as failed, but actually succeeds
153-
if check_connected "$chosen_id"; then
159+
if ! check_connected "$chosen_id"; then
154160
echo "could not connect"
155161
exit 1
156162
fi
157163
fi
164+
echo "done."
158165
else
159166
echo -n "not paired, pairing and connecting ${DEVICE}..."
160167
if ! bluetoothctl pair $chosen_id > /dev/null; then
161168
# sometimes pairing reports as failed, but actually succeeds
162-
if check_connected "$chosen_id"; then
169+
if ! check_connected "$chosen_id"; then
163170
echo "could not connect"
164171
exit 1
165172
fi
166173
fi
167-
echo "done"
168-
174+
echo "done."
169175
fi
170176

171177
elif [[ "$1" == "dis" ]] || [[ "$1" == "disconnect" ]]; then
@@ -180,17 +186,28 @@ elif [[ "$1" == "dis" ]] || [[ "$1" == "disconnect" ]]; then
180186

181187
chosen_id=$(cat $IDFILE | awk '$3 == "yes"' | tail -n+"$REPLY" | head -n1 | cut -f1)
182188
echo -n "disconnecting $DEVICE..."
183-
bluetoothctl disconnect $chosen_id
189+
bluetoothctl disconnect $chosen_id > /dev/null
184190
echo "done."
185191

186192
elif [[ "$1" == "disall" ]] || [[ "$1" == "disconnectall" ]]; then
187193
for x in $(cat $IDFILE | awk '$3 == "yes"' | cut -f 1); do
188194
bluetoothctl disconnect $x
189195
done
196+
elif [[ "$1" == "reset" ]]; then
197+
# sometimes bluetooth gets into a bad state
198+
# this lets us completely reset it
199+
# see https://askubuntu.com/questions/1340713/bluetooth-service-failed-to-set-mode
200+
sudo hciconfig hci0 down # Close HCI device.
201+
sudo rmmod btusb # Remove btusb module from the kernel
202+
sudo modprobe btusb # Add it back
203+
sudo hciconfig hci0 up # Open and initialize HCI device
204+
# bluetooth.service should be running at this point
205+
if ! systemctl statu bluetooth | grep Running > /dev/null; then
206+
echo "bluetooth service not running!"
207+
exit 1
208+
fi
190209
else
191210
echo "unknown command '$1'"
192211
exit 1
193212
fi
194213

195-
rm -f $SCANFILE $RAWIDFILE $IDFILE $PAIREDFILE
196-

bin/pulsectrl

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,14 @@ set -- `getopt -n$0 -u -a --longoptions="help" "h" "$@"`
1515
usage="$SCRIPTNAME [option ...] command
1616
1717
commands:
18+
info show info about devices
1819
source set defualt source
1920
sink set efault sink
20-
apploop [loopname] set up a sink that forwards into a sink named loopname
21-
e.g. for streaming app audio
21+
apploop [loopname] set up a sink that forwards into a sink named loopname
22+
e.g. for streaming app audio
23+
monitor|mon set up a loopback monitor from a selected source to a
24+
selected sink, keeps trunning, ctrl-c or exit tears
25+
down the loopback
2226
2327
options:
2428
--source set the default source
@@ -49,10 +53,40 @@ while [ $# -gt 0 ]; do
4953
shift
5054
done
5155

52-
if [ $# -eq 0 ]; then
53-
echo "wtf"
54-
echo "${usage}"
55-
exit 1
56+
if [ $# -eq 0 ] || [[ $1 == "info" ]]; then
57+
echo "default source:"
58+
echo -n " "
59+
cat $SOURCE_FILE | awk -F\\t '$3 == 1' | cut -f 2
60+
61+
echo "default sink:"
62+
echo -n " "
63+
cat $SINK_FILE | awk -F\\t '$3 == 1' | cut -f 2
64+
65+
echo ""
66+
67+
old_ifs="$IFS"
68+
IFS=$'\n'
69+
70+
if [[ -z "$(cat $SOURCE_FILE | awk -F\\t '$3 == 0' | cut -f 2)" ]]; then
71+
echo "no other sources"
72+
else
73+
echo "other sources:"
74+
for x in $(cat $SOURCE_FILE | awk -F\\t '$3 == 0' | cut -f 2); do
75+
echo " ${x}"
76+
done
77+
fi
78+
79+
if [[ -z "$(cat $SINK_FILE | awk -F\\t '$3 == 0' | cut -f 2)" ]]; then
80+
echo "no other sinks"
81+
else
82+
echo "other sinks:"
83+
IFS=$'\n'
84+
for x in $(cat $SINK_FILE | awk -F\\t '$3 == 0' | cut -f 2); do
85+
echo " ${x}"
86+
done
87+
fi
88+
IFS="$old_ifs"
89+
5690
elif [[ $1 == "source" ]]; then
5791
echo "default source:"
5892
cat $SOURCE_FILE | grep "1$" | cut -f2
@@ -114,4 +148,49 @@ elif [[ $1 == "apploop" ]]; then
114148
pacmd update-sink-proplist ${loop_name} device.description=${loop_name}
115149
pactl load-module module-remap-source source_name=${loop_name}.source master=${loop_name}.monitor
116150
pacmd update-source-proplist ${loop_name}.source device.description=${loop_name}.source
151+
elif [[ $1 == "monitor" ]] || [[ $1 == "mon" ]]; then
152+
# set up a loopback from source to sink as long as we're running
153+
154+
old_ifs="$IFS"
155+
IFS=$'\n'
156+
echo "send which source?"
157+
select SOURCE_DESC in $(cat $SOURCE_FILE | cut -f2); do
158+
if [[ -z "$SOURCE_DESC" ]]; then
159+
echo "not a valid option"
160+
exit 1
161+
fi
162+
SELECTED_SOURCE=$(cat $SOURCE_FILE | tail -n+$REPLY | head -n1 | cut -f1)
163+
break
164+
done
165+
166+
echo "send to which sink?"
167+
select SINK_DESC in $(cat $SINK_FILE | cut -f2); do
168+
if [[ -z "$SINK_DESC" ]]; then
169+
echo "not a valid option"
170+
exit 1
171+
fi
172+
# now set the default source to the line matching $REPLY
173+
SELECTED_SINK=$(cat $SINK_FILE | tail -n+$REPLY | head -n1 | cut -f1)
174+
break;
175+
done
176+
IFS="$old_ifs"
177+
178+
MODULE_ID=$(pactl load-module module-loopback source=${SELECTED_SOURCE} sink=${SELECTED_SINK})
179+
echo "monitor loopback is module ${MODULE_ID}"
180+
181+
function cleanup_monitor {
182+
echo "cleaning up monitor loopback"
183+
pacmd unload-module "${MODULE_ID}"
184+
STOP_MONITOR=1
185+
}
186+
187+
# run until ctrl-c or exit
188+
STOP_MONITOR=""
189+
trap 'STOP_MONITOR=1' SIGINT
190+
trap 'cleanup_monitor' EXIT
191+
192+
while [[ -z "${STOP_MONITOR}" ]]; do
193+
sleep 0.25
194+
done
195+
117196
fi

0 commit comments

Comments
 (0)