@@ -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;
}
@@ -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;
}
@@ -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,
@@ -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,
@@ -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);
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> 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(-)