系统版本: Fedora 32

GNOME版本: 3.36.2

问题分析

很久之前买了个天猫精灵X1蓝牙音响,周末偶尔也会用台式机连一下看看电影啥的。

但是GNOME bluetooth 有个问题就是,第一次可以配对成功并连接上,下次开机重启后它就不会自动连接了。并且就算你想手动点击连接,也非常大的概率无法成功,大部分情况下,你尝试点击那个连接的开关它会马上切换到未连接的状态,如图示:

gnome-bluetooth-can-not-reconnect

当然,如果有耐心的话,多点击几次,还是有可能成功的。比如像我这样点了14下才成功:

gnome-bluetooth-device-busy-2020-05-20-20-11.gif

当然,要不是我sudo journalctl -f -u bluetooth打开了日志,我可能会认为这个按钮是“自动反弹”的而放弃继续点击。

现在我们知道了,只要耐心的点,总有一次会成功的。

我们来看看日志:

❯ sudo journalctl -f -u bluetooth 
[sudo] password for ttys3: 
-- Logs begin at Thu 2020-01-09 03:44:38 CST. --
May 20 20:07:43 8700k.localhost bluetoothd[2771]: Exit
May 20 20:07:43 8700k.localhost systemd[1]: bluetooth.service: Succeeded.
May 20 20:07:43 8700k.localhost systemd[1]: Stopped Bluetooth service.
-- Reboot --
May 20 20:08:17 8700k.localhost systemd[1]: Starting Bluetooth service...
May 20 20:08:17 8700k.localhost bluetoothd[2768]: Bluetooth daemon 5.54
May 20 20:08:17 8700k.localhost systemd[1]: Started Bluetooth service.
May 20 20:08:17 8700k.localhost bluetoothd[2768]: Starting SDP server
May 20 20:08:17 8700k.localhost bluetoothd[2768]: Bluetooth management interface 1.15 initialized
May 20 20:08:34 8700k.localhost bluetoothd[2768]: Endpoint registered: sender=:1.76 path=/MediaEndpoint/A2DPSink/sbc
May 20 20:08:34 8700k.localhost bluetoothd[2768]: Endpoint registered: sender=:1.76 path=/MediaEndpoint/A2DPSource/sbc
May 20 20:11:12 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:14 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:16 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:17 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:18 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:19 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:20 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:21 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:22 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:24 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:25 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:26 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:27 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:28 8700k.localhost bluetoothd[2768]: connect error: Device or resource busy (16)
May 20 20:11:32 8700k.localhost bluetoothd[2768]: /org/bluez/hci0/dev_18_BC_5A_A5_54_DB/sep1/fd0: fd(46) ready

可见没法连接成功的情况都是connect error: Device or resource busy (16), 而连接成功的情况则是/org/bluez/hci0/dev_18_BC_5A_A5_54_DB/sep1/fd3: fd(43) ready 这种。

好了,现在我们总结一下问题:

  1. 首次配对是可以连接成功并正常使用的
  2. 系统重启后蓝牙音响没有自动连接。手动点击要点十多下才可能成功。
  3. 根据条件1,我们尝试重启后删除蓝牙音响并重新配对也是OK的。

无论是一次又一次的删除和添加配对,还是每次开机点十几下连接个蓝牙音响,都挺麻烦的,有没有办法让它开机自动重连蓝牙音响呢?

办法当然是有的。

解决开机自动重连问题

bluez 这个Bluetooth utilities包里,包含了bluetoothctl这个实用工具,我们可以用它来完成自动连接。

新建一文件 /opt/scripts/bluetooth-auto-connect.sh/opt/scripts目录不存在,自己新建一个即可), 内容如下:

#!/bin/sh

DEVICE="18:BC:5A:A5:54:DB"

BLCTL=/usr/bin/bluetoothctl

$BLCTL power on
$BLCTL agent on
$BLCTL default-agent

if $BLCTL info $DEVICE; then
$BLCTL trust $DEVICE && $BLCTL connect $DEVICE
fi

18:BC:5A:A5:54:DB 是蓝牙音响的MAC地址(注意这个设备是已经成功配对过的)。

注意这里我们执行了trust命令,这是必要的。要不然无法连接成功。

MAC地址可以通过Gnome图片界面查看到,也可以用命令行:

❯ bluetoothctl devices
Device 03:D1:64:4D:26:A1 03-D1-64-4D-26-A1
Device 70:0E:47:34:2A:F1 70-0E-47-34-2A-F1
Device 62:BB:F2:90:DC:7A 62-BB-F2-90-DC-7A
Device 1E:0F:C3:CF:6D:AF 1E-0F-C3-CF-6D-AF
Device 18:BC:5A:A5:54:DB X1(F0:6B)

18:BC:5A:A5:54:DB 就是天猫精灵X1的MAC了。

然后我们在Gnome的自动启动目录~/.config/autostart下新建一desktop文件bluetooth-auto-connect.desktop, 内容如下:

[Desktop Entry]
Name=bluetooth-auto-connect
GenericName=bluetooth-auto-connect
Exec=/opt/scripts/bluetooth-auto-connect.sh
Terminal=false
Icon=bash
Categories=Audio
Type=Application
StartupNotify=false
X-GNOME-Autostart-enabled=true

这样就能在用户登录后自动执行蓝牙连接了。

如果开启了selinux, 注意设置一下:

sudo chcon -t bin_t /opt/scripts/bluetooth-auto-connect.sh

连接成功后可以通过以下命令查看蓝牙设备信息:

❯ bluetoothctl info 18:BC:5A:A5:54:DB
Device 18:BC:5A:A5:54:DB (public)
	Name: X1(F0:6B)
	Alias: X1(F0:6B)
	Class: 0x002c0414
	Icon: audio-card
	Paired: yes
	Trusted: yes
	Blocked: no
	Connected: yes
	LegacyPairing: no
	UUID: Audio Sink                (0000110b-0000-1000-8000-00805f9b34fb)
	UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
	UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)
	UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)
	UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
	UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
	Modalias: bluetooth:v000Fp1200d1436

开机连接成功后自动切换

如果你希望PulseAudio自动连接到新发现的输出设备, 可以修改/etc/pulse/default.pa, 增加:

# bluetooth: automatically switch to newly-connected devices
# https://wiki.archlinux.org/index.php/Bluetooth_headset#Setting_up_auto_connection
load-module module-switch-on-connect

或者添加到pulse用户配置文件~/.config/pulse/default.pa也OK。 文件不存在则新建一个或从/etc/pulse/default.pa copy一个过来。

什么是PulseAudio?

PulseAudio 是在 GNOME 或 KDE 等桌面环境中广泛使用的音频服务。它在内核音频组件(比如ALSA 和 OSS)和应用程序之间充当代理的角色。 PulseAudio经常和ALSA协同使用。

所以PulseAudio它是一个middleware, 应用程序想要输出声音,可以找Pulse,然后Pulse再找底层的组件比如ALSA。

当然,PulseAudio并不是必须的。一些应用程序,比如DeaDBeeF和SMPlayer 允许用户配置声音输出。 比如DeaDBeeF就有三个选择,ALSA, OSS或 Pulse。当选择为ALSA时,DeaDBeeF还会允许你选择用哪个设备输出声音。

一般来说,我们让应用程序都使用PulseAudio, 然后让PulseAudio统一管理会比较好。 比如我们将输出设备从Audioengine D1切换到天猫精灵X1时, 所有应用程序就统一切换了,假如是单独用ALSA设置的,那还得单个去改,挺麻烦的。

参数文档

https://wiki.archlinux.org/index.php/PulseAudio

https://wiki.debian.org/BluetoothUser#Can.27t_reconnect_after_sleep

https://wiki.archlinux.org/index.php/Bluetooth_headset#Configuration_via_CLI