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/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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.