mirror of
https://git.kernel.org/pub/scm/bluetooth/bluez.git
synced 2024-11-27 06:04:32 +08:00
shared/bap: Make bt_bap_select match the channel map
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
This commit is contained in:
parent
511d58b06c
commit
e7e8b2a3d7
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user