diff mbox series

[v2,5/6] Update bluetoothctl with support for broadcast source

Message ID 20230525153452.125789-6-silviu.barbulescu@nxp.com (mailing list archive)
State Superseded
Headers show
Series Add initial support for BAP broadcast source | expand

Checks

Context Check Description
tedd_an/pre-ci_am success Success
tedd_an/CheckPatch warning WARNING:LONG_LINE: line length of 86 exceeds 80 columns #211: FILE: client/player.c:1796: + if ((!cfg->ep->broadcast) && (cfg->ep->iso_group != BT_ISO_QOS_GROUP_UNSET)) { WARNING:LONG_LINE: line length of 88 exceeds 80 columns #224: FILE: client/player.c:1806: + if ((!cfg->ep->broadcast) && (cfg->ep->iso_stream != BT_ISO_QOS_STREAM_UNSET)) { WARNING:LONG_LINE_STRING: line length of 81 exceeds 80 columns #243: FILE: client/player.c:1823: + bt_shell_printf("Framing %s\n", qos->framing ? "true" : "false"); WARNING:LONG_LINE: line length of 92 exceeds 80 columns #250: FILE: client/player.c:1828: + bt_shell_printf("Framing %s\n", bcast_qos.bcast.framing ? "true" : "false"); WARNING:LONG_LINE: line length of 82 exceeds 80 columns #253: FILE: client/player.c:1831: + &bcast_qos.bcast.framing); WARNING:LONG_LINE: line length of 106 exceeds 80 columns #309: FILE: client/player.c:1904: + DBUS_TYPE_BYTE, &cfg->ep->bcode->iov_base, WARNING:LONG_LINE: line length of 89 exceeds 80 columns #310: FILE: client/player.c:1905: + cfg->ep->bcode->iov_len); WARNING:LONG_LINE: line length of 98 exceeds 80 columns #322: FILE: client/player.c:1947: + iov_append(&cfg->ep->bcode, bcast_qos.bcast.bcode, sizeof(bcast_qos.bcast.bcode)); WARNING:LONG_LINE: line length of 81 exceeds 80 columns #324: FILE: client/player.c:1949: + iov_append(&cfg->caps, base_lc3_16_2_1, sizeof(base_lc3_16_2_1)); WARNING:LONG_LINE: line length of 84 exceeds 80 columns #327: FILE: client/player.c:1952: + iov_append(&cfg->caps, preset->data.iov_base, preset->data.iov_len); WARNING:LONG_LINE: line length of 94 exceeds 80 columns #384: FILE: client/player.c:2408: + bt_shell_prompt_input(ep->path, "CIS (auto/value):", endpoint_iso_stream, ep); WARNING:LONG_LINE: line length of 94 exceeds 80 columns #386: FILE: client/player.c:2410: + bt_shell_prompt_input(ep->path, "BIS (auto/value):", endpoint_iso_stream, ep); WARNING:LONG_LINE: line length of 93 exceeds 80 columns #396: FILE: client/player.c:2433: + bt_shell_prompt_input(ep->path, "BIG (auto/value):", endpoint_iso_group, ep); WARNING:LONG_LINE: line length of 93 exceeds 80 columns #398: FILE: client/player.c:2435: + bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_iso_group, ep); WARNING:LONG_LINE: line length of 93 exceeds 80 columns #420: FILE: client/player.c:2461: + bt_shell_prompt_input(ep->path, "BIG (auto/value):", endpoint_iso_group, ep); WARNING:LONG_LINE: line length of 93 exceeds 80 columns #422: FILE: client/player.c:2463: + bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_iso_group, ep); WARNING:LONG_LINE_STRING: line length of 86 exceeds 80 columns #451: FILE: client/player.c:3755: + bt_shell_printf("Transport %s already in acquiring process\n", WARNING:LONG_LINE_STRING: line length of 89 exceeds 80 columns #463: FILE: client/player.c:3767: + bt_shell_printf("Link %s already in acquiring process\n", WARNING:LONG_LINE: line length of 82 exceeds 80 columns #465: FILE: client/player.c:3769: + return bt_shell_noninteractive_quit(EXIT_FAILURE); /github/workspace/src/src/13255387.patch total: 0 errors, 19 warnings, 350 lines checked NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. /github/workspace/src/src/13255387.patch has style problems, please review. NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS.
tedd_an/GitLint success Gitlint PASS
tedd_an/IncrementalBuild success Incremental Build PASS

Commit Message

Silviu Florian Barbulescu May 25, 2023, 3:34 p.m. UTC
This adds bluetoothctl support for broadcast source.

---
 client/player.c | 209 ++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 185 insertions(+), 24 deletions(-)

Comments

Luiz Augusto von Dentz May 25, 2023, 5:47 p.m. UTC | #1
Hi Silviu,

On Thu, May 25, 2023 at 8:37 AM Silviu Florian Barbulescu
<silviu.barbulescu@nxp.com> wrote:
>
> This adds bluetoothctl support for broadcast source.

You forgot to add an example of how these changes can be used in the
patch description, I know you have it in the cover letter but that
will not be committed.

> ---
>  client/player.c | 209 ++++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 185 insertions(+), 24 deletions(-)
>
> diff --git a/client/player.c b/client/player.c
> index a9f56fb94..408118fca 100644
> --- a/client/player.c
> +++ b/client/player.c
> @@ -74,11 +74,13 @@ struct endpoint {
>         bool auto_accept;
>         bool acquiring;
>         uint8_t max_transports;
> -       uint8_t cig;
> -       uint8_t cis;
> +       uint8_t iso_group;
> +       uint8_t iso_stream;
>         char *transport;
>         DBusMessage *msg;
>         struct preset *preset;
> +       bool broadcast;
> +       struct iovec *bcode;
>  };
>
>  static DBusConnection *dbus_conn;
> @@ -104,6 +106,22 @@ struct transport {
>         struct io *timer_io;
>  };
>
> +static const uint8_t base_lc3_16_2_1[] = {
> +       0x28, 0x00, 0x00, /* Presentation Delay */
> +       0x01, /* Number of Subgroups */
> +       0x01, /* Number of BIS */
> +       0x06, 0x00, 0x00, 0x00, 0x00, /* Code ID = LC3 (0x06) */
> +       0x11, /* Codec Specific Configuration */
> +       0x02, 0x01, 0x03, /* 16 KHZ */
> +       0x02, 0x02, 0x01, /* 10 ms */
> +       0x05, 0x03, 0x01, 0x00, 0x00, 0x00,  /* Front Left */
> +       0x03, 0x04, 0x28, 0x00, /* Frame Length 40 bytes */
> +       0x04, /* Metadata */
> +       0x03, 0x02, 0x02, 0x00, /* Audio Context: Convertional */
> +       0x01, /* BIS */
> +       0x00, /* Codec Specific Configuration */
> +};
> +
>  static void endpoint_unregister(void *data)
>  {
>         struct endpoint *ep = data;
> @@ -1154,6 +1172,16 @@ static const struct capabilities {
>         CODEC_CAPABILITIES(PAC_SOURCE_UUID, LC3_ID,
>                                         LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY,
>                                                 3u, 30, 240)),
> +       /* Broadcast LC3 Source:
> +        *
> +        * Frequencies: 8Khz 11Khz 16Khz 22Khz 24Khz 32Khz 44.1Khz 48Khz
> +        * Duration: 7.5 ms 10 ms
> +        * Channel count: 3
> +        * Frame length: 30-240
> +        */
> +       CODEC_CAPABILITIES(BAA_SERVICE_UUID, LC3_ID,
> +                                       LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY,
> +                                               3u, 30, 240)),
>  };
>
>  struct codec_qos {
> @@ -1435,6 +1463,7 @@ static struct preset {
>         PRESET(A2DP_SINK_UUID, A2DP_CODEC_SBC, sbc_presets, 6),
>         PRESET(PAC_SINK_UUID, LC3_ID, lc3_presets, 3),
>         PRESET(PAC_SOURCE_UUID, LC3_ID, lc3_presets, 3),
> +       PRESET(BAA_SERVICE_UUID,  LC3_ID, lc3_presets, 3),
>  };
>
>  static void parse_vendor_codec(const char *codec, uint16_t *vid, uint16_t *cid)
> @@ -1707,6 +1736,27 @@ struct endpoint_config {
>         const struct codec_qos *qos;
>  };
>
> +#define BCODE {0x01, 0x02, 0x68, 0x05, 0x53, 0xf1, 0x41, 0x5a, \
> +                               0xa2, 0x65, 0xbb, 0xaf, 0xc6, 0xea, 0x03, 0xb8}
> +
> +static struct bt_iso_qos bcast_qos = {
> +               .bcast = {
> +                       .big = BT_ISO_QOS_BIG_UNSET,
> +                       .bis = BT_ISO_QOS_BIS_UNSET,
> +                       .sync_interval = 0x07,
> +                       .packing = 0x00,
> +                       .framing = 0x00,
> +                       .encryption = 0x00,
> +                       .bcode = BCODE,
> +                       .options = 0x00,
> +                       .skip = 0x0000,
> +                       .sync_timeout = 0x4000,
> +                       .sync_cte_type = 0x00,
> +                       .mse = 0x00,
> +                       .timeout = 0x4000,
> +               }
> +       };
> +
>  static void append_properties(DBusMessageIter *iter,
>                                                 struct endpoint_config *cfg)
>  {
> @@ -1714,6 +1764,7 @@ static void append_properties(DBusMessageIter *iter,
>         struct codec_qos *qos = (void *)cfg->qos;
>         const char *key = "Capabilities";
>         const char *meta = "Metadata";
> +       const char *keyBCode = "BroadcastCode";
>
>         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
>
> @@ -1742,16 +1793,25 @@ static void append_properties(DBusMessageIter *iter,
>                                         DBUS_TYPE_BYTE, &cfg->target_latency);
>         }
>
> -       if (cfg->ep->cig != BT_ISO_QOS_CIG_UNSET) {
> -               bt_shell_printf("CIG 0x%2.2x\n", cfg->ep->cig);
> +       if ((!cfg->ep->broadcast) && (cfg->ep->iso_group != BT_ISO_QOS_GROUP_UNSET)) {
> +               bt_shell_printf("CIG 0x%2.2x\n", cfg->ep->iso_group);
>                 g_dbus_dict_append_entry(&dict, "CIG", DBUS_TYPE_BYTE,
> -                                                       &cfg->ep->cig);
> +                                                       &cfg->ep->iso_group);
> +       } else {
> +               bt_shell_printf("BIG 0x%2.2x\n", bcast_qos.bcast.big);
> +               g_dbus_dict_append_entry(&dict, "BIG", DBUS_TYPE_BYTE,
> +                                                       &bcast_qos.bcast.big);
>         }
>
> -       if (cfg->ep->cis != BT_ISO_QOS_CIS_UNSET) {
> -               bt_shell_printf("CIS 0x%2.2x\n", cfg->ep->cis);
> +       if ((!cfg->ep->broadcast) && (cfg->ep->iso_stream != BT_ISO_QOS_STREAM_UNSET)) {
> +               bt_shell_printf("CIS 0x%2.2x\n", cfg->ep->iso_stream);
>                 g_dbus_dict_append_entry(&dict, "CIS", DBUS_TYPE_BYTE,
> -                                                       &cfg->ep->cis);
> +                                                       &cfg->ep->iso_stream);
> +
> +       } else {
> +               bt_shell_printf("BIS 0x%2.2x\n", bcast_qos.bcast.bis);
> +               g_dbus_dict_append_entry(&dict, "BIS", DBUS_TYPE_BYTE,
> +                                                       &bcast_qos.bcast.bis);
>         }
>
>         bt_shell_printf("Interval %u\n", qos->interval);
> @@ -1759,10 +1819,17 @@ static void append_properties(DBusMessageIter *iter,
>         g_dbus_dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT32,
>                                                 &qos->interval);
>
> -       bt_shell_printf("Framing %s\n", qos->framing ? "true" : "false");
> +       if (!cfg->ep->broadcast) {
> +               bt_shell_printf("Framing %s\n", qos->framing ? "true" : "false");
>
> -       g_dbus_dict_append_entry(&dict, "Framing", DBUS_TYPE_BOOLEAN,
> -                                               &qos->framing);
> +               g_dbus_dict_append_entry(&dict, "Framing", DBUS_TYPE_BOOLEAN,
> +                                                       &qos->framing);
> +       } else {
> +               bt_shell_printf("Framing %s\n", bcast_qos.bcast.framing ? "true" : "false");
> +
> +               g_dbus_dict_append_entry(&dict, "Framing", DBUS_TYPE_BOOLEAN,
> +                                                       &bcast_qos.bcast.framing);
> +       }
>
>         bt_shell_printf("PHY %s\n", qos->phy);
>
> @@ -1787,6 +1854,56 @@ static void append_properties(DBusMessageIter *iter,
>         g_dbus_dict_append_entry(&dict, "Delay", DBUS_TYPE_UINT32,
>                                                 &qos->delay);
>
> +       if (!cfg->ep->broadcast)
> +               goto done;
> +
> +       bt_shell_printf("SyncInterval %u\n", bcast_qos.bcast.sync_interval);
> +
> +       g_dbus_dict_append_entry(&dict, "SyncInterval", DBUS_TYPE_BYTE,
> +                                               &bcast_qos.bcast.sync_interval);
> +
> +       bt_shell_printf("Encryption %u\n", bcast_qos.bcast.encryption);
> +
> +       g_dbus_dict_append_entry(&dict, "Encryption", DBUS_TYPE_BYTE,
> +                                               &bcast_qos.bcast.encryption);
> +
> +       bt_shell_printf("Options %u\n", bcast_qos.bcast.options);
> +
> +       g_dbus_dict_append_entry(&dict, "Options", DBUS_TYPE_BYTE,
> +                                               &bcast_qos.bcast.options);
> +
> +       bt_shell_printf("Skip %u\n", bcast_qos.bcast.skip);
> +
> +       g_dbus_dict_append_entry(&dict, "Skip", DBUS_TYPE_UINT16,
> +                                               &bcast_qos.bcast.skip);
> +
> +       bt_shell_printf("SyncTimeout %u\n", bcast_qos.bcast.sync_timeout);
> +
> +       g_dbus_dict_append_entry(&dict, "SyncTimeout", DBUS_TYPE_UINT16,
> +                                               &bcast_qos.bcast.sync_timeout);
> +
> +       bt_shell_printf("SyncCteType %u\n", bcast_qos.bcast.sync_cte_type);
> +
> +       g_dbus_dict_append_entry(&dict, "SyncCteType", DBUS_TYPE_BYTE,
> +                                               &bcast_qos.bcast.sync_cte_type);
> +
> +       bt_shell_printf("MSE %u\n", bcast_qos.bcast.mse);
> +
> +       g_dbus_dict_append_entry(&dict, "MSE", DBUS_TYPE_BYTE,
> +                                               &bcast_qos.bcast.mse);
> +
> +       bt_shell_printf("Timeout %u\n", bcast_qos.bcast.timeout);
> +
> +       g_dbus_dict_append_entry(&dict, "Timeout", DBUS_TYPE_UINT16,
> +                                               &bcast_qos.bcast.timeout);
> +
> +       bt_shell_printf("BroadcastCode:\n");
> +       bt_shell_hexdump(cfg->ep->bcode->iov_base, cfg->ep->bcode->iov_len);
> +
> +       g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &keyBCode,
> +                                                               DBUS_TYPE_BYTE, &cfg->ep->bcode->iov_base,
> +                                                               cfg->ep->bcode->iov_len);
> +
>  done:
>         dbus_message_iter_close_container(iter, &dict);
>  }
> @@ -1826,8 +1943,15 @@ static DBusMessage *endpoint_select_properties_reply(struct endpoint *ep,
>         cfg = new0(struct endpoint_config, 1);
>         cfg->ep = ep;
>
> -       /* Copy capabilities */
> -       iov_append(&cfg->caps, preset->data.iov_base, preset->data.iov_len);
> +       if (ep->broadcast) {
> +               iov_append(&cfg->ep->bcode, bcast_qos.bcast.bcode, sizeof(bcast_qos.bcast.bcode));
> +               /* Copy capabilities for broadcast*/
> +               iov_append(&cfg->caps, base_lc3_16_2_1, sizeof(base_lc3_16_2_1));
> +       } else {
> +               /* Copy capabilities */
> +               iov_append(&cfg->caps, preset->data.iov_base, preset->data.iov_len);
> +       }
> +
>         cfg->target_latency = preset->target_latency;
>
>         /* Copy metadata */
> @@ -2239,14 +2363,14 @@ fail:
>
>  }
>
> -static void endpoint_cis(const char *input, void *user_data)
> +static void endpoint_iso_stream(const char *input, void *user_data)
>  {
>         struct endpoint *ep = user_data;
>         char *endptr = NULL;
>         int value;
>
>         if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) {
> -               ep->cis = BT_ISO_QOS_CIS_UNSET;
> +               ep->iso_stream = BT_ISO_QOS_STREAM_UNSET;
>         } else {
>                 value = strtol(input, &endptr, 0);
>
> @@ -2255,20 +2379,20 @@ static void endpoint_cis(const char *input, void *user_data)
>                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
>                 }
>
> -               ep->cis = value;
> +               ep->iso_stream = value;
>         }
>
>         endpoint_register(ep);
>  }
>
> -static void endpoint_cig(const char *input, void *user_data)
> +static void endpoint_iso_group(const char *input, void *user_data)
>  {
>         struct endpoint *ep = user_data;
>         char *endptr = NULL;
>         int value;
>
>         if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) {
> -               ep->cig = BT_ISO_QOS_CIG_UNSET;
> +               ep->iso_group = BT_ISO_QOS_GROUP_UNSET;
>         } else {
>                 value = strtol(input, &endptr, 0);
>
> @@ -2277,10 +2401,13 @@ static void endpoint_cig(const char *input, void *user_data)
>                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
>                 }
>
> -               ep->cig = value;
> +               ep->iso_group = value;
>         }
>
> -       bt_shell_prompt_input(ep->path, "CIS (auto/value):", endpoint_cis, ep);
> +       if (!ep->broadcast)
> +               bt_shell_prompt_input(ep->path, "CIS (auto/value):", endpoint_iso_stream, ep);
> +       else
> +               bt_shell_prompt_input(ep->path, "BIS (auto/value):", endpoint_iso_stream, ep);
>  }
>
>  static void endpoint_max_transports(const char *input, void *user_data)
> @@ -2302,13 +2429,22 @@ static void endpoint_max_transports(const char *input, void *user_data)
>                 ep->max_transports = value;
>         }
>
> -       bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_cig, ep);
> +       if (ep->broadcast)
> +               bt_shell_prompt_input(ep->path, "BIG (auto/value):", endpoint_iso_group, ep);
> +       else
> +               bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_iso_group, ep);
>  }
>
>  static void endpoint_auto_accept(const char *input, void *user_data)
>  {
>         struct endpoint *ep = user_data;
>
> +       if (!strcmp(ep->uuid, BAA_SERVICE_UUID)) {
> +               ep->broadcast = true;
> +       } else {
> +               ep->broadcast = false;
> +       }
> +
>         if (!strcasecmp(input, "y") || !strcasecmp(input, "yes")) {
>                 ep->auto_accept = true;
>                 bt_shell_prompt_input(ep->path, "Max Transports (auto/value):",
> @@ -2321,7 +2457,10 @@ static void endpoint_auto_accept(const char *input, void *user_data)
>                 return bt_shell_noninteractive_quit(EXIT_FAILURE);
>         }
>
> -       bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_cig, ep);
> +       if (ep->broadcast)
> +               bt_shell_prompt_input(ep->path, "BIG (auto/value):", endpoint_iso_group, ep);
> +       else
> +               bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_iso_group, ep);
>  }
>
>  static void endpoint_set_metadata(const char *input, void *user_data)
> @@ -3050,8 +3189,8 @@ static void register_endpoints(GDBusProxy *proxy)
>                                                                 ep->cid);
>                 ep->max_transports = UINT8_MAX;
>                 ep->auto_accept = true;
> -               ep->cig = BT_ISO_QOS_CIG_UNSET;
> -               ep->cis = BT_ISO_QOS_CIS_UNSET;
> +               ep->iso_group = BT_ISO_QOS_GROUP_UNSET;
> +               ep->iso_stream = BT_ISO_QOS_STREAM_UNSET;
>                 endpoint_register(ep);
>         }
>  }
> @@ -3595,6 +3734,7 @@ static void cmd_acquire_transport(int argc, char *argv[])
>  {
>         GDBusProxy *proxy;
>         int i;
> +       struct endpoint *ep, *link;
>
>         for (i = 1; i < argc; i++) {
>                 proxy = g_dbus_proxy_lookup(transports, NULL, argv[i],
> @@ -3610,6 +3750,27 @@ static void cmd_acquire_transport(int argc, char *argv[])
>                         return bt_shell_noninteractive_quit(EXIT_FAILURE);
>                 }
>
> +               ep = find_ep_by_transport(g_dbus_proxy_get_path(proxy));
> +               if (!ep || ep->acquiring) {
> +                       bt_shell_printf("Transport %s already in acquiring process\n",
> +                                       argv[i]);
> +                       return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +               }
> +
> +               ep->acquiring = true;
> +
> +               link = find_link_by_proxy(proxy);
> +               if (link) {
> +                       bt_shell_printf("Link %s found\n", link->transport);
> +                       /* If link already acquiring wait it to be complete */
> +                       if (link->acquiring) {
> +                               bt_shell_printf("Link %s already in acquiring process\n",
> +                                       argv[i]);
> +                               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +                       }
> +                       link->acquiring = true;
> +               }
> +
>                 if (!g_dbus_proxy_method_call(proxy, "Acquire", NULL,
>                                                 acquire_reply, proxy, NULL)) {
>                         bt_shell_printf("Failed acquire transport\n");
> --
> 2.34.1
>
diff mbox series

Patch

diff --git a/client/player.c b/client/player.c
index a9f56fb94..408118fca 100644
--- a/client/player.c
+++ b/client/player.c
@@ -74,11 +74,13 @@  struct endpoint {
 	bool auto_accept;
 	bool acquiring;
 	uint8_t max_transports;
-	uint8_t cig;
-	uint8_t cis;
+	uint8_t iso_group;
+	uint8_t iso_stream;
 	char *transport;
 	DBusMessage *msg;
 	struct preset *preset;
+	bool broadcast;
+	struct iovec *bcode;
 };
 
 static DBusConnection *dbus_conn;
@@ -104,6 +106,22 @@  struct transport {
 	struct io *timer_io;
 };
 
+static const uint8_t base_lc3_16_2_1[] = {
+	0x28, 0x00, 0x00, /* Presentation Delay */
+	0x01, /* Number of Subgroups */
+	0x01, /* Number of BIS */
+	0x06, 0x00, 0x00, 0x00, 0x00, /* Code ID = LC3 (0x06) */
+	0x11, /* Codec Specific Configuration */
+	0x02, 0x01, 0x03, /* 16 KHZ */
+	0x02, 0x02, 0x01, /* 10 ms */
+	0x05, 0x03, 0x01, 0x00, 0x00, 0x00,  /* Front Left */
+	0x03, 0x04, 0x28, 0x00, /* Frame Length 40 bytes */
+	0x04, /* Metadata */
+	0x03, 0x02, 0x02, 0x00, /* Audio Context: Convertional */
+	0x01, /* BIS */
+	0x00, /* Codec Specific Configuration */
+};
+
 static void endpoint_unregister(void *data)
 {
 	struct endpoint *ep = data;
@@ -1154,6 +1172,16 @@  static const struct capabilities {
 	CODEC_CAPABILITIES(PAC_SOURCE_UUID, LC3_ID,
 					LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY,
 						3u, 30, 240)),
+	/* Broadcast LC3 Source:
+	 *
+	 * Frequencies: 8Khz 11Khz 16Khz 22Khz 24Khz 32Khz 44.1Khz 48Khz
+	 * Duration: 7.5 ms 10 ms
+	 * Channel count: 3
+	 * Frame length: 30-240
+	 */
+	CODEC_CAPABILITIES(BAA_SERVICE_UUID, LC3_ID,
+					LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY,
+						3u, 30, 240)),
 };
 
 struct codec_qos {
@@ -1435,6 +1463,7 @@  static struct preset {
 	PRESET(A2DP_SINK_UUID, A2DP_CODEC_SBC, sbc_presets, 6),
 	PRESET(PAC_SINK_UUID, LC3_ID, lc3_presets, 3),
 	PRESET(PAC_SOURCE_UUID, LC3_ID, lc3_presets, 3),
+	PRESET(BAA_SERVICE_UUID,  LC3_ID, lc3_presets, 3),
 };
 
 static void parse_vendor_codec(const char *codec, uint16_t *vid, uint16_t *cid)
@@ -1707,6 +1736,27 @@  struct endpoint_config {
 	const struct codec_qos *qos;
 };
 
+#define BCODE {0x01, 0x02, 0x68, 0x05, 0x53, 0xf1, 0x41, 0x5a, \
+				0xa2, 0x65, 0xbb, 0xaf, 0xc6, 0xea, 0x03, 0xb8}
+
+static struct bt_iso_qos bcast_qos = {
+		.bcast = {
+			.big = BT_ISO_QOS_BIG_UNSET,
+			.bis = BT_ISO_QOS_BIS_UNSET,
+			.sync_interval = 0x07,
+			.packing = 0x00,
+			.framing = 0x00,
+			.encryption = 0x00,
+			.bcode = BCODE,
+			.options = 0x00,
+			.skip = 0x0000,
+			.sync_timeout = 0x4000,
+			.sync_cte_type = 0x00,
+			.mse = 0x00,
+			.timeout = 0x4000,
+		}
+	};
+
 static void append_properties(DBusMessageIter *iter,
 						struct endpoint_config *cfg)
 {
@@ -1714,6 +1764,7 @@  static void append_properties(DBusMessageIter *iter,
 	struct codec_qos *qos = (void *)cfg->qos;
 	const char *key = "Capabilities";
 	const char *meta = "Metadata";
+	const char *keyBCode = "BroadcastCode";
 
 	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
 
@@ -1742,16 +1793,25 @@  static void append_properties(DBusMessageIter *iter,
 					DBUS_TYPE_BYTE, &cfg->target_latency);
 	}
 
-	if (cfg->ep->cig != BT_ISO_QOS_CIG_UNSET) {
-		bt_shell_printf("CIG 0x%2.2x\n", cfg->ep->cig);
+	if ((!cfg->ep->broadcast) && (cfg->ep->iso_group != BT_ISO_QOS_GROUP_UNSET)) {
+		bt_shell_printf("CIG 0x%2.2x\n", cfg->ep->iso_group);
 		g_dbus_dict_append_entry(&dict, "CIG", DBUS_TYPE_BYTE,
-							&cfg->ep->cig);
+							&cfg->ep->iso_group);
+	} else {
+		bt_shell_printf("BIG 0x%2.2x\n", bcast_qos.bcast.big);
+		g_dbus_dict_append_entry(&dict, "BIG", DBUS_TYPE_BYTE,
+							&bcast_qos.bcast.big);
 	}
 
-	if (cfg->ep->cis != BT_ISO_QOS_CIS_UNSET) {
-		bt_shell_printf("CIS 0x%2.2x\n", cfg->ep->cis);
+	if ((!cfg->ep->broadcast) && (cfg->ep->iso_stream != BT_ISO_QOS_STREAM_UNSET)) {
+		bt_shell_printf("CIS 0x%2.2x\n", cfg->ep->iso_stream);
 		g_dbus_dict_append_entry(&dict, "CIS", DBUS_TYPE_BYTE,
-							&cfg->ep->cis);
+							&cfg->ep->iso_stream);
+
+	} else {
+		bt_shell_printf("BIS 0x%2.2x\n", bcast_qos.bcast.bis);
+		g_dbus_dict_append_entry(&dict, "BIS", DBUS_TYPE_BYTE,
+							&bcast_qos.bcast.bis);
 	}
 
 	bt_shell_printf("Interval %u\n", qos->interval);
@@ -1759,10 +1819,17 @@  static void append_properties(DBusMessageIter *iter,
 	g_dbus_dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT32,
 						&qos->interval);
 
-	bt_shell_printf("Framing %s\n", qos->framing ? "true" : "false");
+	if (!cfg->ep->broadcast) {
+		bt_shell_printf("Framing %s\n", qos->framing ? "true" : "false");
 
-	g_dbus_dict_append_entry(&dict, "Framing", DBUS_TYPE_BOOLEAN,
-						&qos->framing);
+		g_dbus_dict_append_entry(&dict, "Framing", DBUS_TYPE_BOOLEAN,
+							&qos->framing);
+	} else {
+		bt_shell_printf("Framing %s\n", bcast_qos.bcast.framing ? "true" : "false");
+
+		g_dbus_dict_append_entry(&dict, "Framing", DBUS_TYPE_BOOLEAN,
+							&bcast_qos.bcast.framing);
+	}
 
 	bt_shell_printf("PHY %s\n", qos->phy);
 
@@ -1787,6 +1854,56 @@  static void append_properties(DBusMessageIter *iter,
 	g_dbus_dict_append_entry(&dict, "Delay", DBUS_TYPE_UINT32,
 						&qos->delay);
 
+	if (!cfg->ep->broadcast)
+		goto done;
+
+	bt_shell_printf("SyncInterval %u\n", bcast_qos.bcast.sync_interval);
+
+	g_dbus_dict_append_entry(&dict, "SyncInterval", DBUS_TYPE_BYTE,
+						&bcast_qos.bcast.sync_interval);
+
+	bt_shell_printf("Encryption %u\n", bcast_qos.bcast.encryption);
+
+	g_dbus_dict_append_entry(&dict, "Encryption", DBUS_TYPE_BYTE,
+						&bcast_qos.bcast.encryption);
+
+	bt_shell_printf("Options %u\n", bcast_qos.bcast.options);
+
+	g_dbus_dict_append_entry(&dict, "Options", DBUS_TYPE_BYTE,
+						&bcast_qos.bcast.options);
+
+	bt_shell_printf("Skip %u\n", bcast_qos.bcast.skip);
+
+	g_dbus_dict_append_entry(&dict, "Skip", DBUS_TYPE_UINT16,
+						&bcast_qos.bcast.skip);
+
+	bt_shell_printf("SyncTimeout %u\n", bcast_qos.bcast.sync_timeout);
+
+	g_dbus_dict_append_entry(&dict, "SyncTimeout", DBUS_TYPE_UINT16,
+						&bcast_qos.bcast.sync_timeout);
+
+	bt_shell_printf("SyncCteType %u\n", bcast_qos.bcast.sync_cte_type);
+
+	g_dbus_dict_append_entry(&dict, "SyncCteType", DBUS_TYPE_BYTE,
+						&bcast_qos.bcast.sync_cte_type);
+
+	bt_shell_printf("MSE %u\n", bcast_qos.bcast.mse);
+
+	g_dbus_dict_append_entry(&dict, "MSE", DBUS_TYPE_BYTE,
+						&bcast_qos.bcast.mse);
+
+	bt_shell_printf("Timeout %u\n", bcast_qos.bcast.timeout);
+
+	g_dbus_dict_append_entry(&dict, "Timeout", DBUS_TYPE_UINT16,
+						&bcast_qos.bcast.timeout);
+
+	bt_shell_printf("BroadcastCode:\n");
+	bt_shell_hexdump(cfg->ep->bcode->iov_base, cfg->ep->bcode->iov_len);
+
+	g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &keyBCode,
+								DBUS_TYPE_BYTE, &cfg->ep->bcode->iov_base,
+								cfg->ep->bcode->iov_len);
+
 done:
 	dbus_message_iter_close_container(iter, &dict);
 }
@@ -1826,8 +1943,15 @@  static DBusMessage *endpoint_select_properties_reply(struct endpoint *ep,
 	cfg = new0(struct endpoint_config, 1);
 	cfg->ep = ep;
 
-	/* Copy capabilities */
-	iov_append(&cfg->caps, preset->data.iov_base, preset->data.iov_len);
+	if (ep->broadcast) {
+		iov_append(&cfg->ep->bcode, bcast_qos.bcast.bcode, sizeof(bcast_qos.bcast.bcode));
+		/* Copy capabilities for broadcast*/
+		iov_append(&cfg->caps, base_lc3_16_2_1, sizeof(base_lc3_16_2_1));
+	} else {
+		/* Copy capabilities */
+		iov_append(&cfg->caps, preset->data.iov_base, preset->data.iov_len);
+	}
+
 	cfg->target_latency = preset->target_latency;
 
 	/* Copy metadata */
@@ -2239,14 +2363,14 @@  fail:
 
 }
 
-static void endpoint_cis(const char *input, void *user_data)
+static void endpoint_iso_stream(const char *input, void *user_data)
 {
 	struct endpoint *ep = user_data;
 	char *endptr = NULL;
 	int value;
 
 	if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) {
-		ep->cis = BT_ISO_QOS_CIS_UNSET;
+		ep->iso_stream = BT_ISO_QOS_STREAM_UNSET;
 	} else {
 		value = strtol(input, &endptr, 0);
 
@@ -2255,20 +2379,20 @@  static void endpoint_cis(const char *input, void *user_data)
 			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 
-		ep->cis = value;
+		ep->iso_stream = value;
 	}
 
 	endpoint_register(ep);
 }
 
-static void endpoint_cig(const char *input, void *user_data)
+static void endpoint_iso_group(const char *input, void *user_data)
 {
 	struct endpoint *ep = user_data;
 	char *endptr = NULL;
 	int value;
 
 	if (!strcasecmp(input, "a") || !strcasecmp(input, "auto")) {
-		ep->cig = BT_ISO_QOS_CIG_UNSET;
+		ep->iso_group = BT_ISO_QOS_GROUP_UNSET;
 	} else {
 		value = strtol(input, &endptr, 0);
 
@@ -2277,10 +2401,13 @@  static void endpoint_cig(const char *input, void *user_data)
 			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 
-		ep->cig = value;
+		ep->iso_group = value;
 	}
 
-	bt_shell_prompt_input(ep->path, "CIS (auto/value):", endpoint_cis, ep);
+	if (!ep->broadcast)
+		bt_shell_prompt_input(ep->path, "CIS (auto/value):", endpoint_iso_stream, ep);
+	else
+		bt_shell_prompt_input(ep->path, "BIS (auto/value):", endpoint_iso_stream, ep);
 }
 
 static void endpoint_max_transports(const char *input, void *user_data)
@@ -2302,13 +2429,22 @@  static void endpoint_max_transports(const char *input, void *user_data)
 		ep->max_transports = value;
 	}
 
-	bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_cig, ep);
+	if (ep->broadcast)
+		bt_shell_prompt_input(ep->path, "BIG (auto/value):", endpoint_iso_group, ep);
+	else
+		bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_iso_group, ep);
 }
 
 static void endpoint_auto_accept(const char *input, void *user_data)
 {
 	struct endpoint *ep = user_data;
 
+	if (!strcmp(ep->uuid, BAA_SERVICE_UUID)) {
+		ep->broadcast = true;
+	} else {
+		ep->broadcast = false;
+	}
+
 	if (!strcasecmp(input, "y") || !strcasecmp(input, "yes")) {
 		ep->auto_accept = true;
 		bt_shell_prompt_input(ep->path, "Max Transports (auto/value):",
@@ -2321,7 +2457,10 @@  static void endpoint_auto_accept(const char *input, void *user_data)
 		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
-	bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_cig, ep);
+	if (ep->broadcast)
+		bt_shell_prompt_input(ep->path, "BIG (auto/value):", endpoint_iso_group, ep);
+	else
+		bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_iso_group, ep);
 }
 
 static void endpoint_set_metadata(const char *input, void *user_data)
@@ -3050,8 +3189,8 @@  static void register_endpoints(GDBusProxy *proxy)
 								ep->cid);
 		ep->max_transports = UINT8_MAX;
 		ep->auto_accept = true;
-		ep->cig = BT_ISO_QOS_CIG_UNSET;
-		ep->cis = BT_ISO_QOS_CIS_UNSET;
+		ep->iso_group = BT_ISO_QOS_GROUP_UNSET;
+		ep->iso_stream = BT_ISO_QOS_STREAM_UNSET;
 		endpoint_register(ep);
 	}
 }
@@ -3595,6 +3734,7 @@  static void cmd_acquire_transport(int argc, char *argv[])
 {
 	GDBusProxy *proxy;
 	int i;
+	struct endpoint *ep, *link;
 
 	for (i = 1; i < argc; i++) {
 		proxy = g_dbus_proxy_lookup(transports, NULL, argv[i],
@@ -3610,6 +3750,27 @@  static void cmd_acquire_transport(int argc, char *argv[])
 			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 
+		ep = find_ep_by_transport(g_dbus_proxy_get_path(proxy));
+		if (!ep || ep->acquiring) {
+			bt_shell_printf("Transport %s already in acquiring process\n",
+					argv[i]);
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
+		}
+
+		ep->acquiring = true;
+
+		link = find_link_by_proxy(proxy);
+		if (link) {
+			bt_shell_printf("Link %s found\n", link->transport);
+			/* If link already acquiring wait it to be complete */
+			if (link->acquiring) {
+				bt_shell_printf("Link %s already in acquiring process\n",
+					argv[i]);
+				return bt_shell_noninteractive_quit(EXIT_FAILURE);
+			}
+			link->acquiring = true;
+		}
+
 		if (!g_dbus_proxy_method_call(proxy, "Acquire", NULL,
 						acquire_reply, proxy, NULL)) {
 			bt_shell_printf("Failed acquire transport\n");