@@ -62,6 +62,13 @@
#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
#define MEDIA_INTERFACE "org.bluez.Media1"
+/* Periodic advertisments are performed by an idle timer, which,
+ * at every tick, checks a queue for pending PA requests.
+ * When there is no pending requests, an item is popped from the
+ * queue, marked as pending and then it gets processed.
+ */
+#define PA_IDLE_TIMEOUT 2
+
struct bap_setup {
struct bap_ep *ep;
struct bt_bap_stream *stream;
@@ -105,7 +112,62 @@ struct bap_data {
void *user_data;
};
+enum {
+ BAP_PA_SHORT_REQ = 0, /* Request for short PA sync */
+ BAP_PA_BIG_SYNC_REQ, /* Request for PA Sync and BIG Sync */
+};
+
+struct bap_bcast_pa_req {
+ uint8_t type;
+ bool in_progress;
+ union {
+ struct btd_service *service;
+ struct bap_setup *setup;
+ } data;
+};
+
static struct queue *sessions;
+static struct queue *bcast_pa_requests;
+static unsigned int pa_timer_id;
+
+/* Structure holding the parameters for Periodic Advertisement create sync.
+ * The full QOS is populated at the time the user selects and endpoint and
+ * configures it using SetConfiguration.
+ */
+static struct bt_iso_qos bap_sink_pa_qos = {
+ .bcast = {
+ .options = 0x00,
+ .skip = 0x0000,
+ .sync_timeout = 0x4000,
+ .sync_cte_type = 0x00,
+ /* TODO: The following parameters are not needed for PA Sync.
+ * They will be removed when the kernel checks will be removed.
+ */
+ .big = BT_ISO_QOS_BIG_UNSET,
+ .bis = BT_ISO_QOS_BIS_UNSET,
+ .encryption = 0x00,
+ .bcode = {0x00},
+ .mse = 0x00,
+ .timeout = 0x4000,
+ .sync_factor = 0x07,
+ .packing = 0x00,
+ .framing = 0x00,
+ .in = {
+ .interval = 10000,
+ .latency = 10,
+ .sdu = 40,
+ .phy = 0x02,
+ .rtn = 2,
+ },
+ .out = {
+ .interval = 10000,
+ .latency = 10,
+ .sdu = 40,
+ .phy = 0x02,
+ .rtn = 2,
+ }
+ }
+};
static bool bap_data_set_user_data(struct bap_data *data, void *user_data)
{
@@ -422,113 +484,6 @@ static int parse_array(DBusMessageIter *iter, struct iovec *iov)
return 0;
}
-static bool parse_base(void *data, size_t len, util_debug_func_t func,
- uint32_t *presDelay, uint8_t *numSubgroups, uint8_t *numBis,
- struct bt_bap_codec *codec, struct iovec **caps,
- struct iovec **meta)
-{
- struct iovec iov = {
- .iov_base = data,
- .iov_len = len,
- };
-
- uint8_t capsLen, metaLen;
- struct iovec cc;
- struct iovec metadata;
-
- if (presDelay) {
- if (!util_iov_pull_le24(&iov, presDelay))
- return false;
- util_debug(func, NULL, "PresentationDelay %d", *presDelay);
- }
-
- if (numSubgroups) {
- if (!util_iov_pull_u8(&iov, numSubgroups))
- return false;
- util_debug(func, NULL, "NumSubgroups %d", *numSubgroups);
- }
-
- if (numBis) {
- if (!util_iov_pull_u8(&iov, numBis))
- return false;
- util_debug(func, NULL, "NumBis %d", *numBis);
- }
-
- if (codec) {
- codec = util_iov_pull_mem(&iov, sizeof(*codec));
- if (!codec)
- return false;
- util_debug(func, NULL, "%s: ID %d CID 0x%2.2x VID 0x%2.2x",
- "Codec", codec->id, codec->cid, codec->vid);
- }
-
- if (!util_iov_pull_u8(&iov, &capsLen))
- return false;
- util_debug(func, NULL, "CC Len %d", capsLen);
-
- if (!capsLen)
- return false;
-
- cc.iov_len = capsLen;
- cc.iov_base = util_iov_pull_mem(&iov, capsLen);
- if (!cc.iov_base)
- return false;
-
- if (caps) {
- if (*caps)
- util_iov_free(*caps, 1);
-
- *caps = util_iov_dup(&cc, 1);
- }
-
- for (int i = 0; capsLen > 1; i++) {
- struct bt_ltv *ltv = util_iov_pull_mem(&cc, sizeof(*ltv));
- uint8_t *caps;
-
- if (!ltv) {
- util_debug(func, NULL, "Unable to parse %s",
- "Capabilities");
- return false;
- }
-
- util_debug(func, NULL, "%s #%u: len %u type %u",
- "CC", i, ltv->len, ltv->type);
-
- caps = util_iov_pull_mem(&cc, ltv->len - 1);
- if (!caps) {
- util_debug(func, NULL, "Unable to parse %s",
- "CC");
- return false;
- }
- util_hexdump(' ', caps, ltv->len - 1, func, NULL);
-
- capsLen -= (ltv->len + 1);
- }
-
- if (!util_iov_pull_u8(&iov, &metaLen))
- return false;
- util_debug(func, NULL, "Metadata Len %d", metaLen);
-
- if (!metaLen)
- return false;
-
- metadata.iov_len = metaLen;
- metadata.iov_base = util_iov_pull_mem(&iov, metaLen);
- if (!metadata.iov_base)
- return false;
-
- if (meta) {
- if (*meta)
- util_iov_free(*meta, 1);
-
- *meta = util_iov_dup(&metadata, 1);
- }
-
- util_hexdump(' ', metadata.iov_base, metaLen, func, NULL);
-
- return true;
-}
-
static int parse_io_qos(const char *key, int var, DBusMessageIter *iter,
struct bt_bap_io_qos *qos)
{
@@ -954,9 +909,20 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
return btd_error_invalid_args(msg);
}
+ /* For BAP Broadcast Sink, the capabilities and metadata are coming
+ * from the source's BIS, which are present in the remote PAC
+ */
+ if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK) {
+ util_iov_free(setup->caps, 1);
+ setup->caps = util_iov_dup(bt_bap_pac_get_data(ep->rpac), 1);
+ util_iov_free(setup->metadata, 1);
+ setup->metadata = util_iov_dup(
+ bt_bap_pac_get_metadata(ep->rpac), 1);
+ }
+
setup->stream = bt_bap_stream_new(ep->data->bap, ep->lpac, ep->rpac,
&setup->qos, setup->caps);
-
+ bt_bap_stream_set_user_data(setup->stream, ep->path);
setup->id = bt_bap_stream_config(setup->stream, &setup->qos,
setup->caps, config_cb, setup);
if (!setup->id) {
@@ -965,8 +931,6 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
return btd_error_invalid_args(msg);
}
- bt_bap_stream_set_user_data(setup->stream, ep->path);
-
if (setup->metadata && setup->metadata->iov_len)
bt_bap_stream_metadata(setup->stream, setup->metadata, NULL,
NULL);
@@ -977,95 +941,29 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
break;
case BT_BAP_STREAM_TYPE_BCAST:
/* No message sent over the air for broadcast */
- if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SINK)
- setup->msg = dbus_message_ref(msg);
- else {
+ if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE)
setup->base = bt_bap_stream_get_base(setup->stream);
- setup->id = 0;
}
+ setup->id = 0;
if (ep->data->service)
service_set_connecting(ep->data->service);
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_factor = qos->bcast.sync_factor;
- 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;
- if (!bap_qos->bcast.bcode)
- bap_qos->bcast.bcode = new0(struct iovec, 1);
- util_iov_memcpy(bap_qos->bcast.bcode, qos->bcast.bcode,
- sizeof(qos->bcast.bcode));
-}
-
static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
{
- struct bap_setup *setup = user_data;
- struct bap_ep *ep = setup->ep;
- struct bap_data *data = ep->data;
- struct bt_iso_qos qos;
- struct bt_iso_base base;
- char address[18];
+ struct bap_bcast_pa_req *req = user_data;
+ struct bap_setup *setup = req->data.setup;
int fd;
- struct iovec *base_io;
- uint32_t presDelay;
- uint8_t numSubgroups;
- uint8_t numBis;
- struct bt_bap_codec codec;
-
- 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);
- btd_service_connecting_complete(data->service, 0);
- DBG("BCAST ISO: sync with %s (BIG 0x%02x BIS 0x%02x)",
- address, qos.bcast.big, qos.bcast.bis);
- update_bcast_qos(&qos, &setup->qos);
+ queue_remove(bcast_pa_requests, req);
- base_io = new0(struct iovec, 1);
- util_iov_memcpy(base_io, base.base, base.base_len);
-
- parse_base(base_io->iov_base, base_io->iov_len, bap_debug,
- &presDelay, &numSubgroups, &numBis,
- &codec, &setup->caps, &setup->metadata);
-
- /* Update pac with BASE information */
- bt_bap_update_bcast_source(ep->rpac, &codec, setup->caps,
- setup->metadata);
- setup->id = bt_bap_stream_config(setup->stream, &setup->qos,
- setup->caps, NULL, NULL);
-
- bt_bap_stream_set_user_data(setup->stream, ep->path);
+ /* This device is no longer needed */
+ btd_service_connecting_complete(setup->ep->data->service, 0);
fd = g_io_channel_unix_get_fd(io);
@@ -1074,26 +972,44 @@ static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
g_io_channel_set_close_on_unref(io, FALSE);
return;
}
-
-
- return;
-
-drop:
- g_io_channel_shutdown(io, TRUE, NULL);
-
}
static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
{
GError *err = NULL;
+ struct bap_bcast_pa_req *pa_req = user_data;
+ struct bap_data *data = btd_service_get_user_data(pa_req->data.service);
+ struct bt_iso_base base;
+ struct bt_bap_base base_s;
+ struct bt_iso_qos qos;
- if (!bt_io_bcast_accept(io, iso_bcast_confirm_cb,
- user_data, NULL, &err, BT_IO_OPT_INVALID)) {
- error("bt_io_bcast_accept: %s", err->message);
+ DBG("PA Sync done");
+
+ bt_io_get(io, &err,
+ BT_IO_OPT_BASE, &base,
+ BT_IO_OPT_QOS, &qos,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
g_error_free(err);
g_io_channel_shutdown(io, TRUE, NULL);
+ return;
}
+ /* Close the io and remove the queue request for another PA Sync */
+ g_io_channel_shutdown(data->listen_io, TRUE, NULL);
+ g_io_channel_unref(data->listen_io);
+ g_io_channel_shutdown(io, TRUE, NULL);
+ data->listen_io = NULL;
+ queue_remove(bcast_pa_requests, pa_req);
+
+ /* Analyze received BASE data and create remote media endpoints for each
+ * matching BIS
+ */
+ base_s.subgroups = queue_new();
+ bt_bap_parse_base(data->bap, base.base, base.base_len, bap_debug,
+ &base_s);
+ queue_foreach(base_s.subgroups, bt_bap_parse_bis, NULL);
}
static bool match_data_bap_data(const void *data, const void *match_data)
@@ -1675,7 +1591,7 @@ static bool is_cig_busy(struct bap_data *data, uint8_t cig)
return queue_find(sessions, cig_busy_session, &info);
}
-static void setup_create_io(struct bap_data *data, struct bap_setup *setup,
+static bool setup_create_io(struct bap_data *data, struct bap_setup *setup,
struct bt_bap_stream *stream, int defer);
static gboolean setup_io_recreate(void *user_data)
@@ -1934,47 +1850,58 @@ static void setup_listen_io(struct bap_data *data, struct bt_bap_stream *stream,
data->listen_io = io;
}
-static void setup_listen_io_broadcast(struct bap_data *data,
- struct bap_setup *setup,
- struct bt_bap_stream *stream,
- struct bt_iso_qos *qos)
+static void check_pa_req_in_progress(void *data, void *user_data)
{
- GIOChannel *io;
- GError *err = NULL;
- struct sockaddr_iso_bc iso_bc_addr;
+ struct bap_bcast_pa_req *req = data;
- 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;
+ if (req->in_progress == TRUE)
+ *((bool *)user_data) = TRUE;
+}
- DBG("stream %p", stream);
+static int short_lived_pa_sync(struct bap_bcast_pa_req *req);
+static void pa_and_big_sync(struct bap_bcast_pa_req *req);
- /* If IO already set skip creating it again */
- if (bt_bap_stream_get_io(stream) || data->listen_io)
- return;
+static gboolean pa_idle_timer(gpointer user_data)
+{
+ struct bap_bcast_pa_req *req = user_data;
+ bool in_progress = FALSE;
- io = bt_io_listen(NULL, iso_pa_sync_confirm_cb, setup, NULL, &err,
- BT_IO_OPT_SOURCE_BDADDR,
- btd_adapter_get_address(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);
+ /* Handle timer if no request is in progress */
+ queue_foreach(bcast_pa_requests, check_pa_req_in_progress,
+ &in_progress);
+ if (in_progress == FALSE) {
+ req = queue_peek_head(bcast_pa_requests);
+ if (req != NULL)
+ switch (req->type) {
+ case BAP_PA_SHORT_REQ:
+ DBG("do short lived PA Sync");
+ short_lived_pa_sync(req);
+ break;
+ case BAP_PA_BIG_SYNC_REQ:
+ DBG("do PA Sync and BIG Sync");
+ pa_and_big_sync(req);
+ break;
+ }
}
- setup->io = io;
- data->listen_io = io;
+ return TRUE;
+}
+
+static void setup_accept_io_broadcast(struct bap_data *data,
+ struct bap_setup *setup)
+{
+ struct bap_bcast_pa_req *pa_req = new0(struct bap_bcast_pa_req, 1);
+
+ /* Add this request to the PA queue.
+ * We don't need to check the queue here and the timer, as we cannot
+ * have BAP_PA_BIG_SYNC_REQ before a short PA (BAP_PA_SHORT_REQ)
+ */
+ pa_req->type = BAP_PA_BIG_SYNC_REQ;
+ pa_req->in_progress = FALSE;
+ pa_req->data.setup = setup;
+ queue_push_tail(bcast_pa_requests, pa_req);
}
+
static void setup_create_ucast_io(struct bap_data *data,
struct bap_setup *setup,
struct bt_bap_stream *stream,
@@ -2037,10 +1964,10 @@ done:
if (bt_bap_pac_get_type(setup->ep->lpac) == BT_BAP_BCAST_SOURCE)
setup_connect_io_broadcast(data, setup, stream, &iso_qos);
else
- setup_listen_io_broadcast(data, setup, stream, &iso_qos);
+ setup_accept_io_broadcast(data, setup);
}
-static void setup_create_io(struct bap_data *data, struct bap_setup *setup,
+static bool setup_create_io(struct bap_data *data, struct bap_setup *setup,
struct bt_bap_stream *stream, int defer)
{
DBG("setup %p stream %p defer %s", setup, stream,
@@ -2060,6 +1987,15 @@ static void setup_create_io(struct bap_data *data, struct bap_setup *setup,
setup_create_bcast_io(data, setup, stream, defer);
break;
}
+
+ /* The function succeeds if the IO was created, but for BAP Broadcast
+ * Sink the call is asynchronous, as it is handled by the Idle timer
+ */
+ if (setup->io ||
+ bt_bap_pac_get_type(setup->ep->lpac) == BT_BAP_BCAST_SINK)
+ return TRUE;
+
+ return FALSE;
}
static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,
@@ -2091,8 +2027,7 @@ static void bap_state(struct bt_bap_stream *stream, uint8_t old_state,
break;
case BT_BAP_STREAM_STATE_CONFIG:
if (setup && !setup->id) {
- setup_create_io(data, setup, stream, true);
- if (!setup->io) {
+ if (!setup_create_io(data, setup, stream, true)) {
error("Unable to create io");
if (old_state != BT_BAP_STREAM_STATE_RELEASING)
bt_bap_stream_release(stream, NULL,
@@ -2415,32 +2350,23 @@ static void bap_detached(struct bt_bap *bap, void *user_data)
bap_data_remove(data);
}
-static int bap_bcast_probe(struct btd_service *service)
+static int short_lived_pa_sync(struct bap_bcast_pa_req *req)
{
+ struct btd_service *service = req->data.service;
struct btd_device *device = btd_service_get_device(service);
struct btd_adapter *adapter = device_get_adapter(device);
struct btd_gatt_database *database = btd_adapter_get_database(adapter);
struct bap_data *data = btd_service_get_user_data(service);
- char addr[18];
-
- ba2str(device_get_address(device), addr);
-
- if (!btd_adapter_has_exp_feature(adapter, EXP_FEAT_ISO_SOCKET)) {
- error("BAP requires ISO Socket which is not enabled");
- return -ENOTSUP;
- }
+ GError *err = NULL;
- /* Ignore, if we were probed for this device already */
if (data) {
- error("Profile probed twice for the same device!");
- return -EINVAL;
+ DBG("Already probed");
+ return -1;
}
-
data = bap_data_new(device);
data->service = service;
data->adapter = adapter;
data->device = device;
-
data->bap = bt_bap_new(btd_gatt_database_get_db(database),
btd_gatt_database_get_db(database));
if (!data->bap) {
@@ -2457,15 +2383,137 @@ static int bap_bcast_probe(struct btd_service *service)
bap_data_add(data);
data->ready_id = bt_bap_ready_register(data->bap, bap_ready, service,
- NULL);
+ NULL);
data->state_id = bt_bap_state_register(data->bap, bap_state,
- bap_connecting, data, NULL);
+ bap_connecting, data, NULL);
data->pac_id = bt_bap_pac_register(data->bap, pac_added_broadcast,
- pac_removed_broadcast, data, NULL);
+ pac_removed_broadcast, data, NULL);
bt_bap_set_user_data(data->bap, service);
- bt_bap_new_bcast_source(data->bap, device_get_path(device));
+ DBG("Create PA sync with this source");
+ req->in_progress = TRUE;
+ data->listen_io = bt_io_listen(NULL, iso_pa_sync_confirm_cb, req,
+ NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR,
+ btd_adapter_get_address(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, &bap_sink_pa_qos,
+ BT_IO_OPT_INVALID);
+ if (!data->listen_io) {
+ error("%s", err->message);
+ g_error_free(err);
+ }
+
+ return 0;
+}
+
+static void iso_do_big_sync(GIOChannel *io, void *user_data)
+{
+ GError *err = NULL;
+ struct bap_bcast_pa_req *req = user_data;
+ struct bap_setup *setup = req->data.setup;
+ struct bap_data *data = setup->ep->data;
+ struct sockaddr_iso_bc iso_bc_addr;
+ struct bt_iso_qos qos;
+
+ DBG("PA Sync done, do BIG Sync");
+ g_io_channel_unref(setup->io);
+ setup->io = NULL;
+
+ setup->io = io;
+ g_io_channel_ref(setup->io);
+
+ /* TODO
+ * We can only synchronize with a single BIS to a BIG.
+ * In order to have multiple BISes targeting this BIG we need to have
+ * all the BISes before doing this request. This request is triggered
+ * by an endpoint "SetConfiguration" command. For multiple BISes
+ * we need another way to specify which BISes user is requesting
+ */
+ 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;
+
+ /* Set the user requested QOS */
+ bt_bap_bcast_qos_bap_to_iso(&qos, &setup->qos);
+ if (!bt_io_set(setup->io, &err,
+ BT_IO_OPT_QOS, &qos,
+ BT_IO_OPT_INVALID)) {
+ error("bt_io_set: %s", err->message);
+ g_error_free(err);
+ }
+
+ if (!bt_io_bcast_accept(setup->io,
+ iso_bcast_confirm_cb,
+ req, NULL, &err,
+ 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)) {
+ error("bt_io_bcast_accept: %s", err->message);
+ g_error_free(err);
+ }
+}
+
+static void pa_and_big_sync(struct bap_bcast_pa_req *req)
+{
+ GError *err = NULL;
+ struct bap_setup *setup = req->data.setup;
+ struct bap_data *data = setup->ep->data;
+
+ req->in_progress = TRUE;
+
+ DBG("Create PA sync with this source");
+ setup->io = bt_io_listen(NULL, iso_do_big_sync, req,
+ NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR,
+ btd_adapter_get_address(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, &bap_sink_pa_qos,
+ BT_IO_OPT_INVALID);
+ if (!setup->io) {
+ error("%s", err->message);
+ g_error_free(err);
+ }
+}
+
+static int bap_bcast_probe(struct btd_service *service)
+{
+ struct btd_device *device = btd_service_get_device(service);
+ struct btd_adapter *adapter = device_get_adapter(device);
+ struct bap_bcast_pa_req *pa_req =
+ new0(struct bap_bcast_pa_req, 1);
+
+ if (!btd_adapter_has_exp_feature(adapter, EXP_FEAT_ISO_SOCKET)) {
+ error("BAP requires ISO Socket which is not enabled");
+ return -ENOTSUP;
+ }
+
+ /* First time initialize the queue and start the idle timer */
+ if (bcast_pa_requests == NULL) {
+ bcast_pa_requests = queue_new();
+ pa_timer_id = g_timeout_add_seconds(PA_IDLE_TIMEOUT,
+ pa_idle_timer, NULL);
+ }
+
+ /* Enqueue this device advertisement so that we can do short-lived
+ */
+ DBG("enqueue service: %p", service);
+ pa_req->type = BAP_PA_SHORT_REQ;
+ pa_req->in_progress = FALSE;
+ pa_req->data.service = service;
+ queue_push_tail(bcast_pa_requests, pa_req);
+
return 0;
}
@@ -1677,11 +1677,8 @@ static unsigned int bap_bcast_config(struct bt_bap_stream *stream,
bt_bap_stream_func_t func, void *user_data)
{
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);
- }
+ stream->lpac->ops->config(stream, stream->cc, &stream->qos,
+ ep_config_cb, stream->lpac->user_data);
return 1;
}
@@ -5255,10 +5252,6 @@ bool bt_bap_stream_set_user_data(struct bt_bap_stream *stream, void *user_data)
stream->user_data = user_data;
- if (bt_bap_stream_get_type(stream) == BT_BAP_STREAM_TYPE_BCAST)
- stream->lpac->ops->config(stream, stream->cc, &stream->qos,
- ep_config_cb, stream->lpac->user_data);
-
return true;
}