@@ -105,6 +105,44 @@ struct bap_data {
void *user_data;
};
+/* Structure holding the parameters for periodic train and BIG
+ * synchronization
+ */
+static struct bt_iso_qos bap_sink_sync_parameters = {
+ .bcast = {
+ .big = BT_ISO_QOS_BIG_UNSET,
+ .bis = BT_ISO_QOS_BIS_UNSET,
+ /* HCI_LE_Periodic_Advertising_Create_Sync */
+ .options = 0x00,
+ .skip = 0x0000,
+ .sync_timeout = 0x4000,
+ .sync_cte_type = 0x00,
+ /* HCI_LE_BIG_Create_Sync */
+ .encryption = 0x00,
+ .bcode = {0x00},
+ .mse = 0x00,
+ .timeout = 0x4000,
+ /* to remove from kernel check */
+ .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 struct queue *sessions;
static bool bap_data_set_user_data(struct bap_data *data, void *user_data)
@@ -422,113 +460,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,6 +885,17 @@ 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);
@@ -977,95 +919,27 @@ 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];
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);
-
- 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);
+ /* listen channel is not needed anymore */
+ g_io_channel_unref(setup->io);
+ setup->io = NULL;
fd = g_io_channel_unix_get_fd(io);
@@ -1074,26 +948,43 @@ 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_data *data = user_data;
+ 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);
+ btd_service_connecting_complete(data->service, 0);
+
+ 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;
}
+ /* The PA Sync channel becomes the new listen_io.
+ * It will be later used to listen for a BIS io.
+ */
+ g_io_channel_unref(data->listen_io);
+ data->listen_io = io;
+ g_io_channel_ref(io);
+
+ /* 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)
@@ -1934,12 +1825,11 @@ 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,
+static void setup_accept_io_broadcast(struct bap_data *data,
struct bap_setup *setup,
struct bt_bap_stream *stream,
struct bt_iso_qos *qos)
{
- GIOChannel *io;
GError *err = NULL;
struct sockaddr_iso_bc iso_bc_addr;
@@ -1951,29 +1841,18 @@ static void setup_listen_io_broadcast(struct bap_data *data,
DBG("stream %p", stream);
- /* If IO already set skip creating it again */
- if (bt_bap_stream_get_io(stream) || data->listen_io)
- return;
-
- 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);
+ if (!bt_io_bcast_accept(data->listen_io,
+ iso_bcast_confirm_cb,
+ 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)) {
+ error("bt_io_bcast_accept: %s", err->message);
g_error_free(err);
}
- setup->io = io;
- data->listen_io = io;
+ setup->io = data->listen_io;
+ data->listen_io = NULL;
}
static void setup_create_ucast_io(struct bap_data *data,
struct bap_setup *setup,
@@ -2037,7 +1916,7 @@ 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, stream, &iso_qos);
}
static void setup_create_io(struct bap_data *data, struct bap_setup *setup,
@@ -2422,6 +2301,7 @@ static int bap_bcast_probe(struct btd_service *service)
struct btd_gatt_database *database = btd_adapter_get_database(adapter);
struct bap_data *data = btd_service_get_user_data(service);
char addr[18];
+ GError *err = NULL;
ba2str(device_get_address(device), addr);
@@ -2465,7 +2345,23 @@ static int bap_bcast_probe(struct btd_service *service)
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");
+ 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),
+ 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_sync_parameters,
+ BT_IO_OPT_INVALID);
+ if (!data->listen_io) {
+ error("%s", err->message);
+ g_error_free(err);
+ }
+
return 0;
}