2023-08-02 13:49:18

by Claudia Draghicescu

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

This series of patches adds support for BAP broadcast sink.
It consists in registering a broadcastsink endpoint using the
Basic Audio Announcement Service 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 00001851-0000-1000-8000-00805f9b34fb 0x06
[bluetooth]# scan on
[NEW] Endpoint /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/pac_bcast0
[bluetooth]# endpoint.config
/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/pac_bcast0
/local/endpoint/ep0 16_2_1

Claudia Draghicescu (6):
client/player: Add broadcast sink endpoint registration
btio: Add support for getsockopt(BT_ISO_BASE)
adapter: Broadcast source discovery
bap: Create synchronization with source and create BAP broadcast sink
stream
media: Add broadcast sink media endpoint
transport: Update transport properties for a broadcast stream

btio/btio.c | 13 +-
client/player.c | 61 +++++++-
profiles/audio/bap.c | 300 +++++++++++++++++++++++++++++++++----
profiles/audio/media.c | 81 ++++++++--
profiles/audio/media.h | 3 +-
profiles/audio/transport.c | 245 +++++++++++++++++++++++++++++-
src/adapter.c | 48 ++++++
src/adapter.h | 2 +
src/shared/bap.c | 153 ++++++++++++++++---
src/shared/bap.h | 11 +-
10 files changed, 835 insertions(+), 82 deletions(-)


base-commit: 8eb1dee87e019f29b6c8233dfe0f9aef8ee44461
--
2.34.1



2023-08-02 13:49:18

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v4 1/6] client/player: Add broadcast sink endpoint

Added support for broadcast sink registration using the 0x1851 UUID.
Added support for remote endpoint creation when a broadcast source
is discovered.
Added support for creating a local endpoint when the broadcast sink
endpoint was registered from an external application (Pipewire).
To test this feature use the following commands:

[bluetooth]# endpoint.register 00001851-0000-1000-8000-00805f9b34fb 0x06
[bluetooth]# scan on
[NEW] Endpoint /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/pac_bcast0
[bluetooth]# endpoint.config
/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/pac_bcast0
/local/endpoint/ep0 16_2_1

---
client/player.c | 61 ++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 53 insertions(+), 8 deletions(-)

diff --git a/client/player.c b/client/player.c
index 9bc5f2a36..3611a8dfe 100644
--- a/client/player.c
+++ b/client/player.c
@@ -1183,6 +1183,17 @@ static const struct capabilities {
CODEC_CAPABILITIES(BCAA_SERVICE_UUID, LC3_ID,
LC3_DATA(LC3_FREQ_ANY, LC3_DURATION_ANY,
3u, 30, 240)),
+
+ /* Broadcast LC3 Sink:
+ *
+ * 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 {
@@ -1465,6 +1476,7 @@ static struct preset {
PRESET(PAC_SINK_UUID, LC3_ID, lc3_presets, 3),
PRESET(PAC_SOURCE_UUID, LC3_ID, lc3_presets, 3),
PRESET(BCAA_SERVICE_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)
@@ -2285,6 +2297,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);
}

@@ -2455,7 +2470,8 @@ static void endpoint_auto_accept(const char *input, void *user_data)
{
struct endpoint *ep = user_data;

- if (!strcmp(ep->uuid, BCAA_SERVICE_UUID)) {
+ if (!strcmp(ep->uuid, BCAA_SERVICE_UUID) ||
+ !strcmp(ep->uuid, BAA_SERVICE_UUID)) {
ep->broadcast = true;
} else {
ep->broadcast = false;
@@ -2728,13 +2744,20 @@ static void endpoint_config(const char *input, void *user_data)
endpoint_set_config(cfg);
}

+static struct endpoint *endpoint_new(const struct capabilities *cap);
+
static void cmd_config_endpoint(int argc, char *argv[])
{
struct endpoint_config *cfg;
const struct codec_preset *preset;
+ const struct capabilities *cap;
+ char *uuid;
+ uint8_t codec_id;
+ bool broadcast = false;

cfg = new0(struct endpoint_config, 1);

+ /* Search for the remote endpoint name on DBUS */
cfg->proxy = g_dbus_proxy_lookup(endpoints, NULL, argv[1],
BLUEZ_MEDIA_ENDPOINT_INTERFACE);
if (!cfg->proxy) {
@@ -2742,16 +2765,36 @@ static void cmd_config_endpoint(int argc, char *argv[])
goto fail;
}

+ /* Search for the local endpoint */
cfg->ep = endpoint_find(argv[2]);
if (!cfg->ep) {
- bt_shell_printf("Local Endpoint %s not found\n", argv[2]);
- goto fail;
+
+ /* When the local endpoint was not found either we received
+ * UUID, or the provided local endpoint is not available
+ */
+ uuid = argv[2];
+ codec_id = strtol(argv[3], NULL, 0);
+ cap = find_capabilities(uuid, codec_id);
+ if (cap) {
+ broadcast = true;
+ cfg->ep = endpoint_new(cap);
+ cfg->ep->preset = find_presets_name(uuid, argv[3]);
+ if (!cfg->ep->preset)
+ bt_shell_printf("Preset not found\n");
+ } else {
+ bt_shell_printf("Local Endpoint %s,"
+ "or capabilities not found\n", uuid);
+ goto fail;
+ }
}

- if (argc > 3) {
- preset = preset_find_name(cfg->ep->preset, argv[3]);
+ if (((broadcast == false) && (argc > 3)) ||
+ ((broadcast == true) && (argc > 4))) {
+ char *preset_name = (broadcast == false)?argv[3]:argv[4];
+
+ preset = preset_find_name(cfg->ep->preset, preset_name);
if (!preset) {
- bt_shell_printf("Preset %s not found\n", argv[3]);
+ bt_shell_printf("Preset %s not found\n", preset_name);
goto fail;
}

@@ -3172,7 +3215,8 @@ 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/UUID] [preset/codec id] [preset]",
cmd_config_endpoint,
"Configure Endpoint",
endpoint_generator },
@@ -3189,7 +3233,8 @@ static struct endpoint *endpoint_new(const struct capabilities *cap)

ep = new0(struct endpoint, 1);
ep->uuid = g_strdup(cap->uuid);
- ep->broadcast = strcmp(cap->uuid, BCAA_SERVICE_UUID) ? false : true;
+ ep->broadcast = (strcmp(cap->uuid, BCAA_SERVICE_UUID) &&
+ strcmp(cap->uuid, BAA_SERVICE_UUID)) ? false : true;
ep->codec = cap->codec_id;
ep->path = g_strdup_printf("%s/ep%u", BLUEZ_MEDIA_ENDPOINT_PATH,
g_list_length(local_endpoints));
--
2.34.1


2023-08-02 13:49:19

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v4 3/6] adapter: Broadcast source discovery

This adds a new method in the adapter driver, device_resolved() called
when a broadcast source that advertises the BCAA_UUID is discovered.

---
src/adapter.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
src/adapter.h | 2 ++
2 files changed, 50 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 491bd7031..29c6a576a 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -7029,6 +7029,45 @@ static bool is_filter_match(GSList *discovery_filter, struct eir_data *eir_data,
return got_match;
}

+static int find_baas(gconstpointer a, gconstpointer b)
+{
+ const struct eir_sd *sd = a;
+ const char *baas_uuid = b;
+
+ return strcmp(sd->uuid, baas_uuid);
+}
+
+static bool accept_bcast_adv(struct btd_adapter *adapter)
+{
+ if ((btd_adapter_has_settings(adapter, MGMT_SETTING_ISO_SYNC_RECEIVER)))
+ return true;
+
+ return false;
+}
+
+static bool is_bcast_source(struct eir_data *eir_data)
+{
+ if (!(eir_data->flags & (EIR_LIM_DISC | EIR_GEN_DISC))
+ && (g_slist_find_custom(eir_data->sd_list,
+ BCAA_SERVICE_UUID, find_baas))) {
+ return true;
+ }
+
+ return false;
+}
+static void bcast_new_source(struct btd_adapter *adapter,
+ struct btd_device *device)
+{
+ GSList *l;
+
+ for (l = adapter->drivers; l; l = g_slist_next(l)) {
+ struct btd_adapter_driver *driver = l->data;
+
+ if (!strcmp(driver->name, "bcast"))
+ driver->device_discovered(adapter, device);
+ }
+}
+
static void filter_duplicate_data(void *data, void *user_data)
{
struct discovery_client *client = data;
@@ -7152,12 +7191,21 @@ void btd_adapter_device_found(struct btd_adapter *adapter,
return;
}

+ if (accept_bcast_adv(adapter) && is_bcast_source(&eir_data))
+ monitoring = true;
+
if (!discoverable && !monitoring && !eir_data.rsi) {
eir_data_free(&eir_data);
return;
}

dev = adapter_create_device(adapter, bdaddr, bdaddr_type);
+
+ if (dev && is_bcast_source(&eir_data)) {
+ bcast_new_source(adapter, dev);
+ btd_device_set_temporary(dev, false);
+ }
+
}

if (!dev) {
diff --git a/src/adapter.h b/src/adapter.h
index ca96c1f65..ee32f7110 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -125,6 +125,8 @@ struct btd_adapter_driver {
struct btd_device *device);
void (*device_resolved)(struct btd_adapter *adapter,
struct btd_device *device);
+ void (*device_discovered)(struct btd_adapter *adapter,
+ struct btd_device *device);

/* Indicates the driver is experimental and shall only be registered
* when experimental has been enabled (see: main.conf:Experimental).
--
2.34.1


2023-08-02 13:49:33

by Claudia Draghicescu

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

This adds support for BAP broadcast sink, creates a remote endpoint when a
broadcast source is discovered and synchronizes with the source upon
endpoint configuration.
This feature was tested using bluetoothctl with the following commands:

[bluetooth]# endpoint.register 00001851-0000-1000-8000-00805f9b34fb 0x06
[bluetooth]# scan on
[NEW] Endpoint /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/pac_bcast0
[bluetooth]# endpoint.config
/org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/pac_bcast0
/local/endpoint/ep0 16_2_1

---
profiles/audio/bap.c | 300 ++++++++++++++++++++++++++++++++++++++-----
src/shared/bap.c | 153 +++++++++++++++++++---
src/shared/bap.h | 11 +-
3 files changed, 410 insertions(+), 54 deletions(-)

diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index 8cbb238ef..112e0673d 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"
@@ -58,6 +59,7 @@
#define ISO_SOCKET_UUID "6fbaf188-05e0-496a-9885-d6ddfdb4e03e"
#define PACS_UUID_STR "00001850-0000-1000-8000-00805f9b34fb"
#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
+#define MEDIA_INTERFACE "org.bluez.Media1"

struct bap_ep {
char *path;
@@ -186,8 +188,11 @@ 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
+ else if ((queue_find(ep->data->bcast, NULL, ep)
+ && (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)))
uuid = BAA_SERVICE_UUID;
+ else
+ uuid = BCAA_SERVICE_UUID;

dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);

@@ -341,15 +346,18 @@ static int parse_properties(DBusMessageIter *props, struct iovec **caps,
} else if (!strcasecmp(key, "PHY")) {
const char *str;

- if (var != DBUS_TYPE_STRING)
- goto fail;
-
- dbus_message_iter_get_basic(&value, &str);
-
- if (!strcasecmp(str, "1M"))
- io_qos.phy = 0x01;
- else if (!strcasecmp(str, "2M"))
- io_qos.phy = 0x02;
+ if (var == DBUS_TYPE_STRING) {
+ dbus_message_iter_get_basic(&value, &str);
+
+ if (!strcasecmp(str, "1M"))
+ io_qos.phy = 0x01;
+ else if (!strcasecmp(str, "2M"))
+ io_qos.phy = 0x02;
+ else
+ goto fail;
+ } else if (var == DBUS_TYPE_BYTE)
+ dbus_message_iter_get_basic(&value,
+ &io_qos.phy);
else
goto fail;
} else if (!strcasecmp(key, "SDU")) {
@@ -556,7 +564,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 {
@@ -577,8 +585,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);
@@ -597,13 +609,120 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
break;
case BT_BAP_STREAM_TYPE_BCAST:
/* No message sent over the air for broadcast */
- ep->id = 0;
+ if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)
+ ep->msg = dbus_message_ref(msg);
+ else
+ ep->id = 0;
+
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}

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_ep_type(const void *data, const void *user_data)
+{
+ const struct bap_ep *ep = data;
+
+ return (bt_bap_pac_get_type(ep->lpac) == PTR_TO_INT(user_data));
+}
+
+static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
+{
+ struct bap_data *data = user_data;
+ struct bt_iso_qos qos;
+ struct bt_iso_base base;
+ char address[18];
+ 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);
+
+ ep = queue_find(data->bcast, match_ep_type,
+ INT_TO_PTR(BT_BAP_BCAST_SINK));
+ 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);
+
+ if (ep->stream == NULL)
+ DBG("stream is null");
+ 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);
+
+ fd = g_io_channel_unix_get_fd(io);
+
+ if (bt_bap_stream_set_io(ep->stream, fd)) {
+ bt_bap_stream_enable(ep->stream, true, NULL, NULL, NULL);
+ g_io_channel_set_close_on_unref(io, FALSE);
+ return;
+ }
+
+
+ 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;
+}
+
static const GDBusMethodTable ep_methods[] = {
{ GDBUS_EXPERIMENTAL_ASYNC_METHOD("SetConfiguration",
GDBUS_ARGS({ "endpoint", "o" },
@@ -650,14 +769,23 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,
struct bt_bap_pac *rpac)
{
struct btd_adapter *adapter = data->user_data;
+ struct btd_device *device = data->device;
struct bap_ep *ep;
struct queue *queue;
- int i, err;
+ int i, err = 0;
const char *suffix;
struct match_ep match = { lpac, rpac };

+ if (!adapter)
+ DBG("adapter is null");
+
+ if (!device)
+ device = btd_adapter_find_device_by_path(adapter,
+ bt_bap_pac_get_name(rpac));
+
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";
@@ -675,8 +803,24 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,
ep->lpac = lpac;
ep->rpac = rpac;

- err = asprintf(&ep->path, "%s/pac_%s%d", adapter_get_path(adapter),
- suffix, i);
+ if (device)
+ ep->data->device = device;
+
+ switch (bt_bap_pac_get_type(rpac)) {
+ case BT_BAP_BCAST_SINK:
+ DBG("sink");
+ err = asprintf(&ep->path, "%s/pac_%s%d",
+ adapter_get_path(adapter), suffix, i);
+ DBG("sink path %s", ep->path);
+ break;
+ case BT_BAP_BCAST_SOURCE:
+ DBG("source");
+ err = asprintf(&ep->path, "%s/pac_%s%d",
+ device_get_path(device), suffix, i);
+ DBG("source path %s", ep->path);
+ break;
+ }
+
if (err < 0) {
error("Could not allocate path for remote pac %s/pac%d",
adapter_get_path(adapter), i);
@@ -685,14 +829,13 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,
}

if (g_dbus_register_interface(btd_get_dbus_connection(),
- ep->path, MEDIA_ENDPOINT_INTERFACE,
- ep_methods, NULL, ep_properties,
- ep, ep_free) == FALSE) {
+ 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;
}
-
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);
@@ -824,6 +967,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,
@@ -1310,6 +1454,46 @@ static void bap_listen_io(struct bap_data *data, struct bt_bap_stream *stream,
data->listen_io = io;
}

+static void bap_listen_io_broadcast(struct bap_data *data, struct bap_ep *ep,
+ struct bt_bap_stream *stream, struct bt_iso_qos *qos)
+{
+ GIOChannel *io;
+ GError *err = NULL;
+ struct sockaddr_iso_bc iso_bc_addr;
+
+ iso_bc_addr.bc_bdaddr_type = btd_device_get_bdaddr_type(data->device);
+ memcpy(&iso_bc_addr.bc_bdaddr, device_get_address(data->device),
+ sizeof(bdaddr_t));
+ iso_bc_addr.bc_bis[0] = 1;
+ iso_bc_addr.bc_num_bis = 1;
+
+ DBG("stream %p", stream);
+
+ /* If IO already set skip creating it again */
+ if (bt_bap_stream_get_io(stream) || data->listen_io)
+ return;
+
+ 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,
+ device_get_address(data->device),
+ BT_IO_OPT_DEST_TYPE,
+ btd_device_get_bdaddr_type(data->device),
+ 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);
+ } else
+ DBG("io created");
+
+ ep->data->listen_io = io;
+
+}
static void bap_create_ucast_io(struct bap_data *data, struct bap_ep *ep,
struct bt_bap_stream *stream, int defer)
{
@@ -1364,10 +1548,10 @@ static void bap_create_bcast_io(struct bap_data *data, struct bap_ep *ep,
memcpy(&iso_qos.bcast.out, &ep->qos.bcast.io_qos,
sizeof(struct bt_iso_io_qos));
done:
- if (ep)
+ if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE)
bap_connect_io_broadcast(data, ep, stream, &iso_qos);
else
- bap_listen_io(data, stream, &iso_qos);
+ bap_listen_io_broadcast(data, ep, stream, &iso_qos);
}

static void bap_create_io(struct bap_data *data, struct bap_ep *ep,
@@ -1417,6 +1601,11 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,
break;
case BT_BAP_STREAM_STATE_CONFIG:
if (ep && !ep->id) {
+ if
+ (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK) {
+ bap_create_bcast_io(data, ep, stream, true);
+ return;
+ }
bap_create_io(data, ep, stream, true);
if (!ep->io) {
error("Unable to create io");
@@ -1424,7 +1613,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 */
@@ -1480,6 +1668,10 @@ 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) {
+ DBG("sink pac %p", pac);
+ bt_bap_foreach_pac(data->bap, BT_BAP_BCAST_SINK,
+ pac_found_bcast, data);
}
}

@@ -1596,14 +1788,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;
@@ -1854,7 +2038,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;
}
@@ -1901,12 +2085,62 @@ static struct btd_profile bap_profile = {
.experimental = true,
};

+static GDBusProxy *media;
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+ const char *interface;
+
+ interface = g_dbus_proxy_get_interface(proxy);
+
+ if (!strcmp(interface, MEDIA_INTERFACE)) {
+ DBG("proxy added %s ", g_dbus_proxy_get_path(proxy));
+ media = proxy;
+ }
+}
+
+static int bcast_server_probe(struct btd_adapter *adapter)
+{
+ static GDBusClient *client;
+
+ client = g_dbus_client_new(btd_get_dbus_connection(),
+ "org.bluez", "/org/bluez");
+
+ g_dbus_client_set_proxy_handlers(client, proxy_added, NULL,
+ NULL, NULL);
+
+ return 0;
+}
+
+static void bcast_server_remove(struct btd_adapter *adapter)
+{
+ DBG("path %s", adapter_get_path(adapter));
+}
+
+static void bcast_new_source(struct btd_adapter *adapter,
+ struct btd_device *device)
+{
+ struct bap_data *data = queue_find(sessions, match_data_bap_data,
+ adapter);
+
+ bt_bap_new_bcast_source(data->bap, device_get_path(device), 0x06);
+}
+
+static struct btd_adapter_driver bcast_driver = {
+ .name = "bcast",
+ .probe = bcast_server_probe,
+ .remove = bcast_server_remove,
+ .device_discovered = bcast_new_source,
+ .experimental = true,
+};
+
static unsigned int bap_id = 0;

static int bap_init(void)
{
int err;

+ btd_register_adapter_driver(&bcast_driver);
err = btd_profile_register(&bap_profile);
if (err)
return err;
diff --git a/src/shared/bap.c b/src/shared/bap.c
index 72ce67c08..ae3f64730 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -633,14 +633,18 @@ 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_broadcast(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;
+ if (type == BT_BAP_BCAST_SINK)
+ ep->dir = BT_BAP_BCAST_SOURCE;
+ else
+ ep->dir = BT_BAP_BCAST_SINK;

return ep;
}
@@ -667,22 +671,27 @@ static struct bt_bap_endpoint *bap_get_endpoint(struct queue *endpoints,
return ep;
}

+static bool match_ep_type(const void *data, const void *match_data)
+{
+ const struct bt_bap_endpoint *ep = data;
+ const uint8_t type = PTR_TO_INT(match_data);
+
+ return (ep->dir == type);
+}
+
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;

if (!db)
return NULL;
- /*
- * We have support for only one stream so we will have
- * only one endpoint.
- * TO DO add support for more then one stream
- */
- if (queue_length(endpoints) > 0)
- return queue_peek_head(endpoints);

- ep = bap_endpoint_new_broacast(db);
+ ep = queue_find(endpoints, match_ep_type, INT_TO_PTR(type));
+ if (ep)
+ return ep;
+
+ ep = bap_endpoint_new_broadcast(db, type);
if (!ep)
return NULL;

@@ -1317,6 +1326,8 @@ static void stream_set_state_broadcast(struct bt_bap_stream *stream,
struct bt_bap *bap = stream->bap;
const struct queue_entry *entry;

+ if (ep->old_state == state)
+ return;
ep->old_state = ep->state;
ep->state = state;

@@ -1348,6 +1359,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;

@@ -2379,6 +2393,10 @@ static struct bt_bap_pac *bap_pac_find(struct bt_bap_db *bdb, uint8_t type,
return queue_find(bdb->sources, match_codec, codec);
case BT_BAP_SINK:
return queue_find(bdb->sinks, match_codec, codec);
+ case BT_BAP_BCAST_SOURCE:
+ return queue_find(bdb->broadcast_sources, match_codec, codec);
+ case BT_BAP_BCAST_SINK:
+ return queue_find(bdb->broadcast_sinks, match_codec, codec);
}

return NULL;
@@ -2518,7 +2536,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_broadcast_sink;
struct bt_bap_codec codec;

if (!db)
@@ -2545,11 +2563,19 @@ struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db,
bap_add_source(pac);
break;
case BT_BAP_BCAST_SOURCE:
- // For broadcast add local pac and remote pac
bap_add_broadcast_source(pac);
- pac_brodcast_sink = bap_pac_new(bdb, name, type, &codec, qos,
+ if (queue_isempty(bdb->broadcast_sinks)) {
+ /* When adding a local broadcast source, add also a
+ * local broadcast sink
+ */
+ pac_broadcast_sink = bap_pac_new(bdb, name,
+ BT_BAP_BCAST_SINK, &codec, qos,
data, metadata);
- bap_add_broadcast_sink(pac_brodcast_sink);
+ bap_add_broadcast_sink(pac_broadcast_sink);
+ }
+ break;
+ case BT_BAP_BCAST_SINK:
+ bap_add_broadcast_sink(pac);
break;
default:
bap_pac_free(pac);
@@ -2579,6 +2605,14 @@ uint8_t bt_bap_pac_get_type(struct bt_bap_pac *pac)
return pac->type;
}

+char *bt_bap_pac_get_name(struct bt_bap_pac *pac)
+{
+ if (!pac)
+ return NULL;
+
+ return pac->name;
+}
+
uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac)
{
struct bt_pacs *pacs = pac->bdb->pacs;
@@ -3996,7 +4030,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 +4042,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;

@@ -4221,9 +4255,19 @@ void bt_bap_foreach_pac(struct bt_bap *bap, uint8_t type,
return bap_foreach_pac(bap->ldb->sinks, bap->rdb->sources,
func, user_data);
case BT_BAP_BCAST_SOURCE:
- return bap_foreach_pac(bap->ldb->broadcast_sources,
+ if (queue_isempty(bap->rdb->broadcast_sources)
+ && queue_isempty(bap->rdb->broadcast_sinks))
+ return bap_foreach_pac(bap->ldb->broadcast_sources,
bap->ldb->broadcast_sinks,
func, user_data);
+
+ return bap_foreach_pac(bap->ldb->broadcast_sinks,
+ bap->rdb->broadcast_sources,
+ func, user_data);
+ case BT_BAP_BCAST_SINK:
+ return bap_foreach_pac(bap->ldb->broadcast_sinks,
+ bap->rdb->broadcast_sources,
+ func, user_data);
}
}

@@ -4382,6 +4426,11 @@ 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 +4495,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 +4968,18 @@ struct io *bt_bap_stream_get_io(struct bt_bap_stream *stream)
return io->io;
}

+char *bt_bap_stream_get_remote_name(struct bt_bap_stream *stream)
+{
+ return bt_bap_pac_get_name(stream->rpac);
+}
+
+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;
@@ -4944,6 +5011,14 @@ static bool match_req_id(const void *data, const void *match_data)
return (req->id == id);
}

+static bool match_name(const void *data, const void *match_data)
+{
+ const struct bt_bap_pac *pac = data;
+ const char *name = match_data;
+
+ return (!strcmp(pac->name, name));
+}
+
int bt_bap_stream_cancel(struct bt_bap_stream *stream, unsigned int id)
{
struct bt_bap_req *req;
@@ -5132,3 +5207,43 @@ bool bt_bap_stream_io_is_connecting(struct bt_bap_stream *stream, int *fd)

return io->connecting;
}
+
+bool bt_bap_new_bcast_source(struct bt_bap *bap, const char *name,
+ uint8_t codec)
+{
+ struct bt_bap_endpoint *ep;
+ struct bt_bap_pac *pac_broadcast_source, *local_sink;
+ struct bt_bap_codec bap_codec;
+
+ bap_codec.id = codec;
+ bap_codec.cid = 0;
+ bap_codec.vid = 0;
+
+ /* Add remote source endpoint */
+ if (!bap->rdb->broadcast_sources)
+ bap->rdb->broadcast_sources = queue_new();
+
+ if (queue_find(bap->rdb->broadcast_sources, match_name, name)) {
+ DBG(bap, "broadcast source already registered");
+ return true;
+ }
+
+ local_sink = queue_peek_head(bap->ldb->broadcast_sinks);
+ pac_broadcast_source = bap_pac_new(bap->rdb, name, BT_BAP_BCAST_SOURCE,
+ &bap_codec, NULL, local_sink->data, NULL);
+ queue_push_tail(bap->rdb->broadcast_sources, pac_broadcast_source);
+
+ if (!pac_broadcast_source) {
+ DBG(bap, "No broadcast source could be created");
+ return false;
+ }
+ queue_foreach(bap->pac_cbs, notify_pac_added, pac_broadcast_source);
+
+ /* Push remote endpoint with direction sink */
+ ep = bap_endpoint_new_broadcast(bap->rdb, BT_BAP_BCAST_SINK);
+
+ if (ep)
+ queue_push_tail(bap->remote_eps, ep);
+
+ return true;
+}
diff --git a/src/shared/bap.h b/src/shared/bap.h
index 50b567663..cf98ec8b7 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -163,6 +163,8 @@ bool bt_bap_remove_pac(struct bt_bap_pac *pac);

uint8_t bt_bap_pac_get_type(struct bt_bap_pac *pac);

+char *bt_bap_pac_get_name(struct bt_bap_pac *pac);
+
uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac);

uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream);
@@ -186,7 +188,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 +291,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);
@@ -305,3 +307,8 @@ uint8_t bt_bap_stream_io_dir(struct bt_bap_stream *stream);

int bt_bap_stream_io_connecting(struct bt_bap_stream *stream, int fd);
bool bt_bap_stream_io_is_connecting(struct bt_bap_stream *stream, int *fd);
+
+bool bt_bap_new_bcast_source(struct bt_bap *bap, const char *name,
+ uint8_t codec);
+
+char *bt_bap_stream_get_remote_name(struct bt_bap_stream *stream);
--
2.34.1


2023-08-02 13:49:34

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v4 6/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 | 245 ++++++++++++++++++++++++++++++++++++-
1 file changed, 243 insertions(+), 2 deletions(-)

diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
index cf5662d1d..aa2fa4397 100644
--- a/profiles/audio/transport.c
+++ b/profiles/audio/transport.c
@@ -552,6 +552,8 @@ static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg,
owner = media_owner_create(msg);

if (!strcmp(media_endpoint_get_uuid(transport->endpoint),
+ BAA_SERVICE_UUID)
+ && !strcmp(media_endpoint_get_uuid(transport->endpoint),
BCAA_SERVICE_UUID)) {
req = media_request_create(msg, 0x00);
media_owner_add(owner, req);
@@ -853,6 +855,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 +873,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 +897,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 +928,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 +942,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 +960,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 +1084,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 +1218,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 +1511,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 +1728,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 +1741,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;
}

@@ -1631,7 +1871,8 @@ struct media_transport *media_transport_create(struct btd_device *device,
properties = a2dp_properties;
} else if (!strcasecmp(uuid, PAC_SINK_UUID) ||
!strcasecmp(uuid, PAC_SOURCE_UUID) ||
- !strcasecmp(uuid, BCAA_SERVICE_UUID)) {
+ !strcasecmp(uuid, BCAA_SERVICE_UUID) ||
+ !strcasecmp(uuid, BAA_SERVICE_UUID)) {
if (media_transport_init_bap(transport, stream) < 0)
goto fail;
properties = bap_properties;
--
2.34.1


2023-08-02 13:49:54

by Claudia Draghicescu

[permalink] [raw]
Subject: [PATCH BlueZ v4 5/6] media: Add broadcast sink media endpoint

This patch adds the possibility to register a broadcast
media endpoint if the controller has support for ISO Sync Receiver.

---
profiles/audio/media.c | 81 ++++++++++++++++++++++++++++++++++--------
profiles/audio/media.h | 3 +-
2 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/profiles/audio/media.c b/profiles/audio/media.c
index 15c64c8d6..edf106a12 100644
--- a/profiles/audio/media.c
+++ b/profiles/audio/media.c
@@ -105,6 +105,7 @@ struct media_endpoint {
GSList *requests;
struct media_adapter *adapter;
GSList *transports;
+ bool broadcast;
};

struct media_player {
@@ -1059,6 +1060,9 @@ static struct media_transport *pac_bcast_config(struct bt_bap_stream *stream,
{
struct bt_bap *bap = bt_bap_stream_get_session(stream);
struct btd_adapter *adapter = bt_bap_get_user_data(bap);
+ struct btd_device *device =
+ btd_adapter_find_device_by_path(bt_bap_get_user_data(bap),
+ bt_bap_stream_get_remote_name(stream));
const char *path;

if (!adapter) {
@@ -1066,9 +1070,17 @@ static struct media_transport *pac_bcast_config(struct bt_bap_stream *stream,
return NULL;
}

+ if (!device) {
+ DBG("no device found");
+ } else {
+ char name[30];
+
+ device_get_name(device, name, 30);
+ DBG("device found name %s", name);
+ }
path = bt_bap_stream_get_user_data(stream);

- return media_transport_create(NULL, path, cfg->iov_base, cfg->iov_len,
+ return media_transport_create(device, path, cfg->iov_base, cfg->iov_len,
endpoint, stream);
}

@@ -1238,6 +1250,12 @@ static bool endpoint_init_broadcast_source(struct media_endpoint *endpoint,
return endpoint_init_pac(endpoint, BT_BAP_BCAST_SOURCE, err);
}

+static bool endpoint_init_broadcast_sink(struct media_endpoint *endpoint,
+ int *err)
+{
+ return endpoint_init_pac(endpoint, BT_BAP_BCAST_SINK, err);
+}
+
static bool endpoint_properties_exists(const char *uuid,
struct btd_device *dev,
void *user_data)
@@ -1351,6 +1369,17 @@ static bool experimental_broadcaster_ep_supported(struct btd_adapter *adapter)
return g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL;
}

+static bool experimental_bcast_sink_ep_supported(struct btd_adapter *adapter)
+{
+ if (!btd_adapter_has_exp_feature(adapter, EXP_FEAT_ISO_SOCKET))
+ return false;
+
+ if (!btd_adapter_has_settings(adapter, MGMT_SETTING_ISO_SYNC_RECEIVER))
+ return false;
+
+ return g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL;
+}
+
static struct media_endpoint_init {
const char *uuid;
bool (*func)(struct media_endpoint *endpoint, int *err);
@@ -1366,6 +1395,8 @@ static struct media_endpoint_init {
experimental_endpoint_supported },
{ BCAA_SERVICE_UUID, endpoint_init_broadcast_source,
experimental_broadcaster_ep_supported },
+ { BAA_SERVICE_UUID, endpoint_init_broadcast_sink,
+ experimental_bcast_sink_ep_supported },
};

static struct media_endpoint *
@@ -1382,6 +1413,7 @@ media_endpoint_create(struct media_adapter *adapter,
int size,
uint8_t *metadata,
int metadata_size,
+ bool broadcast,
int *err)
{
struct media_endpoint *endpoint;
@@ -1397,6 +1429,7 @@ media_endpoint_create(struct media_adapter *adapter,
endpoint->cid = cid;
endpoint->vid = vid;
endpoint->delay_reporting = delay_reporting;
+ endpoint->broadcast = broadcast;

if (qos)
endpoint->qos = *qos;
@@ -1458,11 +1491,11 @@ struct vendor {
} __packed;

static int parse_properties(DBusMessageIter *props, const char **uuid,
- gboolean *delay_reporting, uint8_t *codec,
- uint16_t *cid, uint16_t *vid,
- struct bt_bap_pac_qos *qos,
- uint8_t **capabilities, int *size,
- uint8_t **metadata, int *metadata_size)
+ gboolean *delay_reporting, uint8_t *codec,
+ uint16_t *cid, uint16_t *vid,
+ struct bt_bap_pac_qos *qos,
+ uint8_t **capabilities, int *size,
+ uint8_t **metadata, int *metadata_size, bool *broadcast)
{
gboolean has_uuid = FALSE;
gboolean has_codec = FALSE;
@@ -1546,6 +1579,10 @@ static int parse_properties(DBusMessageIter *props, const char **uuid,
if (var != DBUS_TYPE_UINT16)
return -EINVAL;
dbus_message_iter_get_basic(&value, &qos->ppd_max);
+ } else if (strcasecmp(key, "Broadcast") == 0) {
+ if (var != DBUS_TYPE_BOOLEAN)
+ return -EINVAL;
+ dbus_message_iter_get_basic(&value, broadcast);
}

dbus_message_iter_next(props);
@@ -1569,6 +1606,7 @@ static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg,
uint8_t *metadata = NULL;
int size = 0;
int metadata_size = 0;
+ bool broadcast = false;
int err;

sender = dbus_message_get_sender(msg);
@@ -1587,13 +1625,13 @@ static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg,

if (parse_properties(&props, &uuid, &delay_reporting, &codec, &cid,
&vid, &qos, &capabilities, &size, &metadata,
- &metadata_size) < 0)
+ &metadata_size, &broadcast) < 0)
return btd_error_invalid_args(msg);

if (media_endpoint_create(adapter, sender, path, uuid, delay_reporting,
- codec, cid, vid, &qos, capabilities,
- size, metadata, metadata_size,
- &err) == NULL) {
+ codec, cid, vid, &qos, capabilities,
+ size, metadata, metadata_size, broadcast,
+ &err) == NULL) {
if (err == -EPROTONOSUPPORT)
return btd_error_not_supported(msg);
else
@@ -2627,6 +2665,7 @@ static void app_register_endpoint(void *data, void *user_data)
int metadata_size = 0;
DBusMessageIter iter, array;
struct media_endpoint *endpoint;
+ bool broadcast = false;

if (app->err)
return;
@@ -2736,12 +2775,18 @@ static void app_register_endpoint(void *data, void *user_data)
dbus_message_iter_get_basic(&iter, &qos.ppd_min);
}

+ if (g_dbus_proxy_get_property(proxy, "Broadcast", &iter)) {
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_BOOLEAN)
+ goto fail;
+ dbus_message_iter_get_basic(&iter, &broadcast);
+ }
+
endpoint = media_endpoint_create(app->adapter, app->sender, path, uuid,
- delay_reporting, codec,
- vendor.cid, vendor.vid, &qos,
- capabilities, size,
- metadata, metadata_size,
- &app->err);
+ delay_reporting, codec,
+ vendor.cid, vendor.vid, &qos,
+ capabilities, size,
+ metadata, metadata_size, broadcast,
+ &app->err);
if (!endpoint) {
error("Unable to register endpoint %s:%s: %s", app->sender,
path, strerror(-app->err));
@@ -3245,3 +3290,9 @@ struct btd_adapter *media_endpoint_get_btd_adapter(
{
return endpoint->adapter->btd_adapter;
}
+
+bool media_endpoint_is_broadcast(
+ struct media_endpoint *endpoint)
+{
+ return endpoint->broadcast;
+}
diff --git a/profiles/audio/media.h b/profiles/audio/media.h
index 1de84a8ff..0eeb5746a 100644
--- a/profiles/audio/media.h
+++ b/profiles/audio/media.h
@@ -22,5 +22,6 @@ const char *media_endpoint_get_uuid(struct media_endpoint *endpoint);
uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint);
struct btd_adapter *media_endpoint_get_btd_adapter(
struct media_endpoint *endpoint);
-
+bool media_endpoint_is_broadcast(
+ struct media_endpoint *endpoint);
int8_t media_player_get_device_volume(struct btd_device *device);
--
2.34.1


2023-08-02 16:34:23

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=772179

---Test result---

Test Summary:
CheckPatch PASS 3.67 seconds
GitLint PASS 1.81 seconds
BuildEll PASS 28.39 seconds
BluezMake PASS 1068.10 seconds
MakeCheck PASS 12.93 seconds
MakeDistcheck PASS 164.14 seconds
CheckValgrind PASS 267.38 seconds
CheckSmatch PASS 354.46 seconds
bluezmakeextell PASS 106.80 seconds
IncrementalBuild PASS 5253.67 seconds
ScanBuild PASS 1103.91 seconds



---
Regards,
Linux Bluetooth

2023-08-02 18:01:16

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH BlueZ v4 3/6] adapter: Broadcast source discovery

Hi Claudia,

On Wed, Aug 2, 2023 at 6:49 AM Claudia Draghicescu <[email protected]> wrote:
>
> This adds a new method in the adapter driver, device_resolved() called
> when a broadcast source that advertises the BCAA_UUID is discovered.
>
> ---
> src/adapter.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
> src/adapter.h | 2 ++
> 2 files changed, 50 insertions(+)
>
> diff --git a/src/adapter.c b/src/adapter.c
> index 491bd7031..29c6a576a 100644
> --- a/src/adapter.c
> +++ b/src/adapter.c
> @@ -7029,6 +7029,45 @@ static bool is_filter_match(GSList *discovery_filter, struct eir_data *eir_data,
> return got_match;
> }
>
> +static int find_baas(gconstpointer a, gconstpointer b)
> +{
> + const struct eir_sd *sd = a;
> + const char *baas_uuid = b;
> +
> + return strcmp(sd->uuid, baas_uuid);
> +}
> +
> +static bool accept_bcast_adv(struct btd_adapter *adapter)
> +{
> + if ((btd_adapter_has_settings(adapter, MGMT_SETTING_ISO_SYNC_RECEIVER)))
> + return true;
> +
> + return false;
> +}
> +
> +static bool is_bcast_source(struct eir_data *eir_data)
> +{
> + if (!(eir_data->flags & (EIR_LIM_DISC | EIR_GEN_DISC))
> + && (g_slist_find_custom(eir_data->sd_list,
> + BCAA_SERVICE_UUID, find_baas))) {
> + return true;
> + }
> +
> + return false;
> +}
> +static void bcast_new_source(struct btd_adapter *adapter,
> + struct btd_device *device)
> +{
> + GSList *l;
> +
> + for (l = adapter->drivers; l; l = g_slist_next(l)) {
> + struct btd_adapter_driver *driver = l->data;
> +
> + if (!strcmp(driver->name, "bcast"))
> + driver->device_discovered(adapter, device);
> + }
> +}

This code probably doesn't belong here, profile specific code like the
above shall be left to the plugin to handle.

> static void filter_duplicate_data(void *data, void *user_data)
> {
> struct discovery_client *client = data;
> @@ -7152,12 +7191,21 @@ void btd_adapter_device_found(struct btd_adapter *adapter,
> return;
> }
>
> + if (accept_bcast_adv(adapter) && is_bcast_source(&eir_data))
> + monitoring = true;
> +
> if (!discoverable && !monitoring && !eir_data.rsi) {
> eir_data_free(&eir_data);
> return;
> }
>
> dev = adapter_create_device(adapter, bdaddr, bdaddr_type);
> +
> + if (dev && is_bcast_source(&eir_data)) {
> + bcast_new_source(adapter, dev);
> + btd_device_set_temporary(dev, false);
> + }
> +
> }
>
> if (!dev) {
> diff --git a/src/adapter.h b/src/adapter.h
> index ca96c1f65..ee32f7110 100644
> --- a/src/adapter.h
> +++ b/src/adapter.h
> @@ -125,6 +125,8 @@ struct btd_adapter_driver {
> struct btd_device *device);
> void (*device_resolved)(struct btd_adapter *adapter,
> struct btd_device *device);
> + void (*device_discovered)(struct btd_adapter *adapter,
> + struct btd_device *device);

Let me figure out the driver interface since I think it is better to
use the btd_device_driver and then have a generic match by UUID.

> /* Indicates the driver is experimental and shall only be registered
> * when experimental has been enabled (see: main.conf:Experimental).
> --
> 2.34.1
>


--
Luiz Augusto von Dentz

2023-08-02 18:13:51

by Luiz Augusto von Dentz

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

Hi Claudia,

On Wed, Aug 2, 2023 at 6:49 AM Claudia Draghicescu <[email protected]> wrote:
>
> This adds support for BAP broadcast sink, creates a remote endpoint when a
> broadcast source is discovered and synchronizes with the source upon
> endpoint configuration.
> This feature was tested using bluetoothctl with the following commands:
>
> [bluetooth]# endpoint.register 00001851-0000-1000-8000-00805f9b34fb 0x06
> [bluetooth]# scan on
> [NEW] Endpoint /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/pac_bcast0
> [bluetooth]# endpoint.config
> /org/bluez/hci0/dev_XX_XX_XX_XX_XX_XX/pac_bcast0
> /local/endpoint/ep0 16_2_1
>
> ---
> profiles/audio/bap.c | 300 ++++++++++++++++++++++++++++++++++++++-----
> src/shared/bap.c | 153 +++++++++++++++++++---
> src/shared/bap.h | 11 +-
> 3 files changed, 410 insertions(+), 54 deletions(-)
>
> diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
> index 8cbb238ef..112e0673d 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"
> @@ -58,6 +59,7 @@
> #define ISO_SOCKET_UUID "6fbaf188-05e0-496a-9885-d6ddfdb4e03e"
> #define PACS_UUID_STR "00001850-0000-1000-8000-00805f9b34fb"
> #define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
> +#define MEDIA_INTERFACE "org.bluez.Media1"
>
> struct bap_ep {
> char *path;
> @@ -186,8 +188,11 @@ 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
> + else if ((queue_find(ep->data->bcast, NULL, ep)
> + && (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)))
> uuid = BAA_SERVICE_UUID;
> + else
> + uuid = BCAA_SERVICE_UUID;
>
> dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
>
> @@ -341,15 +346,18 @@ static int parse_properties(DBusMessageIter *props, struct iovec **caps,
> } else if (!strcasecmp(key, "PHY")) {
> const char *str;
>
> - if (var != DBUS_TYPE_STRING)
> - goto fail;
> -
> - dbus_message_iter_get_basic(&value, &str);
> -
> - if (!strcasecmp(str, "1M"))
> - io_qos.phy = 0x01;
> - else if (!strcasecmp(str, "2M"))
> - io_qos.phy = 0x02;
> + if (var == DBUS_TYPE_STRING) {
> + dbus_message_iter_get_basic(&value, &str);
> +
> + if (!strcasecmp(str, "1M"))
> + io_qos.phy = 0x01;
> + else if (!strcasecmp(str, "2M"))
> + io_qos.phy = 0x02;
> + else
> + goto fail;
> + } else if (var == DBUS_TYPE_BYTE)
> + dbus_message_iter_get_basic(&value,
> + &io_qos.phy);
> else
> goto fail;
> } else if (!strcasecmp(key, "SDU")) {
> @@ -556,7 +564,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 {
> @@ -577,8 +585,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);
> @@ -597,13 +609,120 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
> break;
> case BT_BAP_STREAM_TYPE_BCAST:
> /* No message sent over the air for broadcast */
> - ep->id = 0;
> + if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)
> + ep->msg = dbus_message_ref(msg);
> + else
> + ep->id = 0;
> +
> return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
> }
>
> 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_ep_type(const void *data, const void *user_data)
> +{
> + const struct bap_ep *ep = data;
> +
> + return (bt_bap_pac_get_type(ep->lpac) == PTR_TO_INT(user_data));
> +}
> +
> +static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
> +{
> + struct bap_data *data = user_data;
> + struct bt_iso_qos qos;
> + struct bt_iso_base base;
> + char address[18];
> + 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);
> +
> + ep = queue_find(data->bcast, match_ep_type,
> + INT_TO_PTR(BT_BAP_BCAST_SINK));
> + 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);
> +
> + if (ep->stream == NULL)
> + DBG("stream is null");
> + 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);
> +
> + fd = g_io_channel_unix_get_fd(io);
> +
> + if (bt_bap_stream_set_io(ep->stream, fd)) {
> + bt_bap_stream_enable(ep->stream, true, NULL, NULL, NULL);
> + g_io_channel_set_close_on_unref(io, FALSE);
> + return;
> + }
> +
> +
> + 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;
> +}
> +
> static const GDBusMethodTable ep_methods[] = {
> { GDBUS_EXPERIMENTAL_ASYNC_METHOD("SetConfiguration",
> GDBUS_ARGS({ "endpoint", "o" },
> @@ -650,14 +769,23 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,
> struct bt_bap_pac *rpac)
> {
> struct btd_adapter *adapter = data->user_data;
> + struct btd_device *device = data->device;
> struct bap_ep *ep;
> struct queue *queue;
> - int i, err;
> + int i, err = 0;
> const char *suffix;
> struct match_ep match = { lpac, rpac };
>
> + if (!adapter)
> + DBG("adapter is null");
> +
> + if (!device)
> + device = btd_adapter_find_device_by_path(adapter,
> + bt_bap_pac_get_name(rpac));
> +
> 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";
> @@ -675,8 +803,24 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,
> ep->lpac = lpac;
> ep->rpac = rpac;
>
> - err = asprintf(&ep->path, "%s/pac_%s%d", adapter_get_path(adapter),
> - suffix, i);
> + if (device)
> + ep->data->device = device;
> +
> + switch (bt_bap_pac_get_type(rpac)) {
> + case BT_BAP_BCAST_SINK:
> + DBG("sink");
> + err = asprintf(&ep->path, "%s/pac_%s%d",
> + adapter_get_path(adapter), suffix, i);
> + DBG("sink path %s", ep->path);
> + break;
> + case BT_BAP_BCAST_SOURCE:
> + DBG("source");
> + err = asprintf(&ep->path, "%s/pac_%s%d",
> + device_get_path(device), suffix, i);
> + DBG("source path %s", ep->path);
> + break;
> + }
> +
> if (err < 0) {
> error("Could not allocate path for remote pac %s/pac%d",
> adapter_get_path(adapter), i);
> @@ -685,14 +829,13 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,
> }
>
> if (g_dbus_register_interface(btd_get_dbus_connection(),
> - ep->path, MEDIA_ENDPOINT_INTERFACE,
> - ep_methods, NULL, ep_properties,
> - ep, ep_free) == FALSE) {
> + 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;
> }
> -
> 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);
> @@ -824,6 +967,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,
> @@ -1310,6 +1454,46 @@ static void bap_listen_io(struct bap_data *data, struct bt_bap_stream *stream,
> data->listen_io = io;
> }
>
> +static void bap_listen_io_broadcast(struct bap_data *data, struct bap_ep *ep,
> + struct bt_bap_stream *stream, struct bt_iso_qos *qos)
> +{
> + GIOChannel *io;
> + GError *err = NULL;
> + struct sockaddr_iso_bc iso_bc_addr;
> +
> + iso_bc_addr.bc_bdaddr_type = btd_device_get_bdaddr_type(data->device);
> + memcpy(&iso_bc_addr.bc_bdaddr, device_get_address(data->device),
> + sizeof(bdaddr_t));
> + iso_bc_addr.bc_bis[0] = 1;
> + iso_bc_addr.bc_num_bis = 1;
> +
> + DBG("stream %p", stream);
> +
> + /* If IO already set skip creating it again */
> + if (bt_bap_stream_get_io(stream) || data->listen_io)
> + return;
> +
> + 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,
> + device_get_address(data->device),
> + BT_IO_OPT_DEST_TYPE,
> + btd_device_get_bdaddr_type(data->device),
> + 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);
> + } else
> + DBG("io created");
> +
> + ep->data->listen_io = io;
> +
> +}
> static void bap_create_ucast_io(struct bap_data *data, struct bap_ep *ep,
> struct bt_bap_stream *stream, int defer)
> {
> @@ -1364,10 +1548,10 @@ static void bap_create_bcast_io(struct bap_data *data, struct bap_ep *ep,
> memcpy(&iso_qos.bcast.out, &ep->qos.bcast.io_qos,
> sizeof(struct bt_iso_io_qos));
> done:
> - if (ep)
> + if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE)
> bap_connect_io_broadcast(data, ep, stream, &iso_qos);
> else
> - bap_listen_io(data, stream, &iso_qos);
> + bap_listen_io_broadcast(data, ep, stream, &iso_qos);
> }
>
> static void bap_create_io(struct bap_data *data, struct bap_ep *ep,
> @@ -1417,6 +1601,11 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,
> break;
> case BT_BAP_STREAM_STATE_CONFIG:
> if (ep && !ep->id) {
> + if
> + (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK) {
> + bap_create_bcast_io(data, ep, stream, true);
> + return;
> + }
> bap_create_io(data, ep, stream, true);
> if (!ep->io) {
> error("Unable to create io");
> @@ -1424,7 +1613,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 */
> @@ -1480,6 +1668,10 @@ 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) {
> + DBG("sink pac %p", pac);
> + bt_bap_foreach_pac(data->bap, BT_BAP_BCAST_SINK,
> + pac_found_bcast, data);
> }
> }
>
> @@ -1596,14 +1788,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;
> @@ -1854,7 +2038,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;
> }
> @@ -1901,12 +2085,62 @@ static struct btd_profile bap_profile = {
> .experimental = true,
> };
>
> +static GDBusProxy *media;
> +
> +static void proxy_added(GDBusProxy *proxy, void *user_data)
> +{
> + const char *interface;
> +
> + interface = g_dbus_proxy_get_interface(proxy);
> +
> + if (!strcmp(interface, MEDIA_INTERFACE)) {
> + DBG("proxy added %s ", g_dbus_proxy_get_path(proxy));
> + media = proxy;
> + }
> +}
> +
> +static int bcast_server_probe(struct btd_adapter *adapter)
> +{
> + static GDBusClient *client;
> +
> + client = g_dbus_client_new(btd_get_dbus_connection(),
> + "org.bluez", "/org/bluez");
> +
> + g_dbus_client_set_proxy_handlers(client, proxy_added, NULL,
> + NULL, NULL);
> +
> + return 0;
> +}
> +
> +static void bcast_server_remove(struct btd_adapter *adapter)
> +{
> + DBG("path %s", adapter_get_path(adapter));
> +}
> +
> +static void bcast_new_source(struct btd_adapter *adapter,
> + struct btd_device *device)
> +{
> + struct bap_data *data = queue_find(sessions, match_data_bap_data,
> + adapter);

I was expecting the use of bt_ad to look up the codec details, etc,
but this seems to assume it is always using LC3?

> + bt_bap_new_bcast_source(data->bap, device_get_path(device), 0x06);
> +}
> +
> +static struct btd_adapter_driver bcast_driver = {
> + .name = "bcast",
> + .probe = bcast_server_probe,
> + .remove = bcast_server_remove,
> + .device_discovered = bcast_new_source,
> + .experimental = true,
> +};
> +
> static unsigned int bap_id = 0;
>
> static int bap_init(void)
> {
> int err;
>
> + btd_register_adapter_driver(&bcast_driver);
> err = btd_profile_register(&bap_profile);
> if (err)
> return err;
> diff --git a/src/shared/bap.c b/src/shared/bap.c
> index 72ce67c08..ae3f64730 100644
> --- a/src/shared/bap.c
> +++ b/src/shared/bap.c
> @@ -633,14 +633,18 @@ 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_broadcast(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;
> + if (type == BT_BAP_BCAST_SINK)
> + ep->dir = BT_BAP_BCAST_SOURCE;
> + else
> + ep->dir = BT_BAP_BCAST_SINK;
>
> return ep;
> }
> @@ -667,22 +671,27 @@ static struct bt_bap_endpoint *bap_get_endpoint(struct queue *endpoints,
> return ep;
> }
>
> +static bool match_ep_type(const void *data, const void *match_data)
> +{
> + const struct bt_bap_endpoint *ep = data;
> + const uint8_t type = PTR_TO_INT(match_data);
> +
> + return (ep->dir == type);
> +}
> +
> 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;
>
> if (!db)
> return NULL;
> - /*
> - * We have support for only one stream so we will have
> - * only one endpoint.
> - * TO DO add support for more then one stream
> - */
> - if (queue_length(endpoints) > 0)
> - return queue_peek_head(endpoints);
>
> - ep = bap_endpoint_new_broacast(db);
> + ep = queue_find(endpoints, match_ep_type, INT_TO_PTR(type));
> + if (ep)
> + return ep;
> +
> + ep = bap_endpoint_new_broadcast(db, type);
> if (!ep)
> return NULL;
>
> @@ -1317,6 +1326,8 @@ static void stream_set_state_broadcast(struct bt_bap_stream *stream,
> struct bt_bap *bap = stream->bap;
> const struct queue_entry *entry;
>
> + if (ep->old_state == state)
> + return;
> ep->old_state = ep->state;
> ep->state = state;
>
> @@ -1348,6 +1359,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;
>
> @@ -2379,6 +2393,10 @@ static struct bt_bap_pac *bap_pac_find(struct bt_bap_db *bdb, uint8_t type,
> return queue_find(bdb->sources, match_codec, codec);
> case BT_BAP_SINK:
> return queue_find(bdb->sinks, match_codec, codec);
> + case BT_BAP_BCAST_SOURCE:
> + return queue_find(bdb->broadcast_sources, match_codec, codec);
> + case BT_BAP_BCAST_SINK:
> + return queue_find(bdb->broadcast_sinks, match_codec, codec);
> }
>
> return NULL;
> @@ -2518,7 +2536,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_broadcast_sink;
> struct bt_bap_codec codec;
>
> if (!db)
> @@ -2545,11 +2563,19 @@ struct bt_bap_pac *bt_bap_add_vendor_pac(struct gatt_db *db,
> bap_add_source(pac);
> break;
> case BT_BAP_BCAST_SOURCE:
> - // For broadcast add local pac and remote pac
> bap_add_broadcast_source(pac);
> - pac_brodcast_sink = bap_pac_new(bdb, name, type, &codec, qos,
> + if (queue_isempty(bdb->broadcast_sinks)) {
> + /* When adding a local broadcast source, add also a
> + * local broadcast sink
> + */
> + pac_broadcast_sink = bap_pac_new(bdb, name,
> + BT_BAP_BCAST_SINK, &codec, qos,
> data, metadata);
> - bap_add_broadcast_sink(pac_brodcast_sink);
> + bap_add_broadcast_sink(pac_broadcast_sink);
> + }
> + break;
> + case BT_BAP_BCAST_SINK:
> + bap_add_broadcast_sink(pac);
> break;
> default:
> bap_pac_free(pac);
> @@ -2579,6 +2605,14 @@ uint8_t bt_bap_pac_get_type(struct bt_bap_pac *pac)
> return pac->type;
> }
>
> +char *bt_bap_pac_get_name(struct bt_bap_pac *pac)
> +{
> + if (!pac)
> + return NULL;

Not really following what is this for? Are you using pac->name to
return the object path?

> + return pac->name;
> +}
> +
> uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac)
> {
> struct bt_pacs *pacs = pac->bdb->pacs;
> @@ -3996,7 +4030,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 +4042,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;
>
> @@ -4221,9 +4255,19 @@ void bt_bap_foreach_pac(struct bt_bap *bap, uint8_t type,
> return bap_foreach_pac(bap->ldb->sinks, bap->rdb->sources,
> func, user_data);
> case BT_BAP_BCAST_SOURCE:
> - return bap_foreach_pac(bap->ldb->broadcast_sources,
> + if (queue_isempty(bap->rdb->broadcast_sources)
> + && queue_isempty(bap->rdb->broadcast_sinks))
> + return bap_foreach_pac(bap->ldb->broadcast_sources,
> bap->ldb->broadcast_sinks,
> func, user_data);
> +
> + return bap_foreach_pac(bap->ldb->broadcast_sinks,
> + bap->rdb->broadcast_sources,
> + func, user_data);
> + case BT_BAP_BCAST_SINK:
> + return bap_foreach_pac(bap->ldb->broadcast_sinks,
> + bap->rdb->broadcast_sources,
> + func, user_data);
> }
> }
>
> @@ -4382,6 +4426,11 @@ 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 +4495,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 +4968,18 @@ struct io *bt_bap_stream_get_io(struct bt_bap_stream *stream)
> return io->io;
> }
>
> +char *bt_bap_stream_get_remote_name(struct bt_bap_stream *stream)
> +{
> + return bt_bap_pac_get_name(stream->rpac);
> +}
> +
> +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;
> @@ -4944,6 +5011,14 @@ static bool match_req_id(const void *data, const void *match_data)
> return (req->id == id);
> }
>
> +static bool match_name(const void *data, const void *match_data)
> +{
> + const struct bt_bap_pac *pac = data;
> + const char *name = match_data;
> +
> + return (!strcmp(pac->name, name));
> +}
> +
> int bt_bap_stream_cancel(struct bt_bap_stream *stream, unsigned int id)
> {
> struct bt_bap_req *req;
> @@ -5132,3 +5207,43 @@ bool bt_bap_stream_io_is_connecting(struct bt_bap_stream *stream, int *fd)
>
> return io->connecting;
> }
> +
> +bool bt_bap_new_bcast_source(struct bt_bap *bap, const char *name,
> + uint8_t codec)
> +{
> + struct bt_bap_endpoint *ep;
> + struct bt_bap_pac *pac_broadcast_source, *local_sink;
> + struct bt_bap_codec bap_codec;
> +
> + bap_codec.id = codec;
> + bap_codec.cid = 0;
> + bap_codec.vid = 0;
> +
> + /* Add remote source endpoint */
> + if (!bap->rdb->broadcast_sources)
> + bap->rdb->broadcast_sources = queue_new();
> +
> + if (queue_find(bap->rdb->broadcast_sources, match_name, name)) {
> + DBG(bap, "broadcast source already registered");
> + return true;
> + }
> +
> + local_sink = queue_peek_head(bap->ldb->broadcast_sinks);
> + pac_broadcast_source = bap_pac_new(bap->rdb, name, BT_BAP_BCAST_SOURCE,
> + &bap_codec, NULL, local_sink->data, NULL);
> + queue_push_tail(bap->rdb->broadcast_sources, pac_broadcast_source);
> +
> + if (!pac_broadcast_source) {
> + DBG(bap, "No broadcast source could be created");
> + return false;
> + }
> + queue_foreach(bap->pac_cbs, notify_pac_added, pac_broadcast_source);
> +
> + /* Push remote endpoint with direction sink */
> + ep = bap_endpoint_new_broadcast(bap->rdb, BT_BAP_BCAST_SINK);
> +
> + if (ep)
> + queue_push_tail(bap->remote_eps, ep);
> +
> + return true;
> +}
> diff --git a/src/shared/bap.h b/src/shared/bap.h
> index 50b567663..cf98ec8b7 100644
> --- a/src/shared/bap.h
> +++ b/src/shared/bap.h
> @@ -163,6 +163,8 @@ bool bt_bap_remove_pac(struct bt_bap_pac *pac);
>
> uint8_t bt_bap_pac_get_type(struct bt_bap_pac *pac);
>
> +char *bt_bap_pac_get_name(struct bt_bap_pac *pac);
> +
> uint32_t bt_bap_pac_get_locations(struct bt_bap_pac *pac);
>
> uint8_t bt_bap_stream_get_type(struct bt_bap_stream *stream);
> @@ -186,7 +188,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 +291,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);
> @@ -305,3 +307,8 @@ uint8_t bt_bap_stream_io_dir(struct bt_bap_stream *stream);
>
> int bt_bap_stream_io_connecting(struct bt_bap_stream *stream, int fd);
> bool bt_bap_stream_io_is_connecting(struct bt_bap_stream *stream, int *fd);
> +
> +bool bt_bap_new_bcast_source(struct bt_bap *bap, const char *name,
> + uint8_t codec);
> +
> +char *bt_bap_stream_get_remote_name(struct bt_bap_stream *stream);
> --
> 2.34.1
>


--
Luiz Augusto von Dentz