Create a gist now

Instantly share code, notes, and snippets.

@pylover /a2dp.py
Last active Aug 17, 2017

What would you like to do?
Fixing bluetooth stereo headphone/headset problem in ubuntu 16.04, 16.10 and also debian jessie, with bluez5.
#! /usr/bin/env python3.5
"""
Fixing bluetooth stereo headphone/headset problem in ubuntu 16.04 and also debian jessie, with bluez5.
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
See ``python3.5 a2dp.py -h``.
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
Check here for the latest 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.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.5.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(prog=sys.argv[0])
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 is '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

Thanks @pylover, you made my day!

Owner

pylover commented Sep 13, 2016 edited

After two years of disconnectiong & reconnectin my headset manually about 6-7 times per day, i decided to throw the pain away, for ever.
Anyway.

I am so happy if it's useful for you.
Feel free to edit and enhance it.

Thank you so, so much!

I am on a fresh Linux Mint installation and I am encountering the problem described here: http://askubuntu.com/questions/763539/bluetooth-speaker-no-sound-in-ubuntu-16-04

This script is a great workaround. I don't have to switch off and back on my headphones any more.

Thank you!

herrfz commented Sep 25, 2016 edited

Without the main function this could actually be an async/await-based library for interacting with bluetoothctl ... brilliant!

Owner

pylover commented Sep 25, 2016

@herrfz, yes

Interacting with sub-processes is always headache. Feeding stdin and waiting for stdout while observing stderr for unexpected situations.

So the python asyncio facility is very useful.

Thanks for complement.

tavurth commented Sep 29, 2016 edited

Great script, fixed my issue for bluetooth headphones MDR-ZX770BT. Thanks @pylover!

Anuj8826 commented Oct 1, 2016

Man u are a savior, thanks bro #<3 python

dginev commented Oct 4, 2016

Thanks @pylover this gist is a major convenience boost for me. Do you have any advice who/where to ping to resolve the mainline issue?

Ubuntu 16.10 changed the way the bluetooth details are outputted. They are now prefixed by [NEW]
You need to change line 105 to

m = re.match(r'^.*Device\s(?P<mac>[:A-F0-9]{17})\s(?P<name>.*)', l)

And line 119 to

m = re.match(r'^.*Controller\s(?P<mac>[:A-F0-9]{17})\s(?P<name>.*)', l)

I'd make the regex stricter, but I couldn't get the matching to work on the square brackets (not a python guru)

Owner

pylover commented Oct 20, 2016

@wdullaer: the code just updated, please confirm the new version: 0.1.1 is working on 16.10.

Thanks in advance.

I am using Ubuntu-Gnome 16.10 and get the following when a2dp.py -e:

Connection MADE
Selecting device:
[bluetooth]# deviceso bluetoothd...
[NEW] Controller 5C:F3:70:68:D9:1B desktop [default]
[NEW] Device FC:F1:52:1E:DB:99 MDR-ZX750BN
[bluetooth]# There is no connected device.
Exiting bluetoothctl
[MDR-ZX750BN]# quit
[DEL] Controller 5C:F3:70:68:D9:1B desktop [default]
Owner

pylover commented Oct 21, 2016

@RobbieFM: Thanks a lot.

So the current version(0.2.2) must working. Could you please confirm it ?

sorry, still not working:

./bin/a2dp.py 
Connection MADE
Selecting device:
There is no connected device.
Exiting bluetoothctl
bluetoothctl 
[NEW] Controller 5C:F3:70:68:D9:1B desktop [default]
[NEW] Device FC:F1:52:1E:DB:99 MDR-ZX750BN
[bluetooth]# 
Owner

pylover commented Oct 21, 2016

@RobbieFM: Please pair and connect your headset before running this script.

The Sony headset MDR-ZX750BN was paired and connected. I can switch to a2dp by first settings the profile to HSP/Hfp profile, then disconnect and reconnect via blueman, then I can switch to a2dp. I was hoping your script would automate this.

If you need me to test anything, just let me know.

I have a Sony headset MDR-ZX750BN and Sony speaker Srs-x33 to test with.

Owner

pylover commented Oct 22, 2016

@RobbieFM, Interesting, thanks a lot for feedback.

I have no ubuntu 16.10 installed, so wait to i download, install & test it.

Owner

pylover commented Oct 23, 2016 edited

@RobbieFM, it's fixed on 0.2.3.

Thanks a lot for reporting.

@pylover, sorry still not working. I do get new errors:

Connection MADE
Selecting device:
Device MAC: FC:F1:52:1E:DB:99
Cannot find bluez_sink.FC_F1_52_1E_DB_99 using pacmd list-sinks. Retrying 8 more times
Cannot find bluez_sink.FC_F1_52_1E_DB_99 using pacmd list-sinks. Retrying 7 more times
Cannot find bluez_sink.FC_F1_52_1E_DB_99 using pacmd list-sinks. Retrying 6 more times
Cannot find bluez_sink.FC_F1_52_1E_DB_99 using pacmd list-sinks. Retrying 5 more times
Cannot find bluez_sink.FC_F1_52_1E_DB_99 using pacmd list-sinks. Retrying 4 more times
Cannot find bluez_sink.FC_F1_52_1E_DB_99 using pacmd list-sinks. Retrying 3 more times
Cannot find bluez_sink.FC_F1_52_1E_DB_99 using pacmd list-sinks. Retrying 2 more times
Cannot find bluez_sink.FC_F1_52_1E_DB_99 using pacmd list-sinks. Retrying 1 more times
Command: pactl set-card-profile bluez_card.FC_F1_52_1E_DB_99 a2dp_sink failed with status: 1
stderr: Mislukt: Invoer-/Uitvoerfout (I/O)

Exiting bluetoothctl

Ps. thanks for your very quick responses

Owner

pylover commented Oct 24, 2016 edited

It's may be something else, here is working well on ubuntu 16.10.

So, ensure the headset is shown on sound control. increasing wait time -w and tries -t. may help.

Run pacmd list-sinks manually to ensure the sink is created.

You can't imagine how much I appreciate this! Thanks a lot mate, big help!

Owner

pylover commented Nov 8, 2016

@romanovzky, Thanks for comment.

MoonDogg commented Nov 9, 2016

I can confirm this working on GalliumOS 2.0 (Xubuntu 16.04) on a Acer C720. Thanks!! My only issue is that I have if I disconnect my headset and reconnect I have to delete it and re-pair and rerun script for it to work again. Any suggestions?

Owner

pylover commented Nov 9, 2016 edited

@MoonDogg, This script is written to prevent manualy turning off, and connection again. so if it's not working, as well as i told you. there are some problems.

MoonDogg commented Nov 9, 2016

I think it was a miss communication... it works... I meant after I turn my device off and then go to reconnect it later... it connects but not working in A2PD if I re-run the script it works fine. Is there a way to make the script run automatically every time I connect a A2DP device?

AJMaxwell commented Nov 9, 2016 edited

I get the following error when running this...

`python3.5 a2dp.py
Connection MADE
Selecting device:
Device MAC: 00:02:5B:00:2E:43
Device ID: bluez_card.00_02_5B_00_2E_43
Sink: bluez_sink.00_02_5B_00_2E_43
Turning off audio profile.
Disconnecting the device.
Connecting again.
Setting A2DP profile
Device ID: bluez_card.00_02_5B_00_2E_43
Command: pactl set-card-profile bluez_card.00_02_5B_00_2E_43 a2dp_sink failed with status: 1
stderr: Failure: Input/Output error

Exiting bluetoothctl`

Owner

pylover commented Nov 10, 2016 edited

@AJMaxwell

It relates to pactl set-card-profile bluez_card.00_02_5B_00_2E_43 a2dp_sink, run and troubleshoot it manualy.

Make sure to another bluetooth device is not trying to connect to your host.
Try to get working HSP/HFP profile. before running this script.

This script will only works if your headset is acting well on HSP/HFP profile.

Owner

pylover commented Nov 10, 2016

@MoonDogg, Good idea, but how ?

@pylover, I was hoping you would know. :P I am going to do some research see if I can figure it out. I will let you know what I find.

@pylover, I found this.. http://askubuntu.com/questions/138522/how-do-i-run-a-script-when-a-bluetooth-device-connects and it uses this script ( https://github.com/yxlao/bluetooth-runner ) when a blue-tooth device connects.. I just don't know the syntax to edit it to call your script. Maybe you could modify it?

Owner

pylover commented Nov 10, 2016

@MoonDogg, Thanks a lot

Thank you! This is great, works flawlessly :)

@pylover are you editing the script I linked to call your script or are you incorporating it into your script? Either way let me know and I can test it out for you. Thanks for you help.

Owner

pylover commented Nov 14, 2016

@MoonDogg, i'll do it in the next a few days . thanks a lot for contribution

This script saves me from a giant headache I was suffering through on a daily basis. You are THE MAN @pylover!!

edelreal commented Nov 25, 2016 edited

Wonderful workaround, thanks!

I've posted details of my debugging attempts to https://bugs.freedesktop.org/show_bug.cgi?id=92102 ;
perhaps it is something pulseaudio can learn to handle (unless this is a bug that needs to fixed in bluez instead).

Owner

pylover commented Nov 25, 2016

@edelreal Thanks a lot for following.

3 years of Connecting/deconnecting were just solved. Thank you @pylover .

Baldrs commented Dec 6, 2016

Kind thanks for this script kind sirs! You have saved my from six month struggle with bluetooth on my laptop!

Thanks Sir Awesome!

One great addition would be using pactl subsribe to automatically perform this when a device is connected.

Owner

pylover commented Dec 8, 2016

@peteruithoven thanks a lot

Hi look at

> jonathan@jonathan-desktop:~/d68be364adac5f946887b85e6ed6e7ae$ python a2dp.py 
>   File "a2dp.py", line 118
>     print(d, end='')
>                 ^
> SyntaxError: invalid syntax

how can fix this

Owner

pylover commented Dec 12, 2016 edited

Use python 3.5 or higher

ok thanks for use python 3.5

nano ~/.bashrc
alias python=python3.5
source ~/.bashrc

and working

hi pylover

also getting
Setting A2DP profile Device ID: bluez_card.0C_E0_E4_6B_48_AB Command: pactl set-card-profile bluez_card.0C_E0_E4_6B_48_AB a2dp_sink failed with status: 1 stderr: Failure: Input/Output error
my bluetooth device when connected:
https://dpaste.de/bZk6

any ideas?

Owner

pylover commented Dec 16, 2016

Your headset is not connected well as well. check /var/log/syslog

Maaaan! Thanks!!! I wasted my whole afternoon with this shit. God. Just a chmod u+x a2dp.py && mv a2dp.py ~/.bin/speakers and everything's good to go. Working on Lubuntu 16.04.1.

Works great in ubuntu 16.04.1, thank you so much

Thanks, worked perfectly!

Awesome. Works like a charm. Thank you!

Thanks a lot! Confirmed working on Linux Mint Sarah (is also ubuntu 16.04.1but you never know)

dcbeckett commented Jan 9, 2017 edited

I also got the following error Command: pactl set-card-profile bluez_card..... a2dp_sink failed with status: 1 error

The issue was was my plantronics backbeat pro headset being slow to re-connect (mostly due to it crashing and restarting), just had to add in a longer wait time of longer than 7 seconds (obviously headset dependent)

e.g. for 7 seconds wait
python3.5 a2dp.py -w 7

oofnikj commented Jan 9, 2017 edited

Hi,
Very cool script, thanks 👍
I had a problem where my device connected automatically with 'off' profile, which meant that it did not appear in pacmd list-sinks.
So I modified the code a little bit to connect in HSP/HFP mode and then look for the sink again.
Now it works flawlessly. I launch the script with a keyboard shortcut when I turn on my speakers.
Running Xubuntu 16.04.
Cheers

wayne003 commented Jan 9, 2017

Life saver!

has anyone gotten the mic in the bluetooth headphones to work the system sees it but gets no input

Thank you so much!

bill-mavromatis commented Jan 18, 2017 edited

Works like a charm @ Lubuntu 16.10. Thanks!
I tried @moondog's suggestion for bluetooth-runner but unfortunately that script does not detect my bluetooth connection....

Worked perfectly first time but since reboot I keep getting the following error:
Command: pactl set-card-profile bluez_card.00_18_09_9B_EA_2F a2dp_sink failed with status: 1 stderr: Failure: Input/Output error
I tried setting a wait time to no avail, any other suggestions?

peteruithoven commented Jan 21, 2017 edited

I have a Bose Quietcontrol 30, switched laptops (now on a XPS15) (both ran Elementary Loki, based on Ubuntu 16.04), and it all worked fine for a while but after some updates the device stopped showing up as sound output. So I tried this script (thanks for sharing!) and just like @RobbieFM now I'm getting the following error:

Cannot find `bluez_card.04_52_C7_1B_7B_BC` using `pactl list cards short`. Retrying 8 more times

The device isn't showing up in the sound output's list, but that was the problem that I hoped to fix with this script. I don't see the device in the pacmd list-sinks list.

I tried the following suggestion: http://askubuntu.com/a/865214/519324

I tried pactl list short | grep bluetooth, but I'm not sure whether it's result is a good sign.

$ pactl list short | grep bluetooth
7	module-bluetooth-policy		
22	module-bluetooth-discover

I'll try to do some more research, but tips are welcome.

I found http://askubuntu.com/a/836202/519324 but Audio Profile didn't have a submenu. So I tried a couple of things, like pressing the Setup button and selecting Connect to: Handsfree. Suddenly it did appear in the Sounds output menu and the Audio Profile menu has options.
I also noticed that earlier my laptop appeared without a name in the bluetooth connects and now the proper name is shown.
Looks solved... No clue why or what went wrong.

peteruithoven commented Jan 22, 2017 edited

I can't edit my previous comment anymore, so I'll continue in a new one.
Using blueman to connect to my bluetooth device as handsfree doesn't seem to be a permanent fix, I have to do it after every reboot. I did notice that when I reboot my bluetooth device I get the following notification:

Bluetooth Authentication
Authorization request for: Bose QuietControl 30 (04:52:C7:1B:7B:BC)
Service: Advanced Audio

And a reboot later it works great, I only need to reboot the bluetooth device.

Owner

pylover commented Jan 22, 2017

@peteruithoven, yes you have to reboot your headset also

Mihara commented Jan 26, 2017

In case it might be helpful to someone, here's how I invoke a2dp.py automatically in Ubuntu 16.04, only for specific headsets:

#!/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()

Usage: Put the device IDs of your A2DP devices into DEV_IDS and the full path of your a2dp.py into the A2DP variable. Run from Startup Applications. Whenever you connect an audio device listed, a2dp.py will be automatically run shortly to sort it out. This will not work on earlier versions of Ubuntu, because it depends on the DBus API flavor introduced in Bluez 5.

Owner

pylover commented Jan 28, 2017

@Mihara, Thank's a lot.

@pylover holy shit, thank you for saving my sanity

You guys are my personal heroes!

Hi @pylover

Thanks for the script, but unfortunately I got this.

Connection MADE
Selecting device:
1. 00:01:01:00:02:DF AWEI-A980BL
2. AC:C1:EE:0D:9B:EA Mimin-R4
Select device[1]:
1
Device MAC: 00:01:01:00:02:DF
Cannot find `bluez_sink.00_01_01_00_02_DF` using `pacmd list-sinks`. Retrying 8 more times
Cannot find `bluez_sink.00_01_01_00_02_DF` using `pacmd list-sinks`. Retrying 7 more times
Cannot find `bluez_sink.00_01_01_00_02_DF` using `pacmd list-sinks`. Retrying 6 more times
Cannot find `bluez_sink.00_01_01_00_02_DF` using `pacmd list-sinks`. Retrying 5 more times
Cannot find `bluez_sink.00_01_01_00_02_DF` using `pacmd list-sinks`. Retrying 4 more times
Cannot find `bluez_sink.00_01_01_00_02_DF` using `pacmd list-sinks`. Retrying 3 more times
Cannot find `bluez_sink.00_01_01_00_02_DF` using `pacmd list-sinks`. Retrying 2 more times
Cannot find `bluez_sink.00_01_01_00_02_DF` using `pacmd list-sinks`. Retrying 1 more times
Device ID: bluez_card.00_01_01_00_02_DF
Sink: bluez_sink.00_01_01_00_02_DF
Turning off audio profile.
Disconnecting the device.
Connecting again.
Expression "Failed to connect: org.bluez.Error.Failed" failed with fail pattern: "fail"
Exiting bluetoothctl

Any idea?

Update: I had to put my headphones into "pairing" mode before running the script. After that, the script ran successfully.

Worked very well on ubuntu 16.10, thank's a lot!

Perfect! Problem solved! Thanks a ton @pylover

jtryan commented Mar 5, 2017

@pylover Fantastic work! Using it on 16.10. Now I can get off fedora. Thanks

Owner

pylover commented Mar 5, 2017

@jtryan, Good for you, get rid of yum and a lot of old and crappy tools.

IzzySoft commented Mar 6, 2017

@feryardiant Yes. I just had the same, easy to fix. First, the bunch of "cannot find" can be ignored. The trouble is the connect command being issued before the device is ready, it needs a little sleep.

@pylover easy fix:

from time import sleep
…
print('Connecting again.')
sleep(2)
await protocol.connect(mac)

Did the job for me. Comment: importing sleep from time, then right after the print('Connecting again.') line add a sleep for 2 secs. Shouldn't hurt too much for those not needing it – but helps a lot for those who do 😺

Owner

pylover commented Mar 6, 2017 edited

@IzzySoft, This an asyncio script, You should not use time.sleep, because it will block the all async tasks. So, it's good to use asyncio.sleep function instead. And making a CLI argument for sleep time is appreciated.

DominicWatson commented Mar 7, 2017 edited

This is so good, thank you! I made some additions in my own fork to be able to specify which profile to use. This way I can add a -p headset_head_unit argument and use all the same logic to switch to headset mode for calls. I realize there's probably a separate script that could do this without as much code, but figured it made sense to re-use all the good logic you had around setting the output device, etc.

https://gist.github.com/DominicWatson/b1ea0563df1dcdad858926edca3cee01

For me, I then bind two keyboard shortcuts to the two commands:

python3.5 /path/to/a2dp.py -p a2dp_sink
python3.5 /path/to/a2dp.py -p headset_head_unit

# I should probably rename the script to something else given that its now not exclusively about a2dp, but meh

Again, thanks for the script. Fracking awesome. License is a bit restrictive though.

p.s. do you have a git tip / amazon wishlist or somesuch? would love to repay you.

Owner

pylover commented Mar 8, 2017 edited

@DominicWatson, I'm very appreciate you comment. But i'm living at a country which the banking operations with the world are embargoed.
So, please find a homeless around your area and make him/her happy,

Owner

pylover commented Mar 9, 2017

@DominicWatson, I merged your fork, thank's a lot for contributing. The -p/--profile is very useful.

@pylover

This an asyncio script, You should not use time.sleep, because it will block the all async tasks. So, it's good to use asyncio.sleep function instead. And making a CLI argument for sleep time is appreciated.

Sure! Mine was just a "quick hack". I use Python myself here and there, but am not that deep into it – especially not into asyncio, which I admittedly never used myself. Thanks for picking up my "dirty fix" and converting it into a "clean update" 😸

@DominicWatson Very useful addition! I was asking myself for that as well. Glad I now can simply use it!

dabrovnijk commented Mar 12, 2017 edited

Thanks alot for the script, pylover for the a2dp.py and Mihara for the autostart script.

I have made this fix-bt.service as below. It will run the first time if I disconnect and reconnect my bluetooth speaker and it will fix a2dp_sink properly but it will only run one time and then I will have to restart the service.

fix-bt.py contains the script that Mihara have addded above.

But I do not know if I have made something wrong in my .service or if I should change something in Miharas script (besides what is already told to change in the script).

Should I use Type=dbus? But I do not know what I should write at BusName=, or how I will find that out.

[Unit]
Description=Fix BT Speaker

[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/fix-bt.py

[Install]
WantedBy=multi-user.target
Owner

pylover commented Mar 12, 2017

@dabrovnijk, Interesting, the systemd service is great!

dabrovnijk commented Mar 12, 2017 edited

Apperantly it seems to work I just had to be patient. When I tested again after couple of minutes it did what it was supposed to do.

I am running this on a headless Ubuntu 16.10 with pulseaudio running as system. I had to replace pacmd with pactl in your original script as pacmd did not find the pulseaudio daemon.

I love this output, and I can't praise you enough. +1:

mar 12 23:48:58 kompakt fix-bt.py[1107]: Device ID: bluez_card.00_02_3C_5E_28_91
mar 12 23:48:58 kompakt fix-bt.py[1107]: Sink: bluez_sink.00_02_3C_5E_28_91
mar 12 23:48:58 kompakt fix-bt.py[1107]: Turning off audio profile.
mar 12 23:48:58 kompakt fix-bt.py[1107]: Disconnecting the device.
mar 12 23:48:58 kompakt fix-bt.py[1107]: Connecting again.
mar 12 23:48:58 kompakt fix-bt.py[1107]: Device ID: bluez_card.00_02_3C_5E_28_91
mar 12 23:48:58 kompakt fix-bt.py[1107]: Setting the a2dp profile
mar 12 23:48:58 kompakt fix-bt.py[1107]: Updating default sink
mar 12 23:48:58 kompakt fix-bt.py[1107]: Exiting bluetoothctl
mar 12 23:48:58 kompakt fix-bt.py[1107]: "Enjoy" the HiFi stereo music :)

l

Owner

pylover commented Mar 13, 2017 edited

@dabrovnijk, It's OK, replace and test it.

ktatts commented Mar 18, 2017

Hi, thank you for the work you have put into this script and sharing it.

Unfortunately, I haven't had success with it. Output is as follows:
Device MAC: 00:0C:8A:FF:24:39
Cannot find bluez_card.00_0C_8A_FF_24_39 using pactl list cards short. Retrying 4 more times
Cannot find bluez_card.00_0C_8A_FF_24_39 using pactl list cards short. Retrying 3 more times
Cannot find bluez_card.00_0C_8A_FF_24_39 using pactl list cards short. Retrying 2 more times
Cannot find bluez_card.00_0C_8A_FF_24_39 using pactl list cards short. Retrying 1 more times
It seems device: 00:0C:8A:FF:24:39 is not connected yet, trying to connect.
Expression "Failed to connect: org.bluez.Error.Failed" failed with fail pattern: "fail"
Exiting bluetoothctl

I am using Lubuntu 16 on HP Pavilion g series. Possibly the problem may lie in the bluetooth chip - as I believe it operates the wireless also. My Bose speak connects fine with my android phone. Also, when I use the blueman-assistant, I can find and pair with devices. The problem comes when connecting to audio sink - error message being "device added successfully, but failed to connect".

Owner

pylover commented Mar 18, 2017

@ktatts, You have to pair/connect you headphones before running this script.

guyviner commented Mar 24, 2017 edited

NOOB/NOVICE/EASY/HOW TO INSTALL INSTRUCTIONS:

  1. Click 'Download Zip' at the top right corner of this page
  2. Save to desktop, choose a short name for it, like 'bluetooth'
  3. Go to your desktop
  4. Right click the file you just downloaded
  5. Choose 'Extract Here'
    5b) Pair your bluetooth headset.
  6. Open your terminal
  7. Navigate to the file by typing cd ~/Desktop/bluetooth
  8. Type python3.5 a2dp.py
  9. Choose the headset from the list, if a list pops up
  10. Done! Enjoy.

Thanks so much to @pylover for this script.

**Update. My guide may or may not be correct, because the script hasn't worked for me. I still need to connect twice to get A2DP to work. Can someone review my guide to see what I could have done wrong?

Thank you very much! Works perfectly for Ubuntu 16.04

thanks! Work on Elementary OS 0.4

hamedaakhlaghi commented Apr 9, 2017 edited

Thanks. It's worked perfect, I'm proud of you.

Owner

pylover commented Apr 9, 2017

@hamedaakhlaghi, It's my pleasure.

Awesome thanks!

It Work ! You make my day 👍

AmploDev commented Apr 12, 2017 edited

You helped a lot! Hope I can do something back!

I had the problem that the already running audio streams were not being transferred to my bluetooth headphone. I had to manually set the running playback to my headphone in volume control.

I first had to add an ignore_fail to the execute_command to suppress errors when there are no currently playing audio streams (so the execute_command doesn't find anything, which is no problem here).

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 ignore_fail == False and (p.returncode != 0 or stderr.strip() != ''):
        raise SubprocessError('Command: %s failed with status: %s\nstderr: %s' % (cmd, p.returncode, stderr))
    return stdout

Than I added the following on line 282 to move all streams to the new 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

and than on (the now) line 347, after the line with await set_default_sink(sink), I added:

await move_streams_to_sink(sink)

This helps sending all running audio to your headphones. This is my very first python attempt, so I'm sure it can be more effective. Hopes this helpes you guys/girls!

PS: Sorry for all the edits, I'm new to github. I have made a fork to make things easier!

I love you :)
This is why I love linus.

marcusbesjes commented Apr 13, 2017 edited

works! awesome!

flymike commented Apr 14, 2017 edited

Thanks to @pylover for the wonderful script, @Mihara for that auto-run daemon and @dabrovnijk for the systemd service file, now my headphone is automatically set whenever I switch it on.

Just wanted to add, if you like it run as a systemd service, you have to set it in the user space, the system-wide service won't work due to pactl can't run as pid 1.

  1. Name @dabrovnijk's systemd service code to fix-bt.service and copy it into /etc/systemd/user

  2. Run
    systemctl --user enable fix-bt.service

  3. Reboot

That's it.

Update:
Found out that the systemd service is always dead after fresh boot up (It does work with manual start), so google around and here is the solution:

[Unit]
Description=Fix BT Speaker

[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/fix-bt.py

[Install]
WantedBy=multi-user.target

Just change the multi-user.target to default.target, then disable/re-enable the service. Now it really works.

[Install]
WantedBy=default.target
Owner

pylover commented Apr 16, 2017 edited

@AmploDev, Your fork is merged. Thanks a lot for enhancement.

@pylover You're welcome and thank you for your awesome script! I was ready to throw my headphones through my screen till you saved the day!

bikashg commented Apr 16, 2017

What a wonderful gift! Thanks, man.

jacopotolja commented Apr 27, 2017 edited

I envy all of you because you know how to run a script. I made a file in my home dir i copied the script I made it executable by the properties and execute, nothing happen, sorry bothering you but I need more instructions

Owner

pylover commented Apr 27, 2017 edited

run

chmod +x a2dp.py

then

./a2dp.py

For people using Ubuntu 17.04 with gnome 3 with the script failing randomly this comment has the solution:

If you think you might have the same issue, first check your pulseaudio instances:

$ ps aux | grep pulseaudio
gdm 2578 4.3 0.1 2350536 12896 ? S<l 15:40 2:10 /usr/bin/pulseaudio --start --log-target=syslog
user 1533 4.3 0.1 2350536 12896 ? S<l 15:48 2:18 /usr/bin/pulseaudio --start --log-target=syslog

If you see a process owned by gdm, you can try to disable pulseaudio spawning by gdm during startup:

$ sudo nano /var/lib/gdm3/.config/pulse/client.conf
autospawn = no
daemon-binary = /bin/true

$ sudo chown gdm:gdm /var/lib/gdm3/.config/pulse/client.conf

It worked for me.

takeseem commented May 5, 2017 edited

I use xubuntu 16.04.2

if you use blueman-manager, reference:https://askubuntu.com/questions/763539/bluetooth-speaker-no-sound-in-ubuntu-16-04?answertab=votes#tab-top

  1. connect -> set profile off
  2. reconnect -> set profile a2dp
  3. now your headset is ok!

It‘s very complicated.
The python script is very nice :)

I found that when reconnecting use a2dp.py, the headset is the max volume.
insert a wait 1s, after the reconnect, before set profile a2dp. It can keep my headset volume config.

I refer to your Python script, use bash to implement a script, it's work for me! https://gist.github.com/takeseem/d45814b7eb39eda208998fdefce20f47

Last, I think the main logic in the python script is too complicated.
It's hard undstand for me, i not python program.
simple logic:

  1. choice device
  2. connect -> set profile off
  3. reconnect -> set profile a2dp

i change the main logic, it's work good for me:

	try:

		if mac is None:
			mac, _ = await protocol.select_paired_device()
		# ready mac
		mac = mac.split(':' if ':' in mac else '_')
		print('Device MAC: %s' % ':'.join(mac))
		device_id = 'bluez_card.%s' % '_'.join(mac)
		print('Device ID: %s' % device_id)

		# connect -> set profile off
		await protocol.trust(mac)
		await protocol.connect(mac)
		await wait()
		await set_profile(device_id, 'off')

		#reconnect -> set profile a2dp
		await protocol.disconnect(mac)
		await wait()
		await protocol.connect(mac)
		await wait()
		await set_profile(device_id, args.profile)
	except (SubprocessError, RetryExceededError) as ex:
		print(str(ex), file=sys.stderr)
		return 1
Owner

pylover commented May 6, 2017

@jvalenciag, Thanks a lot.

HifeFish commented May 10, 2017 edited

Thank you very much for providing this script. I had been using it manually for a few months, when I decided to automate the process about 10 days ago, unaware that it had already been done. Nevertheless, in case anyone is interested, my successful efforts to accomplish this with a udev rule are documented here: https://askubuntu.com/questions/910501/udev-rule-to-run-python-script/912838#912838

Owner

pylover commented May 11, 2017

@HifeFish, Thanks

Thank you! It worked easy. How did you learn to do this?
I'm a py learner and to me this is amazing.

Owner

pylover commented May 18, 2017 edited

@mehdi-gital, Thanks for completion. I owe the C language.

DrunkCat159 commented May 25, 2017 edited

@pylover
cat@RS1254345554:~/BluethootFix$ ./a2dp.py
Connection MADE
Selecting device:

  1. 1C:52:16:05:25:A8 Mpow Swift
  2. 00:1E:7C:35:1A:47 Philips SHB5500
    Select device[1]:
    2
    Device MAC: 00:1E:7C:35:1A:47
    Device ID: bluez_card.00_1E_7C_35_1A_47
    Sink: bluez_sink.00_1E_7C_35_1A_47
    Updating default sink to bluez_sink.00_1E_7C_35_1A_47
    Setting the off profile
    Disconnecting the device.
    Connecting again.
    Device ID: bluez_card.00_1E_7C_35_1A_47
    Setting the a2dp profile
    Updating default sink to bluez_sink.00_1E_7C_35_1A_47
    Ignoring: Command: pacmd list-sink-inputs | grep "index:" failed with status: 1
    stderr:
    Exiting bluetoothctl
    "Enjoy" the HiFi stereo music :)

It stops working after some minutes :<
And the if i try to run the script gain:

cat@RS1254345554:~/BluethootFix$ ./a2dp.py Connection MADE
Selecting device:

  1. 1C:52:16:05:25:A8 Mpow Swift
  2. 00:1E:7C:35:1A:47 Philips SHB5500
    Select device[1]:
    2
    Device MAC: 00:1E:7C:35:1A:47
    Cannot find bluez_sink.00_1E_7C_35_1A_47 using pacmd list-sinks. Retrying 4 more times
    Cannot find bluez_sink.00_1E_7C_35_1A_47 using pacmd list-sinks. Retrying 3 more times
    Cannot find bluez_sink.00_1E_7C_35_1A_47 using pacmd list-sinks. Retrying 2 more times
    Cannot find bluez_sink.00_1E_7C_35_1A_47 using pacmd list-sinks. Retrying 1 more times
    Setting the a2dp profile
    Command: pactl set-card-profile bluez_card.00_1E_7C_35_1A_47 a2dp_sink failed with status: 1
    stderr: Failure: Input/Output error

Exiting bluetoothctl

Btw thanks very much for the work you made :)

@pylover trying out your script on Ubuntu 17.04, with Gnome

running fix-bt.py gives me this error, running it with sudo too.

ERROR:dbus.connection:Exception in handler for D-Bus signal:
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/dbus/connection.py", line 230, in maybe_handle_message
self._handler(*args, **kwargs)
File "/usr/bin/fix-bt.py", line 32, in cb
subprocess.call([A2DP,device_id])
File "/usr/lib/python2.7/subprocess.py", line 168, in call
return Popen(*popenargs, **kwargs).wait()
File "/usr/lib/python2.7/subprocess.py", line 390, in init
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1024, in _execute_child
raise child_exception
OSError: [Errno 13] Permission denied

Owner

pylover commented May 26, 2017

@DrunkCat159, A simple workaround is to turn off and on again your Bluetooth.

ehzawad commented Jun 1, 2017

sudo apt-get install pulseaudio-module-bluetooth

I need to run this first as dependencies @pylover

Owner

pylover commented Jun 1, 2017

@ehzawad, Thanks

Thanks a lot, PyLover!!!
Getting disappointed for months over my headphone, I suddenly found your script!
It worked like a charm and I couldn't really believe it the moment I heard the A2DP sink quality; lol!
Thanks for sharing, man!

Owner

pylover commented Jun 5, 2017

@MohsenHassani, You are welcome.

After three years of every day connect/disconnect dance.One time I told myself: مرگ یه بار شیون یه بار.

Thank you so much for this great script. I was having to constantly manually restart my bluetooth connection to my CANZ speaker I have setup on my computer running Ubuntu GNOME 16.04 LTS. This is what I did to use the script...

1/. chmod +x a2dp.py
2/. sudo ln -s /path/to/script/a2dp.py /usr/local/bin/a2dp
3/. Added a2dp to my startup applications with the MAC for the CANZ speaker.
4/. Reboot and instant joy!

Thanks again!

Owner

pylover commented Jun 6, 2017

@jkhamilton62, Good trick.

juaryR commented Jun 20, 2017

Muito Obrigado, uma mão na roda ... Cabo Verde agradece.
thank you, very useful ... Cabo verde thank you so ...

samhains commented Jun 23, 2017 edited

This worked great for me with Bose OE bluetooth headphones/ just make sure that your device is not on the 'Off' profile, and instead place it on the 'Headset Head Unit' profile before running the script.

YijunXie commented Jul 5, 2017 edited

This is what I got

`Connection MADE
Selecting device:

  1. E7:69:96:08:75:31 vívosmart HR
  2. 00:9E:C8:9A:12:54 Android Bluedroid
  3. F4:0E:11:73:62:19 KUWO_K1
    Select device[1]:
    3
    Device MAC: F4:0E:11:73:62:19
    Device ID: bluez_card.F4_0E_11_73_62_19
    Sink: bluez_sink.F4_0E_11_73_62_19
    Turning off audio profile.
    Disconnecting the device.
    Connecting again.
    Setting A2DP profile
    Device ID: bluez_card.F4_0E_11_73_62_19
    Command: pactl set-card-profile bluez_card.F4_0E_11_73_62_19 a2dp_sink failed with status: 1
    stderr: Failure: Input/Output error

Exiting bluetoothctl
`

Not sure what is happening....

Owner

pylover commented Jul 5, 2017 edited

@YijunXie, You should wait about 1 minute before running this script, if not working:

Try this:
sudo service bluetooth restart

pulseaudio --kill

Turn off and on bluetooth.

Hope this works.

mlinfoot commented Jul 5, 2017

I cannot thank you and the other contributors enough for this!!! This is the way bluetooth speakers/headsets SHOULD work - simply turn them on.

Owner

pylover commented Jul 8, 2017

@juaryR, você é bem-vindo.

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