Skip to content

Instantly share code, notes, and snippets.

@pylover
Last active August 11, 2024 06:11
Show Gist options
  • Save pylover/d68be364adac5f946887b85e6ed6e7ae to your computer and use it in GitHub Desktop.
Save pylover/d68be364adac5f946887b85e6ed6e7ae to your computer and use it in GitHub Desktop.
Fixing bluetooth stereo headphone/headset problem in ubuntu 16.04, 16.10 and also debian jessie, with bluez5.
#! /usr/bin/env python3
"""Fixing bluetooth stereo headphone/headset problem in debian distros.
Workaround for bug: https://bugs.launchpad.net/ubuntu/+source/indicator-sound/+bug/1577197
Run it with python3.5 or higher after pairing/connecting the bluetooth stereo headphone.
This will be only fixes the bluez5 problem mentioned above .
Licence: Freeware
Install with:
curl "https://gist.githubusercontent.com/pylover/d68be364adac5f946887b85e6ed6e7ae/raw/install.sh" | sh
Shorthands:
$ alias speakers="a2dp.py 10:08:C1:44:AE:BC"
$ alias headphones="a2dp.py 00:22:37:3D:DA:50"
$ alias headset="a2dp.py 00:22:37:F8:A0:77 -p hsp"
$ speakers
See ``a2dp.py -h`` for help.
Check here for updates: https://gist.github.com/pylover/d68be364adac5f946887b85e6ed6e7ae
Thanks to:
* https://github.com/DominicWatson, for adding the ``-p/--profile`` argument.
* https://github.com/IzzySoft, for mentioning wait before connecting again.
* https://github.com/AmploDev, for v0.4.0
* https://github.com/Mihara, for autodetect & autorun service
* https://github.com/dabrovnijk, for systemd service
Change Log
----------
- 0.6.2
* Fix program name inside the help message.
- 0.6.1
* Fix Py warning
- 0.6.0
* Install script
- 0.5.2
* Increasing the number of tries to 15.
- 0.5.2
* Optimizing waits.
- 0.5.1
* Increasing WAIT_TIME and TRIES
- 0.5.0
* Autodetect & autorun service
- 0.4.1
* Sorting device list
- 0.4.0
* Adding ignore_fail argument by @AmploDev.
* Sending all available streams into selected sink, after successfull connection by @AmploDev.
- 0.3.3
* Updating default sink before turning to ``off`` profile.
- 0.3.2
* Waiting a bit: ``-w/--wait`` before connecting again.
- 0.3.0
* Adding -p / --profile option for using the same script to switch between headset and A2DP audio profiles
- 0.2.5
* Mentioning [mac] argument.
- 0.2.4
* Removing duplicated devices in select device list.
- 0.2.3
* Matching ANSI escape characters. Tested on 16.10 & 16.04
- 0.2.2
* Some sort of code enhancements.
- 0.2.0
* Adding `-V/--version`, `-w/--wait` and `-t/--tries` CLI arguments.
- 0.1.1
* Supporting the `[NEW]` prefix for devices & controllers as advised by @wdullaer
* Drying the code.
"""
import sys
import re
import asyncio
import subprocess as sb
import argparse
__version__ = '0.6.2'
HEX_DIGIT_PATTERN = '[0-9A-F]'
HEX_BYTE_PATTERN = '%s{2}' % HEX_DIGIT_PATTERN
MAC_ADDRESS_PATTERN = ':'.join((HEX_BYTE_PATTERN, ) * 6)
DEVICE_PATTERN = re.compile('^(?:.*\s)?Device\s(?P<mac>%s)\s(?P<name>.*)' % MAC_ADDRESS_PATTERN)
CONTROLLER_PATTERN = re.compile('^(?:.*\s)?Controller\s(?P<mac>%s)\s(?P<name>.*)' % MAC_ADDRESS_PATTERN)
WAIT_TIME = 2.25
TRIES = 15
PROFILE = 'a2dp'
_profiles = {
'a2dp': 'a2dp_sink',
'hsp': 'headset_head_unit',
'off': 'off'
}
# CLI Arguments
parser = argparse.ArgumentParser()
parser.add_argument('-e', '--echo', action='store_true', default=False,
help='If given, the subprocess stdout will be also printed on stdout.')
parser.add_argument('-w', '--wait', default=WAIT_TIME, type=float,
help='The seconds to wait for subprocess output, default is: %s' % WAIT_TIME)
parser.add_argument('-t', '--tries', default=TRIES, type=int,
help='The number of tries if subprocess is failed. default is: %s' % TRIES)
parser.add_argument('-p', '--profile', default=PROFILE,
help='The profile to switch to. available options are: hsp, a2dp. default is: %s' % PROFILE)
parser.add_argument('-V', '--version', action='store_true', help='Show the version.')
parser.add_argument('mac', nargs='?', default=None)
# Exceptions
class SubprocessError(Exception):
pass
class RetryExceededError(Exception):
pass
class BluetoothctlProtocol(asyncio.SubprocessProtocol):
def __init__(self, exit_future, echo=True):
self.exit_future = exit_future
self.transport = None
self.output = None
self.echo = echo
def listen_output(self):
self.output = ''
def not_listen_output(self):
self.output = None
def pipe_data_received(self, fd, raw):
d = raw.decode()
if self.echo:
print(d, end='')
if self.output is not None:
self.output += d
def process_exited(self):
self.exit_future.set_result(True)
def connection_made(self, transport):
self.transport = transport
print('Connection MADE')
async def send_command(self, c):
stdin_transport = self.transport.get_pipe_transport(0)
# noinspection PyProtectedMember
stdin_transport._pipe.write(('%s\n' % c).encode())
async def search_in_output(self, expression, fail_expression=None):
if self.output is None:
return None
for l in self.output.splitlines():
if fail_expression and re.search(fail_expression, l, re.IGNORECASE):
raise SubprocessError('Expression "%s" failed with fail pattern: "%s"' % (l, fail_expression))
if re.search(expression, l, re.IGNORECASE):
return True
async def send_and_wait(self, cmd, wait_expression, fail_expression='fail'):
try:
self.listen_output()
await self.send_command(cmd)
while not await self.search_in_output(wait_expression.lower(), fail_expression=fail_expression):
await wait()
finally:
self.not_listen_output()
async def disconnect(self, mac):
print('Disconnecting the device.')
await self.send_and_wait('disconnect %s' % ':'.join(mac), 'Successful disconnected')
async def connect(self, mac):
print('Connecting again.')
await self.send_and_wait('connect %s' % ':'.join(mac), 'Connection successful')
async def trust(self, mac):
await self.send_and_wait('trust %s' % ':'.join(mac), 'trust succeeded')
async def quit(self):
await self.send_command('quit')
async def get_list(self, command, pattern):
result = set()
try:
self.listen_output()
await self.send_command(command)
await wait()
for l in self.output.splitlines():
m = pattern.match(l)
if m:
result.add(m.groups())
return sorted(list(result), key=lambda i: i[1])
finally:
self.not_listen_output()
async def list_devices(self):
return await self.get_list('devices', DEVICE_PATTERN)
async def list_paired_devices(self):
return await self.get_list('paired-devices', DEVICE_PATTERN)
async def list_controllers(self):
return await self.get_list('list', CONTROLLER_PATTERN)
async def select_paired_device(self):
print('Selecting device:')
devices = await self.list_paired_devices()
count = len(devices)
if count < 1:
raise SubprocessError('There is no connected device.')
elif count == 1:
return devices[0]
for i, d in enumerate(devices):
print('%d. %s %s' % (i+1, d[0], d[1]))
print('Select device[1]:')
selected = input()
return devices[0 if not selected.strip() else (int(selected) - 1)]
async def wait(delay=None):
return await asyncio.sleep(WAIT_TIME or delay)
async def execute_command(cmd, ignore_fail=False):
p = await asyncio.create_subprocess_shell(cmd, stdout=sb.PIPE, stderr=sb.PIPE)
stdout, stderr = await p.communicate()
stdout, stderr = \
stdout.decode() if stdout is not None else '', \
stderr.decode() if stderr is not None else ''
if p.returncode != 0 or stderr.strip() != '':
message = 'Command: %s failed with status: %s\nstderr: %s' % (cmd, p.returncode, stderr)
if ignore_fail:
print('Ignoring: %s' % message)
else:
raise SubprocessError(message)
return stdout
async def execute_find(cmd, pattern, tries=0, fail_safe=False):
tries = tries or TRIES
message = 'Cannot find `%s` using `%s`.' % (pattern, cmd)
retry_message = message + ' Retrying %d more times'
while True:
stdout = await execute_command(cmd)
match = re.search(pattern, stdout)
if match:
return match.group()
elif tries > 0:
await wait()
print(retry_message % tries)
tries -= 1
continue
if fail_safe:
return None
raise RetryExceededError('Retry times exceeded: %s' % message)
async def find_dev_id(mac, **kw):
return await execute_find('pactl list cards short', 'bluez_card.%s' % '_'.join(mac), **kw)
async def find_sink(mac, **kw):
return await execute_find('pacmd list-sinks', 'bluez_sink.%s' % '_'.join(mac), **kw)
async def set_profile(device_id, profile):
print('Setting the %s profile' % profile)
try:
return await execute_command('pactl set-card-profile %s %s' % (device_id, _profiles[profile]))
except KeyError:
print('Invalid profile: %s, please select one one of a2dp or hsp.' % profile, file=sys.stderr)
raise SystemExit(1)
async def set_default_sink(sink):
print('Updating default sink to %s' % sink)
return await execute_command('pacmd set-default-sink %s' % sink)
async def move_streams_to_sink(sink):
streams = await execute_command('pacmd list-sink-inputs | grep "index:"', True)
for i in streams.split():
i = ''.join(n for n in i if n.isdigit())
if i != '':
print('Moving stream %s to sink' % i)
await execute_command('pacmd move-sink-input %s %s' % (i, sink))
return sink
async def main(args):
global WAIT_TIME, TRIES
if args.version:
print(__version__)
return 0
mac = args.mac
# Hacking, Changing the constants!
WAIT_TIME = args.wait
TRIES = args.tries
exit_future = asyncio.Future()
transport, protocol = await asyncio.get_event_loop().subprocess_exec(
lambda: BluetoothctlProtocol(exit_future, echo=args.echo), 'bluetoothctl'
)
try:
if mac is None:
mac, _ = await protocol.select_paired_device()
mac = mac.split(':' if ':' in mac else '_')
print('Device MAC: %s' % ':'.join(mac))
device_id = await find_dev_id(mac, fail_safe=True)
if device_id is None:
print('It seems device: %s is not connected yet, trying to connect.' % ':'.join(mac))
await protocol.trust(mac)
await protocol.connect(mac)
device_id = await find_dev_id(mac)
sink = await find_sink(mac, fail_safe=True)
if sink is None:
await set_profile(device_id, args.profile)
sink = await find_sink(mac)
print('Device ID: %s' % device_id)
print('Sink: %s' % sink)
await set_default_sink(sink)
await wait()
await set_profile(device_id, 'off')
if args.profile == 'a2dp':
await protocol.disconnect(mac)
await wait()
await protocol.connect(mac)
device_id = await find_dev_id(mac)
print('Device ID: %s' % device_id)
await wait(2)
await set_profile(device_id, args.profile)
await set_default_sink(sink)
await move_streams_to_sink(sink)
except (SubprocessError, RetryExceededError) as ex:
print(str(ex), file=sys.stderr)
return 1
finally:
print('Exiting bluetoothctl')
await protocol.quit()
await exit_future
# Close the stdout pipe
transport.close()
if args.profile == 'a2dp':
print('"Enjoy" the HiFi stereo music :)')
else:
print('"Enjoy" your headset audio :)')
if __name__ == '__main__':
sys.exit(asyncio.get_event_loop().run_until_complete(main(parser.parse_args())))
#!/usr/bin/python
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import gobject
import subprocess
import time
# Where you keep the above script. Must be executable, obviously.
A2DP = '/home/mihara/.local/bin/a2dp'
# A list of device IDs that you wish to run it on.
DEV_IDS = ['00:18:09:30:FC:D8','FC:58:FA:B1:2D:25']
device_paths = []
devices = []
dbus_loop = DBusGMainLoop()
bus = dbus.SystemBus(mainloop=dbus_loop)
def generate_handler(device_id):
last_ran = [0] # WHOA, this is crazy closure behavior: A simple variable does NOT work.
def cb(*args, **kwargs):
if args[0] == 'org.bluez.MediaControl1':
if args[1].get('Connected'):
print("Connected {}".format(device_id))
if last_ran[0] < time.time() - 120:
print("Fixing...")
subprocess.call([A2DP,device_id])
last_ran[0] = time.time()
else:
print("Disconnected {}".format(device_id))
return cb
# Figure out the path to the headset
man = bus.get_object('org.bluez', '/')
iface = dbus.Interface(man, 'org.freedesktop.DBus.ObjectManager')
for device in iface.GetManagedObjects().keys():
for id in DEV_IDS:
if device.endswith(id.replace(':','_')):
device_paths.append((id, device))
for id, device in device_paths:
headset = bus.get_object('org.bluez', device)
headset.connect_to_signal("PropertiesChanged", generate_handler(id), dbus_interface='org.freedesktop.DBus.Properties')
devices.append(headset)
loop = gobject.MainLoop()
loop.run()
[Unit]
Description=Fix BT Speaker
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/fix-bt.py
[Install]
WantedBy=multi-user.target
#! /usr/bin/env bash
URL="https://gist.githubusercontent.com/pylover/d68be364adac5f946887b85e6ed6e7ae/raw/a2dp.py"
TARGET=/usr/local/bin/a2dp.py
curl $URL | sudo tee ${TARGET} > /dev/null
sudo chmod +x $TARGET
echo "a2dp installation was successfull."
echo "Run a2dp.py [-h/--help] and enjoy the HiFi music!"
@arsinclair
Copy link

The issue with my Jabra Elite 75t was something like:

Cannot find bluez_card.00_5A_5A_A6_00_CF using pactl list cards short. Retrying 6 more times

The headset would be connected in Bluetooth manager successfully, but the audio interface wouldn't appear. Turns out, the only supported by the device protocol is not immediately available in my debian 10 KDE. However, based on this reddit thread https://www.reddit.com/r/Jabra/comments/j5489d/if_you_use_jabra_earbuds_with_linux_you_need_to I've found that someone has made a package integrating this stuff - available in https://github.com/EHfive/pulseaudio-modules-bt. The package is deprecated as maintainer now switched to PipeWire (and it supports the codec), but I've built pulseaudio-modules-bt and installed it on my debian, and it still works perfectly.

Someone even made an installer here https://github.com/lagerimsi-ds/debian-buster_bluetooth_aptX-LDAC, but use it with caution.

@moorepants
Copy link

I'm getting this failure:

Ignoring: Command: pacmd list-sink-inputs | grep "index:" failed with status: 1
stderr:

Running that command gives:

$ pacmd list-sink-inputs
0 sink input(s) available.

The headset is connected, ubuntu settings show the headset selected with a2dp sink, but the sound continues to come out of my speakers that are connected by traditional audio cable to my sound card.

@juliolopeztorres
Copy link

Already tried in various version of kubuntu and always did the trick. Thank you for sharing!

@rvelascop
Copy link

Cara muito obrigado, resolvido aqui! Se eu tivesse dinheiro para te pagar pela solução eu te mandaria, mas só tenho gratidão para lhe dar. Muito obrigado!

@pylover
Copy link
Author

pylover commented Oct 6, 2023

@rvelascop, Glad.
You are welcome, man!

Open source is about sharing everything—no money needed. We're helping each other to make a better world.

@aniruddha81
Copy link

bro tnx for it. but it is required to run this script everytime i connect the earbuds..is there any other way that i can permanently solve this?

@pylover
Copy link
Author

pylover commented Dec 29, 2023

@aniruddha564, A fix-bt.py script is already available in this page, Thanks to https://github.com/Mihara.

@aniruddha81
Copy link

aniruddha81 commented Dec 29, 2023

@aniruddha564, A fix-bt.py script is already available in this page, Thanks to https://github.com/Mihara.

@pylover actually brother, i am fully newbee to linux and also in github... i don't know anything about running scripts..so can you please guide me to run that file?

@aniruddha81
Copy link

bro how to uninstall this program?

@DominicWatson
Copy link

@aniruddha564 All the installation does is to create the file /usr/local/bin/a2dp.py. This file will do nothing unless you explicitly call it somehow, e.g. from a terminal:

$ a2dp.py

Or from some other launcher like a custom keyboard shortcut.

If you wish to uninstall it, you could do so from the terminal with:

$ sudo rm /usr/local/bin/a2dp.py

@Kreijstal
Copy link

Kreijstal commented Feb 9, 2024

@samds49 mine is very simmilar:

╰─➤  python3 ./a2dp.py
./a2dp.py:365: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if args.profile is 'a2dp':
Connection MADE
Selecting device:
Device MAC: 00:5A:5A:A6:00:CF
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 15 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 14 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 13 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 12 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 11 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 10 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 9 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 8 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 7 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 6 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 5 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 4 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 3 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 2 more times
Cannot find `bluez_card.00_5A_5A_A6_00_CF` using `pactl list cards short`. Retrying 1 more times
It seems device: 00:5A:5A:A6:00:CF is not connected yet, trying to connect.
Connecting again.
Expression "Failed to connect: org.bluez.Error.Failed" failed with fail pattern: "fail"
Exiting bluetoothctl

This is on a freshly installed Linux Mint 20.1

I got the same issue linux mint 21.3 nothing has changed eh, the a2dp unfixes the fix when you use

sudo dpkg-reconfigure bluez
sudo dpkg-reconfigure linux-sound-base

For example, right now I have sound and it works. Then I do a2dpy, and the following happens.

kreijstal@kreijstalnuc:~$ pactl list sinks short
5       bluez_sink.E8_AB_FA_40_25_3B.a2dp_sink  module-bluez5-device.c  s16le 2ch 48000Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ a2dp.py
Connection MADE
Selecting device:
Device MAC: E8:AB:FA:40:25:3B
Device ID: bluez_card.E8_AB_FA_40_25_3B
Sink: bluez_sink.E8_AB_FA_40_25_3B
Updating default sink to bluez_sink.E8_AB_FA_40_25_3B
Setting the off profile
Disconnecting the device.
Connecting again.
Cannot find `bluez_card.E8_AB_FA_40_25_3B` using `pactl list cards short`. Retrying 15 more times
Cannot find `bluez_card.E8_AB_FA_40_25_3B` using `pactl list cards short`. Retrying 14 more times
Cannot find `bluez_card.E8_AB_FA_40_25_3B` using `pactl list cards short`. Retrying 13 more times
Cannot find `bluez_card.E8_AB_FA_40_25_3B` using `pactl list cards short`. Retrying 12 more times

So running the script unfixes the situation, do no harm, eh?

@Kreijstal
Copy link

just something I am testing

kreijstal@kreijstalnuc:~$ pactl list sinks short
Verbindungsfehler: Verbindung verweigert
pa_context_new() fehlgeschlagen: Verbindung verweigert
kreijstal@kreijstalnuc:~$ pulseaudio -D
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       IDLE
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       IDLE
kreijstal@kreijstalnuc:~$ pkill pulseaudio
pkill: Abwürgen von Prozess-ID 5970 fehlgeschlagen: Vorgang nicht zulässig
kreijstal@kreijstalnuc:~$ pactl list sinks short
Verbindungsfehler: Verbindung verweigert
pa_context_new() fehlgeschlagen: Verbindung verweigert
kreijstal@kreijstalnuc:~$ sudo pulseaudio -D
[sudo] Passwort für kreijstal:
W: [pulseaudio] main.c: Dieses Programm sollte ohne die Option --system nicht als Administrator ausgeführt werden.
kreijstal@kreijstalnuc:~$ pactl list sinks short
Verbindungsfehler: Verbindung verweigert
pa_context_new() fehlgeschlagen: Verbindung verweigert
kreijstal@kreijstalnuc:~$ pulseaudio -D
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       IDLE
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       IDLE
kreijstal@kreijstalnuc:~$ sudo pulseaudio -D^C
kreijstal@kreijstalnuc:~$ sudo dpkg-reconfigure linux-sound-base
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ sudo dpkg-reconfigure bluez
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ pactl list sinks short
1       bluez_sink.E8_AB_FA_40_25_3B.handsfree_head_unit        module-bluez5-device.c  s16le 1ch 16000Hz       IDLE
kreijstal@kreijstalnuc:~$ pactl list sinks short
1       bluez_sink.E8_AB_FA_40_25_3B.handsfree_head_unit        module-bluez5-device.c  s16le 1ch 16000Hz       IDLE
kreijstal@kreijstalnuc:~$ pactl list sinks short
1       bluez_sink.E8_AB_FA_40_25_3B.handsfree_head_unit        module-bluez5-device.c  s16le 1ch 16000Hz       IDLE
kreijstal@kreijstalnuc:~$ echo we have now audio
we have now audio
kreijstal@kreijstalnuc:~$ pulseaudio -k
kreijstal@kreijstalnuc:~$ pulseaudio -D
kreijstal@kreijstalnuc:~$ pactl list sinks short
0       auto_null       module-null-sink.c      s16le 2ch 44100Hz       IDLE
kreijstal@kreijstalnuc:~$ echo we have no audio
we have no audio

@Kreijstal
Copy link

Kreijstal commented Feb 9, 2024

sledge hammer solution, experts please help

kreijstal@kreijstalnuc:~$ pactl list sources short
13      bluez_sink.E8_AB_FA_40_25_3B.handsfree_head_unit.monitor        module-bluez5-device.c  s16le 1ch 16000Hz       SUSPENDED
14      bluez_source.E8_AB_FA_40_25_3B.handsfree_head_unit      module-bluez5-device.c  s16le 1ch 16000Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ bluetoothctl
Agent registered
[TaoTronics SoundSurge 90]# disconnect E8:AB:FA:40:25:3B
Attempting to disconnect from E8:AB:FA:40:25:3B
Successful disconnected
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B Connected: no
[bluetooth]# isconnect E8:AB:FA:40:25:3B
[bluetooth]# exit
kreijstal@kreijstalnuc:~$ rm -rf /var/lib/blue
blueman/   bluetooth/
kreijstal@kreijstalnuc:~$ rm -rf /var/lib/blue
blueman/   bluetooth/
kreijstal@kreijstalnuc:~$ sudo rm -rf /var/lib/bluetooth/
kreijstal@kreijstalnuc:~$ pacmd set-card-profile 1 handsfree_head_unit^C
kreijstal@kreijstalnuc:~$ sudo dpkg-reconfigure bluez
Job for bluetooth.service failed because the control process exited with error code.
See "systemctl status bluetooth.service" and "journalctl -xeu bluetooth.service" for details.
invoke-rc.d: initscript bluetooth, action "restart" failed.
● bluetooth.service - Bluetooth service
     Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset: enabled)
     Active: activating (auto-restart) (Result: exit-code) since Fri 2024-02-09 16:13:46 CET; 25ms ago
       Docs: man:bluetoothd(8)
    Process: 51980 ExecStart=/usr/lib/bluetooth/bluetoothd (code=exited, status=226/NAMESPACE)
   Main PID: 51980 (code=exited, status=226/NAMESPACE)
        CPU: 4ms
kreijstal@kreijstalnuc:~$ sudo mkdir /var/lib/bluetooth/
kreijstal@kreijstalnuc:~$ ls
Bilder  CytoscapeConfiguration  Downloads  go       micromamba  OldRunescapeSoundtrack_vbr.m3u  Schreibtisch  thinclient_drives  Videos
bin     Dokumente               git        LICENSE  Musik       Passwörter.kdbx                 tar           Untitled.ipynb     Vorlagen
kreijstal@kreijstalnuc:~$ bluetoothctl
Waiting to connect to bluetoothd...
kreijstal@kreijstalnuc:~$ sudo service bluetooth restart
kreijstal@kreijstalnuc:~$ bluetoothctl
Agent registered
[bluetooth]# scan
☺☻Missing on/off/bredr/le argument☺☻
[bluetooth]# scan on
Discovery started
[☺☻CHG☺☻] Controller B0:DC:EF:9E:2B:35 Discovering: yes
[☺☻NEW☺☻] Device 48:74:12:56:42:1A OnePlus 10 Pro 5G
[☺☻NEW☺☻] Device 2F:E0:1C:4C:5E:C0 2F-E0-1C-4C-5E-C0
[☺☻NEW☺☻] Device 00:1A:7D:DA:71:15 LPT-FFO-00-0134
[☺☻NEW☺☻] Device E8:AB:FA:40:25:3B TaoTronics SoundSurge 90
[☺☻NEW☺☻] Device D4:D7:CF:2C:B3:B2 D4-D7-CF-2C-B3-B2
[☺☻CHG☺☻] Device 2F:E0:1C:4C:5E:C0 Name: DQ-M2
[☺☻CHG☺☻] Device 2F:E0:1C:4C:5E:C0 Alias: DQ-M2
[☺☻CHG☺☻] Device 2F:E0:1C:4C:5E:C0 ManufacturerData Key: 0x5754
[☺☻CHG☺☻] Device 2F:E0:1C:4C:5E:C0 ManufacturerData Value:
  53 4d 4f aa 58                                   SMO.X
[bluetooth]# pair E8:AB:FA:40:25:3B
Attempting to pair with E8:AB:FA:40:25:3B
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B Connected: yes
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B UUIDs: 0000110b-0000-1000-8000-00805f9b34fb
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B UUIDs: 0000111e-0000-1000-8000-00805f9b34fb
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B ServicesResolved: yes
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B Paired: yes
Pairing successful
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B ServicesResolved: no
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B Connected: no
[bluetooth]# connect E8:AB:FA:40:25:3B
Attempting to connect to E8:AB:FA:40:25:3B
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B Connected: yes
Connection successful
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B ServicesResolved: yes
[TaoTronics SoundSurge 90]# trust E8:AB:FA:40:25:3B
[☺☻CHG☺☻] Device E8:AB:FA:40:25:3B Trusted: yes
Changing E8:AB:FA:40:25:3B trust succeeded
[TaoTronics SoundSurge 90]# exit
kreijstal@kreijstalnuc:~$ pactl list sinks short
11      bluez_sink.E8_AB_FA_40_25_3B.a2dp_sink  module-bluez5-device.c  s16le 2ch 44100Hz       SUSPENDED
kreijstal@kreijstalnuc:~$ it works now, wow, was that hard?

I have to do this party trick almost every day lol

kreijstal@kreijstalnuc:~$ a2dp.py
Connection MADE
Selecting device:
Device MAC: E8:AB:FA:40:25:3B
Device ID: bluez_card.E8_AB_FA_40_25_3B
Sink: bluez_sink.E8_AB_FA_40_25_3B
Updating default sink to bluez_sink.E8_AB_FA_40_25_3B
Setting the off profile
Disconnecting the device.
Connecting again.
Device ID: bluez_card.E8_AB_FA_40_25_3B
Setting the a2dp profile
Updating default sink to bluez_sink.E8_AB_FA_40_25_3B
Moving stream 1 to sink
Moving stream 2 to sink
Exiting bluetoothctl
"Enjoy" the HiFi stereo music :)
kreijstal@kreijstalnuc:~$

Ok, but we know it can also do microphone just like before, let us try it.

kreijstal@kreijstalnuc:~$ a2dp.py -p hsp
Connection MADE
Selecting device:
Device MAC: E8:AB:FA:40:25:3B
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 15 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 14 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 13 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 12 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 11 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 10 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 9 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 8 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 7 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 6 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 5 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 4 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 3 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 2 more times
Cannot find `bluez_sink.E8_AB_FA_40_25_3B` using `pacmd list-sinks`. Retrying 1 more times
Setting the hsp profile
Command: pactl set-card-profile bluez_card.E8_AB_FA_40_25_3B headset_head_unit failed with status: 1
stderr: Fehlgeschlagen: Entität nicht vorhanden

Exiting bluetoothctl

huh, so now I can not do audio calls? but before I could :(

@Kreijstal
Copy link

i just need to start pipewire service locally, not glboally, so no pulseaudio, right, systemctl --user status pipewire should fix pactl lists not being available, right?

@Kreijstal
Copy link

so everytime I restarted pactl list was unavailable because pipewire pulseaudio was masked,

sudo apt update
sudo apt install --reinstall pipewire pipewire-pulse pipewire-audio-client-libraries

after this noo other tricks ever worked and audio never worked again and I gave up, I could uninstall and reinstall pulseaudio but I cant bother.

@Kreijstal
Copy link

Kreijstal commented Feb 11, 2024

I kinda solved it, these were the steps...

upgraded to latest version pipewire ppa
remove blueman
edit /etc/bluetooth/audio.conf

~$ cat /etc/bluetooth/audio.conf
[General]
Enable=Control,Gateway,Headset,Media,Sink,Socket,Source

mv .config/systemd to .config/systemd.backup
uninstall https://old.reddit.com/r/pop_os/comments/ol9nxx/installing_latest_pipewire_with_working_bluetooth/
install wireplumber
sudo rm /etc/systemd/user/pipewire-media-session.service

systemctl --user --now enable wireplumber.service
systemctl --user start wireplumber.service

sudo rm -rf /var/lib/bluetooth/*
DEVICE_MAC=$(bluetoothctl devices | awk '/Device/{print $2}')
# Step 5: Pair, trust, and connect to the Bluetooth device
echo "Pairing, trusting, and connecting to the Bluetooth device..."
echo -e "pair $DEVICE_MAC\ntrust $DEVICE_MAC\nconnect $DEVICE_MAC\nquit" | bluetoothctl

New problems: Now it is either a2p or hfp , cant switch, but now I get 3 different profiles..
Profile:
off: Off (Ziele: 0, Quellen: 0, Priorität: 0, verfügbar: ja)
a2dp-sink-sbc: High Fidelity Playback (A2DP Sink, codec SBC) (Ziele: 1, Quellen: 0, Priorität: 18, verfügbar: ja)
a2dp-sink-sbc_xq: High Fidelity Playback (A2DP Sink, codec SBC-XQ) (Ziele: 1, Quellen: 0, Priorität: 17, verfügbar: ja)
a2dp-sink: High Fidelity Playback (A2DP Sink, codec AAC) (Ziele: 1, Quellen: 0, Priorität: 19, verfügbar: ja)
Aktives Profil: a2dp-sink
```

remove bluetooth reconenct and pray you get the hfp profile
Settings
└─ Default Configured Node Names:
0. Audio/Sink bluez_output.E8_AB_FA_40_25_3B.headset-head-unit
kreijstal@kreijstalnuc:~$ pactl list sinks short
165 bluez_output.E8_AB_FA_40_25_3B.headset-head-unit PipeWire s16le 1ch 16000Hz RUNNING

It's either stuck on headset-head-unit or a2dp-sink, only with wireplumber, things worked before, but oh well. omg

@Kreijstal
Copy link

after installing blueman again
powering off and on the headphones, I get..
grafik
linux is not for the weak of mind

@Kreijstal
Copy link

so I rebooted and sound was gone again, and I perfomed my daily ritual of trying random commands to see what sticks to the wall, I dont like casting

sudo dpkg-reconfigure bluez
sudo dpkg-reconfigure linux-sound-base

but it seems in this case that did the trick along with other things.. let's see if it survives this reboot,

@Kreijstal
Copy link

everything was fixed with Mint 22. Finally.

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