blob: 5ae5281c0db594944472ffcec1ea17d8d4868490 (
plain)
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
|
#!/usr/bin/env bash
set -uo pipefail # Keep -e off so our self-healing logic can handle error codes safely
# Define the Rofi menu layout.
declare -a order=(
"⚡ Power On Bluetooth"
"🛑 Power Off Bluetooth"
"🔌 Disconnect All Devices"
"---"
"Speaker"
"Earphones"
"Earphones Left"
"Living Room"
)
# Map profiles to hardware MAC addresses.
declare -A devices
devices[Speaker]="A0:E9:DB:0E:43:79"
devices[Earphones]="98:52:3D:F2:6E:3E"
devices["Earphones Left"]="98:52:3D:F2:36:78"
devices["Living Room"]="42:46:9F:D0:2C:53"
# Prompt User via Rofi.
MENU_OPTIONS=$(printf "%s\n" "${order[@]}")
SELECTION=$(echo "$MENU_OPTIONS" | rofi -dmenu -p "Bluetooth Menu:")
# Exit gracefully if the user hits Escape.
if [ -z "$SELECTION" ] || [ "$SELECTION" = "---" ]; then
exit 0
fi
if [ "$SELECTION" = "⚡ Power On Bluetooth" ]; then
notify-send "BT" "Powering adapter on..."
bluetoothctl power on
exit 0
fi
if [ "$SELECTION" = "🛑 Power Off Bluetooth" ]; then
notify-send "BT" "Powering adapter off..."
bluetoothctl power off
exit 0
fi
if [ "$SELECTION" = "🔌 Disconnect All Devices" ]; then
notify-send "BT" "Clearing all active connections..."
for name in "${!devices[@]}"; do
bluetoothctl disconnect "${devices[$name]}" >/dev/null 2>&1 || true
done
notify-send "BT" "All devices disconnected."
exit 0
fi
if [ -z "${devices[$SELECTION]:-}" ]; then
notify-send "ERROR" "Invalid choice: $SELECTION"
exit 1
fi
TARGET_MAC="${devices[$SELECTION]}"
# Ensure controller is actually powered up before trying to connect.
if ! bluetoothctl show | grep -q "Powered: yes"; then
notify-send "BT" "Waking up Bluetooth adapter..."
bluetoothctl power on
sleep 2
fi
# Force controller runtime options to accept incoming passthroughs.
bluetoothctl pairable on >/dev/null 2>&1 || true
bluetoothctl discoverable on >/dev/null 2>&1 || true
# Disconnect existing targets to free up the system audio pipelines.
for name in "${!devices[@]}"; do
bluetoothctl disconnect "${devices[$name]}" >/dev/null 2>&1 || true
done
# Query the machine's local hardware database cache.
DEVICE_CHECK=$(bluetoothctl info "$TARGET_MAC" 2>&1 || true)
if echo "$DEVICE_CHECK" | grep -q "not available"; then
notify-send "BT: Provisioning" "Device missing from system cache. Probing airwaves..."
# Run a targeted background scan pass to register device metadata.
bluetoothctl --timeout 5 scan on >/dev/null 2>&1 &
SCAN_PID=$!
sleep 4
kill "$SCAN_PID" 2>/dev/null || true
wait "$SCAN_PID" 2>/dev/null || true
sleep 1
notify-send "BT: Provisioning" "Exchanging encryption keys..."
bluetoothctl pair "$TARGET_MAC"
bluetoothctl trust "$TARGET_MAC"
fi
# Attempt targeted connection sequence.
notify-send "BT Switch" "Routing audio to $SELECTION..."
CONNECT_OUT=$(bluetoothctl connect "$TARGET_MAC" 2>&1 || true)
echo "$CONNECT_OUT"
if echo "$CONNECT_OUT" | grep -q "Connection successful"; then
bluetoothctl trust "$TARGET_MAC" >/dev/null 2>&1 || true
# WirePlumber Sinks Syncing Engine.
CLEAN_MAC="${TARGET_MAC//:/_}"
SINK_NAME=$(wpctl status | grep -o "bluez_output\.[^\ ]*${CLEAN_MAC}[^\ ]*" | head -n 1 || true)
if [ ! -z "$SINK_NAME" ]; then
wpctl set-default "$SINK_NAME"
# Set a safe volumne just in case we connect to earphones.
wpctl set-volume "$SINK_NAME" 0.10
fi
notify-send "BT Switch" "$SELECTION connected successfully!"
# Handle key synchronization issues seamlessly....
elif echo "$CONNECT_OUT" | grep -q "br-connection-key-missing"; then
notify-send "BT Error" "Key mismatch! Purging and re-pairing..."
bluetoothctl remove "$TARGET_MAC" >/dev/null 2>&1 || true
sleep 1
bluetoothctl --timeout 5 scan on >/dev/null 2>&1 &
SCAN_PID=$!
sleep 4
kill "$SCAN_PID" 2>/dev/null || true
wait "$SCAN_PID" 2>/dev/null || true
sleep 1
notify-send "BT Recovery" "Put device in pairing mode!"
bluetoothctl pair "$TARGET_MAC"
bluetoothctl trust "$TARGET_MAC"
if bluetoothctl connect "$TARGET_MAC"; then
notify-send "BT Switch" "$SELECTION repaired and connected!"
else
notify-send "BT ERROR" "Repair fallback routing failed."
fi
else
notify-send "BT ERROR" "Failed to link with $SELECTION. Check pairing state or other devices."
fi
|