Automatically turn off bluetooth headset after time out audio?
I have a Sony bluetooth headset connected to Ubuntu 20.04. They work very well, bluetooth can reconnect, I can even (mpris) control players from it.
The problem I have is that if I forget to turn the off while connected the headset will run out of battery overnight. I checked and there is nothing I can do from the headset side to automatically turn it off when there is no sound.
However the headset auto-turn off when there is no bluetooth connection. Therefore I think the only good option I have is if Ubuntu would disconnect the bluetooth after a certain period of silence.
Is there such option to auto disconnect a bluetooth audio device when there is no sound?
There is no much configuration I could find for the bluetooth device except this from the Settings window:
After some searching around I came to the following solution based on this answer, which works when running PulseAudio:
Using the command pacmd list-sink-inputs
one can see all the audio sinks. The output looks something like this:
Example output of "pacmd list-sink-inputs"
Important for the solution here is state: RUNNING
and sink: 31 <bluez_sink.[hardware address].a2dp_sink>
because with this information one can check, if audio is currently streaming via Bluetooth or not. BlueZ is the technology running Linux's Bluetooth services. A sink that is connect but no music is played would have the following state state: CORKED
Based on this information one can now change the status of the Bluetooth adapter using the package bluez-tools
. More specifically the command bt-adapter --set Powered false
is used to turn of the the adapter when needed. Here is a link to all options and commans.
I wrote a bash script which sporadically checks if the PC is streaming audio via Bluetooth and if not turns off the Bluetooth adapter after a given timeout duration. Please forgive my scripting, its only the second script I've ever written in bash.
#!/bin/bash
deviceName="WH-1000XM3" # Name of the BT-Device
timeout=120 # Delay in seconds after which Device is disconnected
halfTimeout=$((timeout / 2))
# Checks if Sound is played via BT.
# Returns true if sound is play and false if not.
checkBTSound() {
sinks=$(pacmd list-sink-inputs) # Gets all sinks
# Check if "bluez_sink" is in the list of sinks and if it also has
# "state: RUNNING".
[[ ("$sinks" == *"bluez_sink"*) &&\
("$sinks" == *"state: RUNNING"*) ]] && true || false
}
# Checks if specified BT-Device is connected
# Returns "true" if connected, "false" else.
deviceIsConnected() {
response=$(bt-device -i $deviceName)
[[ "$response" == *"Connected: 1"* ]] && true || false
}
# Endless Loop
while :
do
counting=false
inital=true
notification=false
start=1
# Only take action, if device is connected and no sound is streaming.
while
(! checkBTSound && deviceIsConnected) && true || false
do
# Sound has stopped playing. Start counting.
counting=true
# Only on first loop mark the time to calc the duration later.
if $inital; then
inital=false
start=$SECONDS
fi
# Calculate time passed since first loop.
timePassed=$(($SECONDS - $start))
# Check if half of timeout time has passed and send notification if that is
# the case and the notification has not already been sent.
if [ $timePassed -ge $halfTimeout ] && ! $notification; then
notify-send "Headphone Timeout"\
"Headphone will be disconnected in $halfTimeout seconds."
notification=true
# Check if timout time has been surpassed and take corresponding actions if
# that is the case.
elif [ $timePassed -ge $timeout ]; then
# Sending notification
notify-send "Headphone Timeout"\
"Disconnecting headphones \"$deviceName\"."
# Disconnecting specified device
bt-device -d $deviceName
# Go back to outer loop waiting for device to connect again
break
fi
sleep 1
done
sleep 5
done
Edit: You can also disconnect your device using
bt-device --disconnect=<Name of your Device>
That way you don't have to turn off the adapter. The name is the human readable Device-Name which you can also change to whatever you like in the Bluetooth settings.