@@ -335,6 +335,8 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
GError *gerr = NULL;
struct bt_bap_qos *bap_qos = bt_bap_stream_get_qos(stream);
struct bt_iso_qos qos;
+ struct bass_setup *setup = queue_find(dg->setups,
+ match_setup_stream, stream);
if (dg->bap != bap)
return;
@@ -392,6 +394,10 @@ static void bap_state_changed(struct bt_bap_stream *stream, uint8_t old_state,
*/
bt_bass_clear_bis_sync(dg->src, bis);
break;
+ case BT_BAP_STREAM_STATE_IDLE:
+ bt_bass_clear_bis_sync(dg->src, bis);
+ setup->stream = NULL;
+ break;
}
}
@@ -417,6 +423,44 @@ static void setup_configure_stream(struct bass_setup *setup)
NULL, NULL);
}
+static void stream_unlink(void *data, void *user_data)
+{
+ struct bt_bap_stream *link = data;
+ struct bt_bap_stream *stream = user_data;
+
+ bt_bap_stream_io_unlink(link, stream);
+}
+
+static void bass_remove_bis(struct bass_setup *setup)
+{
+ struct queue *links = bt_bap_stream_io_get_links(setup->stream);
+
+ queue_foreach(links, stream_unlink, setup->stream);
+ bt_bap_stream_release(setup->stream, NULL, NULL);
+}
+
+static void setup_disable_streaming(void *data, void *user_data)
+{
+ struct bass_setup *setup = data;
+ struct queue *links = bt_bap_stream_io_get_links(setup->stream);
+
+ if (!setup->stream)
+ return;
+
+ if (bt_bap_stream_get_state(setup->stream) !=
+ BT_BAP_STREAM_STATE_STREAMING)
+ return;
+
+ queue_foreach(links, stream_unlink, setup->stream);
+ bt_bap_stream_disable(setup->stream, false, NULL, NULL);
+}
+
+static void bass_add_bis(struct bass_setup *setup)
+{
+ queue_foreach(setup->dg->setups, setup_disable_streaming, NULL);
+ setup_configure_stream(setup);
+}
+
static void bis_handler(uint8_t bis, uint8_t sgrp, struct iovec *caps,
struct iovec *meta, struct bt_bap_qos *qos, void *user_data)
{
@@ -566,8 +610,13 @@ static void setup_free(void *data)
util_iov_free(setup->meta, 1);
util_iov_free(setup->config, 1);
- bt_bass_clear_bis_sync(setup->dg->src,
+ if (setup->stream) {
+ uint8_t state = bt_bap_stream_get_state(setup->stream);
+
+ if (state == BT_BAP_STREAM_STATE_STREAMING)
+ bt_bass_clear_bis_sync(setup->dg->src,
stream_get_bis(setup->stream));
+ }
}
bool bass_bcast_remove(struct btd_device *device)
@@ -1231,6 +1280,98 @@ static int handle_set_bcode_req(struct bt_bcast_src *bcast_src,
return 0;
}
+static bool setup_match_bis(const void *data, const void *match_data)
+{
+ const struct bass_setup *setup = data;
+ const int bis = PTR_TO_INT(match_data);
+
+ return setup->bis == bis;
+}
+
+static void bass_update_bis_sync(struct bass_delegator *dg,
+ struct bt_bcast_src *bcast_src)
+{
+ for (int bis = 1; bis < ISO_MAX_NUM_BIS; bis++) {
+ struct bass_setup *setup = queue_find(dg->setups,
+ setup_match_bis, INT_TO_PTR(bis));
+ uint8_t state;
+
+ if (!setup)
+ continue;
+
+ state = bt_bap_stream_get_state(setup->stream);
+
+ if (!setup->stream && bt_bass_check_bis(bcast_src, bis))
+ bass_add_bis(setup);
+ else if (setup->stream &&
+ state == BT_BAP_STREAM_STATE_STREAMING &&
+ !bt_bass_check_bis(bcast_src, bis))
+ bass_remove_bis(setup);
+ }
+}
+
+static int handle_mod_src_req(struct bt_bcast_src *bcast_src,
+ struct bt_bass_mod_src_params *params,
+ struct bass_data *data)
+{
+ struct bass_delegator *dg;
+ uint8_t sync_state;
+ int err = 0;
+
+ DBG("");
+
+ dg = queue_find(delegators, delegator_match_src, bcast_src);
+ if (!dg)
+ return -EINVAL;
+
+ err = bt_bass_get_pa_sync(bcast_src, &sync_state);
+ if (err)
+ return err;
+
+ switch (sync_state) {
+ case BT_BASS_SYNCHRONIZED_TO_PA:
+ if (params->pa_sync == PA_SYNC_NO_SYNC) {
+ 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);
+ } else {
+ bass_update_bis_sync(dg, bcast_src);
+ }
+ break;
+ case BT_BASS_NOT_SYNCHRONIZED_TO_PA:
+ if (params->pa_sync == PA_SYNC_NO_PAST) {
+ struct btd_adapter *adapter =
+ device_get_adapter(dg->device);
+ GError *err = NULL;
+
+ dg->io = bt_io_listen(NULL, confirm_cb, dg,
+ NULL, &err,
+ BT_IO_OPT_SOURCE_BDADDR,
+ btd_adapter_get_address(adapter),
+ BT_IO_OPT_SOURCE_TYPE,
+ btd_adapter_get_address_type(adapter),
+ BT_IO_OPT_DEST_BDADDR,
+ device_get_address(dg->device),
+ BT_IO_OPT_DEST_TYPE,
+ btd_device_get_bdaddr_type(dg->device),
+ BT_IO_OPT_MODE, BT_IO_MODE_ISO,
+ BT_IO_OPT_QOS, &bap_sink_pa_qos,
+ BT_IO_OPT_INVALID);
+ if (!dg->io) {
+ error("%s", err->message);
+ g_error_free(err);
+ }
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
static int cp_handler(struct bt_bcast_src *bcast_src, uint8_t op, void *params,
void *user_data)
{
@@ -1244,6 +1385,9 @@ static int cp_handler(struct bt_bcast_src *bcast_src, uint8_t op, void *params,
case BT_BASS_SET_BCAST_CODE:
err = handle_set_bcode_req(bcast_src, params, data);
break;
+ case BT_BASS_MOD_SRC:
+ err = handle_mod_src_req(bcast_src, params, data);
+ break;
}
return err;