This removes BAP support for long-lived PA sync (added for Scan Delegator support), since it is now handled inside the BASS plugin. This also removes the PA idle timer logic, since PA/BIG sync requests are now ordered inside the kernel. --- profiles/audio/bap.c | 368 ++++++++++--------------------------------- 1 file changed, 80 insertions(+), 288 deletions(-) diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c index beab85cff..e927a4404 100644 --- a/profiles/audio/bap.c +++ b/profiles/audio/bap.c @@ -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; -- 2.43.0