@@ -65,15 +65,9 @@
#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 bap_data *data;
struct bt_bap_stream *stream;
struct bt_bap_qos qos;
int (*qos_parser)(struct bap_setup *setup, const char *key, int var,
@@ -101,15 +95,9 @@ struct bap_ep {
struct queue *setups;
};
-struct bap_adapter {
- struct btd_adapter *adapter;
- unsigned int pa_timer_id;
- struct queue *bcast_pa_requests;
-};
-
struct bap_data {
struct btd_device *device;
- struct bap_adapter *adapter;
+ struct btd_adapter *adapter;
struct btd_service *service;
struct bt_bap *bap;
unsigned int ready_id;
@@ -121,30 +109,12 @@ struct bap_data {
struct queue *bcast_snks;
struct queue *streams;
GIOChannel *listen_io;
+ unsigned int io_id;
int selecting;
void *user_data;
};
-enum {
- BAP_PA_SHORT_REQ = 0, /* Request for short PA sync */
- BAP_PA_LONG_REQ, /* Request for long 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;
- struct bap_data *bap_data;
- union {
- struct btd_service *service;
- struct queue *setups;
- } data;
- unsigned int io_id; /* io_id for BIG Info watch */
- GIOChannel *io;
-};
-
static struct queue *sessions;
-static struct queue *adapters;
/* Structure holding the parameters for Periodic Advertisement create sync.
* The full QOS is populated at the time the user selects and endpoint and
@@ -219,6 +189,9 @@ static void bap_data_free(struct bap_data *data)
g_io_channel_unref(data->listen_io);
}
+ if (data->io_id)
+ g_source_remove(data->io_id);
+
if (data->service) {
btd_service_set_user_data(data->service, NULL);
bt_bap_set_user_data(data->bap, NULL);
@@ -382,7 +355,7 @@ static gboolean get_device(const GDBusPropertyTable *property,
const char *path;
if (bt_bap_pac_get_type(ep->lpac) == BT_BAP_BCAST_SOURCE)
- path = adapter_get_path(ep->data->adapter->adapter);
+ path = adapter_get_path(ep->data->adapter);
else
path = device_get_path(ep->data->device);
@@ -996,12 +969,19 @@ static DBusMessage *set_configuration(DBusConnection *conn, DBusMessage *msg,
return NULL;
}
+static bool stream_io_unset(const void *data, const void *user_data)
+{
+ struct bt_bap_stream *stream = (struct bt_bap_stream *)data;
+
+ return !bt_bap_stream_get_io(stream);
+}
+
static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
{
- struct bap_bcast_pa_req *req = user_data;
- struct bap_setup *setup;
+ struct bap_setup *setup = user_data;
+ struct bt_bap_stream *stream = setup->stream;
int fd;
- struct bap_data *bap_data = req->bap_data;
+ struct bap_data *bap_data = setup->data;
DBG("BIG Sync completed");
@@ -1009,28 +989,23 @@ static void iso_bcast_confirm_cb(GIOChannel *io, GError *err, void *user_data)
* to the order of the BISes that were enqueued before
* calling bt_io_bcast_accept.
*/
- setup = queue_pop_head(req->data.setups);
-
- if (queue_isempty(req->data.setups)) {
- /* All fds have been notified. Mark service as connected. */
- btd_service_connecting_complete(bap_data->service, 0);
-
- if (req->io) {
- g_io_channel_unref(req->io);
- g_io_channel_shutdown(req->io, TRUE, NULL);
- req->io = NULL;
- }
-
- queue_remove(bap_data->adapter->bcast_pa_requests, req);
- queue_destroy(req->data.setups, NULL);
- free(req);
- }
+ if (bt_bap_stream_get_io(stream))
+ stream = queue_find(bt_bap_stream_io_get_links(stream),
+ stream_io_unset, NULL);
fd = g_io_channel_unix_get_fd(io);
- if (bt_bap_stream_set_io(setup->stream, fd)) {
+ if (bt_bap_stream_set_io(stream, fd))
g_io_channel_set_close_on_unref(io, FALSE);
- return;
+
+ if (!queue_find(bt_bap_stream_io_get_links(stream),
+ stream_io_unset, NULL)) {
+ /* All fds have been notified. Mark service as connected. */
+ btd_service_connecting_complete(bap_data->service, 0);
+
+ g_io_channel_unref(bap_data->listen_io);
+ g_io_channel_shutdown(bap_data->listen_io, TRUE, NULL);
+ bap_data->listen_io = NULL;
}
}
@@ -1099,6 +1074,7 @@ static void create_stream_for_bis(struct bap_data *bap_data,
struct bap_setup *setup;
setup = setup_new(NULL);
+ setup->data = bap_data;
/* Create BAP QoS structure */
bap_iso_qos_to_bap_qos(qos, &setup->qos);
@@ -1280,8 +1256,7 @@ static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond,
gpointer user_data)
{
GError *err = NULL;
- struct bap_bcast_pa_req *req = user_data;
- struct bap_data *data = btd_service_get_user_data(req->data.service);
+ struct bap_data *data = user_data;
struct bt_iso_base base;
struct bt_iso_qos qos;
@@ -1295,7 +1270,7 @@ static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond,
error("%s", err->message);
g_error_free(err);
g_io_channel_shutdown(io, TRUE, NULL);
- req->io_id = 0;
+ data->io_id = 0;
return FALSE;
}
@@ -1304,41 +1279,31 @@ static gboolean big_info_report_cb(GIOChannel *io, GIOCondition cond,
g_io_channel_unref(data->listen_io);
data->listen_io = NULL;
- if (req->type == BAP_PA_LONG_REQ) {
- /* If long-lived PA sync was requested, keep a reference
- * to the PA sync io to keep the sync active.
- */
- data->listen_io = io;
- g_io_channel_ref(io);
- } else {
- /* For short-lived PA, the sync is no longer needed at
- * this point, so the io can be closed.
- */
- g_io_channel_shutdown(io, TRUE, NULL);
- }
+ /* For short-lived PA, the sync is no longer needed at
+ * this point, so the io can be closed.
+ */
+ g_io_channel_shutdown(io, TRUE, NULL);
/* Analyze received BASE data and create remote media endpoints for each
* BIS matching our capabilities
*/
parse_base(&base, &qos, bap_debug, bis_handler, data);
- service_set_connecting(req->data.service);
+ service_set_connecting(data->service);
- queue_remove(data->adapter->bcast_pa_requests, req);
- req->io_id = 0;
- free(req);
+ data->io_id = 0;
return FALSE;
}
static void iso_pa_sync_confirm_cb(GIOChannel *io, void *user_data)
{
- struct bap_bcast_pa_req *req = user_data;
+ struct bap_data *data = user_data;
/* PA Sync was established, wait for BIG Info report so that the
* encryption flag is also available.
*/
DBG("PA Sync done");
- req->io_id = g_io_add_watch(io, G_IO_OUT, big_info_report_cb,
+ data->io_id = g_io_add_watch(io, G_IO_OUT, big_info_report_cb,
user_data);
}
@@ -1393,7 +1358,7 @@ static struct bap_ep *ep_register_bcast(struct bap_data *data,
struct bt_bap_pac *lpac,
struct bt_bap_pac *rpac)
{
- struct btd_adapter *adapter = data->adapter->adapter;
+ struct btd_adapter *adapter = data->adapter;
struct btd_device *device = data->device;
struct bap_ep *ep;
struct queue *queue;
@@ -2240,95 +2205,13 @@ static void setup_listen_io(struct bap_data *data, struct bt_bap_stream *stream,
data->listen_io = io;
}
-static void check_pa_req_in_progress(void *data, void *user_data)
-{
- struct bap_bcast_pa_req *req = data;
-
- if (req->in_progress == TRUE)
- *((bool *)user_data) = TRUE;
-}
-
-static int pa_sync(struct bap_bcast_pa_req *req);
-static void pa_and_big_sync(struct bap_bcast_pa_req *req);
-
-static gboolean pa_idle_timer(gpointer user_data)
-{
- struct bap_adapter *adapter = user_data;
- struct bap_bcast_pa_req *req;
- bool in_progress = FALSE;
-
- /* Handle timer if no request is in progress */
- queue_foreach(adapter->bcast_pa_requests, check_pa_req_in_progress,
- &in_progress);
- if (in_progress == FALSE) {
- req = queue_peek_head(adapter->bcast_pa_requests);
- if (req != NULL)
- switch (req->type) {
- case BAP_PA_SHORT_REQ:
- DBG("do short lived PA Sync");
- pa_sync(req);
- break;
- case BAP_PA_LONG_REQ:
- DBG("do long lived PA Sync");
- pa_sync(req);
- break;
- case BAP_PA_BIG_SYNC_REQ:
- DBG("do PA Sync and BIG Sync");
- pa_and_big_sync(req);
- break;
- }
- else {
- /* pa_req queue is empty, stop the timer by returning
- * FALSE and set the pa_timer_id to 0. This will later
- * be used to check if the timer is active.
- */
- adapter->pa_timer_id = 0;
- return FALSE;
- }
- }
-
- return TRUE;
-}
+static int pa_sync(struct bap_data *data);
+static void pa_and_big_sync(struct bap_setup *setup);
static void setup_accept_io_broadcast(struct bap_data *data,
struct bap_setup *setup)
{
- struct bap_bcast_pa_req *req = new0(struct bap_bcast_pa_req, 1);
- struct bap_adapter *adapter = data->adapter;
- struct queue *links = bt_bap_stream_io_get_links(setup->stream);
- const struct queue_entry *entry;
-
- /* Timer could be stopped if all other requests were treated.
- * Check the state of the timer and turn it on so that this request
- * can also be treated.
- */
- if (adapter->pa_timer_id == 0)
- adapter->pa_timer_id = g_timeout_add_seconds(PA_IDLE_TIMEOUT,
- pa_idle_timer,
- adapter);
-
- /* Add this request to the PA queue.
- * We don't need to check the queue here, as we cannot have
- * BAP_PA_BIG_SYNC_REQ before a short PA (BAP_PA_SHORT_REQ)
- */
- req->type = BAP_PA_BIG_SYNC_REQ;
- req->in_progress = FALSE;
- req->bap_data = data;
-
- req->data.setups = queue_new();
-
- /* Enqueue all linked setups to the request */
- queue_push_tail(req->data.setups, setup);
-
- for (entry = queue_get_entries(links); entry;
- entry = entry->next) {
- struct bt_bap_stream *stream = entry->data;
-
- queue_push_tail(req->data.setups,
- bap_find_setup_by_stream(data, stream));
- }
-
- queue_push_tail(adapter->bcast_pa_requests, req);
+ pa_and_big_sync(setup);
}
static void setup_create_ucast_io(struct bap_data *data,
@@ -3083,10 +2966,8 @@ static void bap_detached(struct bt_bap *bap, void *user_data)
bap_data_remove(data);
}
-static int pa_sync(struct bap_bcast_pa_req *req)
+static int pa_sync(struct bap_data *data)
{
- struct btd_service *service = req->data.service;
- struct bap_data *data = btd_service_get_user_data(service);
GError *err = NULL;
if (data->listen_io) {
@@ -3095,13 +2976,13 @@ static int pa_sync(struct bap_bcast_pa_req *req)
}
DBG("Create PA sync with this source");
- req->in_progress = TRUE;
- data->listen_io = bt_io_listen(NULL, iso_pa_sync_confirm_cb, req,
+
+ data->listen_io = bt_io_listen(NULL, iso_pa_sync_confirm_cb, data,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR,
- btd_adapter_get_address(data->adapter->adapter),
+ btd_adapter_get_address(data->adapter),
BT_IO_OPT_SOURCE_TYPE,
- btd_adapter_get_address_type(data->adapter->adapter),
+ btd_adapter_get_address_type(data->adapter),
BT_IO_OPT_DEST_BDADDR,
device_get_address(data->device),
BT_IO_OPT_DEST_TYPE,
@@ -3119,9 +3000,9 @@ static int pa_sync(struct bap_bcast_pa_req *req)
static void append_setup(void *data, void *user_data)
{
- struct bap_setup *setup = data;
+ struct bt_bap_stream *stream = data;
struct sockaddr_iso_bc *addr = user_data;
- char *path = bt_bap_stream_get_user_data(setup->stream);
+ char *path = bt_bap_stream_get_user_data(stream);
int bis = 1;
int s_err;
const char *strbis = NULL;
@@ -3146,39 +3027,36 @@ static void append_setup(void *data, void *user_data)
static void setup_refresh_qos(void *data, void *user_data)
{
- struct bap_setup *setup = data;
+ struct bt_bap_stream *stream = data;
+ struct bap_data *bap_data = user_data;
+ struct bap_setup *setup = bap_find_setup_by_stream(bap_data, stream);
- setup->qos = *bt_bap_stream_get_qos(setup->stream);
+ setup->qos = *bt_bap_stream_get_qos(stream);
}
static void iso_do_big_sync(GIOChannel *io, void *user_data)
{
GError *err = NULL;
- struct bap_bcast_pa_req *req = user_data;
- struct queue *setups = req->data.setups;
- struct bap_setup *setup = queue_peek_head(setups);
- struct bap_data *data = req->bap_data;
+ struct bap_setup *setup = user_data;
+ struct bap_data *data = setup->data;
struct sockaddr_iso_bc iso_bc_addr = {0};
struct bt_iso_qos qos;
+ struct queue *links = bt_bap_stream_io_get_links(setup->stream);
DBG("PA Sync done");
- if (req->io) {
- g_io_channel_unref(req->io);
- g_io_channel_shutdown(req->io, TRUE, NULL);
- req->io = io;
- g_io_channel_ref(req->io);
- }
-
- 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));
+ g_io_channel_unref(data->listen_io);
+ g_io_channel_shutdown(data->listen_io, TRUE, NULL);
+ data->listen_io = io;
+ g_io_channel_ref(data->listen_io);
/* Append each linked BIS to the BIG sync request */
- queue_foreach(setups, append_setup, &iso_bc_addr);
+ append_setup(setup->stream, &iso_bc_addr);
+ queue_foreach(links, append_setup, &iso_bc_addr);
/* Refresh qos stored in setups */
- queue_foreach(setups, setup_refresh_qos, NULL);
+ setup->qos = *bt_bap_stream_get_qos(setup->stream);
+ queue_foreach(links, setup_refresh_qos, data);
/* Set the user requested QOS */
bap_qos_to_iso_qos(&setup->qos, &qos);
@@ -3192,7 +3070,7 @@ static void iso_do_big_sync(GIOChannel *io, void *user_data)
if (!bt_io_bcast_accept(io,
iso_bcast_confirm_cb,
- req, NULL, &err,
+ setup, 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)) {
@@ -3201,28 +3079,16 @@ static void iso_do_big_sync(GIOChannel *io, void *user_data)
}
}
-static void pa_and_big_sync(struct bap_bcast_pa_req *req)
+static void pa_and_big_sync(struct bap_setup *setup)
{
GError *err = NULL;
- struct bap_data *bap_data = req->bap_data;
-
- req->in_progress = TRUE;
-
- if (bap_data->listen_io) {
- /* If there is an active listen io for the BAP session
- * with the Broadcast Source, it means that PA sync is
- * already established. Go straight to establishing BIG
- * sync.
- */
- iso_do_big_sync(bap_data->listen_io, req);
- return;
- }
+ struct bap_data *bap_data = setup->data;
DBG("Create PA sync with this source");
- req->io = bt_io_listen(NULL, iso_do_big_sync, req,
+ bap_data->listen_io = bt_io_listen(NULL, iso_do_big_sync, setup,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR,
- btd_adapter_get_address(bap_data->adapter->adapter),
+ btd_adapter_get_address(bap_data->adapter),
BT_IO_OPT_DEST_BDADDR,
device_get_address(bap_data->device),
BT_IO_OPT_DEST_TYPE,
@@ -3230,26 +3096,17 @@ static void pa_and_big_sync(struct bap_bcast_pa_req *req)
BT_IO_OPT_MODE, BT_IO_MODE_ISO,
BT_IO_OPT_QOS, &bap_sink_pa_qos,
BT_IO_OPT_INVALID);
- if (!req->io) {
+ if (!bap_data->listen_io) {
error("%s", err->message);
g_error_free(err);
}
}
-static bool match_bap_adapter(const void *data, const void *match_data)
-{
- struct bap_adapter *adapter = (struct bap_adapter *)data;
-
- return adapter->adapter == match_data;
-}
-
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 btd_gatt_database *database = btd_adapter_get_database(adapter);
- struct bap_bcast_pa_req *req;
- uint8_t type = BAP_PA_LONG_REQ;
struct bap_data *data;
int ret = 0;
@@ -3258,27 +3115,10 @@ static int bap_bcast_probe(struct btd_service *service)
return -ENOTSUP;
}
- data = queue_find(sessions, match_device, device);
- if (data && data->service) {
- error("Profile probed twice for the same device!");
- return -EINVAL;
- }
-
- if (!data) {
- data = bap_data_new(device);
- data->device = device;
- bap_data_add(data);
-
- /* The Broadcaster was scanned autonomously,
- * so it should be probed short-lived.
- */
- type = BAP_PA_SHORT_REQ;
- }
-
+ data = bap_data_new(device);
data->service = service;
- btd_service_set_user_data(service, data);
-
- data->adapter = queue_find(adapters, match_bap_adapter, adapter);
+ 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) {
@@ -3286,9 +3126,6 @@ static int bap_bcast_probe(struct btd_service *service)
free(data);
return -EINVAL;
}
-
- bt_bap_set_debug(data->bap, bap_debug, NULL, NULL);
-
data->bcast_snks = queue_new();
if (!bt_bap_attach(data->bap, NULL)) {
@@ -3296,6 +3133,8 @@ static int bap_bcast_probe(struct btd_service *service)
return -EINVAL;
}
+ bap_data_add(data);
+
data->ready_id = bt_bap_ready_register(data->bap, bap_ready, service,
NULL);
data->state_id = bt_bap_state_register(data->bap, bap_state_bcast_sink,
@@ -3309,36 +3148,15 @@ static int bap_bcast_probe(struct btd_service *service)
/* Return if probed device was handled inside BASS. */
return ret;
- /* Start the PA timer if it hasn't been started yet */
- if (data->adapter->pa_timer_id == 0)
- data->adapter->pa_timer_id = g_timeout_add_seconds(
- PA_IDLE_TIMEOUT,
- pa_idle_timer,
- data->adapter);
-
- /* Enqueue this device advertisement so that we can create PA sync. */
- DBG("enqueue service: %p", service);
- req = new0(struct bap_bcast_pa_req, 1);
- req->type = type;
- req->in_progress = FALSE;
- req->data.service = service;
- queue_push_tail(data->adapter->bcast_pa_requests, req);
+ pa_sync(data);
return 0;
}
-static bool match_service(const void *data, const void *match_data)
-{
- struct bap_bcast_pa_req *req = (struct bap_bcast_pa_req *)data;
-
- return req->data.service == match_data;
-}
-
static void bap_bcast_remove(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
struct bap_data *data;
- struct bap_bcast_pa_req *req;
char addr[18];
ba2str(device_get_address(device), addr);
@@ -3349,17 +3167,6 @@ static void bap_bcast_remove(struct btd_service *service)
error("BAP service not handled by profile");
return;
}
- /* Remove the corresponding entry from the pa_req queue. Any pa_req that
- * are in progress will be stopped by bap_data_remove which calls
- * bap_data_free.
- */
- req = queue_remove_if(data->adapter->bcast_pa_requests,
- match_service, service);
- if (req && req->io_id) {
- g_source_remove(req->io_id);
- req->io_id = 0;
- }
- free(req);
/* Notify the BASS plugin about the removed session. */
bass_bcast_remove(device);
@@ -3501,13 +3308,7 @@ static int bap_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter)
bt_bap_set_user_data(data->bap, adapter);
bap_data_set_user_data(data, adapter);
- data->adapter = new0(struct bap_adapter, 1);
- data->adapter->adapter = adapter;
-
- if (adapters == NULL)
- adapters = queue_new();
- data->adapter->bcast_pa_requests = queue_new();
- queue_push_tail(adapters, data->adapter);
+ data->adapter = adapter;
return 0;
}
@@ -3522,15 +3323,6 @@ static void bap_adapter_remove(struct btd_profile *p,
ba2str(btd_adapter_get_address(adapter), addr);
DBG("%s", addr);
- queue_destroy(data->adapter->bcast_pa_requests, free);
- queue_remove(adapters, data->adapter);
- free(data->adapter);
-
- if (queue_isempty(adapters)) {
- queue_destroy(adapters, NULL);
- adapters = NULL;
- }
-
if (!data) {
error("BAP service not handled by profile");
return;