diff mbox series

[BlueZ,v2,3/3] client: Add support get/set PreferredBearer

Message ID 20250225220059.2821394-3-luiz.dentz@gmail.com
State New
Headers show
Series [BlueZ,v2,1/3] org.bluez.Device: Introduced PreferredBearer | expand

Commit Message

Luiz Augusto von Dentz Feb. 25, 2025, 10 p.m. UTC
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds support for PreferredBearer which is printed with the likes of
info command:

bluetoothctl> info <addr>
...
	PreferredBearer: last-seen

It also introduces a new command to get/set the PreferredBearer:

[bluetoothctl]> bearer --help
Get/Set preferred bearer
Usage:
	 bearer <dev> [last-seen/bredr/le]

[bluetoothctl]> bearer <addr>
	PreferredBearer: last-seen
[bluetoothctl]> bearer <addr> le
bluetoothd: @ MGMT Command: Add Device (0x0033) plen 8
        LE Address: <addr>
        Action: Auto-connect remote device (0x02)
[CHG] Device <addr> PreferredBearer: le
Changing le succeeded
[bluetoothctl]> bearer <addr>
	PreferredBearer: le
[bluetoothctl]> bearer <addr> bredr
bluetoothd: @ MGMT Command: Remove Device (0x0034) plen 7
        LE Address: <addr>
[CHG] Device <addr> PreferredBearer: bredr
Changing bredr succeeded
---
 client/main.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

Comments

Luiz Augusto von Dentz Feb. 25, 2025, 10:10 p.m. UTC | #1
Hi Pauli, Bastien,

On Tue, Feb 25, 2025 at 5:01 PM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This adds support for PreferredBearer which is printed with the likes of
> info command:
>
> bluetoothctl> info <addr>
> ...
>         PreferredBearer: last-seen
>
> It also introduces a new command to get/set the PreferredBearer:
>
> [bluetoothctl]> bearer --help
> Get/Set preferred bearer
> Usage:
>          bearer <dev> [last-seen/bredr/le]
>
> [bluetoothctl]> bearer <addr>
>         PreferredBearer: last-seen
> [bluetoothctl]> bearer <addr> le
> bluetoothd: @ MGMT Command: Add Device (0x0033) plen 8
>         LE Address: <addr>
>         Action: Auto-connect remote device (0x02)
> [CHG] Device <addr> PreferredBearer: le
> Changing le succeeded
> [bluetoothctl]> bearer <addr>
>         PreferredBearer: le
> [bluetoothctl]> bearer <addr> bredr
> bluetoothd: @ MGMT Command: Remove Device (0x0034) plen 7
>         LE Address: <addr>
> [CHG] Device <addr> PreferredBearer: bredr
> Changing bredr succeeded
> ---
>  client/main.c | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
>
> diff --git a/client/main.c b/client/main.c
> index feb21a1163d2..76c9bc329c96 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -1714,6 +1714,7 @@ static void cmd_info(int argc, char *argv[])
>         print_property(proxy, "AdvertisingFlags");
>         print_property(proxy, "AdvertisingData");
>         print_property(proxy, "Sets");
> +       print_property(proxy, "PreferredBearer");
>
>         battery_proxy = find_proxies_by_path(battery_proxies,
>                                         g_dbus_proxy_get_path(proxy));
> @@ -2086,6 +2087,30 @@ static void cmd_wake(int argc, char *argv[])
>         return bt_shell_noninteractive_quit(EXIT_FAILURE);
>  }
>
> +static void cmd_bearer(int argc, char *argv[])
> +{
> +       GDBusProxy *proxy;
> +       char *str;
> +
> +       proxy = find_device(argc, argv);
> +       if (!proxy)
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +
> +       if (argc <= 2) {
> +               print_property(proxy, "PreferredBearer");
> +               return;
> +       }
> +
> +       str = strdup(argv[2]);
> +
> +       if (g_dbus_proxy_set_property_basic(proxy, "PreferredBearer",
> +                                       DBUS_TYPE_STRING, &str,
> +                                       generic_callback, str, free))
> +               return;
> +
> +       return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +}
> +
>  static void cmd_list_attributes(int argc, char *argv[])
>  {
>         GDBusProxy *proxy;
> @@ -3247,6 +3272,8 @@ static const struct bt_shell_menu main_menu = {
>                                                         dev_generator },
>         { "wake",         "[dev] [on/off]",    cmd_wake, "Get/Set wake support",
>                                                         dev_generator },
> +       { "bearer",       "<dev> [last-seen/bredr/le]", cmd_bearer,
> +                               "Get/Set preferred bearer", dev_generator },
>         { } },
>  };
>
> --
> 2.48.1

So I went ahead and implemented the idea of having PreferredBearer,
this works great when setting bredr it really stops from connecting to
LE, the said the other way around when setting to le seems to confuse
some headsets like EarFun and it ends up connecting both bearers:

[EarFun Air Pro 3]> transport.show
Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd1
    UUID: Sink PAC                  (00002bc9-0000-1000-8000-00805f9b34fb)
    Codec: 0x06 (6)
    Configuration.#0: len 0x02 type 0x01
    Configuration.Sampling Frequency: 16 Khz (0x03)
    Configuration.#1: len 0x02 type 0x02
    Configuration.Frame Duration: 7.5 ms (0x00)
    Configuration.#2: len 0x05 type 0x03
    Configuration.Location: 0x00000001
    Configuration.Location: Front Left (0x00000001)
    Configuration.#3: len 0x03 type 0x04
    Configuration.Frame Length: 30 (0x001e)
    Configuration.#4: len 0x02 type 0x05
    Configuration.Frame Blocks per SDU: 1 (0x01)
    Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
    State: idle
    Volume: 0x00c8 (200)
    Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0
    QoS.CIG: 0x00 (0)
    QoS.CIS: 0x00 (0)
    QoS.Framing: 0x00 (0)
    QoS.PresentationDelay: 0x00009c40 (40000)
    QoS.Interval: 0x00001d4c (7500)
    QoS.Latency: 0x0008 (8)
    QoS.SDU: 0x001e (30)
    QoS.PHY: 0x02 (2)
    QoS.Retransmissions: 0x02 (2)
    Location: 0x00000003 (3)
    Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd3
Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd2
    UUID: Sink PAC                  (00002bc9-0000-1000-8000-00805f9b34fb)
    Codec: 0x06 (6)
    Configuration.#0: len 0x02 type 0x01
    Configuration.Sampling Frequency: 16 Khz (0x03)
    Configuration.#1: len 0x02 type 0x02
    Configuration.Frame Duration: 7.5 ms (0x00)
    Configuration.#2: len 0x05 type 0x03
    Configuration.Location: 0x00000002
    Configuration.Location: Front Right (0x00000002)
    Configuration.#3: len 0x03 type 0x04
    Configuration.Frame Length: 30 (0x001e)
    Configuration.#4: len 0x02 type 0x05
    Configuration.Frame Blocks per SDU: 1 (0x01)
    Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
    State: idle
    Volume: 0x00c8 (200)
    Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0
    QoS.CIG: 0x00 (0)
    QoS.CIS: 0x01 (1)
    QoS.Framing: 0x00 (0)
    QoS.PresentationDelay: 0x00009c40 (40000)
    QoS.Interval: 0x00001d4c (7500)
    QoS.Latency: 0x0008 (8)
    QoS.SDU: 0x001e (30)
    QoS.PHY: 0x02 (2)
    QoS.Retransmissions: 0x02 (2)
    Location: 0x00000003 (3)
    Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd4
Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd3
    UUID: Source PAC                (00002bcb-0000-1000-8000-00805f9b34fb)
    Codec: 0x06 (6)
    Configuration.#0: len 0x02 type 0x01
    Configuration.Sampling Frequency: 48 Khz (0x08)
    Configuration.#1: len 0x02 type 0x02
    Configuration.Frame Duration: 7.5 ms (0x00)
    Configuration.#2: len 0x05 type 0x03
    Configuration.Location: 0x00000001
    Configuration.Location: Front Left (0x00000001)
    Configuration.#3: len 0x03 type 0x04
    Configuration.Frame Length: 90 (0x005a)
    Configuration.#4: len 0x02 type 0x05
    Configuration.Frame Blocks per SDU: 1 (0x01)
    Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
    State: idle
    Volume: 0x00c8 (200)
    Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0
    QoS.CIG: 0x00 (0)
    QoS.CIS: 0x00 (0)
    QoS.Framing: 0x00 (0)
    QoS.PresentationDelay: 0x00009c40 (40000)
    QoS.Interval: 0x00001d4c (7500)
    QoS.Latency: 0x000f (15)
    QoS.SDU: 0x005a (90)
    QoS.PHY: 0x02 (2)
    QoS.Retransmissions: 0x05 (5)
    Location: 0x00000003 (3)
    Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd1
Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd4
    UUID: Source PAC                (00002bcb-0000-1000-8000-00805f9b34fb)
    Codec: 0x06 (6)
    Configuration.#0: len 0x02 type 0x01
    Configuration.Sampling Frequency: 48 Khz (0x08)
    Configuration.#1: len 0x02 type 0x02
    Configuration.Frame Duration: 7.5 ms (0x00)
    Configuration.#2: len 0x05 type 0x03
    Configuration.Location: 0x00000002
    Configuration.Location: Front Right (0x00000002)
    Configuration.#3: len 0x03 type 0x04
    Configuration.Frame Length: 90 (0x005a)
    Configuration.#4: len 0x02 type 0x05
    Configuration.Frame Blocks per SDU: 1 (0x01)
    Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
    State: idle
    Volume: 0x00c8 (200)
    Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0
    QoS.CIG: 0x00 (0)
    QoS.CIS: 0x01 (1)
    QoS.Framing: 0x00 (0)
    QoS.PresentationDelay: 0x00009c40 (40000)
    QoS.Interval: 0x00001d4c (7500)
    QoS.Latency: 0x000f (15)
    QoS.SDU: 0x005a (90)
    QoS.PHY: 0x02 (2)
    QoS.Retransmissions: 0x05 (5)
    Location: 0x00000003 (3)
    Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd2
Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/fd5
    UUID: Audio Source              (0000110a-0000-1000-8000-00805f9b34fb)
    Codec: 0x02 (2)
    Media Codec: MPEG24
    Object Types: MPEG-4 AAC LC
    Frequencies: 48kHz
    Channels: 2
    Bitrate: 320000
    VBR: Yes
    Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
    State: idle
    Delay: 0x0960 (2400)
    Volume: 0x0064 (100)

We might need to check if other devices have such behavior, perhaps
the headset is saving the last bearer it connected to so it tries to
restore it or something like that, this may messes up with that, in
the other hand the bearer can be selected even before first connecting
so we may decide to default to bredr instead of last seen for this
type of devices (Classic+LE Audio).

Anyway there are some pieces left that I still need to implement like
save the bearer in the storage so when the daemon is reloaded, or in
case of reboot, it restores the last mode properly.
Luiz Augusto von Dentz Feb. 25, 2025, 10:12 p.m. UTC | #2
Hi Pauli,

On Tue, Feb 25, 2025 at 5:10 PM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> Hi Pauli, Bastien,
>
> On Tue, Feb 25, 2025 at 5:01 PM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
> >
> > From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> >
> > This adds support for PreferredBearer which is printed with the likes of
> > info command:
> >
> > bluetoothctl> info <addr>
> > ...
> >         PreferredBearer: last-seen
> >
> > It also introduces a new command to get/set the PreferredBearer:
> >
> > [bluetoothctl]> bearer --help
> > Get/Set preferred bearer
> > Usage:
> >          bearer <dev> [last-seen/bredr/le]
> >
> > [bluetoothctl]> bearer <addr>
> >         PreferredBearer: last-seen
> > [bluetoothctl]> bearer <addr> le
> > bluetoothd: @ MGMT Command: Add Device (0x0033) plen 8
> >         LE Address: <addr>
> >         Action: Auto-connect remote device (0x02)
> > [CHG] Device <addr> PreferredBearer: le
> > Changing le succeeded
> > [bluetoothctl]> bearer <addr>
> >         PreferredBearer: le
> > [bluetoothctl]> bearer <addr> bredr
> > bluetoothd: @ MGMT Command: Remove Device (0x0034) plen 7
> >         LE Address: <addr>
> > [CHG] Device <addr> PreferredBearer: bredr
> > Changing bredr succeeded
> > ---
> >  client/main.c | 27 +++++++++++++++++++++++++++
> >  1 file changed, 27 insertions(+)
> >
> > diff --git a/client/main.c b/client/main.c
> > index feb21a1163d2..76c9bc329c96 100644
> > --- a/client/main.c
> > +++ b/client/main.c
> > @@ -1714,6 +1714,7 @@ static void cmd_info(int argc, char *argv[])
> >         print_property(proxy, "AdvertisingFlags");
> >         print_property(proxy, "AdvertisingData");
> >         print_property(proxy, "Sets");
> > +       print_property(proxy, "PreferredBearer");
> >
> >         battery_proxy = find_proxies_by_path(battery_proxies,
> >                                         g_dbus_proxy_get_path(proxy));
> > @@ -2086,6 +2087,30 @@ static void cmd_wake(int argc, char *argv[])
> >         return bt_shell_noninteractive_quit(EXIT_FAILURE);
> >  }
> >
> > +static void cmd_bearer(int argc, char *argv[])
> > +{
> > +       GDBusProxy *proxy;
> > +       char *str;
> > +
> > +       proxy = find_device(argc, argv);
> > +       if (!proxy)
> > +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> > +
> > +       if (argc <= 2) {
> > +               print_property(proxy, "PreferredBearer");
> > +               return;
> > +       }
> > +
> > +       str = strdup(argv[2]);
> > +
> > +       if (g_dbus_proxy_set_property_basic(proxy, "PreferredBearer",
> > +                                       DBUS_TYPE_STRING, &str,
> > +                                       generic_callback, str, free))
> > +               return;
> > +
> > +       return bt_shell_noninteractive_quit(EXIT_FAILURE);
> > +}
> > +
> >  static void cmd_list_attributes(int argc, char *argv[])
> >  {
> >         GDBusProxy *proxy;
> > @@ -3247,6 +3272,8 @@ static const struct bt_shell_menu main_menu = {
> >                                                         dev_generator },
> >         { "wake",         "[dev] [on/off]",    cmd_wake, "Get/Set wake support",
> >                                                         dev_generator },
> > +       { "bearer",       "<dev> [last-seen/bredr/le]", cmd_bearer,
> > +                               "Get/Set preferred bearer", dev_generator },
> >         { } },
> >  };
> >
> > --
> > 2.48.1
>
> So I went ahead and implemented the idea of having PreferredBearer,
> this works great when setting bredr it really stops from connecting to
> LE, the said the other way around when setting to le seems to confuse
> some headsets like EarFun and it ends up connecting both bearers:
>
> [EarFun Air Pro 3]> transport.show
> Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd1
>     UUID: Sink PAC                  (00002bc9-0000-1000-8000-00805f9b34fb)
>     Codec: 0x06 (6)
>     Configuration.#0: len 0x02 type 0x01
>     Configuration.Sampling Frequency: 16 Khz (0x03)
>     Configuration.#1: len 0x02 type 0x02
>     Configuration.Frame Duration: 7.5 ms (0x00)
>     Configuration.#2: len 0x05 type 0x03
>     Configuration.Location: 0x00000001
>     Configuration.Location: Front Left (0x00000001)
>     Configuration.#3: len 0x03 type 0x04
>     Configuration.Frame Length: 30 (0x001e)
>     Configuration.#4: len 0x02 type 0x05
>     Configuration.Frame Blocks per SDU: 1 (0x01)
>     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
>     State: idle
>     Volume: 0x00c8 (200)
>     Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0
>     QoS.CIG: 0x00 (0)
>     QoS.CIS: 0x00 (0)
>     QoS.Framing: 0x00 (0)
>     QoS.PresentationDelay: 0x00009c40 (40000)
>     QoS.Interval: 0x00001d4c (7500)
>     QoS.Latency: 0x0008 (8)
>     QoS.SDU: 0x001e (30)
>     QoS.PHY: 0x02 (2)
>     QoS.Retransmissions: 0x02 (2)
>     Location: 0x00000003 (3)
>     Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd3
> Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd2
>     UUID: Sink PAC                  (00002bc9-0000-1000-8000-00805f9b34fb)
>     Codec: 0x06 (6)
>     Configuration.#0: len 0x02 type 0x01
>     Configuration.Sampling Frequency: 16 Khz (0x03)
>     Configuration.#1: len 0x02 type 0x02
>     Configuration.Frame Duration: 7.5 ms (0x00)
>     Configuration.#2: len 0x05 type 0x03
>     Configuration.Location: 0x00000002
>     Configuration.Location: Front Right (0x00000002)
>     Configuration.#3: len 0x03 type 0x04
>     Configuration.Frame Length: 30 (0x001e)
>     Configuration.#4: len 0x02 type 0x05
>     Configuration.Frame Blocks per SDU: 1 (0x01)
>     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
>     State: idle
>     Volume: 0x00c8 (200)
>     Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0
>     QoS.CIG: 0x00 (0)
>     QoS.CIS: 0x01 (1)
>     QoS.Framing: 0x00 (0)
>     QoS.PresentationDelay: 0x00009c40 (40000)
>     QoS.Interval: 0x00001d4c (7500)
>     QoS.Latency: 0x0008 (8)
>     QoS.SDU: 0x001e (30)
>     QoS.PHY: 0x02 (2)
>     QoS.Retransmissions: 0x02 (2)
>     Location: 0x00000003 (3)
>     Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd4
> Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd3
>     UUID: Source PAC                (00002bcb-0000-1000-8000-00805f9b34fb)
>     Codec: 0x06 (6)
>     Configuration.#0: len 0x02 type 0x01
>     Configuration.Sampling Frequency: 48 Khz (0x08)
>     Configuration.#1: len 0x02 type 0x02
>     Configuration.Frame Duration: 7.5 ms (0x00)
>     Configuration.#2: len 0x05 type 0x03
>     Configuration.Location: 0x00000001
>     Configuration.Location: Front Left (0x00000001)
>     Configuration.#3: len 0x03 type 0x04
>     Configuration.Frame Length: 90 (0x005a)
>     Configuration.#4: len 0x02 type 0x05
>     Configuration.Frame Blocks per SDU: 1 (0x01)
>     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
>     State: idle
>     Volume: 0x00c8 (200)
>     Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0
>     QoS.CIG: 0x00 (0)
>     QoS.CIS: 0x00 (0)
>     QoS.Framing: 0x00 (0)
>     QoS.PresentationDelay: 0x00009c40 (40000)
>     QoS.Interval: 0x00001d4c (7500)
>     QoS.Latency: 0x000f (15)
>     QoS.SDU: 0x005a (90)
>     QoS.PHY: 0x02 (2)
>     QoS.Retransmissions: 0x05 (5)
>     Location: 0x00000003 (3)
>     Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd1
> Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd4
>     UUID: Source PAC                (00002bcb-0000-1000-8000-00805f9b34fb)
>     Codec: 0x06 (6)
>     Configuration.#0: len 0x02 type 0x01
>     Configuration.Sampling Frequency: 48 Khz (0x08)
>     Configuration.#1: len 0x02 type 0x02
>     Configuration.Frame Duration: 7.5 ms (0x00)
>     Configuration.#2: len 0x05 type 0x03
>     Configuration.Location: 0x00000002
>     Configuration.Location: Front Right (0x00000002)
>     Configuration.#3: len 0x03 type 0x04
>     Configuration.Frame Length: 90 (0x005a)
>     Configuration.#4: len 0x02 type 0x05
>     Configuration.Frame Blocks per SDU: 1 (0x01)
>     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
>     State: idle
>     Volume: 0x00c8 (200)
>     Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0
>     QoS.CIG: 0x00 (0)
>     QoS.CIS: 0x01 (1)
>     QoS.Framing: 0x00 (0)
>     QoS.PresentationDelay: 0x00009c40 (40000)
>     QoS.Interval: 0x00001d4c (7500)
>     QoS.Latency: 0x000f (15)
>     QoS.SDU: 0x005a (90)
>     QoS.PHY: 0x02 (2)
>     QoS.Retransmissions: 0x05 (5)
>     Location: 0x00000003 (3)
>     Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd2
> Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/fd5
>     UUID: Audio Source              (0000110a-0000-1000-8000-00805f9b34fb)
>     Codec: 0x02 (2)
>     Media Codec: MPEG24
>     Object Types: MPEG-4 AAC LC
>     Frequencies: 48kHz
>     Channels: 2
>     Bitrate: 320000
>     VBR: Yes
>     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
>     State: idle
>     Delay: 0x0960 (2400)
>     Volume: 0x0064 (100)

Forgot to mention, but with the above transports it seems to confuse
the gnome audio output selection, it doesn't seem to be able to mix
A2DP and BAP transports for some reason, so when I select the device
it enables BAP but A2DP is not shown as an option.

> We might need to check if other devices have such behavior, perhaps
> the headset is saving the last bearer it connected to so it tries to
> restore it or something like that, this may messes up with that, in
> the other hand the bearer can be selected even before first connecting
> so we may decide to default to bredr instead of last seen for this
> type of devices (Classic+LE Audio).
>
> Anyway there are some pieces left that I still need to implement like
> save the bearer in the storage so when the daemon is reloaded, or in
> case of reboot, it restores the last mode properly.
>
> --
> Luiz Augusto von Dentz
Pauli Virtanen March 1, 2025, 4:17 p.m. UTC | #3
ti, 2025-02-25 kello 17:12 -0500, Luiz Augusto von Dentz kirjoitti:
> Hi Pauli,
> 
> On Tue, Feb 25, 2025 at 5:10 PM Luiz Augusto von Dentz
> <luiz.dentz@gmail.com> wrote:
> > 
> > Hi Pauli, Bastien,
> > 
> > On Tue, Feb 25, 2025 at 5:01 PM Luiz Augusto von Dentz
> > <luiz.dentz@gmail.com> wrote:
> > > 
> > > From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> > > 
> > > This adds support for PreferredBearer which is printed with the likes of
> > > info command:
> > > 
> > > bluetoothctl> info <addr>
> > > ...
> > >         PreferredBearer: last-seen
> > > 
> > > It also introduces a new command to get/set the PreferredBearer:
> > > 
> > > [bluetoothctl]> bearer --help
> > > Get/Set preferred bearer
> > > Usage:
> > >          bearer <dev> [last-seen/bredr/le]
> > > 
> > > [bluetoothctl]> bearer <addr>
> > >         PreferredBearer: last-seen
> > > [bluetoothctl]> bearer <addr> le
> > > bluetoothd: @ MGMT Command: Add Device (0x0033) plen 8
> > >         LE Address: <addr>
> > >         Action: Auto-connect remote device (0x02)
> > > [CHG] Device <addr> PreferredBearer: le
> > > Changing le succeeded
> > > [bluetoothctl]> bearer <addr>
> > >         PreferredBearer: le
> > > [bluetoothctl]> bearer <addr> bredr
> > > bluetoothd: @ MGMT Command: Remove Device (0x0034) plen 7
> > >         LE Address: <addr>
> > > [CHG] Device <addr> PreferredBearer: bredr
> > > Changing bredr succeeded
> > > ---
> > >  client/main.c | 27 +++++++++++++++++++++++++++
> > >  1 file changed, 27 insertions(+)
> > > 
> > > diff --git a/client/main.c b/client/main.c
> > > index feb21a1163d2..76c9bc329c96 100644
> > > --- a/client/main.c
> > > +++ b/client/main.c
> > > @@ -1714,6 +1714,7 @@ static void cmd_info(int argc, char *argv[])
> > >         print_property(proxy, "AdvertisingFlags");
> > >         print_property(proxy, "AdvertisingData");
> > >         print_property(proxy, "Sets");
> > > +       print_property(proxy, "PreferredBearer");
> > > 
> > >         battery_proxy = find_proxies_by_path(battery_proxies,
> > >                                         g_dbus_proxy_get_path(proxy));
> > > @@ -2086,6 +2087,30 @@ static void cmd_wake(int argc, char *argv[])
> > >         return bt_shell_noninteractive_quit(EXIT_FAILURE);
> > >  }
> > > 
> > > +static void cmd_bearer(int argc, char *argv[])
> > > +{
> > > +       GDBusProxy *proxy;
> > > +       char *str;
> > > +
> > > +       proxy = find_device(argc, argv);
> > > +       if (!proxy)
> > > +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> > > +
> > > +       if (argc <= 2) {
> > > +               print_property(proxy, "PreferredBearer");
> > > +               return;
> > > +       }
> > > +
> > > +       str = strdup(argv[2]);
> > > +
> > > +       if (g_dbus_proxy_set_property_basic(proxy, "PreferredBearer",
> > > +                                       DBUS_TYPE_STRING, &str,
> > > +                                       generic_callback, str, free))
> > > +               return;
> > > +
> > > +       return bt_shell_noninteractive_quit(EXIT_FAILURE);
> > > +}
> > > +
> > >  static void cmd_list_attributes(int argc, char *argv[])
> > >  {
> > >         GDBusProxy *proxy;
> > > @@ -3247,6 +3272,8 @@ static const struct bt_shell_menu main_menu = {
> > >                                                         dev_generator },
> > >         { "wake",         "[dev] [on/off]",    cmd_wake, "Get/Set wake support",
> > >                                                         dev_generator },
> > > +       { "bearer",       "<dev> [last-seen/bredr/le]", cmd_bearer,
> > > +                               "Get/Set preferred bearer", dev_generator },
> > >         { } },
> > >  };
> > > 
> > > --
> > > 2.48.1
> > 
> > So I went ahead and implemented the idea of having PreferredBearer,
> > this works great when setting bredr it really stops from connecting to
> > LE, the said the other way around when setting to le seems to confuse
> > some headsets like EarFun and it ends up connecting both bearers:
> > 
> > [EarFun Air Pro 3]> transport.show
> > Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd1
> >     UUID: Sink PAC                  (00002bc9-0000-1000-8000-00805f9b34fb)
> >     Codec: 0x06 (6)
> >     Configuration.#0: len 0x02 type 0x01
> >     Configuration.Sampling Frequency: 16 Khz (0x03)
> >     Configuration.#1: len 0x02 type 0x02
> >     Configuration.Frame Duration: 7.5 ms (0x00)
> >     Configuration.#2: len 0x05 type 0x03
> >     Configuration.Location: 0x00000001
> >     Configuration.Location: Front Left (0x00000001)
> >     Configuration.#3: len 0x03 type 0x04
> >     Configuration.Frame Length: 30 (0x001e)
> >     Configuration.#4: len 0x02 type 0x05
> >     Configuration.Frame Blocks per SDU: 1 (0x01)
> >     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
> >     State: idle
> >     Volume: 0x00c8 (200)
> >     Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0
> >     QoS.CIG: 0x00 (0)
> >     QoS.CIS: 0x00 (0)
> >     QoS.Framing: 0x00 (0)
> >     QoS.PresentationDelay: 0x00009c40 (40000)
> >     QoS.Interval: 0x00001d4c (7500)
> >     QoS.Latency: 0x0008 (8)
> >     QoS.SDU: 0x001e (30)
> >     QoS.PHY: 0x02 (2)
> >     QoS.Retransmissions: 0x02 (2)
> >     Location: 0x00000003 (3)
> >     Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd3
> > Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd2
> >     UUID: Sink PAC                  (00002bc9-0000-1000-8000-00805f9b34fb)
> >     Codec: 0x06 (6)
> >     Configuration.#0: len 0x02 type 0x01
> >     Configuration.Sampling Frequency: 16 Khz (0x03)
> >     Configuration.#1: len 0x02 type 0x02
> >     Configuration.Frame Duration: 7.5 ms (0x00)
> >     Configuration.#2: len 0x05 type 0x03
> >     Configuration.Location: 0x00000002
> >     Configuration.Location: Front Right (0x00000002)
> >     Configuration.#3: len 0x03 type 0x04
> >     Configuration.Frame Length: 30 (0x001e)
> >     Configuration.#4: len 0x02 type 0x05
> >     Configuration.Frame Blocks per SDU: 1 (0x01)
> >     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
> >     State: idle
> >     Volume: 0x00c8 (200)
> >     Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0
> >     QoS.CIG: 0x00 (0)
> >     QoS.CIS: 0x01 (1)
> >     QoS.Framing: 0x00 (0)
> >     QoS.PresentationDelay: 0x00009c40 (40000)
> >     QoS.Interval: 0x00001d4c (7500)
> >     QoS.Latency: 0x0008 (8)
> >     QoS.SDU: 0x001e (30)
> >     QoS.PHY: 0x02 (2)
> >     QoS.Retransmissions: 0x02 (2)
> >     Location: 0x00000003 (3)
> >     Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd4
> > Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd3
> >     UUID: Source PAC                (00002bcb-0000-1000-8000-00805f9b34fb)
> >     Codec: 0x06 (6)
> >     Configuration.#0: len 0x02 type 0x01
> >     Configuration.Sampling Frequency: 48 Khz (0x08)
> >     Configuration.#1: len 0x02 type 0x02
> >     Configuration.Frame Duration: 7.5 ms (0x00)
> >     Configuration.#2: len 0x05 type 0x03
> >     Configuration.Location: 0x00000001
> >     Configuration.Location: Front Left (0x00000001)
> >     Configuration.#3: len 0x03 type 0x04
> >     Configuration.Frame Length: 90 (0x005a)
> >     Configuration.#4: len 0x02 type 0x05
> >     Configuration.Frame Blocks per SDU: 1 (0x01)
> >     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
> >     State: idle
> >     Volume: 0x00c8 (200)
> >     Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0
> >     QoS.CIG: 0x00 (0)
> >     QoS.CIS: 0x00 (0)
> >     QoS.Framing: 0x00 (0)
> >     QoS.PresentationDelay: 0x00009c40 (40000)
> >     QoS.Interval: 0x00001d4c (7500)
> >     QoS.Latency: 0x000f (15)
> >     QoS.SDU: 0x005a (90)
> >     QoS.PHY: 0x02 (2)
> >     QoS.Retransmissions: 0x05 (5)
> >     Location: 0x00000003 (3)
> >     Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd1
> > Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0/fd4
> >     UUID: Source PAC                (00002bcb-0000-1000-8000-00805f9b34fb)
> >     Codec: 0x06 (6)
> >     Configuration.#0: len 0x02 type 0x01
> >     Configuration.Sampling Frequency: 48 Khz (0x08)
> >     Configuration.#1: len 0x02 type 0x02
> >     Configuration.Frame Duration: 7.5 ms (0x00)
> >     Configuration.#2: len 0x05 type 0x03
> >     Configuration.Location: 0x00000002
> >     Configuration.Location: Front Right (0x00000002)
> >     Configuration.#3: len 0x03 type 0x04
> >     Configuration.Frame Length: 90 (0x005a)
> >     Configuration.#4: len 0x02 type 0x05
> >     Configuration.Frame Blocks per SDU: 1 (0x01)
> >     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
> >     State: idle
> >     Volume: 0x00c8 (200)
> >     Endpoint: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_sink0
> >     QoS.CIG: 0x00 (0)
> >     QoS.CIS: 0x01 (1)
> >     QoS.Framing: 0x00 (0)
> >     QoS.PresentationDelay: 0x00009c40 (40000)
> >     QoS.Interval: 0x00001d4c (7500)
> >     QoS.Latency: 0x000f (15)
> >     QoS.SDU: 0x005a (90)
> >     QoS.PHY: 0x02 (2)
> >     QoS.Retransmissions: 0x05 (5)
> >     Location: 0x00000003 (3)
> >     Links: /org/bluez/hci0/dev_70_5A_6F_63_B6_41/pac_source0/fd2
> > Transport /org/bluez/hci0/dev_70_5A_6F_63_B6_41/fd5
> >     UUID: Audio Source              (0000110a-0000-1000-8000-00805f9b34fb)
> >     Codec: 0x02 (2)
> >     Media Codec: MPEG24
> >     Object Types: MPEG-4 AAC LC
> >     Frequencies: 48kHz
> >     Channels: 2
> >     Bitrate: 320000
> >     VBR: Yes
> >     Device: /org/bluez/hci0/dev_70_5A_6F_63_B6_41
> >     State: idle
> >     Delay: 0x0960 (2400)
> >     Volume: 0x0064 (100)
> 
> Forgot to mention, but with the above transports it seems to confuse
> the gnome audio output selection, it doesn't seem to be able to mix
> A2DP and BAP transports for some reason, so when I select the device
> it enables BAP but A2DP is not shown as an option.

I'll have to see if I can reproduce that on current PW master branch.

The visibility of profiles in theory should only cares about whether
the UUIDs appear in both device properties and transport.
diff mbox series

Patch

diff --git a/client/main.c b/client/main.c
index feb21a1163d2..76c9bc329c96 100644
--- a/client/main.c
+++ b/client/main.c
@@ -1714,6 +1714,7 @@  static void cmd_info(int argc, char *argv[])
 	print_property(proxy, "AdvertisingFlags");
 	print_property(proxy, "AdvertisingData");
 	print_property(proxy, "Sets");
+	print_property(proxy, "PreferredBearer");
 
 	battery_proxy = find_proxies_by_path(battery_proxies,
 					g_dbus_proxy_get_path(proxy));
@@ -2086,6 +2087,30 @@  static void cmd_wake(int argc, char *argv[])
 	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
+static void cmd_bearer(int argc, char *argv[])
+{
+	GDBusProxy *proxy;
+	char *str;
+
+	proxy = find_device(argc, argv);
+	if (!proxy)
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+
+	if (argc <= 2) {
+		print_property(proxy, "PreferredBearer");
+		return;
+	}
+
+	str = strdup(argv[2]);
+
+	if (g_dbus_proxy_set_property_basic(proxy, "PreferredBearer",
+					DBUS_TYPE_STRING, &str,
+					generic_callback, str, free))
+		return;
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
+
 static void cmd_list_attributes(int argc, char *argv[])
 {
 	GDBusProxy *proxy;
@@ -3247,6 +3272,8 @@  static const struct bt_shell_menu main_menu = {
 							dev_generator },
 	{ "wake",         "[dev] [on/off]",    cmd_wake, "Get/Set wake support",
 							dev_generator },
+	{ "bearer",       "<dev> [last-seen/bredr/le]", cmd_bearer,
+				"Get/Set preferred bearer", dev_generator },
 	{ } },
 };