蓝牙连接失败,使用 bluetoothctl 命令

Posted

技术标签:

【中文标题】蓝牙连接失败,使用 bluetoothctl 命令【英文标题】:bluetooth connection fail with bluetoothctl command 【发布时间】:2018-11-27 01:38:43 【问题描述】:

我在Vmware环境下的Ubuntu下尝试了蓝牙连接测试。 Ubuntu 是 14.04 lts,蓝牙是 USB-dongle,BT 堆栈是 Bluez 5.35。 我不使用pulseaudio。

我使用 bluetoothctl 命令进行扫描、配对和连接。 但是连接失败。下面是bluetoothctl的日志

$ sudo bluetoothctl
[bluetooth]# power on
[bluetooth]# show
Controller 00:1A:7D:DA:xx:xx (public)
Name: ubuntu
Alias: ubuntu-0
Class: 0x00000000
Powered: yes
Discoverable: no
Pairable: yes
UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)
UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)
UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
Modalias: usb:v1D6Bp0246d0532
Discovering: no
[bluetooth]# scan on         // Wait until found BT headset
[bluetooth]# scan off
[bluetooth]# devices
Device 11:11:22:xx:xx:xx Test
Device 0C:E0:E4:xx:xx:xx PLT_Legend

[bluetooth]# pair 0C:E0:E4:xx:xx:xx    // try pairing with 0C:E0:E4:xx:xx:xx
Attempting to pair with 0C:E0:E4:xx:xx:xx
[CHG] Device 0C:E0:E4:xx:xx:xx Connected: yes
[PLT_Legend]# interfaces_added
[CHG] Device 0C:E0:E4:xx:xx:xx Modalias: bluetooth:v0055p0113d0067
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 00001108-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 0000110b-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 0000110c-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 0000110e-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 0000111e-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 00001200-0000-1000-8000-00805f9b34fb
[CHG] Device 0C:E0:E4:xx:xx:xx UUIDs: 82972387-294e-4d62-97b5-2668aa35f618
[CHG] Device 0C:E0:E4:xx:xx:xx ServicesResolved: yes
[CHG] Device 0C:E0:E4:xx:xx:xx Paired: yes
Pairing successful
[CHG] Device 0C:E0:E4:xx:xx:xx ServicesResolved: no
[CHG] Device 0C:E0:E4:xx:xx:xx Connected: no
[PLT_Legend]# connect 0C:E0:E4:xx:xx:xx
Attempting to connect to 0C:E0:E4:xx:xx:xx
[CHG] Device 0C:E0:E4:xx:xx:xxConnected: yes
Failed to connect: org.bluez.Error.Failed

我发现上面的 bluez 没有 a2dp 配置文件。 实际上,bluez5.x 和pulseaudio 是紧密结合的。如果不使用 pulseaudio,用户必须添加额外的配置文件(a2dp 或 hspag)。

以下代码是添加 a2dpsink 、 a2dpsource 和 haspag 的示例。

#define A2DP_SOURCE_ENDPOINT "/MediaEndpoint/A2DPSource"
#define A2DP_SINK_ENDPOINT "/MediaEndpoint/A2DPSink"
#define HSP_AG_PROFILE "/Profile/HSPAGProfile"

#define PA_BLUETOOTH_UUID_HSP_AG      "00001112-0000-1000-8000-00805f9b34fb"
#define PA_BLUETOOTH_UUID_A2DP_SOURCE "0000110a-0000-1000-8000-00805f9b34fb"
#define PA_BLUETOOTH_UUID_A2DP_SINK   "0000110b-0000-1000-8000-00805f9b34fb"

static void register_profile_reply(DBusPendingCall *call, void *user_data)

    //struct bluetooth_profile *profile = user_data;
    DBusMessage *reply = dbus_pending_call_steal_reply(call);
    DBusError derr;

    dbus_error_init(&derr);
    if (!dbus_set_error_from_message(&derr, reply)) 
        printf("Profile %s registered", (char *)user_data);
        goto done;
    

    //unregister_profile(profile);

    printf("bluetooth: RequestProfile error: %s, %s", derr.name,
                                derr.message);
    dbus_error_free(&derr);
done:
    dbus_message_unref(reply);

static DBusConnection *connection;
void btd_profile_add_hspag(const char *profile, const char *uuid) 

    DBusMessage *msg;
    DBusMessageIter iter, opt;
    DBusPendingCall *call;

    connection = btd_get_dbus_connection();
    msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
                        "org.bluez.ProfileManager1",
                        "RegisterProfile");
    if( msg == NULL ) 
        printf("%s : msg is null \n", __func__);
    

    dbus_message_iter_init_append(msg, &iter);
    dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &profile);
    dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uuid);
    dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
                    DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
                    DBUS_TYPE_STRING_AS_STRING
                    DBUS_TYPE_VARIANT_AS_STRING
                    DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
                    &opt);
    dbus_message_iter_close_container(&iter, &opt);
    if (!g_dbus_send_message_with_reply(connection, msg, &call, -1)) 
        printf("%s:%s - fail g_dbus_send_message_with_reply() \n", __FILE__, __func__);
        //unregister_profile(profile);
        goto failed;
    
    dbus_pending_call_set_notify(call, register_profile_reply, &profile,
                                    NULL);
    dbus_pending_call_unref(call);
failed:
    dbus_message_unref(msg);
    return;

void btd_profile_add(void)

    btd_profile_add_hspag(HSP_AG_PROFILE, PA_BLUETOOTH_UUID_HSP_AG);
    btd_profile_add_hspag(A2DP_SOURCE_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SOURCE);
    btd_profile_add_hspag(A2DP_SINK_ENDPOINT, PA_BLUETOOTH_UUID_A2DP_SINK);

在那之后,bluez 有了 a2dp、hspag 配置文件,没有 pulseaudio。 我可以用 bluetoothctl 的“show”命令查看。

    [bluetooth]# show
    Controller 00:1A:7D:xx:xx:xx
    Name: ubuntu
    Alias: ubuntu-0
    Class: 0x000000
    Powered: yes
    Discoverable: no
    Pairable: yes
    UUID: Headset AG                (00001112-0000-1000-8000-00805f9b34fb)
    UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
    UUID: A/V Remote Control        (0000110e-0000-1000-8000-00805f9b34fb)
    UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
    UUID: PnP Information           (00001200-0000-1000-8000-00805f9b34fb)
    UUID: A/V Remote Control Target (0000110c-0000-1000-8000-00805f9b34fb)
    UUID: Audio Source              (0000110a-0000-1000-8000-00805f9b34fb)
    UUID: Audio Sink                (0000110b-0000-1000-8000-00805f9b34fb)
    Modalias: usb:v1D6Bp0246d0523
    Discovering: no

即使添加了 a2dp 配置文件,蓝牙连接仍然失败。 通过btmon trace,断开了rfcomm的连接,接下来,l2cap的连接也断开了。 我不知道我错过了什么。 在没有pulseaudio的情况下运行bluez 5.35我还需要什么?

【问题讨论】:

【参考方案1】:

日志显示您的“PLT_Legend”设备支持 A2DP SINK 角色,因此您的 Ubuntu 应充当 A2DP SOURCE 角色。要使其工作,您需要一个工作配置文件实现。

您可能不需要完全实现 A2DP 源配置文件来获取音频数据,但至少您需要注册基本功能才能让 bluetoothd 满意。

下图直接复制自here。

在上面的序列中,您可以看到蓝牙在连接具有 A2DP 功能的新设备时调用“SelectConfiguration”和“SetConfiguration”。

正如您所观察到的,连接状态最初移动到已连接,然后回退到“否”。这是因为,bluetoothd 在获得低级连接后会尝试与配置文件(SDP 服务发现协议)进行连接。低级连接成功后,设备被标记为已连接,SDP 继续进行。

在 SDP 期间,bluetoothd 尝试获取您的设备(在本例中为 ubuntu)的功能,并使用“SelectConfiguration”与终端设备 (PLT_Legend) 就编解码器支持进行协商,并使用“SetConfiguration”选择一个。握手成功后,蓝牙标记 A2DP 配置文件已连接。

因此,使用您的配置文件的虚拟注册,由于它找不到方法并且正确的编解码器返回,它标志着连接失败并终止 Ubuntu 和设备之间的连接。

如果您不想使用 pulseaudio,可以尝试使用 bluez-alsa https://github.com/Arkq/bluez-alsa 并开始收听 A2DP 配置文件。我认为这个包已经在 ubuntu repo 中可用了,你可以试试

sudo apt-get install bluez-alsa

AFAIK,pulseaudio 没有与蓝牙紧密绑定,你仍然可以以蓝牙理解的方式实现自己的 A2DP 实现。

注意,bluez-alsa 使用开源 fdk-aac 进行 AAC 编码和解码。

【讨论】:

以上是关于蓝牙连接失败,使用 bluetoothctl 命令的主要内容,如果未能解决你的问题,请参考以下文章

[BlueZ] 2使用bluetoothctl搜索连接配对读写使能notify蓝牙低功耗设备

bluetoothctl 不显示蓝牙低功耗 (BLE) 设备

ubuntu连接蓝牙鼠标

在 Linux 上检查连接的蓝牙设备的电池电量

读取电池状态蓝牙耳机linux

无法在嵌入式 linux 中使用 bluetoothctl 连接设备