Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Bluetooth headset - switch between quality sound + no mic (A2DP) and crappy sound and mic (HSP/HFP)
#!/bin/bash
#### Restart Bluetooth
if [ "$1" == "resetBT" ] ; then
sudo rfkill block bluetooth && sleep 0.1 && sudo rfkill unblock bluetooth;
exit;
fi;
#### Toggle listen/speak
if [ "$1" == "" -o "$1" == "toggle" ] ; then
LINE=`pacmd list-sinks | grep '\(name:\|alias\)' | grep -B1 F5A | head -1`
if [ "$LINE" == "" ] ; then echo "F5A headset not found."; $0 reset; sleep 2; exit; fi
SINK_NAME="bluez_sink.00_19_5D_25_6F_6C.a2dp_sink"
if $(echo "$LINE" | grep $SINK_NAME &> /dev/null) ; then
echo "Detected quality sound output, that means we can't speak; switch that."
$0 speak;
else
echo "Quality sound not found, switch to the good sound."
$0 listen;
fi
fi
#### Change the output to F5A
if [ "$1" == "listen" ] ; then
LINE=`pacmd list-sinks | grep '\(name:\|alias\)' | grep -B1 F5A | head -1`
if [ "$LINE" == "" ] ; then echo "F5A phones not found."; $0 reset; sleep 2; exit; fi
# name: <bluez_sink.00_19_5D_25_6F_6C.headset_head_unit>
## Get what's between <...>
SINK_NAME=`echo "$LINE" | tr '>' '<' | cut -d'<' -f2`;
## The above gives an ID according to the active profile.
## To set manually:
#SINK_NAME="bluez_sink.00_19_5D_25_6F_6C.headset_head_unit"
#SINK_NAME="bluez_sink.00_19_5D_25_6F_6C.a2dp_sink"
## Switch the output to that.
echo "Switching audio output to $SINK_NAME";
pacmd set-default-sink "$SINK_NAME"
#### Change profile to quality output + no mic. From `pacmd list-cards`:
CARD="bluez_card.00_19_5D_25_6F_6C"
PROFILE="a2dp_sink"
echo "Switching audio profile to $PROFILE";
pacmd set-card-profile $CARD $PROFILE
exit;
fi;
#### Input
if [ "$1" == "speak" ] ; then
## Change profile to crappy output + mic. From `pacmd list-cards`:
CARD="bluez_card.00_19_5D_25_6F_6C"
pacmd set-card-profile $CARD headset_head_unit
LINE=`pacmd list-sources | grep '\(name:\|alias\)' | grep -B1 F5A | head -1`
if [ "$LINE" == "" ] ; then echo "F5A mic not found."; $0 reset; sleep 2; exit; fi
SOURCE_NAME=`echo "$LINE" | tr '>' '<' | cut -d'<' -f2`;
#SOURCE_NAME="bluez_source.00_19_5D_25_6F_6C.headset_head_unit"
#SOURCE_NAME="bluez_sink.00_19_5D_25_6F_6C.a2dp_sink.monitor"
echo "Switching audio input to $SOURCE_NAME";
pacmd set-default-source "$SOURCE_NAME" || echo 'Try `pacmd list-sources`.';
fi;
#### Resources:
## Why this is needed
# https://jimshaver.net/2015/03/31/going-a2dp-only-on-linux/
## My original question
# https://askubuntu.com/questions/1004712/audio-profile-changes-automatically-to-hsp-bad-quality-when-i-change-input-to/1009156#1009156
## Script to monitor plugged earphones and switch when unplugged (Ubuntu does that, but nice script):
# https://github.com/freundTech/linux-helper-scripts/blob/master/padevswitch/padevswitch
@artem328

This comment has been minimized.

Copy link

@artem328 artem328 commented Jan 28, 2019

Thanks for script, i've modified it a little bit to have more universal usage.

#!/bin/bash

# run `pacmd list-sinks  | grep '\(name:\|alias\)'` and fill with value from alias of your bluetooth device
BLUETOOTH_DEVICE="YOUR DEVICE NAME"
PROFILE_A2DP="a2dp_sink"
PROFILE_HEADSET_UNIT="headset_head_unit"

####  Restart Bluetooth
if [ "${1}" == "reset" ] ; then
  sudo rfkill block bluetooth && sleep 0.1 && sudo rfkill unblock bluetooth;
  exit;
fi;

sink_name() {
    pacmd list-sinks  | grep '\(name:\|alias\)' | grep -B1 "${1}"  | head -1 | sed -rn 's/\s*name: <(.*?)>/\1/p'
}

card_name() {
    pacmd list-cards | grep 'name:' | grep "bluez" | sed -rn 's/\s*name: <(.*?)>/\1/p'
}

#### Toggle listen/speak
if [ "${1}" == "" -o "${1}" == "toggle" ] ; then
  SINK_NAME=$(sink_name "${BLUETOOTH_DEVICE}")
 
  if [ "${SINK_NAME}" == "" ] ; then echo "${BLUETOOTH_DEVICE} headset not found."; ${0} reset; sleep 2; exit; fi

  if $(echo "${SINK_NAME}" | grep "${PROFILE_A2DP}" &> /dev/null) ; then
    echo "Detected quality sound output, that means we can't speak; switch that."
    ${0} speak;
  else
    echo "Quality sound not found, switch to the good sound."
    ${0} listen;
  fi
fi

#### Change the output to F5A
if [ "${1}" == "listen" ] ; then
  SINK_NAME=$(sink_name "${BLUETOOTH_DEVICE}")
  if [ "${SINK_NAME}" == "" ] ; then echo "${BLUETOOTH_DEVICE} headset not found."; ${0} reset; sleep 2; exit; fi
  
  ## Switch the output to that.
  echo "Switching audio output to ${SINK_NAME}";
  pacmd set-default-sink "${SINK_NAME}"

  #### Change profile to quality output + no mic.:
  CARD=$(card_name)
  echo "Switching audio profile to ${PROFILE_A2DP}";
  pacmd set-card-profile "${CARD}" "${PROFILE_A2DP}"
  exit;
fi;

#### Input
if [ "${1}" == "speak" ] ; then
  ## Change profile to crappy output + mic.:
  CARD=$(card_name)
  pacmd set-card-profile "${CARD}" "${PROFILE_HEADSET_UNIT}"

  SOURCE_NAME=$(sink_name "${BLUETOOTH_DEVICE}")
  if [ "${SOURCE_NAME}" == "" ] ; then echo "${BLUETOOTH_DEVICE} mic not found."; ${0} reset; sleep 2; exit; fi
  echo "Switching audio input to ${SOURCE_NAME}";
  pacmd set-default-source "${SOURCE_NAME}.monitor" || echo 'Try `pacmd list-sources`.';
fi;


####  Resources:

##  Why this is needed
# https://jimshaver.net/2015/03/31/going-a2dp-only-on-linux/

##  My original question
# https://askubuntu.com/questions/1004712/audio-profile-changes-automatically-to-hsp-bad-quality-when-i-change-input-to/1009156#1009156

##  Script to monitor plugged earphones and switch when unplugged (Ubuntu does that, but nice script):
# https://github.com/freundTech/linux-helper-scripts/blob/master/padevswitch/padevswitch
@emmanuelmathot

This comment has been minimized.

Copy link

@emmanuelmathot emmanuelmathot commented May 21, 2019

Thats great! It Works perfectly with My PLT Focus! Thx!

@hesparza

This comment has been minimized.

Copy link

@hesparza hesparza commented Feb 9, 2020

Thank you very much for this effort. I wonder how can it work on Windows? when I use my bluetooth headphones there I can talk and listen with good quality.

@david-alejandro-reyes-milian

This comment has been minimized.

Copy link

@david-alejandro-reyes-milian david-alejandro-reyes-milian commented Mar 19, 2020

really great, thanks. Bose headsets were giving headache with this. Regards!

@Vafa-Andalibi

This comment has been minimized.

Copy link

@Vafa-Andalibi Vafa-Andalibi commented May 1, 2020

worked like a charm

@jim9835

This comment has been minimized.

Copy link

@jim9835 jim9835 commented May 14, 2020

this looks like exactly what I need for my Mpow M5 headset. It works a treat in Ubuntu, but am now trying to get it to work in Manjaro KDE.

However, I'm getting "line 30: command not found"

Am a 'cut and paster' with code, so very limited understanding. My guess is that I've misunderstood the blanks I need to fill for my device.

My only initial change to the code was BLUETOOTH_DEVICE="Mpow M5"

Do I need to make other changes?

@Dentxinho

This comment has been minimized.

Copy link

@Dentxinho Dentxinho commented May 18, 2020

Thanks for script, i've modified it a little bit to have more universal usage.

Awesome, thank you.

@Dentxinho

This comment has been minimized.

Copy link

@Dentxinho Dentxinho commented May 18, 2020

My only initial change to the code was BLUETOOTH_DEVICE="Mpow M5"

Do I need to make other changes?

I don't think so, that's it.

@Nuke777

This comment has been minimized.

Copy link

@Nuke777 Nuke777 commented Jul 15, 2020

Hey I am new here. Can anyone please tell me what to do with the script? How to use it?

@weslleyspereira

This comment has been minimized.

Copy link

@weslleyspereira weslleyspereira commented Aug 4, 2020

Thank you for this script. It works nicely as expected! I suggest to use it together with a toggle button, e.g.,

#!/usr/bin/env python

''' switchHeadphones.py
Tkinter toggle button to switch microphone On/Off using a script 

Modification of the solution proposed in
    https://www.daniweb.com/posts/jump/1909448
for the Mic On/Off script from
    https://gist.github.com/OndraZizka/2724d353f695dacd73a50883dfdf0fc6
'''

# Define the path for the script below, e.g.,
script = "./switchHeadphones.sh"

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk
import os

__author__ = "Weslley S Pereira"
__email__ = "weslley.spereira@gmail.com"

def toggle(tog=[0]):
    '''
    a list default argument has a fixed address
    '''
    tog[0] = not tog[0]
    if tog[0]:
        os.system(script+' speak')
        t_btn.config(text='Switch Mic Off')
    else:
        os.system(script+' listen')
        t_btn.config(text='Switch Mic On')

root = tk.Tk()
root.title('Headphone  ')

t_btn = tk.Button(text='Switch Mic On', width=15, command=toggle)
t_btn.pack(pady=5)

root.mainloop()
@vvillschneider

This comment has been minimized.

Copy link

@vvillschneider vvillschneider commented Aug 10, 2020

Thanks!

@Paiusco

This comment has been minimized.

Copy link

@Paiusco Paiusco commented Aug 20, 2020

I think this should become a repo by it's own. There're nice improvements to be done to be more generic and w/ toggle functionality @OndraZizka what do you think?

@thedopepirate

This comment has been minimized.

Copy link

@thedopepirate thedopepirate commented Sep 28, 2020

Thank you for this script. It works nicely as expected! I suggest to use it together with a toggle button, e.g.,

#! /usr/bin/python

''' switchHeadphones.py
Tkinter toggle button to switch microphone On/Off using a script 

Modification of the solution proposed in
    https://www.daniweb.com/posts/jump/1909448
for the Mic On/Off script from
    https://gist.github.com/OndraZizka/2724d353f695dacd73a50883dfdf0fc6
'''

# Define the path for the script below, e.g.,
script = "./switchHeadphones.sh"

try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk
import os

__author__ = "Weslley S Pereira"
__email__ = "weslley.spereira@gmail.com"

def toggle(tog=[0]):
    '''
    a list default argument has a fixed address
    '''
    tog[0] = not tog[0]
    if tog[0]:
        os.system(script+' speak')
        t_btn.config(text='Switch Mic Off')
    else:
        os.system(script+' listen')
        t_btn.config(text='Switch Mic On')

root = tk.Tk()
root.title('Headphone  ')

t_btn = tk.Button(text='Switch Mic On', width=15, command=toggle)
t_btn.pack(pady=5)

root.mainloop()

I don't know how to run this, I'm new to linux. Can someone please help me out ?
@weslleyspereira @vvillschneider

@weslleyspereira

This comment has been minimized.

Copy link

@weslleyspereira weslleyspereira commented Sep 28, 2020

Usage:

  1. First, you may need to change the permissions of the original Shell script switchHeadphones.sh:
    chmod +x switchHeadphones.sh
  2. Then, after connecting your headphones, execute the script Python I suggested as follows:
    python <my_script.py> &
  3. Make sure the variable script holds the correct path for the original Shell script switchHeadphones.sh.
@thedopepirate

This comment has been minimized.

Copy link

@thedopepirate thedopepirate commented Sep 28, 2020

Usage:

1. First, you may need to change the permissions of the original Shell script `switchHeadphones.sh`:
   `chmod +x switchHeadphones.sh`

2. Then, after connecting your headphones, execute the script Python I suggested as follows:
   `python <my_script.py> &`

3. Make sure the variable `script` holds the correct path for the original Shell script `switchHeadphones.sh`.

@weslleyspereira, i tried running the above command of your's on ubuntu terminal , the chmod +x switchHeadphones.sh ran perfectly, but later the command python switchHeadphones.py gives me the following error:
File "switchHeadphones.py", line 9 if [ "${1}" == "reset" ] ; then ^ SyntaxError: invalid syntax
i renamed the file from .sh to .py as i could'nt run it
i have saved the file in my /home path. can you please help me out ? it would really mean a lot, thanks ^.^

@weslleyspereira

This comment has been minimized.

Copy link

@weslleyspereira weslleyspereira commented Sep 28, 2020

Hi!

  1. Did you configure the Shell script switchHeadphones.sh? In case not, you should. You can do as suggested in the Shell script:
    -- Run pacmd list-sinks | grep '\(name:\|alias\)' and fill with value from alias of your Bluetooth device
  2. The error you showed relates to the @artem328's script. Try running ./switchHeadphones.sh speak then ./switchHeadphones.sh listen in your terminal and see if everything works. My Python script is only an interface for this nice Shell script.
@Dentxinho

This comment has been minimized.

Copy link

@Dentxinho Dentxinho commented Sep 28, 2020

@thedopepirate you shouldn't rename the .sh to .py
The sh is the script that toggles bt audio. You can use it alone. The py is a GUI that shows a toggle button and it calls the sh under the hood

@appsessive

This comment has been minimized.

Copy link

@appsessive appsessive commented Jan 6, 2021

Thanks !

@tvaillantdeguelis

This comment has been minimized.

Copy link

@tvaillantdeguelis tvaillantdeguelis commented Jan 21, 2021

Hi!

I was looking for a solution to use the mic of my headphones with A2DP mode (in Ubuntu 20.04). I kind of understand that this is technically impossible. Is that correct?!
Then, I understand that I need to switch to HSP/HFP mode if I'd like to use the mic. However, sound quality is terrible...

This code seems to allow to toggle between the 2 modes. I don't understand if it toggles automatically (for example when muting/unmuting in Skype, Teams, or whatever)? Some folks propose to add a toggle button, so I guess the switching is done manually? Is that different from the Sound Input & Output Device Chooser Gnome extension? See a screenshot here: https://ibb.co/s3gjtsH.

@weslleyspereira

This comment has been minimized.

Copy link

@weslleyspereira weslleyspereira commented Jan 21, 2021

Hi!

I was looking for a solution to use the mic of my headphones with A2DP mode (in Ubuntu 20.04). I kind of understand that this is technically impossible. Is that correct?!
Then, I understand that I need to switch to HSP/HFP mode if I'd like to use the mic. However, sound quality is terrible...

As far as I know, it is currently impossible to obtain both good quality mic and phones in Ubuntu.

This code seems to allow to toggle between the 2 modes. I don't understand if it toggles automatically (for example when muting/unmuting in Skype, Teams, or whatever)? Some folks propose to add a toggle button, so I guess the switching is done manually?

The code allows you to toggle between the modes although it is not automatic.

Is that different from the Sound Input & Output Device Chooser Gnome extension? See a screenshot here: https://ibb.co/s3gjtsH.

I've just installed the plugin you suggested, and could not get the menu for changing the output mode like in the screenshot (Ubuntu 18.04.5). Did you have a good experience with that? Anyway, the toggle button I proposed in the Python script works quite fast, which is desirable during a conversation. But sure, it is just a homemade tweak I did to complement the original script.

@tvaillantdeguelis

This comment has been minimized.

Copy link

@tvaillantdeguelis tvaillantdeguelis commented Jan 22, 2021

Thanks for your reply.

You said it is currently impossible in Ubuntu. Do you mean it works fine in Windows?

Did you check in the configurations of the extension if there is something to switch on? Maybe your Gnome shell version is too old (< 3.14)? Maybe it only works in Ubuntu 20.04...
Maybe you also need this other Gnome extension in order to make it works: Bluetooth quick connect. I've both installed.

My understanding is that this bash script added to your Python script allow to toggle between the modes in one click while I need 3 clicks with the Gnome extension. I'm willing to try it. Is there any risk to run the bash script (I don't want to break any system file on my PC)? Do you need to run your Python script each time you start a conversation? Do you think your button could appear to the top bar each time I connect my headphones, so the button is always available?

@weslleyspereira

This comment has been minimized.

Copy link

@weslleyspereira weslleyspereira commented Mar 18, 2021

Thanks for your reply.

You said it is currently impossible in Ubuntu. Do you mean it works fine in Windows?

No... I didn't test it on Windows, but it works fine in my iOS

Did you check in the configurations of the extension if there is something to switch on? Maybe your Gnome shell version is too old (< 3.14)? Maybe it only works in Ubuntu 20.04...
Maybe you also need this other Gnome extension in order to make it works: Bluetooth quick connect. I've both installed.

I checked the configurations and I found nothing I could do. Maybe Ubuntu 20.04 solves it, I don't know. I also tried the Gnome extension, it didn't solve the problem.

My understanding is that this bash script added to your Python script allow to toggle between the modes in one click while I need 3 clicks with the Gnome extension. I'm willing to try it. Is there any risk to run the bash script (I don't want to break any system file on my PC)? Do you need to run your Python script each time you start a conversation? Do you think your button could appear to the top bar each time I connect my headphones, so the button is always available?

Yes, they both work. I don't think there is any risk. The scripts just change the mic/phone configurations.
Yes, every time we need to run this script. It was just an exercise to test the switcher. I am pretty sure there is a way to put the button on the top bar, you just need to improve ii :)

@gobenavides

This comment has been minimized.

Copy link

@gobenavides gobenavides commented Mar 19, 2021

Would it be possible to link this script to .bashrc so it immediately launches every time the device gets connected?

@weslleyspereira

This comment has been minimized.

Copy link

@weslleyspereira weslleyspereira commented Mar 19, 2021

Possible? I think so. The question is how to do it in a clean way.

I just googled "run script when bluetooth device plugged in Linux" and found this: https://askubuntu.com/questions/138522/how-do-i-run-a-script-when-a-bluetooth-device-connects. Maybe it helps.
Maybe you could use the same variable BLUETOOTH_DEVICE from @artem328's comment.

@Fuzzphorescent

This comment has been minimized.

Copy link

@Fuzzphorescent Fuzzphorescent commented Apr 5, 2021

Hi!

1. Did you configure the Shell script `switchHeadphones.sh`? In case not, you should. You can do as suggested in the Shell script:
   -- Run `pacmd list-sinks  | grep '\(name:\|alias\)'` and fill with value from alias of your Bluetooth device

2. The error you showed relates to the @artem328's script. Try running `./switchHeadphones.sh speak` then `./switchHeadphones.sh listen` in your terminal and see if everything works. My Python script is only an interface for this nice Shell script.

When I run ./switchHeadphones.sh speak, I get the message F5A headset not found.
How do I fix this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment