Search code examples
bluetoothblueza2dpavrcp

Bluez 5 - initiate avrcp connection to iPhone from Bluez


Bluez 5.28

Goal - Control iOS track skip, and initiate connection from Bluez programmatically. Do not want a2dp.

Everything works fine if I initiate connection from iPhone/iPad (go to BT settings, click on Pi device), which I want to avoid and not have to fiddle with the phone. (car setup with Pi). I have control, track metadata, etc.

Doing a connect xx:xx:xx:xx:xx:xx in bluetoothctl yields:

 a2dp-source profile connect failed for 6C:70:9F:7E:EF:A8: Protocol not available

Ok. It needs pulseaudio + modules. I install that, and now I can connect from Bluez. However, it now adds and automatically selects Bluez as an audio output device. Do not want that and have to fiddle with the phone again. Only want control. Though I prefer this if nothing at all, as I can change output device from anywhere in the OS & not have to go to settings.

Well, let me disable a2dp all together and see.

/usr/libexec/bluetooth/bluetoothd -d -C -n --noplugin=a2dp

or

/usr/libexec/bluetooth/bluetoothd -d -C -n --plugin=avrcp

Same result for both of the above

bluetoothd[14176]: src/device.c:connect_profiles() /org/bluez/hci0/dev_6C_70_9F_7E_EF_A8 (all), client :1.57
bluetoothd[14176]: src/device.c:connect_profiles() Resolving services for /org/bluez/hci0/dev_6C_70_9F_7E_EF_A8
bluetoothd[14176]: src/adapter.c:connected_callback() hci0 device 6C:70:9F:7E:EF:A8 connected eir_len 19
bluetoothd[14176]: src/device.c:search_cb() 6C:70:9F:7E:EF:A8: No service update
bluetoothd[14176]: src/device.c:device_svc_resolved() /org/bluez/hci0/dev_6C_70_9F_7E_EF_A8 err 0
bluetoothd[14176]: src/device.c:connect_profiles() /org/bluez/hci0/dev_6C_70_9F_7E_EF_A8 (all), client :1.57
bluetoothd[14176]: src/adapter.c:dev_disconnected() Device 6C:70:9F:7E:EF:A8 disconnected, reason 3
bluetoothd[14176]: src/adapter.c:adapter_remove_connection() 
bluetoothd[14176]: plugins/policy.c:disconnect_cb() reason 3
bluetoothd[14176]: src/adapter.c:bonding_attempt_complete() hci0 bdaddr 6C:70:9F:7E:EF:A8 type 0 status 0xe
bluetoothd[14176]: src/device.c:device_bonding_complete() bonding (nil) status 0x0e
bluetoothd[14176]: src/device.c:device_bonding_failed() status 14
bluetoothd[14176]: src/adapter.c:resume_discovery() 

Again, everything works exactly how I want it to if I go into Bluetooth settings & click on the device on the iPhone. The problem is getting the connection going from Bluez.

It looks to me like iOS is requesting a2dp, and I'm not sure how to make Bluez go past that, or stop advertising that its available. I know there are jaibreak options for disabling profiles, but trying to keep it clean.

I also experimented with HID setup that worked to send it keystrokes, but then it hides the on-screen keyboard.

Thanks!


Solution

  • Got it to do what I want to with 5.28 built from source, but had to edit it lightly.

    Not sure of any side-effects, but my goal is pretty narrow, so I don't really care.

    edit profiles/audio/avrcp.c

    ADD

    .auto_connect = true, to

    static struct btd_profile avrcp_target_profile = { @ line 3863

    and

    static struct btd_profile avrcp_controller_profile = { @ line 3946

    make && make install

    Complete blocks

    static struct btd_profile avrcp_target_profile = {
            .name           = "audio-avrcp-target",
            .remote_uuid    = AVRCP_TARGET_UUID,
            .device_probe   = avrcp_target_probe,
            .device_remove  = avrcp_target_remove,
            .auto_connect   = true,
            .connect        = avrcp_connect,
            .disconnect     = avrcp_disconnect,
            .adapter_probe  = avrcp_target_server_probe,
            .adapter_remove = avrcp_target_server_remove,
    };
    

    ...

    static struct btd_profile avrcp_controller_profile = {
            .name           = "avrcp-controller",
            .remote_uuid    = AVRCP_REMOTE_UUID,
            .device_probe   = avrcp_controller_probe,
            .device_remove  = avrcp_controller_remove,
            .auto_connect   = true,
            .connect        = avrcp_connect,
            .disconnect     = avrcp_disconnect,
            .adapter_probe  = avrcp_controller_server_probe,
            .adapter_remove = avrcp_controller_server_remove,
    };