diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index c10f019..0883f6c 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
ep_unregister(ep);
}
-static bool match_device(const void *data, const void *match_data)
-{
- const struct bap_data *bdata = data;
- const struct btd_device *device = match_data;
-
- return bdata->device == device;
-}
-
static struct bap_data *bap_data_new(struct btd_device *device)
{
struct bap_data *data;
return 0;
}
+static bool match_service(const void *data, const void *match_data)
+{
+ const struct bap_data *bdata = data;
+ const struct btd_service *service = match_data;
+
+ return bdata->service == service;
+}
+
static void bap_bcast_remove(struct btd_service *service)
{
struct btd_device *device = btd_service_get_device(service);
ba2str(device_get_address(device), addr);
DBG("%s", addr);
- data = queue_find(sessions, match_device, device);
+ /* Lookup the bap session for this service since in case of
+ * bass_delegator its user data is set by bass plugin.
+ */
+ data = queue_find(sessions, match_service, service);
if (!data) {
error("BAP service not handled by profile");
return;
static int bap_bcast_disconnect(struct btd_service *service)
{
- struct btd_device *device = btd_service_get_device(service);
struct bap_data *data;
- data = queue_find(sessions, match_device, device);
+ /* Lookup the bap session for this service since in case of
+ * bass_delegator its user data is set by bass plugin.
+ */
+ data = queue_find(sessions, match_service, service);
if (!data) {
error("BAP service not handled by profile");
return -EINVAL;
diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c
index 0ba29f9..9ace372 100644
--- a/profiles/audio/bass.c
+++ b/profiles/audio/bass.c
dg->timeout = g_timeout_add_seconds(10, req_timeout, dg);
}
-static bool delegator_match_device(const void *data, const void *match_data)
-{
- const struct bass_delegator *dg = data;
- const struct btd_device *device = match_data;
-
- return dg->device == device;
-}
-
static int stream_get_bis(struct bt_bap_stream *stream)
{
char *path = bt_bap_stream_get_user_data(stream);
free(setup);
}
+static void delegator_disconnect(struct bass_delegator *dg)
+{
+ struct btd_device *device = dg->device;
+ struct btd_service *service = dg->service;
+
+ DBG("%p", dg);
+
+ /* Disconnect service so BAP driver is cleanup properly and bt_bap is
+ * detached from the device.
+ */
+ btd_service_disconnect(service);
+
+ /* Remove service since delegator shold have been freed at this point */
+ device_remove_profile(device, btd_service_get_profile(service));
+
+ /* If the device is no longer consider connected it means no other
+ * service was connected so it has no longer any use and can be safely
+ * removed.
+ */
+ if (!btd_device_is_connected(device)) {
+ struct btd_adapter *adapter;
+
+ adapter = device_get_adapter(device);
+ btd_adapter_remove_device(adapter, device);
+ }
+}
+
static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
uint8_t new_state, void *user_data)
{
setup->stream = NULL;
queue_remove(setup->dg->setups, setup);
setup_free(setup);
+ if (queue_isempty(dg->setups))
+ delegator_disconnect(dg);
break;
}
}
bass_data_add(data);
}
-static void bap_attached(struct bt_bap *bap, void *user_data)
+static bool delegator_match_device(const void *data, const void *match_data)
{
- struct btd_service *service;
- struct btd_profile *p;
- struct btd_device *device;
- struct btd_adapter *adapter;
- struct bass_delegator *dg;
- struct bass_data *data;
- GError *err = NULL;
-
- service = bt_bap_get_user_data(bap);
- if (!service)
- return bap_bc_attached(bap, user_data);
-
- DBG("%p", bap);
-
- p = btd_service_get_profile(service);
- if (!p)
- return;
-
- /* Only handle sessions with Broadcast Sources */
- if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
- return;
-
- device = btd_service_get_device(service);
- adapter = device_get_adapter(device);
+ const struct bass_delegator *dg = data;
+ const struct btd_device *device = match_data;
- /* Create BASS session with the Broadcast Source */
- data = bass_data_new(adapter, device);
- data->bis_id = bt_bap_bis_cb_register(bap, bis_probe,
- bis_remove, device, NULL);
+ return dg->device == device;
+}
- bass_data_add(data);
+static void delegator_attach(struct bt_bap *bap, struct btd_device *device,
+ struct btd_service *service)
+{
+ struct bass_delegator *dg;
+ GError *err = NULL;
dg = queue_find(delegators, delegator_match_device, device);
if (!dg)
/* Only probe devices added via Broadcast Assistants */
return;
+ DBG("delegator %p", dg);
+
if (dg->service)
/* Service has already been probed */
return;
dg->io = bt_io_listen(NULL, confirm_cb, dg,
NULL, &err,
BT_IO_OPT_SOURCE_BDADDR,
- btd_adapter_get_address(adapter),
+ btd_adapter_get_address(device_get_adapter(device)),
BT_IO_OPT_SOURCE_TYPE,
- btd_adapter_get_address_type(adapter),
+ btd_adapter_get_address_type(device_get_adapter(device)),
BT_IO_OPT_DEST_BDADDR,
device_get_address(device),
BT_IO_OPT_DEST_TYPE,
btd_service_set_user_data(service, dg);
}
+static void bap_attached(struct bt_bap *bap, void *user_data)
+{
+ struct btd_service *service;
+ struct btd_profile *p;
+ struct btd_device *device;
+ struct btd_adapter *adapter;
+ struct bass_data *data;
+
+ service = bt_bap_get_user_data(bap);
+ if (!service)
+ return bap_bc_attached(bap, user_data);
+
+ DBG("%p", bap);
+
+ p = btd_service_get_profile(service);
+ if (!p)
+ return;
+
+ /* Only handle sessions with Broadcast Sources */
+ if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
+ return;
+
+ device = btd_service_get_device(service);
+ adapter = device_get_adapter(device);
+
+ /* Create BASS session with the Broadcast Source */
+ data = bass_data_new(adapter, device);
+ data->bis_id = bt_bap_bis_cb_register(bap, bis_probe,
+ bis_remove, device, NULL);
+
+ bass_data_add(data);
+
+ delegator_attach(bap, device, service);
+}
+
static bool match_bap(const void *data, const void *match_data)
{
const struct bass_data *d = data;
free(dg);
}
+static bool match_service(const void *data, const void *match_data)
+{
+ const struct bass_data *bdata = data;
+ const struct btd_service *service = match_data;
+
+ return bdata->service == service;
+}
+
+static void delegator_detach(struct btd_service *service)
+{
+ struct bass_delegator *dg;
+
+ dg = btd_service_get_user_data(service);
+ if (!dg)
+ return;
+
+ if (!queue_remove(delegators, dg))
+ return;
+
+ DBG("%p", dg);
+
+ delegator_free(dg);
+
+ btd_service_set_user_data(service, NULL);
+}
+
static void bap_detached(struct bt_bap *bap, void *user_data)
{
struct btd_service *service;
- struct btd_profile *p;
- struct btd_device *device;
- struct bass_delegator *dg;
struct bass_data *data;
data = queue_find(sessions, match_bap, bap);
if (!service)
return;
- p = btd_service_get_profile(service);
- if (!p)
- return;
-
- /* Only handle sessions with Broadcast Sources */
- if (!g_str_equal(p->remote_uuid, BCAAS_UUID_STR))
- return;
-
- device = btd_service_get_device(service);
-
/* Remove BASS session with the Broadcast Source device */
- data = queue_find(sessions, match_device, device);
+ data = queue_find(sessions, match_service, service);
if (data) {
bt_bap_bis_cb_unregister(bap, data->bis_id);
bt_bap_state_unregister(bap, data->state_id);
bass_data_remove(data);
}
- dg = queue_remove_if(delegators, delegator_match_device, device);
- if (!dg)
- return;
-
- delegator_free(dg);
-
- btd_service_set_user_data(service, NULL);
+ delegator_detach(service);
}
static void bis_probe(uint8_t sid, uint8_t bis, uint8_t sgrp,
switch (sync_state) {
case BT_BASS_SYNCHRONIZED_TO_PA:
bass_update_bis_sync(dg, bcast_src);
-
- /* Check if there are any setups left since it means the PA
- * should be no longer synchronized.
- */
- if (queue_isempty(dg->setups)) {
- /* IO is no longer needed since there are no setups */
- g_io_channel_shutdown(dg->io, TRUE, NULL);
- g_io_channel_unref(dg->io);
- dg->io = NULL;
-
- bt_bass_set_pa_sync(dg->src,
- BT_BASS_NOT_SYNCHRONIZED_TO_PA);
-
- if (!dg->service)
- return 0;
-
- /* Disconnect service so BAP driver is cleanup
- * properly.
- */
- btd_service_disconnect(dg->service);
-
- /* If the device is no longer consider connected
- * it means no other service was connected so it
- * has no longer any use and can be safely removed.
- */
- if (!btd_device_is_connected(dg->device)) {
- struct btd_adapter *adapter;
-
- adapter = device_get_adapter(dg->device);
- btd_adapter_remove_device(adapter, dg->device);
- }
- }
-
break;
case BT_BASS_NOT_SYNCHRONIZED_TO_PA:
if (params->pa_sync == PA_SYNC_NO_PAST) {