2023-12-11 21:04:48

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: [PATCH BlueZ v3 2/6] shared/bap: Make bt_bap_select match the channel map

From: Luiz Augusto von Dentz <[email protected]>

bt_bap_pac may actually map to multiple PAC records and each may have a
different channel count that needs to be matched separately, for
instance when trying with EarFun Air Pro:

< ACL Data TX: Handle 2048 flags 0x00 dlen 85
ATT: Write Command (0x52) len 80
Handle: 0x0098 Type: ASE Control Point (0x2bc6)
Data: 010405020206000000000a020103020201030428000602020600000
0000a0201030202010304280001020206000000000a020103020201030428
0002020206000000000a02010302020103042800
Opcode: Codec Configuration (0x01)
Number of ASE(s): 4
ASE: #0
ASE ID: 0x05
Target Latency: Balance Latency/Reliability (0x02)
PHY: 0x02
LE 2M PHY (0x02)
Codec: LC3 (0x06)
Codec Specific Configuration: #0: len 0x02 type 0x01
Sampling Frequency: 16 Khz (0x03)
Codec Specific Configuration: #1: len 0x02 type 0x02
Frame Duration: 10 ms (0x01)
Codec Specific Configuration: #2: len 0x03 type 0x04
Frame Length: 40 (0x0028)
ASE: #1
ASE ID: 0x06
Target Latency: Balance Latency/Reliability (0x02)
PHY: 0x02
LE 2M PHY (0x02)
Codec: LC3 (0x06)
Codec Specific Configuration: #0: len 0x02 type 0x01
Sampling Frequency: 16 Khz (0x03)
Codec Specific Configuration: #1: len 0x02 type 0x02
Frame Duration: 10 ms (0x01)
Codec Specific Configuration: #2: len 0x03 type 0x04
Frame Length: 40 (0x0028)
ASE: #2
ASE ID: 0x01
Target Latency: Balance Latency/Reliability (0x02)
PHY: 0x02
LE 2M PHY (0x02)
Codec: LC3 (0x06)
Codec Specific Configuration: #0: len 0x02 type 0x01
Sampling Frequency: 16 Khz (0x03)
Codec Specific Configuration: #1: len 0x02 type 0x02
Frame Duration: 10 ms (0x01)
Codec Specific Configuration: #2: len 0x03 type 0x04
Frame Length: 40 (0x0028)
ASE: #3
ASE ID: 0x02
Target Latency: Balance Latency/Reliability (0x02)
PHY: 0x02
LE 2M PHY (0x02)
Codec: LC3 (0x06)
Codec Specific Configuration: #0: len 0x02 type 0x01
Sampling Frequency: 16 Khz (0x03)
Codec Specific Configuration: #1: len 0x02 type 0x02
Frame Duration: 10 ms (0x01)
Codec Specific Configuration: #2: len 0x03 type 0x04
Frame Length: 40 (0x0028)

Fixes: https://github.com/bluez/bluez/issues/612
---
profiles/audio/bap.c | 6 +--
src/shared/bap.c | 87 ++++++++++++++++++++++++++++++++++++++++----
src/shared/bap.h | 3 +-
src/shared/util.c | 43 ++++++++++++++++++++++
src/shared/util.h | 6 +++
5 files changed, 132 insertions(+), 13 deletions(-)

diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index 38eaea055ed2..6fe45281150f 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -1290,10 +1290,8 @@ static bool pac_found(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
}

/* TODO: Cache LRU? */
- if (btd_service_is_initiator(service)) {
- if (!bt_bap_select(lpac, rpac, select_cb, ep))
- ep->data->selecting++;
- }
+ if (btd_service_is_initiator(service))
+ bt_bap_select(lpac, rpac, &ep->data->selecting, select_cb, ep);

return true;
}
diff --git a/src/shared/bap.c b/src/shared/bap.c
index e9d7072ef3be..cb505d1564d6 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -185,6 +185,7 @@ struct bt_bap_pac {
struct bt_bap_pac_qos qos;
struct iovec *data;
struct iovec *metadata;
+ struct queue *chan_map;
struct bt_bap_pac_ops *ops;
void *user_data;
};
@@ -2417,6 +2418,33 @@ static void *ltv_merge(struct iovec *data, struct iovec *cont)
return iov_append(data, cont->iov_len, cont->iov_base);
}

+static void bap_pac_foreach_channel(size_t i, uint8_t l, uint8_t t, uint8_t *v,
+ void *user_data)
+{
+ struct bt_bap_pac *pac = user_data;
+
+ if (!v)
+ return;
+
+ if (!pac->chan_map)
+ pac->chan_map = queue_new();
+
+ printf("PAC %p chan_map 0x%02x\n", pac, *v);
+
+ queue_push_tail(pac->chan_map, UINT_TO_PTR(*v));
+}
+
+static void bap_pac_update_chan_map(struct bt_bap_pac *pac, struct iovec *data)
+{
+ uint8_t type = 0x03;
+
+ if (!data)
+ return;
+
+ util_ltv_foreach(data->iov_base, data->iov_len, &type,
+ bap_pac_foreach_channel, pac);
+}
+
static void bap_pac_merge(struct bt_bap_pac *pac, struct iovec *data,
struct iovec *metadata)
{
@@ -2426,6 +2454,9 @@ static void bap_pac_merge(struct bt_bap_pac *pac, struct iovec *data,
else
pac->data = util_iov_dup(data, 1);

+ /* Update channel map */
+ bap_pac_update_chan_map(pac, data);
+
/* Merge metadata into existing record */
if (pac->metadata)
ltv_merge(pac->metadata, metadata);
@@ -2448,10 +2479,9 @@ static struct bt_bap_pac *bap_pac_new(struct bt_bap_db *bdb, const char *name,
pac->type = type;
if (codec)
pac->codec = *codec;
- if (data)
- pac->data = util_iov_dup(data, 1);
- if (metadata)
- pac->metadata = util_iov_dup(metadata, 1);
+
+ bap_pac_merge(pac, data, metadata);
+
if (qos)
pac->qos = *qos;

@@ -2465,6 +2495,7 @@ static void bap_pac_free(void *data)
free(pac->name);
util_iov_free(pac->metadata, 1);
util_iov_free(pac->data, 1);
+ queue_destroy(pac->chan_map, NULL);
free(pac);
}

@@ -4505,7 +4536,16 @@ static bool find_ep_pacs(const void *data, const void *user_data)
if (ep->stream->lpac != match->lpac)
return false;

- return ep->stream->rpac == match->rpac;
+ if (ep->stream->rpac != match->rpac)
+ return false;
+
+ switch (ep->state) {
+ case BT_BAP_STREAM_STATE_CONFIG:
+ case BT_BAP_STREAM_STATE_QOS:
+ return true;
+ }
+
+ return false;
}

static struct bt_bap_req *bap_req_new(struct bt_bap_stream *stream,
@@ -4626,16 +4666,47 @@ static bool match_pac(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
}

int bt_bap_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
- bt_bap_pac_select_t func, void *user_data)
+ int *count, bt_bap_pac_select_t func,
+ void *user_data)
{
+ const struct queue_entry *lchan, *rchan;
+
if (!lpac || !rpac || !func)
return -EINVAL;

if (!lpac->ops || !lpac->ops->select)
return -EOPNOTSUPP;

- lpac->ops->select(lpac, rpac, &rpac->qos,
- func, user_data, lpac->user_data);
+ for (lchan = queue_get_entries(lpac->chan_map); lchan;
+ lchan = lchan->next) {
+ uint8_t lmap = PTR_TO_UINT(lchan->data);
+
+ for (rchan = queue_get_entries(rpac->chan_map); rchan;
+ rchan = rchan->next) {
+ uint8_t rmap = PTR_TO_UINT(rchan->data);
+
+ printf("lmap 0x%02x rmap 0x%02x\n", lmap, rmap);
+
+ /* Try matching the channel mapping */
+ if (lmap & rmap) {
+ lpac->ops->select(lpac, rpac, &rpac->qos,
+ func, user_data,
+ lpac->user_data);
+ if (count)
+ (*count)++;
+
+ /* Check if there are any channels left */
+ lmap &= ~(lmap & rmap);
+ if (!lmap)
+ break;
+
+ /* Check if device require AC*(i) settings */
+ if (rmap == 0x01)
+ lmap = lmap >> 1;
+ } else
+ break;
+ }
+ }

return 0;
}
diff --git a/src/shared/bap.h b/src/shared/bap.h
index 2c8f9208e6ba..470313e66fc0 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -234,7 +234,8 @@ void *bt_bap_pac_get_user_data(struct bt_bap_pac *pac);

/* Stream related functions */
int bt_bap_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
- bt_bap_pac_select_t func, void *user_data);
+ int *count, bt_bap_pac_select_t func,
+ void *user_data);

struct bt_bap_stream *bt_bap_stream_new(struct bt_bap *bap,
struct bt_bap_pac *lpac,
diff --git a/src/shared/util.c b/src/shared/util.c
index 34491f4e5a56..c0c2c4a17f12 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -175,6 +175,49 @@ ltv_debugger(const struct util_ltv_debugger *debugger, size_t num, uint8_t type)
return NULL;
}

+/* Helper to itertate over LTV entries */
+bool util_ltv_foreach(const uint8_t *data, uint8_t len, uint8_t *type,
+ util_ltv_func_t func, void *user_data)
+{
+ struct iovec iov;
+ int i;
+
+ if (!func)
+ return false;
+
+ iov.iov_base = (void *) data;
+ iov.iov_len = len;
+
+ for (i = 0; iov.iov_len; i++) {
+ uint8_t l, t, *v;
+
+ if (!util_iov_pull_u8(&iov, &l))
+ return false;
+
+ if (!l) {
+ func(i, l, 0, NULL, user_data);
+ continue;
+ }
+
+ if (!util_iov_pull_u8(&iov, &t))
+ return false;
+
+ l--;
+
+ if (l) {
+ v = util_iov_pull_mem(&iov, l);
+ if (!v)
+ return false;
+ } else
+ v = NULL;
+
+ if (!type || *type == t)
+ func(i, l, t, v, user_data);
+ }
+
+ return true;
+}
+
/* Helper to print debug information of LTV entries */
bool util_debug_ltv(const uint8_t *data, uint8_t len,
const struct util_ltv_debugger *debugger, size_t num,
diff --git a/src/shared/util.h b/src/shared/util.h
index 6698d00415de..596663b8519c 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -138,6 +138,12 @@ bool util_debug_ltv(const uint8_t *data, uint8_t len,
const struct util_ltv_debugger *debugger, size_t num,
util_debug_func_t function, void *user_data);

+typedef void (*util_ltv_func_t)(size_t i, uint8_t l, uint8_t t, uint8_t *v,
+ void *user_data);
+
+bool util_ltv_foreach(const uint8_t *data, uint8_t len, uint8_t *type,
+ util_ltv_func_t func, void *user_data);
+
unsigned char util_get_dt(const char *parent, const char *name);

ssize_t util_getrandom(void *buf, size_t buflen, unsigned int flags);
--
2.43.0