From: Silviu Florian Barbulescu <[email protected]>
This adds bluetoothctl support for broadcast source.
---
client/player.c | 207 ++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 182 insertions(+), 25 deletions(-)
diff --git a/client/player.c b/client/player.c
index 7719076c8..1ba722150 100644
--- a/client/player.c
+++ b/client/player.c
@@ -73,10 +73,12 @@ struct endpoint {
struct iovec *meta;
bool auto_accept;
bool acquiring;
- uint8_t cig;
- uint8_t cis;
+ uint8_t iso_group;
+ uint8_t iso_stream;
char *transport;
DBusMessage *msg;
+ bool broadcast;
+ struct iovec *bcode;
};
static DBusConnection *dbus_conn;
@@ -102,6 +104,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;
@@ -1142,6 +1160,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(BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE_UUID, LC3_ID,
+ LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY,
+ 3u, 30, 240)),
};
struct codec_qos {
@@ -1419,6 +1447,7 @@ static struct preset {
PRESET(A2DP_SINK_UUID, sbc_presets, 6),
PRESET(PAC_SINK_UUID, lc3_presets, 3),
PRESET(PAC_SOURCE_UUID, lc3_presets, 3),
+ PRESET(BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE_UUID, lc3_presets, 3),
};
static struct codec_preset *find_preset(const char *uuid, const char *name)
@@ -1588,6 +1617,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)
{
@@ -1595,6 +1645,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);
@@ -1605,7 +1656,7 @@ static void append_properties(DBusMessageIter *iter,
DBUS_TYPE_BYTE, &cfg->caps->iov_base,
cfg->caps->iov_len);
- if (cfg->meta->iov_len) {
+ if ((cfg->ep->meta) && (cfg->meta->iov_len)) {
g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &meta,
DBUS_TYPE_BYTE, &cfg->meta->iov_base,
cfg->meta->iov_len);
@@ -1623,16 +1674,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);
@@ -1640,10 +1700,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);
@@ -1668,6 +1735,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);
}
@@ -1707,12 +1824,20 @@ 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 */
- iov_append(&cfg->meta, cfg->ep->meta->iov_base, cfg->ep->meta->iov_len);
+ if (cfg->ep->meta)
+ iov_append(&cfg->meta, cfg->ep->meta->iov_base, cfg->ep->meta->iov_len);
if (preset->qos.phy)
/* Set QoS parameters */
@@ -2073,14 +2198,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);
@@ -2089,20 +2214,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);
@@ -2111,10 +2236,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_auto_accept(const char *input, void *user_data)
@@ -2130,7 +2258,13 @@ 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 (!strcmp(ep->uuid, BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE_UUID)) {
+ bt_shell_prompt_input(ep->path, "BIG (auto/value):", endpoint_iso_group, ep);
+ ep->broadcast = true;
+ } else {
+ bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_iso_group, ep);
+ ep->broadcast = false;
+ }
}
static void endpoint_set_metadata(const char *input, void *user_data)
@@ -2227,6 +2361,7 @@ static void cmd_register_endpoint(int argc, char *argv[])
char **list;
ep = g_new0(struct endpoint, 1);
+ ep->meta = NULL;
ep->uuid = g_strdup(argv[1]);
ep->codec = strtol(argv[2], &endptr, 0);
ep->cid = 0x0000;
@@ -2861,8 +2996,8 @@ static void register_endpoints(GDBusProxy *proxy)
ep = endpoint_new(cap);
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);
}
@@ -3409,6 +3544,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],
@@ -3424,6 +3560,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
Hi Iulia,
On Tue, May 23, 2023 at 7:45 AM Iulia Tanasescu <[email protected]> wrote:
>
> From: Silviu Florian Barbulescu <[email protected]>
>
> This adds bluetoothctl support for broadcast source.
Can we have an example of how the commands look?
> ---
> client/player.c | 207 ++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 182 insertions(+), 25 deletions(-)
>
> diff --git a/client/player.c b/client/player.c
> index 7719076c8..1ba722150 100644
> --- a/client/player.c
> +++ b/client/player.c
> @@ -73,10 +73,12 @@ struct endpoint {
> struct iovec *meta;
> bool auto_accept;
> bool acquiring;
> - uint8_t cig;
> - uint8_t cis;
> + uint8_t iso_group;
> + uint8_t iso_stream;
> char *transport;
> DBusMessage *msg;
> + bool broadcast;
> + struct iovec *bcode;
> };
>
> static DBusConnection *dbus_conn;
> @@ -102,6 +104,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;
> @@ -1142,6 +1160,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(BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE_UUID, LC3_ID,
> + LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY,
> + 3u, 30, 240)),
> };
>
> struct codec_qos {
> @@ -1419,6 +1447,7 @@ static struct preset {
> PRESET(A2DP_SINK_UUID, sbc_presets, 6),
> PRESET(PAC_SINK_UUID, lc3_presets, 3),
> PRESET(PAC_SOURCE_UUID, lc3_presets, 3),
> + PRESET(BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE_UUID, lc3_presets, 3),
> };
>
> static struct codec_preset *find_preset(const char *uuid, const char *name)
> @@ -1588,6 +1617,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)
> {
> @@ -1595,6 +1645,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);
>
> @@ -1605,7 +1656,7 @@ static void append_properties(DBusMessageIter *iter,
> DBUS_TYPE_BYTE, &cfg->caps->iov_base,
> cfg->caps->iov_len);
>
> - if (cfg->meta->iov_len) {
> + if ((cfg->ep->meta) && (cfg->meta->iov_len)) {
> g_dbus_dict_append_basic_array(&dict, DBUS_TYPE_STRING, &meta,
> DBUS_TYPE_BYTE, &cfg->meta->iov_base,
> cfg->meta->iov_len);
> @@ -1623,16 +1674,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);
> @@ -1640,10 +1700,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);
>
> @@ -1668,6 +1735,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);
> }
> @@ -1707,12 +1824,20 @@ 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 */
> - iov_append(&cfg->meta, cfg->ep->meta->iov_base, cfg->ep->meta->iov_len);
> + if (cfg->ep->meta)
> + iov_append(&cfg->meta, cfg->ep->meta->iov_base, cfg->ep->meta->iov_len);
>
> if (preset->qos.phy)
> /* Set QoS parameters */
> @@ -2073,14 +2198,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);
>
> @@ -2089,20 +2214,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);
>
> @@ -2111,10 +2236,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_auto_accept(const char *input, void *user_data)
> @@ -2130,7 +2258,13 @@ 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 (!strcmp(ep->uuid, BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE_UUID)) {
> + bt_shell_prompt_input(ep->path, "BIG (auto/value):", endpoint_iso_group, ep);
> + ep->broadcast = true;
> + } else {
> + bt_shell_prompt_input(ep->path, "CIG (auto/value):", endpoint_iso_group, ep);
> + ep->broadcast = false;
> + }
> }
>
> static void endpoint_set_metadata(const char *input, void *user_data)
> @@ -2227,6 +2361,7 @@ static void cmd_register_endpoint(int argc, char *argv[])
> char **list;
>
> ep = g_new0(struct endpoint, 1);
> + ep->meta = NULL;
> ep->uuid = g_strdup(argv[1]);
> ep->codec = strtol(argv[2], &endptr, 0);
> ep->cid = 0x0000;
> @@ -2861,8 +2996,8 @@ static void register_endpoints(GDBusProxy *proxy)
>
> ep = endpoint_new(cap);
> 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);
> }
>
> @@ -3409,6 +3544,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],
> @@ -3424,6 +3560,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
>
--
Luiz Augusto von Dentz
Hi Luiz,
To test BAP Broadcast Source support implementation use bluetoothctl with the following commands:
# endpoint.register 00001852-0000-1000-8000-00805f9b34fb 0x06
# transport.acquire /org/bluez/hci0/dev_00_00_00_00_00_00/pac_broadcast0/fd0
# transport.send /org/bluez/hci0/dev_00_00_00_00_00_00/pac_broadcast0/fd0 <file.wav>