2023-07-12 12:46:48

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v2 0/6] Add support for BAP broadcast sink

This series of patches adds support for BAP broadcast sink.
It consists in registering a sink endpoint using the Sink PAC UUID,
discovering of broadcast advertisers that announce the
Broadcast Audio Announcement service, synchronizes to the Periodic
advertisements of the source and synchronizes to the BIG advertised
in the PA train.
To retrieve the BASE info advertised in the PA train, the patch
Bluetooth: ISO: Add support for periodic adv reports processing
was used.

This feature was tested using bluetoothctl with the following commands:

[bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
[/local/endpoint/ep0] Auto Accept (yes/no): y
[/local/endpoint/ep0] Max Transports (auto/value): a
[/local/endpoint/ep0] unicast/broadcast (u/b): b
[/local/endpoint/ep0] BIG (auto/value): a
[/local/endpoint/ep0] BIS (auto/value): a

[bluetooth]# scan on

[bluetooth]# endpoint.config /org/bluez/hci0/pac_bcast0
/local/endpoint/ep0 16_2_1 <source_address>

Claudia Draghicescu (6):
client/player: Add broadcast sink endpoint registration and
configuration.
client/main: Add broadcast source discovery
media: Add support for a broadcast sink media endpoint
transport: Update transport properties for a broadcast stream
btio: Add support for getsockopt(BT_ISO_BASE)
bap: Add gdbus interface for BAP broadcast sink, create
synchronization with source and create BAP broadcast sink stream

btio/btio.c | 13 +-
client/main.c | 57 +++++-
client/player.c | 187 +++++++++++++++++++-
client/player.h | 3 +
profiles/audio/bap.c | 347 ++++++++++++++++++++++++++++++++++---
profiles/audio/media.c | 35 +++-
profiles/audio/media.h | 2 +-
profiles/audio/transport.c | 244 +++++++++++++++++++++++++-
src/shared/bap.c | 50 +++++-
src/shared/bap.h | 4 +-
10 files changed, 888 insertions(+), 54 deletions(-)


base-commit: 838e1578072900d1f98dfb31cc538940d2fad876
--
2.34.1



2023-07-12 12:49:33

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v2 5/6] btio: Add support for getsockopt(BT_ISO_BASE)

This adds the posibility for a broadcast sink to retrieve the
BASE information received from a source afeter a PA synchronization,
using the getsockopt(BT_ISO_BASE) function.
This needs the patch from bluetooth-next:
Bluetooth: ISO: Add support for periodic adv reports processing

---
btio/btio.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/btio/btio.c b/btio/btio.c
index 179be6289..8178250d2 100644
--- a/btio/btio.c
+++ b/btio/btio.c
@@ -1638,6 +1638,7 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args)
BtIOOption opt = opt1;
struct sockaddr_iso src, dst;
struct bt_iso_qos qos;
+ struct bt_iso_base base;
socklen_t len;
uint32_t phy;

@@ -1648,6 +1649,11 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args)
return FALSE;
}

+ if (getsockopt(sock, SOL_BLUETOOTH, BT_ISO_BASE, &base, &len) < 0) {
+ ERROR_FAILED(err, "getsockopt(BT_ISO_BASE)", errno);
+ return FALSE;
+ }
+
if (!get_src(sock, &src, sizeof(src), err))
return FALSE;

@@ -1694,6 +1700,8 @@ static gboolean iso_get(int sock, GError **err, BtIOOption opt1, va_list args)
*(va_arg(args, struct bt_iso_qos *)) = qos;
break;
case BT_IO_OPT_BASE:
+ *(va_arg(args, struct bt_iso_base *)) = base;
+ break;
case BT_IO_OPT_HANDLE:
case BT_IO_OPT_CLASS:
case BT_IO_OPT_DEFER_TIMEOUT:
@@ -1896,8 +1904,9 @@ static GIOChannel *create_io(gboolean server, struct set_opts *opts,
goto failed;
if (!iso_set_qos(sock, &opts->qos, err))
goto failed;
- if (!iso_set_base(sock, &opts->base, err))
- goto failed;
+ if (opts->base.base_len)
+ if (!iso_set_base(sock, &opts->base, err))
+ goto failed;
break;
case BT_IO_INVALID:
default:
--
2.34.1


2023-07-12 12:50:45

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v2 4/6] transport: Update transport properties for a broadcast stream

This patch gets the QOS broadcast stream parameters and passes them
to upper layers.

---
profiles/audio/transport.c | 244 ++++++++++++++++++++++++++++++++++++-
1 file changed, 241 insertions(+), 3 deletions(-)

diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index aa3a718b0..e7f21ff9c 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -551,8 +551,8 @@ static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg,

owner = media_owner_create(msg);

- if (!strcmp(media_endpoint_get_uuid(transport->endpoint),
- BAA_SERVICE_UUID)) {
+ if (bt_bap_stream_get_type(get_stream_bap(transport)) ==
+ BT_BAP_STREAM_TYPE_BCAST) {
req = media_request_create(msg, 0x00);
media_owner_add(owner, req);
media_transport_set_owner(transport, owner);
@@ -853,6 +853,9 @@ static gboolean qos_exists(const GDBusPropertyTable *property, void *data)
struct media_transport *transport = data;
struct bap_transport *bap = transport->data;

+ if (media_endpoint_is_broadcast(transport->endpoint))
+ return bap->qos.bcast.io_qos.sdu != 0x00;
+
return bap->qos.ucast.io_qos.phy != 0x00;
}

@@ -868,6 +871,18 @@ static gboolean get_cig(const GDBusPropertyTable *property,
return TRUE;
}

+static gboolean get_big(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.big);
+
+ return TRUE;
+}
+
static gboolean get_cis(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -880,6 +895,18 @@ static gboolean get_cis(const GDBusPropertyTable *property,
return TRUE;
}

+static gboolean get_bis(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.bis);
+
+ return TRUE;
+}
+
static gboolean get_interval(const GDBusPropertyTable *property,
DBusMessageIter *iter, void *data)
{
@@ -899,6 +926,9 @@ static gboolean get_framing(const GDBusPropertyTable *property,
struct bap_transport *bap = transport->data;
dbus_bool_t val = bap->qos.ucast.framing;

+ if (media_endpoint_is_broadcast(transport->endpoint))
+ val = bap->qos.bcast.framing;
+
dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);

return TRUE;
@@ -910,6 +940,12 @@ static gboolean get_phy(const GDBusPropertyTable *property,
struct media_transport *transport = data;
struct bap_transport *bap = transport->data;

+ if (media_endpoint_is_broadcast(transport->endpoint)) {
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.io_qos.phy);
+ return TRUE;
+ }
+
dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
&bap->qos.ucast.io_qos.phy);

@@ -922,6 +958,12 @@ static gboolean get_sdu(const GDBusPropertyTable *property,
struct media_transport *transport = data;
struct bap_transport *bap = transport->data;

+ if (media_endpoint_is_broadcast(transport->endpoint)) {
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
+ &bap->qos.bcast.io_qos.sdu);
+ return TRUE;
+ }
+
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
&bap->qos.ucast.io_qos.sdu);

@@ -1040,6 +1082,121 @@ static gboolean get_links(const GDBusPropertyTable *property,
return TRUE;
}

+static gboolean get_sync_interval(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.sync_interval);
+
+ return TRUE;
+}
+
+static gboolean get_packing(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.packing);
+
+ return TRUE;
+}
+
+static gboolean get_bcode(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+ DBusMessageIter array;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING, &array);
+
+ if (bap->qos.bcast.bcode && bap->qos.bcast.bcode->iov_len)
+ dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.bcode->iov_base,
+ bap->qos.bcast.bcode->iov_len);
+
+ dbus_message_iter_close_container(iter, &array);
+ return TRUE;
+}
+
+static gboolean get_options(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.options);
+
+ return TRUE;
+}
+
+static gboolean get_skip(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
+ &bap->qos.bcast.skip);
+
+ return TRUE;
+}
+
+static gboolean get_sync_timeout(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
+ &bap->qos.bcast.sync_timeout);
+
+ return TRUE;
+}
+
+static gboolean get_sync_cte_type(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.sync_cte_type);
+
+ return TRUE;
+}
+
+static gboolean get_mse(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+ &bap->qos.bcast.mse);
+
+ return TRUE;
+}
+
+static gboolean get_timeout(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+ struct bap_transport *bap = transport->data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16,
+ &bap->qos.bcast.timeout);
+
+ return TRUE;
+}
+
static const GDBusPropertyTable bap_properties[] = {
{ "Device", "o", get_device },
{ "UUID", "s", get_uuid },
@@ -1059,6 +1216,17 @@ static const GDBusPropertyTable bap_properties[] = {
{ "Location", "u", get_location },
{ "Metadata", "ay", get_metadata },
{ "Links", "ao", get_links, NULL, links_exists },
+ { "BIG", "y", get_big, NULL, qos_exists },
+ { "BIS", "y", get_bis, NULL, qos_exists },
+ { "SyncInterval", "y", get_sync_interval, NULL, qos_exists },
+ { "Packing", "y", get_packing, NULL, qos_exists },
+ { "BCode", "ay", get_bcode, NULL, qos_exists },
+ { "Options", "y", get_options, NULL, qos_exists },
+ { "Skip", "q", get_skip, NULL, qos_exists },
+ { "SyncTimeout", "q", get_sync_timeout, NULL, qos_exists },
+ { "SyncCteType", "y", get_sync_cte_type, NULL, qos_exists },
+ { "MSE", "y", get_mse, NULL, qos_exists },
+ { "Timeout", "q", get_timeout, NULL, qos_exists },
{ }
};

@@ -1341,6 +1509,71 @@ static gboolean bap_resume_wait_cb(void *data)
return FALSE;
}

+static void bap_update_bcast_qos(const struct media_transport *transport)
+{
+ struct bap_transport *bap = transport->data;
+ struct bt_bap_qos *qos;
+
+ qos = bt_bap_stream_get_qos(bap->stream);
+
+ if (!memcmp(qos, &bap->qos, sizeof(struct bt_bap_qos)))
+ return;
+
+ bap->qos = *qos;
+
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "BIG");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "BIS");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "SyncInterval");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "Packing");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "Framing");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "BCode");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "Options");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "Skip");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "SyncTimeout");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "SyncCteType");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "MSE");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "Timeout");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "Interval");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "Latency");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "PHY");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "SDU");
+ g_dbus_emit_property_changed(btd_get_dbus_connection(),
+ transport->path, MEDIA_TRANSPORT_INTERFACE,
+ "RTN");
+}
+
static guint resume_bap(struct media_transport *transport,
struct media_owner *owner)
{
@@ -1493,7 +1726,10 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
if (owner && owner->pending)
return;
bap_update_links(transport);
- bap_update_qos(transport);
+ if (!media_endpoint_is_broadcast(transport->endpoint))
+ bap_update_qos(transport);
+ else if (bt_bap_stream_io_dir(stream) != BT_BAP_BCAST_SOURCE)
+ bap_update_bcast_qos(transport);
transport_update_playing(transport, FALSE);
return;
case BT_BAP_STREAM_STATE_DISABLING:
@@ -1503,6 +1739,8 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
return;
break;
case BT_BAP_STREAM_STATE_STREAMING:
+ if (bt_bap_stream_io_dir(stream) == BT_BAP_BCAST_SOURCE)
+ bap_update_bcast_qos(transport);
break;
}

--
2.34.1


2023-07-12 12:57:00

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v2 1/6] client/main: Add broadcast source discovery

Added support for broadcast sink registration using the UUID for PAC sink.
Added support for broadcast source discovery.
Added in the endpoint configuration command a new parameter for
source address that triggers source synchronization and
stream configuration.
To test this feature use the following commands:

[bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
[/local/endpoint/ep0] Auto Accept (yes/no): y
[/local/endpoint/ep0] Max Transports (auto/value): a
[/local/endpoint/ep0] unicast/broadcast (u/b): b
[/local/endpoint/ep0] BIG (auto/value): a
[/local/endpoint/ep0] BIS (auto/value): a

[bluetooth]# scan on
NOTE! in the list of scanned devices, the broadcast source will be
printed in green.
[bluetooth]# endpoint.config /org/bluez/hci0/pac_bcast0
/local/endpoint/ep0 16_2_1 <source_address>

---
client/player.c | 187 +++++++++++++++++++++++++++++++++++++++++++++---
client/player.h | 3 +
2 files changed, 181 insertions(+), 9 deletions(-)

diff --git a/client/player.c b/client/player.c
index e5084967a..fd2c89f0b 100644
--- a/client/player.c
+++ b/client/player.c
@@ -81,6 +81,7 @@ struct endpoint {
struct preset *preset;
bool broadcast;
struct iovec *bcode;
+ struct queue *bcast_sources;
};

static DBusConnection *dbus_conn;
@@ -94,6 +95,11 @@ static GList *local_endpoints = NULL;
static GList *transports = NULL;
static struct queue *ios = NULL;

+struct bcast_source {
+ GDBusProxy *proxy;
+ uint32_t bcast_id;
+};
+
struct transport {
GDBusProxy *proxy;
int sk;
@@ -2285,6 +2291,9 @@ static void register_endpoint_setup(DBusMessageIter *iter, void *user_data)
bt_shell_hexdump(ep->meta->iov_base, ep->meta->iov_len);
}

+ g_dbus_dict_append_entry(&dict, "Broadcast", DBUS_TYPE_BOOLEAN,
+ &ep->broadcast);
+
dbus_message_iter_close_container(iter, &dict);
}

@@ -2424,6 +2433,28 @@ static void endpoint_iso_group(const char *input, void *user_data)
endpoint_iso_stream, ep);
}

+static void endpoint_iso_mode(const char *input, void *user_data)
+{
+ struct endpoint *ep = user_data;
+
+ if (!strcasecmp(input, "u") || !strcasecmp(input, "unicast")) {
+ ep->broadcast = false;
+ } else if (!strcasecmp(input, "b") || !strcasecmp(input, "broadcast")) {
+ ep->broadcast = true;
+ ep->bcast_sources = queue_new();
+ } else {
+ bt_shell_printf("Invalid input for Auto Accept\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
+ if (!ep->broadcast)
+ bt_shell_prompt_input(ep->path, "CIG (auto/value):",
+ endpoint_iso_group, ep);
+ else
+ bt_shell_prompt_input(ep->path, "BIG (auto/value):",
+ endpoint_iso_group, ep);
+}
+
static void endpoint_max_transports(const char *input, void *user_data)
{
struct endpoint *ep = user_data;
@@ -2445,7 +2476,10 @@ static void endpoint_max_transports(const char *input, void *user_data)

if (ep->broadcast)
bt_shell_prompt_input(ep->path, "BIG (auto/value):",
- endpoint_iso_group, ep);
+ endpoint_iso_group, ep);
+ else if (!strcmp(ep->uuid, PAC_SINK_UUID))
+ bt_shell_prompt_input(ep->path, "unicast/broadcast (u/b):",
+ endpoint_iso_mode, ep);
else
bt_shell_prompt_input(ep->path, "CIG (auto/value):",
endpoint_iso_group, ep);
@@ -2472,13 +2506,6 @@ static void endpoint_auto_accept(const char *input, void *user_data)
bt_shell_printf("Invalid input for Auto Accept\n");
return bt_shell_noninteractive_quit(EXIT_FAILURE);
}
-
- 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)
@@ -2714,6 +2741,103 @@ static void endpoint_set_config(struct endpoint_config *cfg)
}
}

+static void sink_create_reply(DBusMessage *message, void *user_data)
+{
+ DBusError error;
+
+ dbus_error_init(&error);
+
+ if (dbus_set_error_from_message(&error, message) == TRUE) {
+ bt_shell_printf("Failed to create broadcast sink: %s\n",
+ error.name);
+ dbus_error_free(&error);
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
+ return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+}
+
+struct bcast_sink {
+ uint8_t bc_sid;
+ uint8_t bc_num_bis;
+} bcast_sink = {
+ .bc_sid = 1,
+ .bc_num_bis = 1,
+};
+
+static bool match_bcast_source_by_address(
+ const void *data, const void *match_data)
+{
+ const struct bcast_source *source = data;
+ const char *addr = match_data;
+ char *source_addr;
+ DBusMessageIter iter;
+
+ if (!g_dbus_proxy_get_property(source->proxy, "Address", &iter))
+ return false;
+
+ dbus_message_iter_get_basic(&iter, &source_addr);
+
+ if (!strcasecmp(addr, source_addr))
+ return true;
+
+ return false;
+}
+static void sink_create_setup(DBusMessageIter *iter, void *user_data)
+{
+ struct bcast_source *bcast_source = user_data;
+ DBusMessageIter dict, source_iter;
+ const char *source_type, *source_address;
+
+ g_dbus_proxy_get_property(bcast_source->proxy, "Address", &source_iter);
+
+ dbus_message_iter_get_basic(&source_iter, &source_address);
+
+ g_dbus_proxy_get_property(bcast_source->proxy, "AddressType",
+ &source_iter);
+
+ dbus_message_iter_get_basic(&source_iter, &source_type);
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+ g_dbus_dict_append_entry(&dict, "SourceAddress", DBUS_TYPE_STRING,
+ &source_address);
+
+ g_dbus_dict_append_entry(&dict, "SourceAddressType", DBUS_TYPE_STRING,
+ &source_type);
+
+ g_dbus_dict_append_entry(&dict, "BIS", DBUS_TYPE_BYTE,
+ &bcast_sink.bc_sid);
+
+ g_dbus_dict_append_entry(&dict, "NumBis", DBUS_TYPE_BYTE,
+ &bcast_sink.bc_num_bis);
+
+ g_dbus_dict_append_entry(&dict, "BcastID", DBUS_TYPE_UINT32,
+ &bcast_source->bcast_id);
+
+ dbus_message_iter_close_container(iter, &dict);
+}
+
+static void endpoint_bcast_sink_sync(struct endpoint_config *cfg, char *source)
+{
+ struct bcast_source *bcast_source = NULL;
+
+ bcast_source = queue_find(cfg->ep->bcast_sources,
+ match_bcast_source_by_address, source);
+
+ if (!bcast_source) {
+ bt_shell_printf("Source not found\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
+
+ if (g_dbus_proxy_method_call(cfg->proxy, "BcastSinkCreate",
+ sink_create_setup, sink_create_reply,
+ bcast_source, NULL) == FALSE) {
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+}
+
static void endpoint_config(const char *input, void *user_data)
{
struct endpoint_config *cfg = user_data;
@@ -2771,6 +2895,10 @@ static void cmd_config_endpoint(int argc, char *argv[])
cfg->qos = &preset->qos;

endpoint_set_config(cfg);
+
+ if (argv[4])
+ endpoint_bcast_sink_sync(cfg, argv[4]);
+
return;
}

@@ -3172,7 +3300,7 @@ static const struct bt_shell_menu endpoint_menu = {
{ "unregister", "<UUID/object>", cmd_unregister_endpoint,
"Register Endpoint",
local_endpoint_generator },
- { "config", "<endpoint> <local endpoint> [preset]",
+ { "config", "<endpoint> <local endpoint> [preset] [source]",
cmd_config_endpoint,
"Configure Endpoint",
endpoint_generator },
@@ -4238,3 +4366,44 @@ void player_remove_submenu(void)
g_dbus_client_unref(client);
queue_destroy(ios, transport_free);
}
+
+void player_add_bcast_source(GDBusProxy *proxy, uint8_t *service_data, int len)
+{
+ GList *l;
+
+ for (l = local_endpoints; l; l = g_list_next(l)) {
+ struct endpoint *ep = l->data;
+
+ if (ep->broadcast && ep->bcast_sources) {
+ struct bcast_source *bcast_source =
+ new0(struct bcast_source, 1);
+
+ bcast_source->proxy = proxy;
+ bcast_source->bcast_id = get_le24(service_data);
+ queue_push_tail(ep->bcast_sources, bcast_source);
+ }
+ }
+
+}
+static bool match_bcast_source_by_proxy(const void *data,
+ const void *user_data)
+{
+ const struct bcast_source *bcast_source = data;
+
+ if (bcast_source->proxy == user_data)
+ return true;
+
+ return false;
+}
+void player_remove_bcast_source(GDBusProxy *proxy)
+{
+ GList *l;
+
+ for (l = local_endpoints; l; l = g_list_next(l)) {
+ struct endpoint *ep = l->data;
+
+ if (ep->broadcast && ep->bcast_sources)
+ queue_remove_if(ep->bcast_sources,
+ match_bcast_source_by_proxy, proxy);
+ }
+}
diff --git a/client/player.h b/client/player.h
index e7778cb1e..21e73e8ed 100644
--- a/client/player.h
+++ b/client/player.h
@@ -10,3 +10,6 @@

void player_add_submenu(void);
void player_remove_submenu(void);
+void player_add_bcast_source(GDBusProxy *proxy,
+ uint8_t *service_data, int len);
+void player_remove_bcast_source(GDBusProxy *proxy);
--
2.34.1


2023-07-12 12:58:03

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v2 6/6] bap: Add support for BAP broadcast sink

This adds support for BAP broadcast sink, adds a new gdbus method
to synchronize to a given source and sets the QOS and capabilities
of the stream.
This feature was tested using bluetoothctl with the following commands:

[bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
[/local/endpoint/ep0] Auto Accept (yes/no): y
[/local/endpoint/ep0] Max Transports (auto/value): a
[/local/endpoint/ep0] unicast/broadcast (u/b): b
[/local/endpoint/ep0] BIG (auto/value): a
[/local/endpoint/ep0] BIS (auto/value): a

[bluetooth]# scan on

[bluetooth]# endpoint.config /org/bluez/hci0/pac_bcast0
/local/endpoint/ep0 16_2_1 <source_address>

---
profiles/audio/bap.c | 347 ++++++++++++++++++++++++++++++++++++++++---
src/shared/bap.c | 50 ++++++-
src/shared/bap.h | 4 +-
3 files changed, 370 insertions(+), 31 deletions(-)

diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index d7ce9e038..5cb109950 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -34,6 +34,7 @@
#include "lib/hci.h"
#include "lib/sdp.h"
#include "lib/uuid.h"
+#include "lib/iso.h"

#include "src/btd.h"
#include "src/dbus-common.h"
@@ -185,6 +186,9 @@ static gboolean get_uuid(const GDBusPropertyTable *property,
uuid = PAC_SINK_UUID;
else if (queue_find(ep->data->srcs, NULL, ep))
uuid = PAC_SOURCE_UUID;
+ else if ((queue_find(ep->data->bcast, NULL, ep)
+ && (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)))
+ uuid = PAC_SINK_UUID;
else
uuid = BAA_SERVICE_UUID;

@@ -232,7 +236,8 @@ static gboolean get_device(const GDBusPropertyTable *property,
struct bap_ep *ep = data;
const char *path;

- if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE)
+ if ((bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE)
+ || (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK))
path = adapter_get_path(ep->data->adapter);
else
path = device_get_path(ep->data->device);
@@ -555,7 +560,7 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
}

if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE) {
- /* Mark CIG and CIS to be auto assigned */
+ /* Mark BIG and BIS to be auto assigned */
ep->qos.bcast.big = BT_ISO_QOS_BIG_UNSET;
ep->qos.bcast.bis = BT_ISO_QOS_BIS_UNSET;
} else {
@@ -576,8 +581,12 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
ep->stream = bt_bap_stream_new(ep->data->bap, ep->lpac,
ep->rpac, &ep->qos, ep->caps);

- ep->id = bt_bap_stream_config(ep->stream, &ep->qos, ep->caps,
- config_cb, ep);
+ if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)
+ ep->id = bt_bap_stream_config(ep->stream, &ep->qos, NULL,
+ config_cb, ep);
+ else
+ ep->id = bt_bap_stream_config(ep->stream, &ep->qos, ep->caps,
+ config_cb, ep);
if (!ep->id) {
DBG("Unable to config stream");
free(ep->caps);
@@ -603,14 +612,296 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
return NULL;
}

+static void update_bcast_qos(struct bt_iso_qos *qos,
+ struct bt_bap_qos *bap_qos)
+{
+ bap_qos->bcast.big = qos->bcast.big;
+ bap_qos->bcast.bis = qos->bcast.bis;
+ bap_qos->bcast.sync_interval = qos->bcast.sync_interval;
+ bap_qos->bcast.packing = qos->bcast.packing;
+ bap_qos->bcast.framing = qos->bcast.framing;
+ bap_qos->bcast.encryption = qos->bcast.encryption;
+ bap_qos->bcast.options = qos->bcast.options;
+ bap_qos->bcast.skip = qos->bcast.skip;
+ bap_qos->bcast.sync_timeout = qos->bcast.sync_timeout;
+ bap_qos->bcast.sync_cte_type = qos->bcast.sync_cte_type;
+ bap_qos->bcast.mse = qos->bcast.mse;
+ bap_qos->bcast.timeout = qos->bcast.timeout;
+ bap_qos->bcast.io_qos.interval = qos->bcast.in.interval;
+ bap_qos->bcast.io_qos.latency = qos->bcast.in.latency;
+ bap_qos->bcast.io_qos.phy = qos->bcast.in.phy;
+ bap_qos->bcast.io_qos.sdu = qos->bcast.in.sdu;
+ bap_qos->bcast.io_qos.rtn = qos->bcast.in.rtn;
+
+ bap_qos->bcast.bcode = new0(struct iovec, 1);
+ util_iov_memcpy(bap_qos->bcast.bcode, qos->bcast.bcode,
+ sizeof(qos->bcast.bcode));
+}
+
+static bool match_bcast_stream_qos(const void *data, const void *user_data)
+{
+
+ const struct bt_bap_stream *stream = data;
+ const struct bt_iso_qos *iso_qos = user_data;
+ struct bt_bap_qos *qos;
+
+ qos = bt_bap_stream_get_qos((void *)stream);
+
+ if (iso_qos->bcast.big != qos->bcast.big)
+ return false;
+
+ return iso_qos->bcast.bis == qos->bcast.bis;
+}
+
+static void bap_add_stream(struct bap_data *data,
+ struct bt_bap_stream *stream)
+{
+ DBG("stream pointer %p", stream);
+
+ if (!data->streams)
+ data->streams = queue_new();
+
+ if (!queue_find(data->streams, NULL, stream))
+ queue_push_tail(data->streams, stream);
+}
+
+static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
+{
+ struct bap_data *data = user_data;
+ struct bt_bap_stream *stream;
+ struct bt_iso_qos qos;
+ struct bt_iso_base base;
+ char address[18];
+ struct queue *queue;
+ struct bap_ep *ep;
+ int fd;
+ struct iovec *base_io;
+
+ bt_io_get(io, &err,
+ BT_IO_OPT_DEST, address,
+ BT_IO_OPT_QOS, &qos,
+ BT_IO_OPT_BASE, &base,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto drop;
+ }
+
+ g_io_channel_ref(io);
+
+ DBG("BCAST ISO: sync with %s (BIG 0x%02x BIS 0x%02x)",
+ address, qos.bcast.big, qos.bcast.bis);
+
+ queue = data->bcast;
+ ep = queue_pop_head(queue);
+ if (!ep) {
+ DBG("ep not found");
+ return;
+ }
+
+ update_bcast_qos(&qos, &ep->qos);
+
+ base_io = new0(struct iovec, 1);
+ util_iov_memcpy(base_io, base.base, base.base_len);
+
+ ep->id = bt_bap_stream_config(ep->stream, &ep->qos,
+ base_io, NULL, NULL);
+ data->listen_io = io;
+
+ bt_bap_stream_set_user_data(ep->stream, ep->path);
+
+ stream = queue_remove_if(data->streams, match_bcast_stream_qos, &qos);
+ if (!stream) {
+ DBG("stream removed");
+ bap_add_stream(data, ep->stream);
+ stream = ep->stream;
+ fd = g_io_channel_unix_get_fd(io);
+
+ if (bt_bap_stream_set_io(stream, fd)) {
+ bt_bap_stream_enable(stream, true, NULL, NULL, NULL);
+ g_io_channel_set_close_on_unref(io, FALSE);
+ return;
+ }
+ } else
+ DBG("stream not removed");
+
+ return;
+
+drop:
+ g_io_channel_shutdown(io, TRUE, NULL);
+
+}
+
+static bool match_data_bap_data(const void *data, const void *match_data)
+{
+ const struct bap_data *bdata = data;
+ const struct btd_adapter *adapter = match_data;
+
+ return bdata->user_data == adapter;
+}
+
+#define DEFAULT_IO_QOS \
+{ \
+ .interval = 10000, \
+ .latency = 10, \
+ .sdu = 40, \
+ .phy = 0x02, \
+ .rtn = 2, \
+}
+
+static DBusMessage *bcast_sink_create(DBusConnection *conn, DBusMessage *msg,
+ void *user_data)
+{
+ struct bt_iso_qos qos_bcast;
+ struct sockaddr_iso_bc iso_bc_addr;
+ DBusMessageIter iter, args;
+ const char *key;
+ GIOChannel *io;
+ GError *err = NULL;
+ struct bap_ep *ep = user_data;
+ uint32_t bcastid;
+
+ memset(&qos_bcast, 0, sizeof(struct bt_iso_qos));
+ memset(&iso_bc_addr, 0, sizeof(struct sockaddr_iso_bc));
+
+ DBG("sender %s", dbus_message_get_sender(msg));
+
+ dbus_message_iter_init(msg, &args);
+
+ if ((dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) ||
+ (dbus_message_iter_get_element_type(&args) != DBUS_TYPE_DICT_ENTRY))
+ return btd_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&args, &iter);
+
+ while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter value, entry;
+ int var;
+
+ dbus_message_iter_recurse(&iter, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+ dbus_message_iter_recurse(&entry, &value);
+
+ var = dbus_message_iter_get_arg_type(&value);
+
+ if (!strcasecmp(key, "SourceAddress")) {
+ const char *str;
+
+ if (var != DBUS_TYPE_STRING)
+ goto fail;
+
+ dbus_message_iter_get_basic(&value, &str);
+ DBG("SourceAddress %s", str);
+ str2ba(str, &iso_bc_addr.bc_bdaddr);
+ } else if (!strcasecmp(key, "SourceAddressType")) {
+ const char *type;
+
+ if (var != DBUS_TYPE_STRING)
+ goto fail;
+
+ dbus_message_iter_get_basic(&value, &type);
+
+ if (!strcasecmp(type, "public"))
+ iso_bc_addr.bc_bdaddr_type = BDADDR_LE_PUBLIC;
+ else
+ iso_bc_addr.bc_bdaddr_type = BDADDR_LE_RANDOM;
+
+ DBG("SourceAddressType %d", iso_bc_addr.bc_bdaddr_type);
+ } else if (!strcasecmp(key, "BIS")) {
+ uint8_t bis;
+
+ if (var != DBUS_TYPE_BYTE)
+ goto fail;
+
+ dbus_message_iter_get_basic(&value, &bis);
+ iso_bc_addr.bc_bis[0] = bis;
+ DBG("BIS %d", iso_bc_addr.bc_bis[0]);
+ } else if (!strcasecmp(key, "NumBis")) {
+ if (var != DBUS_TYPE_BYTE)
+ goto fail;
+
+ dbus_message_iter_get_basic(&value,
+ &iso_bc_addr.bc_num_bis);
+ DBG("NumBis %d", iso_bc_addr.bc_num_bis);
+ } else if (!strcasecmp(key, "BcastID")) {
+ if (var != DBUS_TYPE_UINT32)
+ goto fail;
+
+ dbus_message_iter_get_basic(&value, &bcastid);
+ DBG("BcastID 0x%4.4x", bcastid);
+ }
+
+ dbus_message_iter_next(&iter);
+ }
+
+ qos_bcast.bcast.big = ep->qos.bcast.big;
+ qos_bcast.bcast.bis = ep->qos.bcast.bis;
+ qos_bcast.bcast.encryption = ep->qos.bcast.encryption;
+ qos_bcast.bcast.framing = ep->qos.bcast.framing;
+ qos_bcast.bcast.mse = ep->qos.bcast.mse;
+ qos_bcast.bcast.options = ep->qos.bcast.options;
+ qos_bcast.bcast.packing = ep->qos.bcast.packing;
+ qos_bcast.bcast.skip = ep->qos.bcast.skip;
+ qos_bcast.bcast.sync_cte_type = ep->qos.bcast.sync_cte_type;
+ qos_bcast.bcast.sync_interval = ep->qos.bcast.sync_interval;
+ qos_bcast.bcast.sync_timeout = ep->qos.bcast.sync_timeout;
+ qos_bcast.bcast.timeout = ep->qos.bcast.timeout;
+ qos_bcast.bcast.in.interval = ep->qos.bcast.io_qos.interval;
+ qos_bcast.bcast.in.phy = ep->qos.bcast.io_qos.phy;
+ qos_bcast.bcast.in.sdu = ep->qos.bcast.io_qos.sdu;
+ qos_bcast.bcast.in.latency = ep->qos.bcast.io_qos.latency;
+ qos_bcast.bcast.in.rtn = ep->qos.bcast.io_qos.rtn;
+
+ io = bt_io_listen(iso_bcast_confirm_cb, NULL, ep->data, NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR,
+ btd_adapter_get_address(ep->data->adapter),
+ BT_IO_OPT_DEST_BDADDR,
+ &iso_bc_addr.bc_bdaddr,
+ BT_IO_OPT_DEST_TYPE,
+ iso_bc_addr.bc_bdaddr_type,
+ BT_IO_OPT_MODE, BT_IO_MODE_ISO,
+ BT_IO_OPT_QOS, &qos_bcast,
+ BT_IO_OPT_ISO_BC_NUM_BIS, iso_bc_addr.bc_num_bis,
+ BT_IO_OPT_ISO_BC_BIS, iso_bc_addr.bc_bis,
+ BT_IO_OPT_INVALID);
+ if (!io) {
+ error("%s", err->message);
+ g_error_free(err);
+ return dbus_message_new_method_return(msg);
+ }
+
+ ep->data->listen_io = io;
+ return dbus_message_new_method_return(msg);
+
+fail:
+ DBG("Failed parsing %s", key);
+ return dbus_message_new_method_return(msg);
+
+}
+
static const GDBusMethodTable ep_methods[] = {
{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("SetConfiguration",
GDBUS_ARGS({ "endpoint", "o" },
- { "properties", "a{sv}" } ),
+ { "properties", "a{sv}" }),
NULL, set_configuration) },
{ },
};

+static const GDBusMethodTable bap_bcast_ep_methods[] = {
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("SetConfiguration",
+ GDBUS_ARGS({ "endpoint", "o" },
+ { "properties", "a{sv}" }),
+ NULL, set_configuration) },
+
+ { GDBUS_EXPERIMENTAL_ASYNC_METHOD("BcastSinkCreate",
+ GDBUS_ARGS({ "properties", "a{sv}" }),
+ NULL, bcast_sink_create) },
+ { },
+};
+
static void ep_free(void *data)
{
struct bap_ep *ep = data;
@@ -657,6 +948,7 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,

switch (bt_bap_pac_get_type(rpac)) {
case BT_BAP_BCAST_SOURCE:
+ case BT_BAP_BCAST_SINK:
queue = data->bcast;
i = queue_length(data->bcast);
suffix = "bcast";
@@ -683,15 +975,24 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,
return NULL;
}

- if (g_dbus_register_interface(btd_get_dbus_connection(),
+ if (bt_bap_pac_get_type(rpac) == BT_BAP_BCAST_SOURCE) {
+ if (g_dbus_register_interface(btd_get_dbus_connection(),
+ ep->path, MEDIA_ENDPOINT_INTERFACE,
+ bap_bcast_ep_methods, NULL, NULL,
+ ep, ep_free) == FALSE) {
+ error("Could not register bap bcast interface %s",
+ ep->path);
+ }
+ } else {
+ if (g_dbus_register_interface(btd_get_dbus_connection(),
ep->path, MEDIA_ENDPOINT_INTERFACE,
ep_methods, NULL, ep_properties,
ep, ep_free) == FALSE) {
- error("Could not register remote ep %s", ep->path);
- ep_free(ep);
- return NULL;
+ error("Could not register remote ep %s", ep->path);
+ ep_free(ep);
+ return NULL;
+ }
}
-
bt_bap_pac_set_user_data(rpac, ep->path);

DBG("ep %p lpac %p rpac %p path %s", ep, ep->lpac, ep->rpac, ep->path);
@@ -724,6 +1025,12 @@ static struct bap_ep *ep_register(struct btd_service *service,
i = queue_length(data->srcs);
suffix = "source";
break;
+ case BT_BAP_BCAST_SOURCE:
+ case BT_BAP_BCAST_SINK:
+ queue = data->bcast;
+ i = queue_length(data->bcast);
+ suffix = "bcast";
+ break;
default:
return NULL;
}
@@ -823,6 +1130,7 @@ done:

queue_foreach(ep->data->srcs, bap_config, NULL);
queue_foreach(ep->data->snks, bap_config, NULL);
+ queue_foreach(ep->data->bcast, bap_config, NULL);
}

static bool pac_found(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
@@ -1416,6 +1724,10 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,
break;
case BT_BAP_STREAM_STATE_CONFIG:
if (ep && !ep->id) {
+ /* For BAP Sink create io when receiving source info */
+ if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)
+ return;
+
bap_create_io(data, ep, stream, true);
if (!ep->io) {
error("Unable to create io");
@@ -1423,7 +1735,6 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,
return;
}

-
if (bt_bap_stream_get_type(stream) ==
BT_BAP_STREAM_TYPE_UCAST) {
/* Wait QoS response to respond */
@@ -1479,7 +1790,9 @@ static void pac_added_broadcast(struct bt_bap_pac *pac, void *user_data)

bt_bap_foreach_pac(data->bap, BT_BAP_BCAST_SOURCE,
pac_found_bcast, data);
- }
+ } else if (bt_bap_pac_get_type(pac) == BT_BAP_BCAST_SINK)
+ bt_bap_foreach_pac(data->bap, BT_BAP_BCAST_SINK,
+ pac_found_bcast, data);
}

static bool ep_match_pac(const void *data, const void *match_data)
@@ -1595,14 +1908,6 @@ static bool match_data(const void *data, const void *match_data)
return bdata->bap == bap;
}

-static bool match_data_bap_data(const void *data, const void *match_data)
-{
- const struct bap_data *bdata = data;
- const struct btd_adapter *adapter = match_data;
-
- return bdata->user_data == adapter;
-}
-
static bool io_get_qos(GIOChannel *io, struct bt_iso_qos *qos)
{
GError *err = NULL;
@@ -1853,7 +2158,7 @@ static int bap_adapter_probe(struct btd_profile *p,

bap_data_add(data);

- if (!bt_bap_attach_broadcast(data->bap)) {
+ if (!bt_bap_attach_broadcast(data->bap, BT_BAP_BCAST_SOURCE)) {
error("BAP unable to attach");
return -EINVAL;
}
diff --git a/src/shared/bap.c b/src/shared/bap.c
index 72ce67c08..1f6527b98 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -633,14 +633,15 @@ static struct bt_bap_endpoint *bap_endpoint_new(struct bt_bap_db *bdb,
return ep;
}

-static struct bt_bap_endpoint *bap_endpoint_new_broacast(struct bt_bap_db *bdb)
+static struct bt_bap_endpoint *bap_endpoint_new_broacast(struct bt_bap_db *bdb,
+ uint8_t type)
{
struct bt_bap_endpoint *ep;

ep = new0(struct bt_bap_endpoint, 1);
ep->bdb = bdb;
ep->attr = NULL;
- ep->dir = BT_BAP_BCAST_SOURCE;
+ ep->dir = type;

return ep;
}
@@ -668,7 +669,7 @@ static struct bt_bap_endpoint *bap_get_endpoint(struct queue *endpoints,
}

static struct bt_bap_endpoint *bap_get_endpoint_bcast(struct queue *endpoints,
- struct bt_bap_db *db)
+ struct bt_bap_db *db, uint8_t type)
{
struct bt_bap_endpoint *ep;

@@ -682,7 +683,7 @@ static struct bt_bap_endpoint *bap_get_endpoint_bcast(struct queue *endpoints,
if (queue_length(endpoints) > 0)
return queue_peek_head(endpoints);

- ep = bap_endpoint_new_broacast(db);
+ ep = bap_endpoint_new_broacast(db, type);
if (!ep)
return NULL;

@@ -1348,6 +1349,9 @@ static void stream_set_state(struct bt_bap_stream *stream, uint8_t state)
ep->old_state = ep->state;
ep->state = state;

+ if (stream->lpac->type == BT_BAP_BCAST_SINK)
+ goto done;
+
if (stream->client)
goto done;

@@ -2518,7 +2522,7 @@ struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db,
struct iovec *metadata)
{
struct bt_bap_db *bdb;
- struct bt_bap_pac *pac, *pac_brodcast_sink;
+ struct bt_bap_pac *pac, *pac_brodcast_sink, *pac_brodcast_source;
struct bt_bap_codec codec;

if (!db)
@@ -2551,6 +2555,13 @@ struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db,
data, metadata);
bap_add_broadcast_sink(pac_brodcast_sink);
break;
+ case BT_BAP_BCAST_SINK:
+ bap_add_broadcast_sink(pac);
+ pac_brodcast_source = bap_pac_new(bdb, name,
+ BT_BAP_BCAST_SOURCE,
+ &codec, qos, data, metadata);
+ bap_add_broadcast_source(pac_brodcast_source);
+ break;
default:
bap_pac_free(pac);
return NULL;
@@ -3996,7 +4007,7 @@ clone:
return true;
}

-bool bt_bap_attach_broadcast(struct bt_bap *bap)
+bool bt_bap_attach_broadcast(struct bt_bap *bap, uint8_t type)
{
struct bt_bap_endpoint *ep;

@@ -4008,7 +4019,7 @@ bool bt_bap_attach_broadcast(struct bt_bap *bap)

queue_push_tail(sessions, bap);

- ep = bap_get_endpoint_bcast(bap->remote_eps, bap->ldb);
+ ep = bap_get_endpoint_bcast(bap->remote_eps, bap->ldb, type);
if (ep)
ep->bap = bap;

@@ -4224,6 +4235,10 @@ void bt_bap_foreach_pac(struct bt_bap *bap, uint8_t type,
return bap_foreach_pac(bap->ldb->broadcast_sources,
bap->ldb->broadcast_sinks,
func, user_data);
+ case BT_BAP_BCAST_SINK:
+ return bap_foreach_pac(bap->ldb->broadcast_sinks,
+ bap->ldb->broadcast_sources,
+ func, user_data);
}
}

@@ -4382,6 +4397,12 @@ unsigned int bt_bap_stream_config(struct bt_bap_stream *stream,
return req->id;
case BT_BAP_STREAM_TYPE_BCAST:
stream->qos = *qos;
+ if (stream->lpac->type == BT_BAP_BCAST_SINK) {
+ if (data)
+ stream_config(stream, data, NULL);
+
+ stream_set_state(stream, BT_BAP_STREAM_STATE_CONFIG);
+ }
return 1;
}

@@ -4446,13 +4467,19 @@ struct bt_bap_stream *bt_bap_stream_new(struct bt_bap *bap,
if (rpac)
type = rpac->type;
else if (lpac) {
- switch(lpac->type) {
+ switch (lpac->type) {
case BT_BAP_SINK:
type = BT_BAP_SOURCE;
break;
case BT_BAP_SOURCE:
type = BT_BAP_SINK;
break;
+ case BT_BAP_BCAST_SOURCE:
+ type = BT_BAP_BCAST_SINK;
+ break;
+ case BT_BAP_BCAST_SINK:
+ type = BT_BAP_BCAST_SOURCE;
+ break;
default:
return NULL;
}
@@ -4913,6 +4940,13 @@ struct io *bt_bap_stream_get_io(struct bt_bap_stream *stream)
return io->io;
}

+bool bt_bap_match_bcast_sink_stream(const void *data, const void *user_data)
+{
+ const struct bt_bap_stream *stream = data;
+
+ return stream->lpac->type == BT_BAP_BCAST_SINK;
+}
+
static bool stream_io_disconnected(struct io *io, void *user_data)
{
struct bt_bap_stream *stream = user_data;
diff --git a/src/shared/bap.h b/src/shared/bap.h
index 50b567663..297ecf0e5 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -186,7 +186,7 @@ struct bt_bap *bt_bap_ref(struct bt_bap *bap);
void bt_bap_unref(struct bt_bap *bap);

bool bt_bap_attach(struct bt_bap *bap, struct bt_gatt_client *client);
-bool bt_bap_attach_broadcast(struct bt_bap *bap);
+bool bt_bap_attach_broadcast(struct bt_bap *bap, uint8_t type);
void bt_bap_detach(struct bt_bap *bap);

bool bt_bap_set_debug(struct bt_bap *bap, bt_bap_debug_func_t cb,
@@ -289,7 +289,7 @@ struct bt_bap_qos *bt_bap_stream_get_qos(struct bt_bap_stream *stream);
struct iovec *bt_bap_stream_get_metadata(struct bt_bap_stream *stream);

struct io *bt_bap_stream_get_io(struct bt_bap_stream *stream);
-
+bool bt_bap_match_bcast_sink_stream(const void *data, const void *user_data);
bool bt_bap_stream_set_io(struct bt_bap_stream *stream, int fd);

int bt_bap_stream_cancel(struct bt_bap_stream *stream, unsigned int id);
--
2.34.1


2023-07-12 14:35:44

by bluez.test.bot

[permalink] [raw]
Subject: RE: Add support for BAP broadcast sink

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=764846

---Test result---

Test Summary:
CheckPatch PASS 3.77 seconds
GitLint PASS 1.88 seconds
BuildEll PASS 28.22 seconds
BluezMake PASS 902.70 seconds
MakeCheck PASS 12.66 seconds
MakeDistcheck PASS 159.29 seconds
CheckValgrind PASS 261.24 seconds
CheckSmatch PASS 347.83 seconds
bluezmakeextell PASS 106.08 seconds
IncrementalBuild PASS 4450.59 seconds
ScanBuild PASS 1077.94 seconds



---
Regards,
Linux Bluetooth

2023-07-12 17:54:28

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ v2 0/6] Add support for BAP broadcast sink

Hi Claudia,

On Wed, Jul 12, 2023 at 5:46 AM Claudia Draghicescu
<[email protected]> wrote:
>
> This series of patches adds support for BAP broadcast sink.
> It consists in registering a sink endpoint using the Sink PAC UUID,
> discovering of broadcast advertisers that announce the
> Broadcast Audio Announcement service, synchronizes to the Periodic
> advertisements of the source and synchronizes to the BIG advertised
> in the PA train.
> To retrieve the BASE info advertised in the PA train, the patch
> Bluetooth: ISO: Add support for periodic adv reports processing
> was used.
>
> This feature was tested using bluetoothctl with the following commands:
>
> [bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
> [/local/endpoint/ep0] Auto Accept (yes/no): y
> [/local/endpoint/ep0] Max Transports (auto/value): a
> [/local/endpoint/ep0] unicast/broadcast (u/b): b
> [/local/endpoint/ep0] BIG (auto/value): a
> [/local/endpoint/ep0] BIS (auto/value): a

Ive thought we would be using BAA UUID instead to follow the same
setup as the broadcaster role.

> [bluetooth]# scan on

Then while scanning if we find an announcement it should create a
remote endpoint under the device object path, just as in case of
unicast, which can later be used with endpoint.config.

> [bluetooth]# endpoint.config /org/bluez/hci0/pac_bcast0
> /local/endpoint/ep0 16_2_1 <source_address>

Here then one would replace /org/bluez/hci0/pac_bcast0 with the one
found during the scanning, so the difference with broadcaster becomes
the source endpoint, if you pass the adapter it is for broadcaster
role or in case it is a remote endpoint the it is for listener role so
the commands would work similarly in all directions

> Claudia Draghicescu (6):
> client/player: Add broadcast sink endpoint registration and
> configuration.
> client/main: Add broadcast source discovery
> media: Add support for a broadcast sink media endpoint
> transport: Update transport properties for a broadcast stream
> btio: Add support for getsockopt(BT_ISO_BASE)
> bap: Add gdbus interface for BAP broadcast sink, create
> synchronization with source and create BAP broadcast sink stream
>
> btio/btio.c | 13 +-
> client/main.c | 57 +++++-
> client/player.c | 187 +++++++++++++++++++-
> client/player.h | 3 +
> profiles/audio/bap.c | 347 ++++++++++++++++++++++++++++++++++---
> profiles/audio/media.c | 35 +++-
> profiles/audio/media.h | 2 +-
> profiles/audio/transport.c | 244 +++++++++++++++++++++++++-
> src/shared/bap.c | 50 +++++-
> src/shared/bap.h | 4 +-
> 10 files changed, 888 insertions(+), 54 deletions(-)
>
>
> base-commit: 838e1578072900d1f98dfb31cc538940d2fad876
> --
> 2.34.1
>


--
Luiz Augusto von Dentz

2023-07-13 19:15:32

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ v2 0/6] Add support for BAP broadcast sink

Hi Claudia,

On Wed, Jul 12, 2023 at 10:45 AM Luiz Augusto von Dentz
<[email protected]> wrote:
>
> Hi Claudia,
>
> On Wed, Jul 12, 2023 at 5:46 AM Claudia Draghicescu
> <[email protected]> wrote:
> >
> > This series of patches adds support for BAP broadcast sink.
> > It consists in registering a sink endpoint using the Sink PAC UUID,
> > discovering of broadcast advertisers that announce the
> > Broadcast Audio Announcement service, synchronizes to the Periodic
> > advertisements of the source and synchronizes to the BIG advertised
> > in the PA train.
> > To retrieve the BASE info advertised in the PA train, the patch
> > Bluetooth: ISO: Add support for periodic adv reports processing
> > was used.
> >
> > This feature was tested using bluetoothctl with the following commands:
> >
> > [bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb 0x06
> > [/local/endpoint/ep0] Auto Accept (yes/no): y
> > [/local/endpoint/ep0] Max Transports (auto/value): a
> > [/local/endpoint/ep0] unicast/broadcast (u/b): b
> > [/local/endpoint/ep0] BIG (auto/value): a
> > [/local/endpoint/ep0] BIS (auto/value): a
>
> Ive thought we would be using BAA UUID instead to follow the same
> setup as the broadcaster role.
>
> > [bluetooth]# scan on
>
> Then while scanning if we find an announcement it should create a
> remote endpoint under the device object path, just as in case of
> unicast, which can later be used with endpoint.config.

I had a few more thoughts about how to enumerate the remote broadcast
endpoints, we may want to introduce a driver for BAA UUID so when a
device is found with BAA as part of the advertised UUID would get
probed and the driver can take care of creating the MediaEndpoint
objects based of the advertised data, probably each BIS should have a
endpoint,

> > [bluetooth]# endpoint.config /org/bluez/hci0/pac_bcast0
> > /local/endpoint/ep0 16_2_1 <source_address>
>
> Here then one would replace /org/bluez/hci0/pac_bcast0 with the one
> found during the scanning, so the difference with broadcaster becomes
> the source endpoint, if you pass the adapter it is for broadcaster
> role or in case it is a remote endpoint the it is for listener role so
> the commands would work similarly in all directions
>
> > Claudia Draghicescu (6):
> > client/player: Add broadcast sink endpoint registration and
> > configuration.
> > client/main: Add broadcast source discovery
> > media: Add support for a broadcast sink media endpoint
> > transport: Update transport properties for a broadcast stream
> > btio: Add support for getsockopt(BT_ISO_BASE)
> > bap: Add gdbus interface for BAP broadcast sink, create
> > synchronization with source and create BAP broadcast sink stream
> >
> > btio/btio.c | 13 +-
> > client/main.c | 57 +++++-
> > client/player.c | 187 +++++++++++++++++++-
> > client/player.h | 3 +
> > profiles/audio/bap.c | 347 ++++++++++++++++++++++++++++++++++---
> > profiles/audio/media.c | 35 +++-
> > profiles/audio/media.h | 2 +-
> > profiles/audio/transport.c | 244 +++++++++++++++++++++++++-
> > src/shared/bap.c | 50 +++++-
> > src/shared/bap.h | 4 +-
> > 10 files changed, 888 insertions(+), 54 deletions(-)
> >
> >
> > base-commit: 838e1578072900d1f98dfb31cc538940d2fad876
> > --
> > 2.34.1
> >
>
>
> --
> Luiz Augusto von Dentz



--
Luiz Augusto von Dentz

Subject: RE: [EXT] Re: [PATCH BlueZ v2 0/6] Add support for BAP broadcast sink

Hi Luiz,

>Hi Claudia,
>
>On Wed, Jul 12, 2023 at 10:45 AM Luiz Augusto von Dentz <[email protected]> wrote:
>>
>> Hi Claudia,
>>
>> On Wed, Jul 12, 2023 at 5:46 AM Claudia Draghicescu
>> <[email protected]> wrote:
>> >
>> > This series of patches adds support for BAP broadcast sink.
>> > It consists in registering a sink endpoint using the Sink PAC UUID,
>> > discovering of broadcast advertisers that announce the Broadcast
>> > Audio Announcement service, synchronizes to the Periodic
>> > advertisements of the source and synchronizes to the BIG advertised
>> > in the PA train.
>> > To retrieve the BASE info advertised in the PA train, the patch
>> > Bluetooth: ISO: Add support for periodic adv reports processing was
>> > used.
>> >
>> > This feature was tested using bluetoothctl with the following commands:
>> >
>> > [bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb
>> > 0x06 [/local/endpoint/ep0] Auto Accept (yes/no): y
>> > [/local/endpoint/ep0] Max Transports (auto/value): a
>> > [/local/endpoint/ep0] unicast/broadcast (u/b): b
>> > [/local/endpoint/ep0] BIG (auto/value): a [/local/endpoint/ep0] BIS
>> > (auto/value): a
>>
>> Ive thought we would be using BAA UUID instead to follow the same
>> setup as the broadcaster role.

We think adding a new UUID for the broadcast sink (0x1851) along with the
UUID for the broadcast source (0x1852) is the best choice because we need
to differentiate the endpoint and transport in other applications like PipeWire.
This follows the same procedure as for bap unicast where PAC_SOURCE_UUID
and PAC_SINK_UUID are used to differentiate between BAP unicast source and sink
endpoints and transports.

>>
>> > [bluetooth]# scan on
>>
>> Then while scanning if we find an announcement it should create a
>> remote endpoint under the device object path, just as in case of
>> unicast, which can later be used with endpoint.config.
>
>I had a few more thoughts about how to enumerate the remote broadcast endpoints, we may want to introduce a driver for BAA UUID so when a device is found with BAA as part of the advertised
>UUID would get probed and the driver can take care of creating the MediaEndpoint objects based of the advertised data, probably each BIS should have a endpoint,
>
>> > [bluetooth]# endpoint.config /org/bluez/hci0/pac_bcast0
>> > /local/endpoint/ep0 16_2_1 <source_address>
>>
>> Here then one would replace /org/bluez/hci0/pac_bcast0 with the one
>> found during the scanning, so the difference with broadcaster becomes
>> the source endpoint, if you pass the adapter it is for broadcaster
>> role or in case it is a remote endpoint the it is for listener role so
>> the commands would work similarly in all directions
>>
>> > Claudia Draghicescu (6):
>> > client/player: Add broadcast sink endpoint registration and
>> > configuration.
>> > client/main: Add broadcast source discovery
>> > media: Add support for a broadcast sink media endpoint
>> > transport: Update transport properties for a broadcast stream
>> > btio: Add support for getsockopt(BT_ISO_BASE)
>> > bap: Add gdbus interface for BAP broadcast sink, create
>> > synchronization with source and create BAP broadcast sink stream
>> >
>> > btio/btio.c | 13 +-
>> > client/main.c | 57 +++++-
>> > client/player.c | 187 +++++++++++++++++++-
>> > client/player.h | 3 +
>> > profiles/audio/bap.c | 347 ++++++++++++++++++++++++++++++++++---
>> > profiles/audio/media.c | 35 +++-
>> > profiles/audio/media.h | 2 +-
>> > profiles/audio/transport.c | 244 +++++++++++++++++++++++++-
>> > src/shared/bap.c | 50 +++++-
>> > src/shared/bap.h | 4 +-
>> > 10 files changed, 888 insertions(+), 54 deletions(-)
>> >
>> >
>> > base-commit: 838e1578072900d1f98dfb31cc538940d2fad876
>> > --
>> > 2.34.1
>> >
>>
>>
>> --
>> Luiz Augusto von Dentz
>
>
>
>--
>Luiz Augusto von Dentz

2023-07-24 17:23:44

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [EXT] Re: [PATCH BlueZ v2 0/6] Add support for BAP broadcast sink

Hi Silviu,

On Mon, Jul 24, 2023 at 8:26 AM Silviu Florian Barbulescu
<[email protected]> wrote:
>
> Hi Luiz,
>
> >Hi Claudia,
> >
> >On Wed, Jul 12, 2023 at 10:45 AM Luiz Augusto von Dentz <[email protected]> wrote:
> >>
> >> Hi Claudia,
> >>
> >> On Wed, Jul 12, 2023 at 5:46 AM Claudia Draghicescu
> >> <[email protected]> wrote:
> >> >
> >> > This series of patches adds support for BAP broadcast sink.
> >> > It consists in registering a sink endpoint using the Sink PAC UUID,
> >> > discovering of broadcast advertisers that announce the Broadcast
> >> > Audio Announcement service, synchronizes to the Periodic
> >> > advertisements of the source and synchronizes to the BIG advertised
> >> > in the PA train.
> >> > To retrieve the BASE info advertised in the PA train, the patch
> >> > Bluetooth: ISO: Add support for periodic adv reports processing was
> >> > used.
> >> >
> >> > This feature was tested using bluetoothctl with the following commands:
> >> >
> >> > [bluetooth]# endpoint.register 00002bc9-0000-1000-8000-00805f9b34fb
> >> > 0x06 [/local/endpoint/ep0] Auto Accept (yes/no): y
> >> > [/local/endpoint/ep0] Max Transports (auto/value): a
> >> > [/local/endpoint/ep0] unicast/broadcast (u/b): b
> >> > [/local/endpoint/ep0] BIG (auto/value): a [/local/endpoint/ep0] BIS
> >> > (auto/value): a
> >>
> >> Ive thought we would be using BAA UUID instead to follow the same
> >> setup as the broadcaster role.
>
> We think adding a new UUID for the broadcast sink (0x1851) along with the
> UUID for the broadcast source (0x1852) is the best choice because we need
> to differentiate the endpoint and transport in other applications like PipeWire.
> This follows the same procedure as for bap unicast where PAC_SOURCE_UUID
> and PAC_SINK_UUID are used to differentiate between BAP unicast source and sink
> endpoints and transports.

Sure, I wasn't aware there was a broadcast sink UUID, anyway the
point is to have a similar flow for both Broadcast and Unicast.

> >>
> >> > [bluetooth]# scan on
> >>
> >> Then while scanning if we find an announcement it should create a
> >> remote endpoint under the device object path, just as in case of
> >> unicast, which can later be used with endpoint.config.
> >
> >I had a few more thoughts about how to enumerate the remote broadcast endpoints, we may want to introduce a driver for BAA UUID so when a device is found with BAA as part of the advertised
> >UUID would get probed and the driver can take care of creating the MediaEndpoint objects based of the advertised data, probably each BIS should have a endpoint,
> >
> >> > [bluetooth]# endpoint.config /org/bluez/hci0/pac_bcast0
> >> > /local/endpoint/ep0 16_2_1 <source_address>
> >>
> >> Here then one would replace /org/bluez/hci0/pac_bcast0 with the one
> >> found during the scanning, so the difference with broadcaster becomes
> >> the source endpoint, if you pass the adapter it is for broadcaster
> >> role or in case it is a remote endpoint the it is for listener role so
> >> the commands would work similarly in all directions
> >>
> >> > Claudia Draghicescu (6):
> >> > client/player: Add broadcast sink endpoint registration and
> >> > configuration.
> >> > client/main: Add broadcast source discovery
> >> > media: Add support for a broadcast sink media endpoint
> >> > transport: Update transport properties for a broadcast stream
> >> > btio: Add support for getsockopt(BT_ISO_BASE)
> >> > bap: Add gdbus interface for BAP broadcast sink, create
> >> > synchronization with source and create BAP broadcast sink stream
> >> >
> >> > btio/btio.c | 13 +-
> >> > client/main.c | 57 +++++-
> >> > client/player.c | 187 +++++++++++++++++++-
> >> > client/player.h | 3 +
> >> > profiles/audio/bap.c | 347 ++++++++++++++++++++++++++++++++++---
> >> > profiles/audio/media.c | 35 +++-
> >> > profiles/audio/media.h | 2 +-
> >> > profiles/audio/transport.c | 244 +++++++++++++++++++++++++-
> >> > src/shared/bap.c | 50 +++++-
> >> > src/shared/bap.h | 4 +-
> >> > 10 files changed, 888 insertions(+), 54 deletions(-)
> >> >
> >> >
> >> > base-commit: 838e1578072900d1f98dfb31cc538940d2fad876
> >> > --
> >> > 2.34.1
> >> >
> >>
> >>
> >> --
> >> Luiz Augusto von Dentz
> >
> >
> >
> >--
> >Luiz Augusto von Dentz



--
Luiz Augusto von Dentz