* [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select()
@ 2025-11-15 12:58 Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 2/6] shared/bap: fix packet length comparison to ATT MTU in bap_queue_req() Pauli Virtanen
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: Pauli Virtanen @ 2025-11-15 12:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
bt_bap_select() does not correctly determine the need for multi-stream
configurations 6,7,8,9,11(i), as its result depends on whether Audio
Locations is read before or after the PACs, doesn't work with general
location bits, etc.
Fix the procedure to be simpler: create streams for all locations, up to
a specific number of channels. By default, limit to max 2 channels per
direction for compatibility (BAP doesn't have explicit AC with larger
channel counts.) Also simplify the code.
Ignore lpac Locations when selecting: the value mostly makes sense for
Unicast Server role, but Client and Server cannot use the same value as
only a few bits can be set. As Client, we should be able to configure
any Location bits. The sound server can simply ignore our suggested
channel allocation if really needed, or use SetConfiguration() API to
build custom configurations.
---
Notes:
v4:
- no change
v3:
- no change
profiles/audio/bap.c | 3 +-
src/shared/bap.c | 205 +++++++++++++++++++++----------------------
src/shared/bap.h | 7 +-
3 files changed, 104 insertions(+), 111 deletions(-)
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index 85bba9543..ec3502b06 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -1919,7 +1919,8 @@ static bool pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
queue_push_tail(select->eps, ep);
}
- bt_bap_select(lpac, rpac, &select->remaining, select_cb, ep);
+ bt_bap_select(data->bap, lpac, rpac, 0, &select->remaining,
+ select_cb, ep);
return true;
}
diff --git a/src/shared/bap.c b/src/shared/bap.c
index a18f393f7..b779f6716 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -204,11 +204,6 @@ struct bt_bap {
void *user_data;
};
-struct bt_bap_chan {
- uint8_t count;
- uint32_t location;
-};
-
struct bt_bap_pac {
struct bt_bap_db *bdb;
char *name;
@@ -3848,50 +3843,6 @@ static void *ltv_merge(struct iovec *data, struct iovec *cont)
return util_iov_append(data, cont->iov_base, cont->iov_len);
}
-static void bap_pac_chan_add(struct bt_bap_pac *pac, uint8_t count,
- uint32_t location)
-{
- struct bt_bap_chan *chan;
-
- if (!pac->channels)
- pac->channels = queue_new();
-
- chan = new0(struct bt_bap_chan, 1);
- chan->count = count;
- chan->location = location;
-
- queue_push_tail(pac->channels, chan);
-}
-
-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;
-
- bap_pac_chan_add(pac, *v, bt_bap_pac_get_locations(pac));
-}
-
-static void bap_pac_update_channels(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);
-
- /* If record didn't set a channel count but set a location use that as
- * channel count.
- */
- if (queue_isempty(pac->channels) && pac->qos.location)
- bap_pac_chan_add(pac, pac->qos.location, pac->qos.location);
-
-}
-
static void bap_pac_merge(struct bt_bap_pac *pac, struct iovec *data,
struct iovec *metadata)
{
@@ -3901,9 +3852,6 @@ static void bap_pac_merge(struct bt_bap_pac *pac, struct iovec *data,
else
pac->data = util_iov_dup(data, 1);
- /* Update channels */
- bap_pac_update_channels(pac, data);
-
/* Merge metadata into existing record */
if (pac->metadata)
ltv_merge(pac->metadata, metadata);
@@ -4845,6 +4793,8 @@ static void read_source_pac_loc(bool success, uint8_t att_ecode,
pacs->source_loc_value = get_le32(value);
+ DBG(bap, "PACS Source Locations: 0x%08x", pacs->source_loc_value);
+
/* Resume reading sinks if supported but for some reason is empty */
if (pacs->source && queue_isempty(bap->rdb->sources)) {
uint16_t value_handle;
@@ -4878,6 +4828,8 @@ static void read_sink_pac_loc(bool success, uint8_t att_ecode,
pacs->sink_loc_value = get_le32(value);
+ DBG(bap, "PACS Sink Locations: 0x%08x", pacs->sink_loc_value);
+
/* Resume reading sinks if supported but for some reason is empty */
if (pacs->sink && queue_isempty(bap->rdb->sinks)) {
uint16_t value_handle;
@@ -4911,6 +4863,9 @@ static void read_pac_context(bool success, uint8_t att_ecode,
pacs->sink_context_value = le16_to_cpu(ctx->snk);
pacs->source_context_value = le16_to_cpu(ctx->src);
+
+ DBG(bap, "PACS Sink Context: 0x%04x", pacs->sink_context_value);
+ DBG(bap, "PACS Source Context: 0x%04x", pacs->source_context_value);
}
static void read_pac_supported_context(bool success, uint8_t att_ecode,
@@ -4934,6 +4889,11 @@ static void read_pac_supported_context(bool success, uint8_t att_ecode,
pacs->supported_sink_context_value = le16_to_cpu(ctx->snk);
pacs->supported_source_context_value = le16_to_cpu(ctx->src);
+
+ DBG(bap, "PACS Supported Sink Context: 0x%04x",
+ pacs->supported_sink_context_value);
+ DBG(bap, "PACS Supported Source Context: 0x%04x",
+ pacs->supported_source_context_value);
}
static void foreach_pacs_char(struct gatt_db_attribute *attr, void *user_data)
@@ -6113,12 +6073,55 @@ static bool match_pac(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
return false;
}
-int bt_bap_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
- int *count, bt_bap_pac_select_t func,
- void *user_data)
+static void bap_pac_ltv_ch_counts(size_t i, uint8_t l, uint8_t t, uint8_t *v,
+ void *user_data)
{
- const struct queue_entry *lchan, *rchan;
- int selected = 0;
+ uint8_t *mask = user_data;
+
+ if (v)
+ *mask |= *v;
+}
+
+static uint8_t bap_pac_ch_counts(struct bt_bap_pac *pac)
+{
+ uint8_t type = 0x03;
+ uint8_t mask = 0;
+
+ if (!pac->data)
+ return 0;
+
+ util_ltv_foreach(pac->data->iov_base, pac->data->iov_len, &type,
+ bap_pac_ltv_ch_counts, &mask);
+
+ if (!mask)
+ mask = 0x01; /* default (BAP v1.0.1 Sec 4.3.1) */
+
+ return mask;
+}
+
+static unsigned int bap_count_eps(struct queue *eps, uint8_t dir)
+{
+ const struct queue_entry *entry;
+ unsigned int count = 0;
+
+ for (entry = queue_get_entries(eps); entry; entry = entry->next) {
+ struct bt_bap_endpoint *ep = entry->data;
+
+ if (ep->dir == dir)
+ count++;
+ }
+
+ return count;
+}
+
+int bt_bap_select(struct bt_bap *bap,
+ struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
+ unsigned int max_channels, int *count,
+ bt_bap_pac_select_t func, void *user_data)
+{
+ uint32_t locations;
+ uint8_t ch_counts;
+ unsigned int num_ase;
if (!lpac || !rpac || !func)
return -EINVAL;
@@ -6126,66 +6129,54 @@ int bt_bap_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
if (!lpac->ops || !lpac->ops->select)
return -EOPNOTSUPP;
- for (lchan = queue_get_entries(lpac->channels); lchan;
- lchan = lchan->next) {
- struct bt_bap_chan *lc = lchan->data;
- struct bt_bap_chan map = *lc;
- int i;
+ if (!max_channels)
+ max_channels = 2; /* By default: don't go beyond BAP AC */
- for (i = 0, rchan = queue_get_entries(rpac->channels); rchan;
- rchan = rchan->next, i++) {
- struct bt_bap_chan *rc = rchan->data;
+ ch_counts = bap_pac_ch_counts(lpac) & bap_pac_ch_counts(rpac);
+ locations = bt_bap_pac_get_locations(rpac);
+ num_ase = bap_count_eps(bap->remote_eps, rpac->type);
- /* Try matching the channel count */
- if (!(map.count & rc->count))
- break;
+ /* Fallback to unspecified/mono allocation if nothing is matching */
+ if (!locations || !ch_counts) {
+ lpac->ops->select(lpac, rpac, 0, &rpac->qos, func, user_data,
+ lpac->user_data);
+ if (count)
+ (*count)++;
+ return 0;
+ }
- /* Check if location was set otherwise attempt to
- * assign one based on the number of channels it
- * supports.
- */
- if (!rc->location) {
- rc->location = bt_bap_pac_get_locations(rpac);
- /* If channel count is 1 use a single
- * location
- */
- if (rc->count == 0x01)
- rc->location &= BIT(i);
- }
+ /* Allocate all locations to streams */
+ while (num_ase) {
+ uint32_t allocation = 0, alloc = 0;
+ unsigned int i, n;
- /* Try matching the channel location */
- if (!(map.location & rc->location))
+ /* Put max number of channels per stream */
+ for (i = 0, n = 0; i < 32 && n < 8; ++i) {
+ uint32_t loc = (1LL << i);
+
+ if (!(locations & loc))
continue;
- lpac->ops->select(lpac, rpac, map.location &
- rc->location, &rpac->qos,
- func, user_data,
- lpac->user_data);
- selected++;
+ alloc |= loc;
+ if ((BIT(n) & ch_counts) && n < max_channels)
+ allocation = alloc;
- /* Check if there are any channels left to select */
- map.count &= ~(map.count & rc->count);
- /* Check if there are any locations left to select */
- map.location &= ~(map.location & rc->location);
-
- if (!map.count || !map.location)
- break;
-
- /* Check if device require AC*(i) settings */
- if (rc->count == 0x01)
- map.count = map.count >> 1;
+ ++n;
}
- }
- /* Fallback to no channel allocation since none could be matched. */
- if (!selected) {
- lpac->ops->select(lpac, rpac, 0, &rpac->qos, func, user_data,
- lpac->user_data);
- selected++;
- }
+ if (!allocation)
+ break;
- if (count)
- *count += selected;
+ /* Configure stream */
+ lpac->ops->select(lpac, rpac, allocation, &rpac->qos,
+ func, user_data, lpac->user_data);
+ if (count)
+ (*count)++;
+
+ locations &= ~allocation;
+ max_channels -= __builtin_popcount(allocation);
+ num_ase--;
+ }
return 0;
}
diff --git a/src/shared/bap.h b/src/shared/bap.h
index efeed604d..80e91f10a 100644
--- a/src/shared/bap.h
+++ b/src/shared/bap.h
@@ -172,9 +172,10 @@ void bt_bap_pac_set_user_data(struct bt_bap_pac *pac, void *user_data);
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,
- int *count, bt_bap_pac_select_t func,
- void *user_data);
+int bt_bap_select(struct bt_bap *bap,
+ struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
+ unsigned int max_channels, int *count,
+ bt_bap_pac_select_t func, void *user_data);
void bt_bap_cancel_select(struct bt_bap_pac *lpac, bt_bap_pac_select_t func,
void *user_data);
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v4 2/6] shared/bap: fix packet length comparison to ATT MTU in bap_queue_req()
2025-11-15 12:58 [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select() Pauli Virtanen
@ 2025-11-15 12:58 ` Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 3/6] bap: don't configure endpoints of all codecs at once Pauli Virtanen
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Pauli Virtanen @ 2025-11-15 12:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
bap_queue_req() forgot to account for ATT command headers when comparing
to MTU, and fail to send if packet too big. Fix the MTU comparison.
---
Notes:
v4:
- no change
v3:
- new patch, bug discovered in test
src/shared/bap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/shared/bap.c b/src/shared/bap.c
index b779f6716..27321a3d1 100644
--- a/src/shared/bap.c
+++ b/src/shared/bap.c
@@ -1730,7 +1730,7 @@ static bool bap_queue_req(struct bt_bap *bap, struct bt_bap_req *req)
struct queue *queue;
struct bt_att *att = bt_bap_get_att(bap);
uint16_t mtu = bt_att_get_mtu(att);
- uint16_t len = 2 + bap_req_len(req);
+ uint16_t len = 3 + 2 + bap_req_len(req);
if (len > mtu) {
DBG(bap, "Unable to queue request: req len %u > %u mtu", len,
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v4 3/6] bap: don't configure endpoints of all codecs at once
2025-11-15 12:58 [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select() Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 2/6] shared/bap: fix packet length comparison to ATT MTU in bap_queue_req() Pauli Virtanen
@ 2025-11-15 12:58 ` Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 4/6] shared/tester: better debug output on io memcmp failure Pauli Virtanen
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Pauli Virtanen @ 2025-11-15 12:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
When device is connected we currently try create all streams for all
endpoints. If there are multiple (= vendor codecs), this likely causes
creating multiple streams for same location, which is not allowed.
Change it to create streams only for the first endpoint, for each
direction.
Sound server can later request switching to another endpoint if
necessary.
---
Notes:
v4:
- no change
v3:
- no change
profiles/audio/bap.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/profiles/audio/bap.c b/profiles/audio/bap.c
index ec3502b06..b07d65e68 100644
--- a/profiles/audio/bap.c
+++ b/profiles/audio/bap.c
@@ -1922,7 +1922,10 @@ static bool pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
bt_bap_select(data->bap, lpac, rpac, 0, &select->remaining,
select_cb, ep);
- return true;
+ /* For initial configuration consider only one endpoint (for each
+ * direction).
+ */
+ return select->reconfigure;
}
static int bap_select_all(struct bap_data *data, bool reconfigure,
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v4 4/6] shared/tester: better debug output on io memcmp failure
2025-11-15 12:58 [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select() Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 2/6] shared/bap: fix packet length comparison to ATT MTU in bap_queue_req() Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 3/6] bap: don't configure endpoints of all codecs at once Pauli Virtanen
@ 2025-11-15 12:58 ` Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 5/6] test-bap: make PDU macros parametrizable Pauli Virtanen
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Pauli Virtanen @ 2025-11-15 12:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
---
Notes:
v4:
- no change
v3:
- new patch
src/shared/tester.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/shared/tester.c b/src/shared/tester.c
index d1e872b8f..1f59322bc 100644
--- a/src/shared/tester.c
+++ b/src/shared/tester.c
@@ -983,10 +983,11 @@ static bool test_io_recv(struct io *io, void *user_data)
if (test->iovcnt && !iov->iov_base)
iov = test_get_iov(test);
- g_assert_cmpint(len, ==, iov->iov_len);
+ if (memcmp(buf, iov->iov_base, len) || (size_t)len != iov->iov_len)
+ tester_monitor('!', 0x0004, 0x0000, iov->iov_base,
+ iov->iov_len);
- if (memcmp(buf, iov->iov_base, len))
- tester_monitor('!', 0x0004, 0x0000, iov->iov_base, len);
+ g_assert_cmpint(len, ==, iov->iov_len);
g_assert(memcmp(buf, iov->iov_base, len) == 0);
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v4 5/6] test-bap: make PDU macros parametrizable
2025-11-15 12:58 [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select() Pauli Virtanen
` (2 preceding siblings ...)
2025-11-15 12:58 ` [PATCH BlueZ v4 4/6] shared/tester: better debug output on io memcmp failure Pauli Virtanen
@ 2025-11-15 12:58 ` Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 6/6] test-bap: add audio configuration selection and streaming tests Pauli Virtanen
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: Pauli Virtanen @ 2025-11-15 12:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
Adjust PDU-forming macros, so that they can be used for connecting
multiple streams to parametrizable locations.
---
Notes:
v4:
- no change
v3:
- make parametrization more complete
unit/test-bap.c | 357 ++++++++++++++++++++++++++++++++++--------------
1 file changed, 258 insertions(+), 99 deletions(-)
diff --git a/unit/test-bap.c b/unit/test-bap.c
index c15afe52d..1a35aaf4a 100644
--- a/unit/test-bap.c
+++ b/unit/test-bap.c
@@ -122,6 +122,22 @@ static void client_ready_cb(bool success, uint8_t att_ecode, void *user_data)
}
/* GATT Discover All procedure */
+
+#define SNK_PAC_HND 0x03, 0x00
+#define SRC_PAC_HND 0x09, 0x00
+#define SNK_LOC_HND 0x06, 0x00
+#define SRC_LOC_HND 0x0c, 0x00
+#define CTX_HND 0x0f, 0x00
+#define SUP_CTX_HND 0x12, 0x00
+#define SNK_HND(i) (0x16 + 3*(i)), 0x00
+#define SRC_HND(i) (0x1c + 3*(i)), 0x00
+#define SNK_CCC_HND(i) (0x17 + 3*(i)), 0x00
+#define SRC_CCC_HND(i) (0x1d + 3*(i)), 0x00
+#define SNK_ID(i) (0x1 + (i))
+#define SRC_ID(i) (0x3 + (i))
+#define CP_HND 0x22, 0x00
+#define CP_CCC_HND 0x23, 0x00
+
static const struct iovec setup_data[] = {
/* ATT: Exchange MTU Response (0x03) len 2
* Server RX MTU: 64
@@ -933,16 +949,26 @@ static void test_teardown(const void *user_data)
* Front Left (0x00000001)
* Front Right (0x00000002)
*/
-#define DISC_SNK_PAC(_caps...) \
- IOV_DATA(0x0a, 0x03, 0x00), \
- IOV_DATA(0x0b, 0x01, _caps), \
- IOV_DATA(0x0a, 0x06, 0x00), \
- IOV_DATA(0x0b, 0x03, 0x00, 0x00, 0x00)
+
+#define IOV_CONTENT(data...) data
+
+#define DISC_SNK_PAC(_caps) \
+ IOV_DATA(0x0a, SNK_PAC_HND), \
+ IOV_DATA(0x0b, 0x01, _caps)
+
+#define DISC_SNK_LOC(locations) \
+ IOV_DATA(0x0a, SNK_LOC_HND), \
+ IOV_DATA(0x0b, locations & 0xff, (locations >> 8) & 0xff, \
+ (locations >> 16) & 0xff, (locations >> 24) & 0xff)
+
+#define LC3_PAC_CAPS(ch_counts) \
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
+ 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, ch_counts, 0x05, 0x04, \
+ 0x1a, 0x00, 0xf0, 0x00, 0x00
#define DISC_SNK_LC3 \
- DISC_SNK_PAC(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
- 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \
- 0x1a, 0x00, 0xf0, 0x00, 0x00)
+ DISC_SNK_PAC(LC3_PAC_CAPS(0x03)), \
+ DISC_SNK_LOC(0x00000003)
/* ATT: Read Request (0x0a) len 2
* Handle: 0x0009 Type: Source PAC (0x2bcb)
@@ -981,17 +1007,28 @@ static void test_teardown(const void *user_data)
* Front Left (0x00000001)
* Front Right (0x00000002)
*/
-#define DISC_SRC_PAC(_caps...) \
- DISC_SNK_PAC(_caps), \
- IOV_DATA(0x0a, 0x09, 0x00), \
- IOV_DATA(0x0b, 0x01, _caps), \
- IOV_DATA(0x0a, 0x0c, 0x00), \
- IOV_DATA(0x0b, 0x03, 0x00, 0x00, 0x00)
+#define DISC_SRC_PAC(_caps) \
+ IOV_DATA(0x0a, SRC_PAC_HND), \
+ IOV_DATA(0x0b, 0x01, _caps)
+
+#define DISC_SRC_LOC(locations) \
+ IOV_DATA(0x0a, SRC_LOC_HND), \
+ IOV_DATA(0x0b, locations & 0xff, (locations >> 8) & 0xff, \
+ (locations >> 16) & 0xff, (locations >> 24) & 0xff)
+
+#define DISC_PACS(snk_locations, src_locations, snk_caps, src_caps) \
+ DISC_SNK_PAC(IOV_CONTENT(snk_caps)), \
+ DISC_SNK_LOC(snk_locations), \
+ DISC_SRC_PAC(IOV_CONTENT(src_caps)), \
+ DISC_SRC_LOC(src_locations)
+
+#define DISC_PACS_NO_LOCATION(snk_caps, src_caps) \
+ DISC_SNK_PAC(IOV_CONTENT(snk_caps)), \
+ DISC_SRC_PAC(IOV_CONTENT(src_caps))
#define DISC_SRC_LC3 \
- DISC_SRC_PAC(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
- 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \
- 0x1a, 0x00, 0xf0, 0x00, 0x00)
+ DISC_PACS(0x00000003, 0x00000003, \
+ LC3_PAC_CAPS(0x03), LC3_PAC_CAPS(0x03))
/* ATT: Read Request (0x0a) len 2
* Handle: 0x000f Type: Available Audio Contexts (0x2bcd)
@@ -999,15 +1036,21 @@ static void test_teardown(const void *user_data)
* Value: ff0fff0f
* Handle: 0x000f Type: Available Audio Contexts (0x2bcd)
*/
-#define DISC_CTX(_caps...) \
- DISC_SRC_PAC(_caps), \
- IOV_DATA(0x0a, 0x0f, 0x00), \
+#define DISC_CTX(snk_locations, src_locations, snk_caps, src_caps) \
+ DISC_PACS(snk_locations, src_locations, \
+ IOV_CONTENT(snk_caps), IOV_CONTENT(src_caps)), \
+ IOV_DATA(0x0a, CTX_HND), \
+ IOV_DATA(0x0b, 0xff, 0x0f, 0xff, 0x0f)
+
+#define DISC_CTX_NO_LOCATION(snk_caps, src_caps) \
+ DISC_PACS_NO_LOCATION(IOV_CONTENT(snk_caps), \
+ IOV_CONTENT(src_caps)), \
+ IOV_DATA(0x0a, CTX_HND), \
IOV_DATA(0x0b, 0xff, 0x0f, 0xff, 0x0f)
#define DISC_CTX_LC3 \
- DISC_CTX(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
- 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \
- 0x1a, 0x00, 0xf0, 0x00, 0x00)
+ DISC_CTX(0x00000003, 0x00000003, \
+ LC3_PAC_CAPS(0x03), LC3_PAC_CAPS(0x03))
/* ATT: Read Request (0x0a) len 2
* Handle: 0x0012 Type: Supported Audio Contexts (0x2bce)
@@ -1015,15 +1058,20 @@ static void test_teardown(const void *user_data)
* Value: ff0fff0f
* Handle: 0x0012 Type: Supported Audio Contexts (0x2bce)
*/
-#define DISC_SUP_CTX(_caps...) \
- DISC_CTX(_caps), \
- IOV_DATA(0x0a, 0x12, 0x00), \
+#define DISC_SUP_CTX(snk_locations, src_locations, snk_caps, src_caps) \
+ DISC_CTX(snk_locations, src_locations, \
+ IOV_CONTENT(snk_caps), IOV_CONTENT(src_caps)), \
+ IOV_DATA(0x0a, SUP_CTX_HND), \
+ IOV_DATA(0x0b, 0xff, 0x0f, 0xff, 0x0f)
+
+#define DISC_SUP_CTX_NO_LOCATION(snk_caps, src_caps) \
+ DISC_CTX_NO_LOCATION(IOV_CONTENT(snk_caps), IOV_CONTENT(src_caps)), \
+ IOV_DATA(0x0a, SUP_CTX_HND), \
IOV_DATA(0x0b, 0xff, 0x0f, 0xff, 0x0f)
#define DISC_SUP_CTX_LC3 \
- DISC_SUP_CTX(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
- 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \
- 0x1a, 0x00, 0xf0, 0x00, 0x00)
+ DISC_SUP_CTX(0x00000003, 0x00000003, \
+ LC3_PAC_CAPS(0x03), LC3_PAC_CAPS(0x03))
/* ATT: Read Request (0x0a) len 2
* Handle: 0x0016 Type: Sink ASE (0x2bc4)
@@ -1046,21 +1094,29 @@ static void test_teardown(const void *user_data)
* Notification (0x01)
* ATT: Write Response (0x13) len 0
*/
-#define DISC_SNK_ASE(_caps...) \
- DISC_SUP_CTX(_caps), \
- IOV_DATA(0x0a, 0x16, 0x00), \
+#define DISC_SNK_ASE(snk_locations, src_locations, snk_caps, src_caps) \
+ DISC_SUP_CTX(snk_locations, src_locations, \
+ IOV_CONTENT(snk_caps), IOV_CONTENT(src_caps)), \
+ IOV_DATA(0x0a, SNK_HND(0)), \
IOV_DATA(0x0b, 0x01, 0x00), \
- IOV_DATA(0x12, 0x17, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x12, SNK_CCC_HND(0), 0x01, 0x00), \
IOV_DATA(0x13), \
- IOV_DATA(0x0a, 0x19, 0x00), \
+ IOV_DATA(0x0a, SNK_HND(1)), \
IOV_DATA(0x0b, 0x02, 0x00), \
- IOV_DATA(0x12, 0x1a, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x12, SNK_CCC_HND(1), 0x01, 0x00), \
+ IOV_DATA(0x13)
+
+#define DISC_SNK_ASE_NO_LOCATION(snk_caps, src_caps) \
+ DISC_SUP_CTX_NO_LOCATION(IOV_CONTENT(snk_caps), \
+ IOV_CONTENT(src_caps)), \
+ IOV_DATA(0x0a, SNK_HND(0)), \
+ IOV_DATA(0x0b, 0x01, 0x00), \
+ IOV_DATA(0x12, SNK_CCC_HND(0), 0x01, 0x00), \
IOV_DATA(0x13)
#define DISC_SNK_ASE_LC3 \
- DISC_SNK_ASE(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
- 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \
- 0x1a, 0x00, 0xf0, 0x00, 0x00)
+ DISC_SNK_ASE(0x00000003, 0x00000003, \
+ LC3_PAC_CAPS(0x03), LC3_PAC_CAPS(0x03))
/* ATT: Read Request (0x0a) len 2
* Handle: 0x001c Type: Source ASE (0x2bc5)
@@ -1088,23 +1144,33 @@ static void test_teardown(const void *user_data)
* Notification (0x01)
* ATT: Write Response (0x13) len 0
*/
-#define DISC_SRC_ASE(_cfg...) \
- DISC_SNK_ASE(_cfg), \
- IOV_DATA(0x0a, 0x1c, 0x00), \
+#define DISC_SRC_ASE(snk_locations, src_locations, snk_pacs, src_pacs) \
+ DISC_SNK_ASE(snk_locations, src_locations, \
+ IOV_CONTENT(snk_pacs), IOV_CONTENT(src_pacs)), \
+ IOV_DATA(0x0a, SRC_HND(0)), \
IOV_DATA(0x0b, 0x03, 0x00), \
- IOV_DATA(0x12, 0x1d, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x12, SRC_CCC_HND(0), 0x01, 0x00), \
IOV_DATA(0x13), \
- IOV_DATA(0x0a, 0x1f, 0x00), \
+ IOV_DATA(0x0a, SRC_HND(1)), \
IOV_DATA(0x0b, 0x04, 0x00), \
- IOV_DATA(0x12, 0x20, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x12, SRC_CCC_HND(1), 0x01, 0x00), \
IOV_DATA(0x13), \
- IOV_DATA(0x12, 0x23, 0x00, 0x01, 0x00), \
+ IOV_DATA(0x12, CP_CCC_HND, 0x01, 0x00), \
+ IOV_DATA(0x13)
+
+#define DISC_SRC_ASE_NO_LOCATION(snk_pacs, src_pacs) \
+ DISC_SNK_ASE_NO_LOCATION(IOV_CONTENT(snk_pacs), \
+ IOV_CONTENT(src_pacs)), \
+ IOV_DATA(0x0a, SRC_HND(0)), \
+ IOV_DATA(0x0b, 0x03, 0x00), \
+ IOV_DATA(0x12, SRC_CCC_HND(0), 0x01, 0x00), \
+ IOV_DATA(0x13), \
+ IOV_DATA(0x12, CP_CCC_HND, 0x01, 0x00), \
IOV_DATA(0x13)
#define DISC_SRC_ASE_LC3 \
- DISC_SRC_ASE(0x06, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x01, \
- 0xff, 0x00, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x05, 0x04, \
- 0x1a, 0x00, 0xf0, 0x00, 0x00)
+ DISC_SRC_ASE(0x00000003, 0x00000003, \
+ LC3_PAC_CAPS(0x03), LC3_PAC_CAPS(0x03))
#define DISC_ASE_LC3 \
DISC_SNK_ASE_LC3, \
@@ -1251,17 +1317,33 @@ static void test_disc(void)
* Handle: 0x0016
* Data: 01010002010a00204e00409c00204e00409c00_cfg
*/
-#define SCC_SNK(_cfg...) \
- IOV_DATA(0x52, 0x22, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, _cfg), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00), \
+
+#define SCC_PDU(count) \
+ 0x52, CP_HND, 0x01, (count)
+
+#define SCC_PDU_ASE(id, _cfg...) \
+ id, 0x02, 0x02, _cfg
+
+#define SCC_ASE(id, _cfg...) \
+ IOV_DATA(SCC_PDU(1), SCC_PDU_ASE(id, _cfg)), \
+ IOV_DATA(0x1b, CP_HND, 0x01, 0x01, id, 0x00, 0x00)
+
+#define SCC_SNK_NOTIFY(i, _cfg...) \
IOV_NULL, \
- IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x01, 0x00, 0x02, 0x01, 0x0a, 0x00, \
+ IOV_DATA(0x1b, SNK_HND(i), SNK_ID(i), 0x01, \
+ 0x00, 0x02, 0x01, 0x0a, 0x00, \
0x20, 0x4e, 0x00, 0x40, 0x9c, 0x00, 0x20, 0x4e, 0x00, \
0x40, 0x9c, 0x00, _cfg)
+#define SCC_SNK(_cfg...) \
+ SCC_ASE(SNK_ID(0), _cfg), SCC_SNK_NOTIFY(0, _cfg)
+
+#define LC3_CODEC_ID_DATA \
+ 0x06, 0x00, 0x00, 0x00, 0x00
+
#define SCC_SNK_LC3(_cc...) \
DISC_SRC_ASE_LC3, \
- SCC_SNK(0x06, 0x00, 0x00, 0x00, 0x00, _cc)
+ SCC_SNK(LC3_CODEC_ID_DATA, _cc)
#define QOS_BALANCED_2M \
{ \
@@ -1442,14 +1524,18 @@ static struct test_config cfg_snk_48_6 = {
* Handle: 0x001c
* Data: 03010002010a00204e00409c00204e00409c00_cfg
*/
-#define SCC_SRC(_cfg...) \
- IOV_DATA(0x52, 0x22, 0x00, 0x01, 0x01, 0x03, 0x02, 0x02, _cfg), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00), \
+
+#define SCC_SRC_NOTIFY(i, _cfg...) \
IOV_NULL, \
- IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x01, 0x00, 0x02, 0x01, 0x0a, 0x00, \
+ IOV_DATA(0x1b, SRC_HND(i), SRC_ID(i), 0x01, \
+ 0x00, 0x02, 0x01, 0x0a, 0x00, \
0x20, 0x4e, 0x00, 0x40, 0x9c, 0x00, 0x20, 0x4e, 0x00, \
0x40, 0x9c, 0x00, _cfg)
+#define SCC_SRC(_cfg...) \
+ SCC_ASE(SRC_ID(0), _cfg), \
+ SCC_SRC_NOTIFY(0, _cfg)
+
#define SCC_SRC_LC3(_cc...) \
DISC_SRC_ASE_LC3, \
SCC_SRC(0x06, 0x00, 0x00, 0x00, 0x00, _cc)
@@ -1867,12 +1953,23 @@ static struct test_config cfg_snk_vs = {
.vs = true,
};
+#define VS_PAC_CAPS(ch_count) \
+ 0xff, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02, 0x03, ch_count, \
+ 0x00
+
+#define VS_PAC_CAPS_NO_COUNT \
+ 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00
+
#define DISC_SRC_ASE_VS \
- DISC_SRC_ASE(0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00)
+ DISC_SRC_ASE(0x00000003, 0x00000003, \
+ VS_PAC_CAPS_NO_COUNT, VS_PAC_CAPS_NO_COUNT)
+
+#define VS_CODEC_ID_DATA \
+ 0xff, 0x01, 0x00, 0x01, 0x00
#define SCC_SNK_VS \
DISC_SRC_ASE_VS, \
- SCC_SNK(0xff, 0x01, 0x00, 0x01, 0x00, 0x00)
+ SCC_SNK(VS_CODEC_ID_DATA, 0x00)
static struct test_config cfg_src_vs = {
.cc = IOV_NULL,
@@ -2066,11 +2163,24 @@ static struct test_config cfg_snk_48_6_1 = {
* Handle: 0x0016
* Data: 01010102010a00204e00409c00204e00409c00_qos
*/
-#define QOS_SNK(_qos...) \
- IOV_DATA(0x52, 0x22, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00, _qos), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x02, 0x01, 0x01, 0x00, 0x00), \
+
+#define QOS_PDU(count) \
+ 0x52, CP_HND, 0x02, (count)
+
+#define QOS_PDU_ASE(id, cis, _qos...) \
+ id, 0x00, cis, _qos
+
+#define QOS_ASE(id, cis, _qos...) \
+ IOV_DATA(QOS_PDU(1), QOS_PDU_ASE(id, cis, _qos)), \
+ IOV_DATA(0x1b, CP_HND, 0x02, 0x01, id, 0x00, 0x00)
+
+#define QOS_SNK_NOTIFY(i, cis, _qos...) \
IOV_NULL, \
- IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x02, 0x00, 0x00, _qos)
+ IOV_DATA(0x1b, SNK_HND(i), SNK_ID(i), 0x02, 0x00, cis, _qos)
+
+#define QOS_SNK(_qos...) \
+ QOS_ASE(SNK_ID(0), 0, _qos), \
+ QOS_SNK_NOTIFY(0, 0, _qos)
#define SCC_SNK_8_1_1 \
SCC_SNK_8_1, \
@@ -2274,16 +2384,22 @@ static struct test_config cfg_src_48_6_1 = {
* Handle: 0x001c
* Data: 03010102010a00204e00409c00204e00409c00_qos
*/
-#define QOS_SRC(_qos...) \
- IOV_DATA(0x52, 0x22, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, _qos), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00), \
+
+#define QOS_SRC_NOTIFY(i, cis, _qos...) \
IOV_NULL, \
- IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x02, 0x00, 0x00, _qos)
+ IOV_DATA(0x1b, SRC_HND(i), SRC_ID(i), 0x02, 0x00, cis, _qos)
+
+#define QOS_SRC(_qos...) \
+ QOS_ASE(SRC_ID(0), 0, _qos), \
+ QOS_SRC_NOTIFY(0, 0, _qos)
+
+#define QOS_SRC_8_1_1_DATA \
+ 0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1a, 0x00, 0x02, 0x08, 0x00, \
+ 0x40, 0x9c, 0x00
#define SCC_SRC_8_1_1 \
SCC_SRC_8_1, \
- QOS_SRC(0x4c, 0x1d, 0x00, 0x00, 0x02, 0x1a, 0x00, 0x02, 0x08, 0x00, \
- 0x40, 0x9c, 0x00)
+ QOS_SRC(QOS_SRC_8_1_1_DATA)
#define SCC_SRC_8_2_1 \
SCC_SRC_8_2, \
@@ -3252,14 +3368,31 @@ static struct test_config cfg_snk_enable = {
* Handle: 0x0016
* Data: 0101010300403020100
*/
+
+#define ENABLE_PDU(count) \
+ 0x52, CP_HND, 0x03, (count)
+
+#define ENABLE_PDU_ASE(id) \
+ id, 0x04, 0x03, 0x02, 0x01, 00
+
+#define ENABLE_ASE(id) \
+ IOV_DATA(ENABLE_PDU(1), ENABLE_PDU_ASE(id)), \
+ IOV_DATA(0x1b, CP_HND, 0x03, 0x01, id, 0x00, 0x00)
+
+#define SNK_ENABLE_NOTIFY(i, cis) \
+ IOV_NULL, \
+ IOV_DATA(0x1b, SNK_HND(i), SNK_ID(i), 0x03, \
+ 0x00, cis, 0x04, 0x03, 0x02, 0x01, 0x00)
+
+#define SNK_START_NOTIFY(i, cis) \
+ IOV_NULL, \
+ IOV_DATA(0x1b, SNK_HND(i), SNK_ID(i), 0x04, \
+ 0x00, cis, 0x04, 0x03, 0x02, 0x01, 0x00)
+
#define SCC_SNK_ENABLE \
SCC_SNK_16_2_1, \
- IOV_DATA(0x52, 0x22, 0x00, 0x03, 0x01, 0x01, 0x04, 0x03, 0x02, 0x01, \
- 00), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x03, 0x01, 0x01, 0x00, 0x00), \
- IOV_NULL, \
- IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x03, 0x00, 0x00, 0x04, 0x03, 0x02, \
- 0x01, 0x00)
+ ENABLE_ASE(SNK_ID(0)), \
+ SNK_ENABLE_NOTIFY(0, 0)
static struct test_config cfg_src_enable = {
.cc = LC3_CONFIG_16_2,
@@ -3278,17 +3411,19 @@ static struct test_config cfg_src_enable = {
* Handle: 0x001c
* Data: 030300000403020100
*/
-#define SRC_ENABLE \
- IOV_DATA(0x52, 0x22, 0x00, 0x03, 0x01, 0x03, 0x04, 0x03, 0x02, 0x01, \
- 00), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x03, 0x01, 0x03, 0x00, 0x00), \
+#define SRC_ENABLE_NOTIFY(i, cis) \
IOV_NULL, \
- IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x03, 0x00, 0x00, 0x04, 0x03, 0x02, \
- 0x01, 0x00)
+ IOV_DATA(0x1b, SRC_HND(i), SRC_ID(i), 0x03, \
+ 0x00, cis, 0x04, 0x03, 0x02, 0x01, 0x00)
+
+#define SRC_ENABLE \
+ ENABLE_ASE(SRC_ID(0)), \
+ SRC_ENABLE_NOTIFY(0, 0)
#define SCC_SRC_ENABLE \
SCC_SRC_16_2_1, \
- SRC_ENABLE
+ ENABLE_ASE(SRC_ID(0)), \
+ SRC_ENABLE_NOTIFY(0, 0)
/* Test Purpose:
* Verify that a Unicast Client IUT can initiate an Enable operation for an ASE
@@ -3353,17 +3488,28 @@ static struct test_config cfg_snk_disable = {
* Handle: 0x0016
* Data: 01010102010a00204e00409c00204e00409c00_qos
*/
-#define ASE_SNK_DISABLE \
- IOV_DATA(0x52, 0x22, 0x00, 0x05, 0x01, 0x01), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x05, 0x01, 0x01, 0x00, 0x00), \
+
+#define DISABLE_PDU(count) \
+ 0x52, CP_HND, 0x05, (count)
+
+#define DISABLE_ASE(id) \
+ IOV_DATA(DISABLE_PDU(1), id), \
+ IOV_DATA(0x1b, CP_HND, 0x05, 0x01, id, 0x00, 0x00)
+
+#define SNK_DISABLE_NOTIFY(i, cis) \
IOV_NULL, \
- IOV_DATA(0x1b, 0x16, 0x00, 0x01, 0x02, 0x00, 0x00, 0x10, 0x27, 0x00, \
+ IOV_DATA(0x1b, SNK_HND(i), SNK_ID(i), 0x02, \
+ 0x00, cis, 0x10, 0x27, 0x00, \
0x00, 0x02, 0x28, 0x00, 0x02, 0x0a, 0x00, 0x40, 0x9c, \
0x00)
+#define SNK_DISABLE \
+ DISABLE_ASE(SNK_ID(0)), \
+ SNK_DISABLE_NOTIFY(0, 0)
+
#define SCC_SNK_DISABLE \
SCC_SNK_ENABLE, \
- ASE_SNK_DISABLE
+ SNK_DISABLE
static struct test_config cfg_src_disable = {
.cc = LC3_CONFIG_16_2,
@@ -3382,15 +3528,19 @@ static struct test_config cfg_src_disable = {
* Handle: 0x001c
* Data: 030300000403020100
*/
-#define ASE_SRC_DISABLE \
- IOV_DATA(0x52, 0x22, 0x00, 0x05, 0x01, 0x03), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x05, 0x01, 0x03, 0x00, 0x00), \
+
+#define SRC_DISABLE_NOTIFY(i, cis) \
IOV_NULL, \
- IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x05, 0x00, 0x00, 0x04, 0x03, 0x02, \
- 0x01, 0x00)
+ IOV_DATA(0x1b, SRC_HND(i), SRC_ID(i), 0x05, \
+ 0x00, cis, 0x04, 0x03, 0x02, 0x01, 0x00)
+
+#define SRC_DISABLE \
+ DISABLE_ASE(SRC_ID(0)), \
+ SRC_DISABLE_NOTIFY(0, 0)
+
#define SCC_SRC_DISABLE \
SCC_SRC_ENABLE, \
- ASE_SRC_DISABLE
+ SRC_DISABLE
static void state_start_disable(struct bt_bap_stream *stream,
uint8_t old_state, uint8_t new_state,
@@ -3426,17 +3576,26 @@ static struct test_config cfg_src_disable_streaming = {
* Handle: 0x0016
* Data: 0101010400403020100
*/
-#define SRC_START \
- IOV_DATA(0x52, 0x22, 0x00, 0x04, 0x01, 0x03), \
- IOV_DATA(0x1b, 0x22, 0x00, 0x04, 0x01, 0x03, 0x00, 0x00), \
+#define START_PDU(count) \
+ 0x52, CP_HND, 0x04, (count)
+
+#define START_ASE(id) \
+ IOV_DATA(START_PDU(1), id), \
+ IOV_DATA(0x1b, CP_HND, 0x04, 0x01, id, 0x00, 0x00)
+
+#define SRC_START_NOTIFY(i, cis) \
IOV_NULL, \
- IOV_DATA(0x1b, 0x1c, 0x00, 0x03, 0x04, 0x00, 0x00, 0x04, 0x03, 0x02, \
- 0x01, 0x00)
+ IOV_DATA(0x1b, SRC_HND(i), SRC_ID(i), 0x04, \
+ 0x00, cis, 0x04, 0x03, 0x02, 0x01, 0x00)
+
+#define SRC_START \
+ START_ASE(SRC_ID(0)), \
+ SRC_START_NOTIFY(0, 0)
#define SCC_SRC_DISABLE_STREAMING \
SCC_SRC_ENABLE, \
SRC_START, \
- ASE_SRC_DISABLE
+ SRC_DISABLE
/* Test Purpose:
* Verify that a Unicast Client IUT can initiate a Disable operation for an ASE
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH BlueZ v4 6/6] test-bap: add audio configuration selection and streaming tests
2025-11-15 12:58 [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select() Pauli Virtanen
` (3 preceding siblings ...)
2025-11-15 12:58 ` [PATCH BlueZ v4 5/6] test-bap: make PDU macros parametrizable Pauli Virtanen
@ 2025-11-15 12:58 ` Pauli Virtanen
2025-11-15 14:03 ` [BlueZ,v4,1/6] shared/bap: fix channel allocation logic in bt_bap_select() bluez.test.bot
2025-11-17 19:10 ` [PATCH BlueZ v4 1/6] " patchwork-bot+bluetooth
6 siblings, 0 replies; 8+ messages in thread
From: Pauli Virtanen @ 2025-11-15 12:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Pauli Virtanen
Add tests from BAP.TS 4.10.
The tests testing (ii) configurations only test configuration selection
with L/R separately. Can be filled in later to use two simultaneous BAP.
The difference between CIS Establishment at QoS vs. Enable is not
properly simulated, so only one variant is added.
---
Notes:
v4:
- fix missing errno.h #include apparently needed on some platforms
v3:
- add most of the streaming tests
unit/test-bap.c | 1475 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 1469 insertions(+), 6 deletions(-)
diff --git a/unit/test-bap.c b/unit/test-bap.c
index 1a35aaf4a..83457bc7b 100644
--- a/unit/test-bap.c
+++ b/unit/test-bap.c
@@ -18,6 +18,7 @@
#include <string.h>
#include <sys/socket.h>
#include <fcntl.h>
+#include <errno.h>
#include <glib.h>
@@ -34,8 +35,11 @@
#include "src/shared/bap.h"
#include "src/shared/lc3.h"
+#define FAIL_TEST() \
+ do { tester_warn("%s:%d: failed in %s", __FILE__, __LINE__, __func__); \
+ tester_test_failed(); } while (0)
+
struct test_config {
- struct bt_bap_pac_qos pqos;
struct iovec cc;
struct iovec base;
struct bt_bap_qos qos;
@@ -45,6 +49,12 @@ struct test_config {
uint8_t state;
bt_bap_state_func_t state_func;
uint8_t streams;
+ uint32_t snk_locations[4];
+ uint32_t src_locations[4];
+ struct bt_bap_pac_qos *pac_qos;
+ struct iovec *pac_caps;
+ const struct iovec *setup_data;
+ size_t setup_data_len;
};
struct test_data {
@@ -65,6 +75,7 @@ struct test_data {
struct queue *streams;
size_t iovcnt;
struct iovec *iov;
+ int fds[8][2];
};
struct notify {
@@ -106,6 +117,10 @@ static struct bt_bap_pac_qos lc3_qos = {
data.caps = &lc3_caps; \
data.qos = &lc3_qos; \
data.cfg = _cfg; \
+ if (data.cfg && data.cfg->pac_caps) \
+ data.caps = data.cfg->pac_caps; \
+ if (data.cfg && data.cfg->pac_qos) \
+ data.qos = data.cfg->pac_qos; \
data.iovcnt = ARRAY_SIZE(iov_data(args)); \
data.iov = util_iov_dup(iov, ARRAY_SIZE(iov_data(args))); \
data.streams = queue_new(); \
@@ -342,6 +357,201 @@ static const struct iovec setup_data[] = {
IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a),
};
+static const struct iovec setup_data_no_location[] = {
+ /* ATT: Exchange MTU Response (0x03) len 2
+ * Server RX MTU: 64
+ */
+ IOV_DATA(0x02, 0x40, 0x00),
+ /* ATT: Exchange MTU Request (0x02) len 2
+ * Client RX MTU: 64
+ */
+ IOV_DATA(0x03, 0x40, 0x00),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute type: Server Supported Features (0x2b3a)
+ */
+ IOV_DATA(0x08, 0x01, 0x00, 0xff, 0xff, 0x3a, 0x2b),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Type Request (0x08)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a),
+ /*
+ * ATT: Read By Group Type Request (0x10) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute group type: Primary Service (0x2800)
+ */
+ IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28),
+ /*
+ * ATT: Read By Group Type Response (0x11) len 37
+ * Attribute data length: 6
+ * Attribute group list: 2 entries
+ * Handle range: 0x0001-0x0013
+ * UUID: Published Audio Capabilities (0x1850)
+ * Handle range: 0x0014-0x0023
+ * UUID: Audio Stream Control (0x184e)
+ */
+ IOV_DATA(0x11, 0x06,
+ 0x01, 0x00, 0x13, 0x00, 0x50, 0x18,
+ 0x14, 0x00, 0x23, 0x00, 0x4e, 0x18),
+ /* ATT: Read By Group Type Request (0x10) len 6
+ * Handle range: 0x0024-0xffff
+ * Attribute group type: Primary Service (0x2800)
+ */
+ IOV_DATA(0x10, 0x24, 0x00, 0xff, 0xff, 0x00, 0x28),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Group Type Request (0x10)
+ * Handle: 0x0024
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x10, 0x24, 0x00, 0x0a),
+ /* ATT: Read By Group Type Request (0x10) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute group type: Secondary Service (0x2801)
+ */
+ IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x01, 0x28),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Group Type Request (0x10)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x10, 0x01, 0x00, 0x0a),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0x0023
+ * Attribute group type: Include (0x2802)
+ */
+ IOV_DATA(0x08, 0x01, 0x00, 0x23, 0x00, 0x02, 0x28),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Group Type Request (0x10)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0x0023
+ * Attribute type: Characteristic (0x2803)
+ */
+ IOV_DATA(0x08, 0x01, 0x00, 0x23, 0x00, 0x03, 0x28),
+ /* ATT: Read By Type Response (0x09) len 57
+ * Attribute data length: 7
+ * Attribute data list: 8 entries
+ * Handle: 0x0002
+ * Value: 120300c92b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0003
+ * Value UUID: Sink PAC (0x2bc9)
+ * Handle: 0x0008
+ * Value: 120900cb2b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0009
+ * Value UUID: Source PAC (0x2bcb)
+ * Handle: 0x000e
+ * Value: 120f00cd2b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x000f
+ * Value UUID: Available Audio Contexts (0x2bcd)
+ * Handle: 0x0011
+ * Value: 121200ce2b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0012
+ * Value UUID: Supported Audio Contexts (0x2bce)
+ * Handle: 0x0015
+ * Value: 121600c42b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x0016
+ * Value UUID: Sink ASE (0x2bc4)
+ * Handle: 0x001b
+ * Value: 121c00c52b
+ * Properties: 0x12
+ * Read (0x02)
+ * Notify (0x10)
+ * Value Handle: 0x001c
+ * Value UUID: Source ASE (0x2bc5)
+ * Handle: 0x0021
+ * Value: 182200c62b
+ * Properties: 0x18
+ * Write (0x08)
+ * Notify (0x10)
+ * Value Handle: 0x0022
+ * Value UUID: ASE Control Point (0x2bc6)
+ */
+ IOV_DATA(0x09, 0x07,
+ /* keep same IDs as above, leaving holes */
+ 0x02, 0x00, 0x12, 0x03, 0x00, 0xc9, 0x2b,
+ 0x08, 0x00, 0x12, 0x09, 0x00, 0xcb, 0x2b,
+ 0x0e, 0x00, 0x12, 0x0f, 0x00, 0xcd, 0x2b,
+ 0x11, 0x00, 0x12, 0x12, 0x00, 0xce, 0x2b,
+ 0x15, 0x00, 0x12, 0x16, 0x00, 0xc4, 0x2b,
+ 0x1b, 0x00, 0x12, 0x1c, 0x00, 0xc5, 0x2b,
+ 0x21, 0x00, 0x18, 0x22, 0x00, 0xc6, 0x2b),
+ /* ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0022-0x0023
+ * Attribute type: Characteristic (0x2803)
+ */
+ IOV_DATA(0x08, 0x22, 0x00, 0x23, 0x00, 0x03, 0x28),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Type Request (0x08)
+ * Handle: 0x0022
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x08, 0x22, 0x00, 0x0a),
+ /* ATT: Find Information Request (0x04) */
+ IOV_DATA(0x04, 0x04, 0x00, 0x07, 0x00),
+ /* ATT: Find Information Response (0x05): CCC */
+ IOV_DATA(0x05, 0x01, 0x04, 0x00, 0x02, 0x29),
+ /* ATT: Find Information Request (0x04) */
+ IOV_DATA(0x04, 0x05, 0x00, 0x07, 0x00),
+ /* ATT: Error Response */
+ IOV_DATA(0x01, 0x04, 0x05, 0x00, 0x0a),
+ /* ATT: Find Information Request (0x04) */
+ IOV_DATA(0x04, 0x0a, 0x00, 0x0d, 0x00),
+ /* ATT: Find Information Response (0x05): CCC */
+ IOV_DATA(0x05, 0x01, 0x0a, 0x00, 0x02, 0x29),
+ /* ATT: Find Information Request (0x04) */
+ IOV_DATA(0x04, 0x0b, 0x00, 0x0d, 0x00),
+ /* ATT: Error Response */
+ IOV_DATA(0x01, 0x04, 0x0b, 0x00, 0x0a),
+ /* ATT: Find Information Request (0x04) */
+ IOV_DATA(0x04, 0x17, 0x00, 0x1a, 0x00),
+ /* ATT: Find Information Response (0x05): CCC */
+ IOV_DATA(0x05, 0x01, 0x17, 0x00, 0x02, 0x29),
+ /* ATT: Find Information Request (0x04) */
+ IOV_DATA(0x04, 0x18, 0x00, 0x1a, 0x00),
+ /* ATT: Error Response */
+ IOV_DATA(0x01, 0x04, 0x1a, 0x00, 0x0a),
+ /* ATT: Find Information Request (0x04) */
+ IOV_DATA(0x04, 0x1d, 0x00, 0x20, 0x00),
+ /* ATT: Find Information Response (0x05): CCC */
+ IOV_DATA(0x05, 0x01, 0x1d, 0x00, 0x02, 0x29),
+ /* ATT: Find Information Request (0x04) */
+ IOV_DATA(0x04, 0x1e, 0x00, 0x20, 0x00),
+ /* ATT: Error Response */
+ IOV_DATA(0x01, 0x04, 0x1e, 0x00, 0x0a),
+ /* ACL Data TX: Handle 42 flags 0x00 dlen 11
+ * ATT: Read By Type Request (0x08) len 6
+ * Handle range: 0x0001-0xffff
+ * Attribute type: Database Hash (0x2b2a)
+ */
+ IOV_DATA(0x08, 0x01, 0x00, 0xff, 0xff, 0x2a, 0x2b),
+ /* ATT: Error Response (0x01) len 4
+ * Read By Type Request (0x08)
+ * Handle: 0x0001
+ * Error: Attribute Not Found (0x0a)
+ */
+ IOV_DATA(0x01, 0x08, 0x01, 0x00, 0x0a),
+};
+
static void print_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
@@ -357,7 +567,11 @@ static void test_setup(const void *user_data)
struct gatt_db *db;
struct io *io;
- io = tester_setup_io(setup_data, ARRAY_SIZE(setup_data));
+ if (!data->cfg || !data->cfg->setup_data)
+ io = tester_setup_io(setup_data, ARRAY_SIZE(setup_data));
+ else
+ io = tester_setup_io(data->cfg->setup_data,
+ data->cfg->setup_data_len);
g_assert(io);
att = bt_att_new(io_get_fd(io), false);
@@ -471,11 +685,13 @@ static void test_setup_pacs(struct test_data *data)
"test-bap-snk",
BT_BAP_SINK, 0x0ff,
0x0001, 0x0001,
- NULL, data->caps, NULL);
+ data->qos, data->caps,
+ NULL);
else
data->snk = bt_bap_add_pac(data->db, "test-bap-snk",
BT_BAP_SINK, LC3_ID,
- NULL, data->caps, NULL);
+ data->qos, data->caps,
+ NULL);
g_assert(data->snk);
}
@@ -485,11 +701,13 @@ static void test_setup_pacs(struct test_data *data)
"test-bap-src",
BT_BAP_SOURCE, 0x0ff,
0x0001, 0x0001,
- NULL, data->caps, NULL);
+ data->qos, data->caps,
+ NULL);
else
data->src = bt_bap_add_pac(data->db, "test-bap-src",
BT_BAP_SOURCE, LC3_ID,
- NULL, data->caps, NULL);
+ data->qos, data->caps,
+ NULL);
g_assert(data->src);
}
}
@@ -891,6 +1109,7 @@ static void test_bcast(const void *user_data)
static void test_teardown(const void *user_data)
{
struct test_data *data = (void *)user_data;
+ unsigned int i, j;
bt_bap_unregister(data->id);
bt_bap_unref(data->bap);
@@ -899,6 +1118,15 @@ static void test_teardown(const void *user_data)
util_iov_free(data->base, 1);
+ for (i = 0; i < ARRAY_SIZE(data->fds); ++i) {
+ for (j = 0; j < ARRAY_SIZE(data->fds[0]); ++j) {
+ if (data->fds[i][j] > 0) {
+ close(data->fds[i][j]);
+ data->fds[i][j] = -1;
+ }
+ }
+ }
+
bt_bap_remove_pac(data->snk);
bt_bap_remove_pac(data->src);
bt_bap_remove_pac(data->bsrc);
@@ -8792,6 +9020,1240 @@ static void test_bsrc_str(void)
test_bsrc_str_2b();
}
+/*
+ * Configuration selection: check example cases for BAP AC.
+ */
+
+#define LC3_PAC_CAPS_NO_COUNT \
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x03, 0x01, \
+ 0xff, 0x00, 0x02, 0x02, 0x03, 0x05, 0x04, \
+ 0x1a, 0x00, 0xf0, 0x00, 0x00
+
+#define UNKNOWN_PAC_CAPS \
+ 0xff, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00
+
+#define DISC_SNK_ONLY(loc, caps) \
+ DISC_SRC_ASE(loc, 0, IOV_CONTENT(caps), UNKNOWN_PAC_CAPS)
+
+#define DISC_SNK_ONLY_NO_LOC(caps) \
+ DISC_SRC_ASE_NO_LOCATION(IOV_CONTENT(caps), UNKNOWN_PAC_CAPS)
+
+#define DISC_SRC_ONLY(loc, caps) \
+ DISC_SRC_ASE(0, loc, UNKNOWN_PAC_CAPS, IOV_CONTENT(caps))
+
+#define DISC_SRC_ONLY_NO_LOC(caps) \
+ DISC_SRC_ASE_NO_LOCATION(UNKNOWN_PAC_CAPS, IOV_CONTENT(caps))
+
+#define STR_SCC_DATA(challoc, codec_id...) \
+ /* NOTE: only channel allocation in CC for simplicity */ \
+ codec_id, 0x06, 0x05, 0x03, \
+ challoc & 0xff, (challoc >> 8) & 0xff, \
+ (challoc >> 16) & 0xff, (challoc >> 24) & 0xff
+
+#define STR_SNK_STREAMING(challoc, codec_id...) \
+ SCC_SNK(STR_SCC_DATA(challoc, codec_id)), \
+ QOS_SNK(QOS_SRC_8_1_1_DATA), \
+ SNK_ENABLE, \
+ SNK_START_NOTIFY(0, 0)
+
+#define STR_SRC_STREAMING(challoc, codec_id...) \
+ SCC_SRC(STR_SCC_DATA(challoc, codec_id)), \
+ QOS_SRC(QOS_SRC_8_1_1_DATA), \
+ SRC_ENABLE, \
+ SRC_START
+
+#define STR_SNK_STREAMING_LC3(challoc) \
+ STR_SNK_STREAMING(challoc, LC3_CODEC_ID_DATA)
+
+#define STR_SRC_STREAMING_LC3(challoc) \
+ STR_SRC_STREAMING(challoc, LC3_CODEC_ID_DATA)
+
+#define STR_SNK_STREAMING_VS(challoc) \
+ STR_SNK_STREAMING(challoc, VS_CODEC_ID_DATA)
+
+#define STR_SRC_STREAMING_VS(challoc) \
+ STR_SRC_STREAMING(challoc, VS_CODEC_ID_DATA)
+
+#define SCC_ASE2(id1, id2, ch1, ch2, codec_id...) \
+ IOV_DATA(SCC_PDU(2), \
+ SCC_PDU_ASE(id1, STR_SCC_DATA(ch1, codec_id)), \
+ SCC_PDU_ASE(id2, STR_SCC_DATA(ch2, codec_id))), \
+ IOV_DATA(0x1b, CP_HND, 0x01, 0x02, id1, 0x00, 0x00, id2, 0x00, 0x00)
+
+#define SCC_ASE3(id1, id2, id3, ch1, ch2, ch3, codec_id...) \
+ IOV_DATA(SCC_PDU(3), \
+ SCC_PDU_ASE(id1, STR_SCC_DATA(ch1, codec_id)), \
+ SCC_PDU_ASE(id2, STR_SCC_DATA(ch2, codec_id)), \
+ SCC_PDU_ASE(id3, STR_SCC_DATA(ch3, codec_id))), \
+ IOV_DATA(0x1b, CP_HND, 0x01, 0x03, id1, 0x00, 0x00, id2, 0x00, 0x00, \
+ id3, 0x00, 0x00)
+
+#define QOS_ASE2(id1, id2, cis1, cis2, _qos...) \
+ IOV_DATA(QOS_PDU(2), QOS_PDU_ASE(id1, cis1, _qos), \
+ QOS_PDU_ASE(id2, cis2, _qos)), \
+ IOV_DATA(0x1b, CP_HND, 0x02, 0x02, id1, 0x00, 0x00, id2, 0x00, 0x00)
+
+#define QOS_ASE3(id1, id2, id3, cis1, cis2, cis3, _qos...) \
+ IOV_DATA(QOS_PDU(3), QOS_PDU_ASE(id1, cis1, _qos), \
+ QOS_PDU_ASE(id2, cis2, _qos), \
+ QOS_PDU_ASE(id3, cis3, _qos)), \
+ IOV_DATA(0x1b, CP_HND, 0x02, 0x03, id1, 0x00, 0x00, id2, 0x00, 0x00, \
+ id3, 0x00, 0x00)
+
+#define ENABLE_ASE2(id1, id2) \
+ IOV_DATA(ENABLE_PDU(2), ENABLE_PDU_ASE(id1), ENABLE_PDU_ASE(id2)), \
+ IOV_DATA(0x1b, CP_HND, 0x03, 0x02, id1, 0x00, 0x00, id2, 0x00, 0x00)
+
+#define ENABLE_ASE3(id1, id2, id3) \
+ IOV_DATA(ENABLE_PDU(3), ENABLE_PDU_ASE(id1), ENABLE_PDU_ASE(id2), \
+ ENABLE_PDU_ASE(id3)), \
+ IOV_DATA(0x1b, CP_HND, 0x03, 0x03, id1, 0x00, 0x00, id2, 0x00, 0x00, \
+ id3, 0x00, 0x00)
+
+#define ENABLE_ASE4(id1, id2, id3, id4) \
+ IOV_DATA(ENABLE_PDU(4), ENABLE_PDU_ASE(id1), ENABLE_PDU_ASE(id2), \
+ ENABLE_PDU_ASE(id3), ENABLE_PDU_ASE(id4)), \
+ IOV_DATA(0x1b, CP_HND, 0x03, 0x03, id1, 0x00, 0x00, id2, 0x00, 0x00, \
+ id3, 0x00, 0x00, id4, 0x00, 0x00)
+
+#define START_ASE2(id1, id2) \
+ IOV_DATA(START_PDU(2), id1, id2), \
+ IOV_DATA(0x1b, CP_HND, 0x04, 0x02, id1, 0x00, 0x00, id2, 0x00, 0x00)
+
+#define STR_SNK_SRC_STREAMING(cis1, cis2, challoc1, challoc2, codec_id...) \
+ SCC_ASE2(SNK_ID(0), SRC_ID(0), challoc1, challoc2, codec_id), \
+ SCC_SNK_NOTIFY(0, STR_SCC_DATA(challoc1, codec_id)), \
+ SCC_SRC_NOTIFY(0, STR_SCC_DATA(challoc2, codec_id)), \
+ QOS_ASE2(SNK_ID(0), SRC_ID(0), cis1, cis2, QOS_SRC_8_1_1_DATA), \
+ QOS_SNK_NOTIFY(0, cis1, QOS_SRC_8_1_1_DATA), \
+ QOS_SRC_NOTIFY(0, cis2, QOS_SRC_8_1_1_DATA), \
+ ENABLE_ASE2(SNK_ID(0), SRC_ID(0)), \
+ SNK_ENABLE_NOTIFY(0, cis1), \
+ SRC_ENABLE_NOTIFY(0, cis2), \
+ SNK_START_NOTIFY(0, cis1), \
+ START_ASE(SRC_ID(0)), \
+ SRC_START_NOTIFY(0, cis2)
+
+#define STR_SNK_SRC_STREAMING_LC3(cis1, cis2, challoc1, challoc2) \
+ STR_SNK_SRC_STREAMING(cis1, cis2, challoc1, challoc2, LC3_CODEC_ID_DATA)
+
+#define STR_SNK_SRC_STREAMING_VS(cis1, cis2, challoc1, challoc2) \
+ STR_SNK_SRC_STREAMING(cis1, cis2, challoc1, challoc2, VS_CODEC_ID_DATA)
+
+#define STR_SNK2_STREAMING(cis1, cis2, challoc1, challoc2, codec_id...) \
+ SCC_ASE2(SNK_ID(0), SNK_ID(1), challoc1, challoc2, codec_id), \
+ SCC_SNK_NOTIFY(0, STR_SCC_DATA(challoc1, codec_id)), \
+ SCC_SNK_NOTIFY(1, STR_SCC_DATA(challoc2, codec_id)), \
+ QOS_ASE2(SNK_ID(0), SNK_ID(1), cis1, cis2, QOS_SRC_8_1_1_DATA), \
+ QOS_SNK_NOTIFY(0, cis1, QOS_SRC_8_1_1_DATA), \
+ QOS_SNK_NOTIFY(1, cis2, QOS_SRC_8_1_1_DATA), \
+ ENABLE_ASE2(SNK_ID(0), SNK_ID(1)), \
+ SNK_ENABLE_NOTIFY(0, cis1), \
+ SNK_ENABLE_NOTIFY(1, cis2), \
+ SNK_START_NOTIFY(0, cis1), \
+ SNK_START_NOTIFY(1, cis2)
+
+#define STR_SNK2_STREAMING_LC3(cis1, cis2, challoc1, challoc2) \
+ STR_SNK2_STREAMING(cis1, cis2, challoc1, challoc2, LC3_CODEC_ID_DATA)
+
+#define STR_SNK2_STREAMING_VS(cis1, cis2, challoc1, challoc2) \
+ STR_SNK2_STREAMING(cis1, cis2, challoc1, challoc2, VS_CODEC_ID_DATA)
+
+#define STR_SRC2_STREAMING(cis1, cis2, challoc1, challoc2, codec_id...) \
+ SCC_ASE2(SRC_ID(0), SRC_ID(1), challoc1, challoc2, codec_id), \
+ SCC_SRC_NOTIFY(0, STR_SCC_DATA(challoc1, codec_id)), \
+ SCC_SRC_NOTIFY(1, STR_SCC_DATA(challoc2, codec_id)), \
+ QOS_ASE2(SRC_ID(0), SRC_ID(1), cis1, cis2, QOS_SRC_8_1_1_DATA), \
+ QOS_SRC_NOTIFY(0, cis1, QOS_SRC_8_1_1_DATA), \
+ QOS_SRC_NOTIFY(1, cis2, QOS_SRC_8_1_1_DATA), \
+ ENABLE_ASE2(SRC_ID(0), SRC_ID(1)), \
+ SRC_ENABLE_NOTIFY(0, cis1), \
+ SRC_ENABLE_NOTIFY(1, cis2), \
+ START_ASE2(SRC_ID(0), SRC_ID(1)), \
+ SRC_START_NOTIFY(0, cis2), \
+ SRC_START_NOTIFY(1, cis2)
+
+#define STR_SRC2_STREAMING_LC3(cis1, cis2, challoc1, challoc2) \
+ STR_SRC2_STREAMING(cis1, cis2, challoc1, challoc2, LC3_CODEC_ID_DATA)
+
+#define STR_SNK2_SRC_STREAMING(cis1, cis2, cis3, ch1, ch2, ch3, codec_id...) \
+ SCC_ASE3(SNK_ID(0), SNK_ID(1), SRC_ID(0), ch1, ch2, ch3, codec_id), \
+ SCC_SNK_NOTIFY(0, STR_SCC_DATA(ch1, codec_id)), \
+ SCC_SNK_NOTIFY(1, STR_SCC_DATA(ch2, codec_id)), \
+ SCC_SRC_NOTIFY(0, STR_SCC_DATA(ch3, codec_id)), \
+ QOS_ASE3(SNK_ID(0), SNK_ID(1), SRC_ID(0), cis1, cis2, cis3, \
+ QOS_SRC_8_1_1_DATA), \
+ QOS_SNK_NOTIFY(0, cis1, QOS_SRC_8_1_1_DATA), \
+ QOS_SNK_NOTIFY(1, cis2, QOS_SRC_8_1_1_DATA), \
+ QOS_SRC_NOTIFY(0, cis3, QOS_SRC_8_1_1_DATA), \
+ ENABLE_ASE3(SNK_ID(0), SNK_ID(1), SRC_ID(0)), \
+ SNK_ENABLE_NOTIFY(0, cis1), \
+ SNK_ENABLE_NOTIFY(1, cis2), \
+ SRC_ENABLE_NOTIFY(0, cis3), \
+ SNK_START_NOTIFY(0, cis1), \
+ SNK_START_NOTIFY(1, cis2), \
+ START_ASE(SRC_ID(0)), \
+ SRC_START_NOTIFY(0, cis3)
+
+#define STR_SNK2_SRC_STREAMING_LC3(cis1, cis2, cis3, ch1, ch2, ch3) \
+ STR_SNK2_SRC_STREAMING(cis1, cis2, cis3, ch1, ch2, ch3, \
+ LC3_CODEC_ID_DATA)
+
+#define STR_SNK2_SRC2_STREAMING(cis1, cis2, cis3, cis4, \
+ ch1, ch2, ch3, ch4, codec_id...) \
+ SCC_ASE3(SNK_ID(0), SNK_ID(1), SRC_ID(0), \
+ ch1, ch2, ch3, codec_id), \
+ SCC_ASE(SRC_ID(1), STR_SCC_DATA(ch4, codec_id)), \
+ SCC_SNK_NOTIFY(0, STR_SCC_DATA(ch1, codec_id)), \
+ SCC_SNK_NOTIFY(1, STR_SCC_DATA(ch2, codec_id)), \
+ SCC_SRC_NOTIFY(0, STR_SCC_DATA(ch3, codec_id)), \
+ SCC_SRC_NOTIFY(1, STR_SCC_DATA(ch4, codec_id)), \
+ QOS_ASE3(SNK_ID(0), SNK_ID(1), SRC_ID(0), \
+ cis1, cis2, cis3, QOS_SRC_8_1_1_DATA), \
+ QOS_ASE(SRC_ID(1), cis4, QOS_SRC_8_1_1_DATA), \
+ QOS_SNK_NOTIFY(0, cis1, QOS_SRC_8_1_1_DATA), \
+ QOS_SNK_NOTIFY(1, cis2, QOS_SRC_8_1_1_DATA), \
+ QOS_SRC_NOTIFY(0, cis3, QOS_SRC_8_1_1_DATA), \
+ QOS_SRC_NOTIFY(1, cis4, QOS_SRC_8_1_1_DATA), \
+ ENABLE_ASE4(SNK_ID(0), SNK_ID(1), SRC_ID(0), SRC_ID(1)), \
+ SNK_ENABLE_NOTIFY(0, cis1), \
+ SNK_ENABLE_NOTIFY(1, cis2), \
+ SRC_ENABLE_NOTIFY(0, cis3), \
+ SRC_ENABLE_NOTIFY(1, cis4), \
+ SNK_START_NOTIFY(0, cis1), \
+ SNK_START_NOTIFY(1, cis2), \
+ START_ASE2(SRC_ID(0), SRC_ID(1)), \
+ SRC_START_NOTIFY(0, cis3), \
+ SRC_START_NOTIFY(1, cis4)
+
+#define STR_SNK2_SRC2_STREAMING_LC3(cis1, cis2, cis3, cis4, \
+ ch1, ch2, ch3, ch4) \
+ STR_SNK2_SRC2_STREAMING(cis1, cis2, cis3, cis4, ch1, ch2, ch3, ch4, \
+ LC3_CODEC_ID_DATA)
+
+/* BAP.TS 4.10.1 configurations */
+#define DISC_AC1_0a DISC_SNK_ONLY(0, LC3_PAC_CAPS(0x01))
+#define DISC_AC1_0b DISC_SNK_ONLY(0, LC3_PAC_CAPS_NO_COUNT)
+#define DISC_AC1_0c DISC_SNK_ONLY_NO_LOC(LC3_PAC_CAPS(0x01))
+#define DISC_AC1_0d DISC_SNK_ONLY_NO_LOC(LC3_PAC_CAPS_NO_COUNT)
+
+#define STR_AC1_0a DISC_AC1_0a, STR_SNK_STREAMING_LC3(0)
+#define STR_AC1_0b DISC_AC1_0b, STR_SNK_STREAMING_LC3(0)
+#define STR_AC1_0c DISC_AC1_0c, STR_SNK_STREAMING_LC3(0)
+#define STR_AC1_0d DISC_AC1_0d, STR_SNK_STREAMING_LC3(0)
+
+#define DISC_AC1_1 DISC_SNK_ONLY(0x2, LC3_PAC_CAPS(0x01))
+#define DISC_AC1_1a DISC_SNK_ONLY(0x2, LC3_PAC_CAPS(0x03))
+#define DISC_AC1_1b DISC_SNK_ONLY(0x22, LC3_PAC_CAPS(0x01))
+#define DISC_AC1_1c DISC_SNK_ONLY(0x22, LC3_PAC_CAPS(0x03))
+
+#define STR_AC1_1 DISC_AC1_1, STR_SNK_STREAMING_LC3(0x2)
+#define STR_AC1_1a DISC_AC1_1a, STR_SNK_STREAMING_LC3(0x2)
+#define STR_AC1_1b DISC_AC1_1b, STR_SNK_STREAMING_LC3(0x2)
+#define STR_AC1_1c DISC_AC1_1c, STR_SNK_STREAMING_LC3(0x2)
+
+#define DISC_AC4_2 DISC_SNK_ONLY(0x44, LC3_PAC_CAPS(0x02))
+#define DISC_AC4_2a DISC_SNK_ONLY(0x44, LC3_PAC_CAPS(0x03))
+#define DISC_AC4_2b DISC_SNK_ONLY(0x444, LC3_PAC_CAPS(0x02))
+#define DISC_AC4_2c DISC_SNK_ONLY(0x444, LC3_PAC_CAPS(0x03))
+
+#define STR_AC4_2 DISC_AC4_2, STR_SNK_STREAMING_LC3(0x44)
+#define STR_AC4_2a DISC_AC4_2a, STR_SNK_STREAMING_LC3(0x44)
+#define STR_AC4_2b DISC_AC4_2b, STR_SNK_STREAMING_LC3(0x44)
+#define STR_AC4_2c DISC_AC4_2c, STR_SNK_STREAMING_LC3(0x44)
+
+#define DISC_AC2_0a DISC_SRC_ONLY(0, LC3_PAC_CAPS(0x01))
+#define DISC_AC2_0b DISC_SRC_ONLY(0, LC3_PAC_CAPS_NO_COUNT)
+#define DISC_AC2_0c DISC_SRC_ONLY_NO_LOC(LC3_PAC_CAPS(0x01))
+#define DISC_AC2_0d DISC_SRC_ONLY_NO_LOC(LC3_PAC_CAPS_NO_COUNT)
+
+#define STR_AC2_0a DISC_AC2_0a, STR_SRC_STREAMING_LC3(0)
+#define STR_AC2_0b DISC_AC2_0b, STR_SRC_STREAMING_LC3(0)
+#define STR_AC2_0c DISC_AC2_0c, STR_SRC_STREAMING_LC3(0)
+#define STR_AC2_0d DISC_AC2_0d, STR_SRC_STREAMING_LC3(0)
+
+#define DISC_AC2_1 DISC_SRC_ONLY(0x2, LC3_PAC_CAPS(0x01))
+#define DISC_AC2_1a DISC_SRC_ONLY(0x2, LC3_PAC_CAPS(0x03))
+#define DISC_AC2_1b DISC_SRC_ONLY(0x22, LC3_PAC_CAPS(0x01))
+#define DISC_AC2_1c DISC_SRC_ONLY(0x22, LC3_PAC_CAPS(0x03))
+
+#define STR_AC2_1 DISC_AC2_1, STR_SRC_STREAMING_LC3(0x2)
+#define STR_AC2_1a DISC_AC2_1a, STR_SRC_STREAMING_LC3(0x2)
+#define STR_AC2_1b DISC_AC2_1b, STR_SRC_STREAMING_LC3(0x2)
+#define STR_AC2_1c DISC_AC2_1c, STR_SRC_STREAMING_LC3(0x2)
+
+#define DISC_AC10_2 DISC_SRC_ONLY(0x44, LC3_PAC_CAPS(0x02))
+#define DISC_AC10_2a DISC_SRC_ONLY(0x44, LC3_PAC_CAPS(0x03))
+#define DISC_AC10_2b DISC_SRC_ONLY(0x444, LC3_PAC_CAPS(0x02))
+#define DISC_AC10_2c DISC_SRC_ONLY(0x444, LC3_PAC_CAPS(0x03))
+
+#define STR_AC10_2 DISC_AC10_2, STR_SRC_STREAMING_LC3(0x44)
+#define STR_AC10_2a DISC_AC10_2a, STR_SRC_STREAMING_LC3(0x44)
+#define STR_AC10_2b DISC_AC10_2b, STR_SRC_STREAMING_LC3(0x44)
+#define STR_AC10_2c DISC_AC10_2c, STR_SRC_STREAMING_LC3(0x44)
+
+/* BAP.TS 4.10.2 configurations */
+#define DISC_VS_AC1 DISC_SNK_ONLY(0x2, VS_PAC_CAPS(0x01))
+#define DISC_VS_AC4 DISC_SNK_ONLY(0x44, VS_PAC_CAPS(0x02))
+#define DISC_VS_AC2 DISC_SRC_ONLY(0x2, VS_PAC_CAPS_NO_COUNT)
+#define DISC_VS_AC10 DISC_SRC_ONLY(0x44, VS_PAC_CAPS(0x02))
+
+#define STR_VS_AC1 DISC_VS_AC1, STR_SNK_STREAMING_VS(0x2)
+#define STR_VS_AC4 DISC_VS_AC4, STR_SNK_STREAMING_VS(0x44)
+#define STR_VS_AC2 DISC_VS_AC2, STR_SRC_STREAMING_VS(0x2)
+#define STR_VS_AC10 DISC_VS_AC10, STR_SRC_STREAMING_VS(0x44)
+
+/* BAP.TS 4.10.3 configurations
+ * Assumed Channels/Locations applies only to Sink ASE, as it's supposed
+ * to test AC 3, 5, 7(i)
+ */
+#define DISC_AC3 DISC_SRC_ASE(0x1, 0x1, LC3_PAC_CAPS(0x01), \
+ LC3_PAC_CAPS(0x01))
+#define DISC_AC5 DISC_SRC_ASE(0x22, 0x2, LC3_PAC_CAPS(0x02), \
+ LC3_PAC_CAPS(0x01))
+#define DISC_AC7i DISC_SRC_ASE(0x4, 0x4, LC3_PAC_CAPS(0x01), \
+ LC3_PAC_CAPS(0x01))
+
+#define STR_AC3 DISC_AC3, STR_SNK_SRC_STREAMING_LC3(0, 0, 0x1, 0x1)
+#define STR_AC5 DISC_AC5, STR_SNK_SRC_STREAMING_LC3(0, 0, 0x22, 0x2)
+#define STR_AC7i DISC_AC7i, STR_SNK_SRC_STREAMING_LC3(0, 1, 0x4, 0x4)
+
+/* BAP.TS 4.10.4 configurations */
+#define DISC_VS_AC3 DISC_SRC_ASE(0x1, 0x1, VS_PAC_CAPS(0x01), \
+ VS_PAC_CAPS(0x01))
+#define DISC_VS_AC5 DISC_SRC_ASE(0x22, 0x2, VS_PAC_CAPS(0x02), \
+ VS_PAC_CAPS(0x01))
+#define DISC_VS_AC7 DISC_SRC_ASE(0x4, 0x4, VS_PAC_CAPS(0x01), \
+ VS_PAC_CAPS(0x01))
+
+#define STR_VS_AC3 DISC_VS_AC3, STR_SNK_SRC_STREAMING_VS(0, 0, 0x1, 0x1)
+#define STR_VS_AC5 DISC_VS_AC5, STR_SNK_SRC_STREAMING_VS(0, 0, 0x22, 0x2)
+#define STR_VS_AC7 DISC_VS_AC7, STR_SNK_SRC_STREAMING_VS(0, 1, 0x4, 0x4)
+
+/* BAP.TS 4.10.5 configurations */
+#define DISC_AC7ii_L DISC_SRC_ONLY(0x01, LC3_PAC_CAPS(0x01))
+#define DISC_AC7ii_R DISC_SRC_ONLY(0x10, LC3_PAC_CAPS(0x01))
+
+/* BAP.TS 4.10.6 configurations */
+#define DISC_AC6i DISC_SNK_ONLY(0x11, LC3_PAC_CAPS(0x01))
+#define DISC_VS_AC6i DISC_SNK_ONLY(0x11, VS_PAC_CAPS(0x01))
+
+#define STR_AC6i DISC_AC6i, STR_SNK2_STREAMING_LC3(0, 1, 0x01, 0x10)
+#define STR_VS_AC6i DISC_VS_AC6i, STR_SNK2_STREAMING_VS(0, 1, 0x01, 0x10)
+
+/* BAP.TS 4.10.7 configurations */
+#define DISC_AC6ii_L DISC_SNK_ONLY(0x01, LC3_PAC_CAPS(0x01))
+#define DISC_AC6ii_R DISC_SNK_ONLY(0x10, LC3_PAC_CAPS(0x01))
+#define DISC_VS_AC6ii_L DISC_SNK_ONLY(0x01, VS_PAC_CAPS(0x01))
+#define DISC_VS_AC6ii_R DISC_SNK_ONLY(0x10, VS_PAC_CAPS(0x01))
+
+/* BAP.TS 4.10.8 configurations */
+#define DISC_AC9i DISC_SRC_ONLY(0x11, LC3_PAC_CAPS(0x01))
+#define DISC_VS_AC9i DISC_SRC_ONLY(0x11, VS_PAC_CAPS(0x01))
+
+#define STR_AC9i DISC_AC9i, \
+ STR_SRC2_STREAMING_LC3(0, 1, 0x01, 0x10)
+
+/* BAP.TS 4.10.9 configurations */
+#define DISC_AC9ii_L DISC_SRC_ONLY(0x01, LC3_PAC_CAPS(0x01))
+#define DISC_AC9ii_R DISC_SRC_ONLY(0x10, LC3_PAC_CAPS(0x01))
+
+/* BAP.TS 4.10.10 configurations */
+#define DISC_AC8i DISC_SRC_ASE(0x11, 0x02, \
+ LC3_PAC_CAPS(0x01), LC3_PAC_CAPS(0x01))
+
+#define STR_AC8i DISC_AC8i, STR_SNK2_SRC_STREAMING_LC3( \
+ 0, 1, 0, 0x01, 0x10, 0x2)
+
+/* BAP.TS 4.10.11 configurations */
+#define DISC_AC8ii_L DISC_SNK_ONLY(0x1, LC3_PAC_CAPS(0x01))
+#define DISC_AC8ii_R DISC_SRC_ASE(0x10, 0x2, \
+ LC3_PAC_CAPS(0x01), LC3_PAC_CAPS(0x01))
+
+/* BAP.TS 4.10.12 configurations */
+#define DISC_AC11i DISC_SRC_ASE(0x11, 0x22, \
+ LC3_PAC_CAPS(0x01), LC3_PAC_CAPS(0x01))
+
+#define STR_AC11i DISC_AC11i, STR_SNK2_SRC2_STREAMING_LC3( \
+ 0, 1, 0, 1, 0x01, 0x10, 0x02, 0x20)
+
+/* BAP.TS 4.10.13 configurations */
+#define DISC_AC11ii_L DISC_SRC_ASE(0x01, 0x02, \
+ LC3_PAC_CAPS(0x01), LC3_PAC_CAPS(0x01))
+#define DISC_AC11ii_R DISC_SRC_ASE(0x10, 0x20, \
+ LC3_PAC_CAPS(0x01), LC3_PAC_CAPS(0x01))
+#define DISC_VS_AC11i_L DISC_SRC_ASE(0x01, 0x02, \
+ VS_PAC_CAPS(0x01), VS_PAC_CAPS(0x01))
+#define DISC_VS_AC11i_R DISC_SRC_ASE(0x10, 0x20, \
+ VS_PAC_CAPS(0x01), VS_PAC_CAPS(0x01))
+
+/* Expected bt_bap_select() results */
+
+static struct test_config cfg_str_ac1_0ab = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0, -1 },
+ .src_locations = { -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac1_0cd = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0, -1 },
+ .src_locations = { -1 },
+ .setup_data = setup_data_no_location,
+ .setup_data_len = ARRAY_SIZE(setup_data_no_location),
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac1_1 = {
+ .snk = true,
+ .src = true,
+ .streams = 1, /* force 1 channel; caps support also AC 4 & 6(i) */
+ .snk_locations = { 0x2, -1 },
+ .src_locations = { -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac4_2 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x44, -1 },
+ .src_locations = { -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac2_0ab = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0, -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac2_0cd = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0, -1 },
+ .setup_data = setup_data_no_location,
+ .setup_data_len = ARRAY_SIZE(setup_data_no_location),
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac2_1 = {
+ .snk = true,
+ .src = true,
+ .streams = 1,
+ .snk_locations = { -1 },
+ .src_locations = { 0x2, -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac10_2 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0x44, -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_vs_ac1 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x2, -1 },
+ .src_locations = { -1 },
+ .qos = LC3_QOS_8_1_1,
+ .vs = true,
+};
+
+static struct test_config cfg_str_vs_ac4 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x44, -1 },
+ .src_locations = { -1 },
+ .qos = LC3_QOS_8_1_1,
+ .vs = true,
+};
+
+static struct test_config cfg_str_vs_ac2 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0x2, -1 },
+ .qos = LC3_QOS_8_1_1,
+ .vs = true,
+};
+
+static struct test_config cfg_str_vs_ac10 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0x44, -1 },
+ .qos = LC3_QOS_8_1_1,
+ .vs = true,
+};
+
+static struct test_config cfg_str_ac3 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, -1 },
+ .src_locations = { 0x1, -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac5 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x22, -1 },
+ .src_locations = { 0x2, -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac7i = {
+ .snk = true,
+ .src = true,
+ .streams = 2,
+ .snk_locations = { 0x4, -1 },
+ .src_locations = { 0x4, -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_vs_ac3 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, -1 },
+ .src_locations = { 0x1, -1 },
+ .qos = LC3_QOS_8_1_1,
+ .vs = true,
+};
+
+static struct test_config cfg_str_vs_ac5 = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x22, -1 },
+ .src_locations = { 0x2, -1 },
+ .qos = LC3_QOS_8_1_1,
+ .vs = true,
+};
+
+static struct test_config cfg_str_vs_ac7 = {
+ .snk = true,
+ .src = true,
+ .streams = 2,
+ .snk_locations = { 0x4, -1 },
+ .src_locations = { 0x4, -1 },
+ .qos = LC3_QOS_8_1_1,
+ .vs = true,
+};
+
+static struct test_config cfg_str_ac7ii_L = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0x1, -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac7ii_R = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0x10, -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac6i = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, 0x10, -1 },
+ .src_locations = { -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_vs_ac6i = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, 0x10, -1 },
+ .src_locations = { -1 },
+ .qos = LC3_QOS_8_1_1,
+ .vs = true,
+};
+
+static struct test_config cfg_str_ac6ii_L = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, -1 },
+ .src_locations = { -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac6ii_R = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x10, -1 },
+ .src_locations = { -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_vs_ac6ii_L = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, -1 },
+ .src_locations = { -1 },
+ .vs = true,
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_vs_ac6ii_R = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x10, -1 },
+ .src_locations = { -1 },
+ .vs = true,
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac9i = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0x1, 0x10, -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac9ii_L = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0x1, -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac9ii_R = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { -1 },
+ .src_locations = { 0x10, -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac8i = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, 0x10, -1 },
+ .src_locations = { 0x2, -1 },
+ .qos = LC3_QOS_8_1_1,
+};
+
+static struct test_config cfg_str_ac8ii_L = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, -1 },
+ .src_locations = { -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac8ii_R = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x10, -1 },
+ .src_locations = { 0x2, -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac11i = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, 0x10, -1 },
+ .src_locations = { 0x2, 0x20, -1 },
+ .qos = LC3_QOS_8_1_1,
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac11ii_L = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x1, -1 },
+ .src_locations = { 0x2, -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_ac11ii_R = {
+ .snk = true,
+ .src = true,
+ .snk_locations = { 0x10, -1 },
+ .src_locations = { 0x20, -1 },
+ /* TODO: no qos: only check select, not streaming */
+};
+
+/* Additional bt_bap_select() tests */
+
+#define DISC_MANY \
+ DISC_SRC_ASE(0x000000ff, 0, LC3_PAC_CAPS(0xf), UNKNOWN_PAC_CAPS)
+
+static struct iovec caps_select_snk_many =
+ LC3_CAPABILITIES(LC3_FREQ_ANY, LC3_DURATION_ANY, 0x0a, 26, 240);
+
+static struct test_config cfg_str_many_2 = {
+ .snk = true,
+ .snk_locations = { 0x00000003, -1 },
+ .src_locations = { -1 },
+ .pac_caps = &caps_select_snk_many,
+ /* TODO: no qos: only check select, not streaming */
+};
+
+static struct test_config cfg_str_many_8 = {
+ .snk = true,
+ .streams = 8,
+ .snk_locations = { 0x0000000f, 0x000000f0, -1 },
+ .src_locations = { -1 },
+ .pac_caps = &caps_select_snk_many,
+ /* TODO: no qos: only check select, not streaming */
+};
+
+struct test_select_data {
+ struct test_data *data;
+ unsigned int num_src;
+ unsigned int num_snk;
+ uint32_t src_locations[4];
+ uint32_t snk_locations[4];
+ struct bt_bap_pac *rpac;
+ int stream_idx;
+};
+
+static void streaming_ucl_do_stream(struct bt_bap_stream *stream,
+ struct test_data *data)
+{
+ unsigned int idx = PTR_TO_UINT(bt_bap_stream_get_user_data(stream));
+ struct bt_bap_qos *qos = bt_bap_stream_get_qos(stream);
+ struct io *io;
+ int fd, fd2, ifd, ofd;
+ unsigned int result;
+ ssize_t err;
+ const char *dir;
+
+ io = bt_bap_stream_get_io(stream);
+ if (!io) {
+ FAIL_TEST();
+ return;
+ }
+
+ g_assert(qos->ucast.cis_id < ARRAY_SIZE(data->fds));
+
+ fd = io_get_fd(io);
+ fd2 = data->fds[qos->ucast.cis_id][1];
+ g_assert(fd == data->fds[qos->ucast.cis_id][0]);
+
+ /* NB: dummy data, LC3 packet encoding/decoding out of scope */
+
+ if (bt_bap_stream_get_dir(stream) == BT_BAP_SINK) {
+ dir = "-->";
+ ofd = fd;
+ ifd = fd2;
+ } else {
+ dir = "<--";
+ ofd = fd2;
+ ifd = fd;
+ }
+
+ tester_debug("streaming stream %p fd:%d %s %d", stream, fd, dir, fd2);
+
+ err = write(ofd, &idx, sizeof(idx));
+ g_assert(err == sizeof(idx));
+
+ /* write sentinel to catch if we read twice from same fd */
+ result = 0xaabbccdd;
+ err = write(ofd, &result, sizeof(result));
+ g_assert(err == sizeof(result));
+
+ err = read(ifd, &result, sizeof(result));
+ g_assert(err == sizeof(result));
+
+ tester_debug("stream %p: data %u = %u (%d left)",
+ stream, idx, result, data->id - 1);
+
+ if (result != idx) {
+ FAIL_TEST();
+ return;
+ }
+
+ if (data->id-- == 0) {
+ FAIL_TEST();
+ return;
+ }
+
+ /* All streams handled */
+ if (data->id == 0)
+ tester_test_passed();
+}
+
+static void streaming_ucl_connect(struct bt_bap_stream *stream)
+{
+ int fd;
+
+ tester_debug("connect stream %p", stream);
+
+ if (!bt_bap_stream_io_is_connecting(stream, &fd))
+ return;
+
+ if (!bt_bap_stream_set_io(stream, fd)) {
+ FAIL_TEST();
+ return;
+ }
+}
+
+static int streaming_ucl_create_io(struct bt_bap_stream *stream,
+ struct test_data *data)
+{
+ struct bt_bap_qos *qos[2] = {};
+ unsigned int i;
+ int err;
+
+ tester_debug("create io stream %p", stream);
+
+ if (bt_bap_stream_get_io(stream)) {
+ FAIL_TEST();
+ return -EINVAL;
+ }
+ if (!bt_bap_stream_io_get_qos(stream, &qos[0], &qos[1])) {
+ FAIL_TEST();
+ return -EINVAL;
+ }
+ if (bt_bap_stream_io_is_connecting(stream, NULL)) {
+ if (qos[0])
+ return qos[0]->ucast.cis_id;
+ return qos[1]->ucast.cis_id;
+ }
+
+ i = qos[0] ? qos[0]->ucast.cis_id : qos[1]->ucast.cis_id;
+
+ if (i == BT_ISO_QOS_CIG_UNSET) {
+ for (i = 0; i < ARRAY_SIZE(data->fds); ++i) {
+ if (data->fds[i][0] > 0)
+ continue;
+
+ if (qos[0])
+ qos[0]->ucast.cis_id = i;
+ if (qos[1])
+ qos[1]->ucast.cis_id = i;
+ break;
+ }
+ }
+
+ g_assert(i < ARRAY_SIZE(data->fds));
+ g_assert(data->fds[i][0] <= 0);
+ g_assert(data->fds[i][1] <= 0);
+
+ err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC,
+ 0, data->fds[i]);
+ g_assert(err == 0);
+
+ err = bt_bap_stream_io_connecting(stream, data->fds[i][0]);
+ if (err) {
+ FAIL_TEST();
+ return -EINVAL;
+ }
+
+ return i;
+}
+
+static void streaming_ucl_state(struct bt_bap_stream *stream,
+ uint8_t old_state, uint8_t new_state,
+ void *user_data)
+{
+ struct test_data *data = user_data;
+ const struct queue_entry *entry;
+ struct bt_bap_qos qos = data->cfg->qos;
+ unsigned int id;
+
+ tester_debug("stream %p state %d -> %d", stream, old_state, new_state);
+
+ switch (new_state) {
+ case BT_BAP_STREAM_STATE_CONFIG:
+ qos.ucast.cig_id = 0;
+ qos.ucast.cis_id = streaming_ucl_create_io(stream, data);
+ id = bt_bap_stream_qos(stream, &qos, NULL, NULL);
+ g_assert(id);
+ break;
+ case BT_BAP_STREAM_STATE_QOS:
+ if (data->id-- == 0)
+ tester_test_failed();
+ if (data->id)
+ return;
+
+ /* All streams in QoS: proceed */
+ for (entry = queue_get_entries(data->streams);
+ entry; entry = entry->next) {
+ struct bt_bap_stream *s = entry->data;
+
+ if (data->cfg->state != BT_BAP_STREAM_STATE_ENABLING)
+ streaming_ucl_connect(s);
+
+ id = bt_bap_stream_enable(s, false, NULL,
+ NULL, NULL);
+ g_assert(id);
+
+ data->id++;
+ }
+ break;
+ case BT_BAP_STREAM_STATE_ENABLING:
+ /* TODO: not correct to call bt_bap_stream_set_io() from this
+ * callback
+ */
+ if (data->cfg->state == BT_BAP_STREAM_STATE_ENABLING)
+ streaming_ucl_connect(stream);
+ break;
+ case BT_BAP_STREAM_STATE_STREAMING:
+ streaming_ucl_do_stream(stream, data);
+ break;
+ }
+}
+
+static void test_select_cb(struct bt_bap_pac *pac, int err,
+ struct iovec *caps, struct iovec *metadata,
+ struct bt_bap_qos *qos, void *user_data)
+{
+ struct test_select_data *sdata = user_data;
+ struct test_data *data = sdata->data;
+ struct bt_bap_stream *stream;
+
+ if (!data->cfg->qos.ucast.target_latency) {
+ tester_warn("TODO: implement streaming test");
+ return;
+ }
+
+ data->id++;
+
+ stream = bt_bap_stream_new(data->bap, pac, sdata->rpac, qos, caps);
+ bt_bap_stream_lock(stream);
+
+ tester_debug("new stream %p", stream);
+
+ queue_push_tail(data->streams, stream);
+
+ if (!data->cfg->streams) {
+ qos->ucast.cig_id = BT_ISO_QOS_CIG_UNSET;
+ qos->ucast.cis_id = BT_ISO_QOS_CIG_UNSET;
+ } else {
+ /* All streams to separate CIS.
+ *
+ * There is no difference in PACS for AC 4 and AC 7(i), so which
+ * one to use has to be specified OOB like this.
+ */
+ qos->ucast.cig_id = 0;
+ qos->ucast.cis_id = sdata->stream_idx;
+ }
+
+ err = bt_bap_stream_config(stream, qos, caps, NULL, NULL);
+ if (!err) {
+ FAIL_TEST();
+ return;
+ }
+
+ bt_bap_stream_set_user_data(stream, UINT_TO_PTR(sdata->stream_idx));
+ sdata->stream_idx++;
+}
+
+static bool test_select_pac(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
+ void *user_data)
+{
+ struct test_select_data *sdata = user_data;
+ struct test_config *cfg = sdata->data->cfg;
+ int err, count = 0;
+
+ sdata->rpac = rpac;
+
+ err = bt_bap_select(sdata->data->bap, lpac, rpac, cfg->streams, &count,
+ test_select_cb, sdata);
+ if (err)
+ tester_test_failed();
+
+ return false;
+}
+
+static void bap_select_ready(struct bt_bap *bap, void *user_data)
+{
+ struct test_select_data sdata = {
+ .data = (void *)user_data,
+ };
+ struct test_config *cfg = sdata.data->cfg;
+ unsigned int i;
+
+ bt_bap_foreach_pac(bap, BT_BAP_SINK, test_select_pac, &sdata);
+ bt_bap_foreach_pac(bap, BT_BAP_SOURCE, test_select_pac, &sdata);
+
+ for (i = 0; i < sdata.num_snk; ++i)
+ if (sdata.snk_locations[i] != cfg->snk_locations[i]) {
+ FAIL_TEST();
+ return;
+ }
+ if (i < ARRAY_SIZE(cfg->snk_locations) &&
+ cfg->snk_locations[i] != (uint32_t)-1) {
+ FAIL_TEST();
+ return;
+ }
+
+ for (i = 0; i < sdata.num_src; ++i)
+ if (sdata.src_locations[i] != cfg->src_locations[i]) {
+ FAIL_TEST();
+ return;
+ }
+ if (i < ARRAY_SIZE(cfg->src_locations) &&
+ cfg->src_locations[i] != (uint32_t)-1) {
+ FAIL_TEST();
+ return;
+ }
+
+ if (!sdata.data->cfg->qos.ucast.target_latency)
+ tester_test_passed();
+}
+
+static int pac_select(struct bt_bap_pac *lpac, struct bt_bap_pac *rpac,
+ uint32_t location, struct bt_bap_pac_qos *qos,
+ bt_bap_pac_select_t cb, void *cb_data, void *user_data)
+{
+ struct test_select_data *sdata = cb_data;
+ struct test_data *data = sdata->data;
+ uint8_t buf[512];
+ struct iovec cc = { .iov_base = buf, .iov_len = 0 };
+ struct iovec metadata = { 0 };
+
+ if (bt_bap_pac_get_type(rpac) == BT_BAP_SINK) {
+ if (sdata->num_snk >= ARRAY_SIZE(sdata->snk_locations)) {
+ FAIL_TEST();
+ return -EINVAL;
+ }
+ tester_debug("select SNK 0x%08x", location);
+ sdata->snk_locations[sdata->num_snk++] = location;
+ } else {
+ if (sdata->num_src >= ARRAY_SIZE(sdata->src_locations)) {
+ FAIL_TEST();
+ return -EINVAL;
+ }
+ tester_debug("select SRC 0x%08x", location);
+ sdata->src_locations[sdata->num_src++] = location;
+ }
+
+ util_iov_push_mem(&cc, data->cfg->cc.iov_len, data->cfg->cc.iov_base);
+
+ /* Audio_Channel_Allocation */
+ util_iov_push_u8(&cc, 0x05);
+ util_iov_push_u8(&cc, 0x03);
+ util_iov_push_le32(&cc, location);
+
+ g_assert(cc.iov_len <= sizeof(buf));
+
+ cb(lpac, 0, &cc, &metadata, &data->cfg->qos, cb_data);
+ return 0;
+}
+
+static struct bt_bap_pac_ops test_select_pac_ops = {
+ .select = pac_select,
+};
+
+static void test_select(const void *user_data)
+{
+ struct test_data *data = (void *)user_data;
+ struct io *io;
+
+ data->id = 0;
+
+ io = tester_setup_io(data->iov, data->iovcnt);
+ g_assert(io);
+
+ tester_io_set_complete_func(NULL);
+
+ data->db = gatt_db_new();
+ g_assert(data->db);
+
+ test_setup_pacs(data);
+
+ if (data->snk)
+ bt_bap_pac_set_ops(data->snk, &test_select_pac_ops, NULL);
+ if (data->src)
+ bt_bap_pac_set_ops(data->src, &test_select_pac_ops, NULL);
+
+ data->bap = bt_bap_new(data->db, bt_gatt_client_get_db(data->client));
+ g_assert(data->bap);
+
+ bt_bap_set_debug(data->bap, print_debug, "bt_bap:", NULL);
+
+ bt_bap_ready_register(data->bap, bap_select_ready, data, NULL);
+
+ bt_bap_state_register(data->bap, streaming_ucl_state, NULL, data, NULL);
+
+ bt_bap_attach(data->bap, data->client);
+}
+
+static void test_ucl_str(void)
+{
+ /*
+ * TODO: QoS vs. Enabling variants not simulated
+ *
+ * TODO: test (ii) variants connecting both sides simultaneously,
+ * currently CIS linking is not tested
+ */
+
+ define_test("BAP/UCL/STR/BV-539-C [UCL, AC 2, Generic, QoS]",
+ test_setup, test_select, &cfg_str_ac2_1, STR_AC2_1);
+ define_test("BAP/UCL/STR/BV-580-C [UCL, AC 2, Generic, QoS, "
+ "Multi Channels]",
+ test_setup, test_select, &cfg_str_ac2_1, STR_AC2_1a);
+ define_test("BAP/UCL/STR/BV-581-C [UCL, AC 2, Generic, QoS, "
+ "Multi Location]",
+ test_setup, test_select, &cfg_str_ac2_1, STR_AC2_1b);
+ define_test("BAP/UCL/STR/BV-582-C [UCL, AC 2, Generic, QoS, "
+ "Multi Channels and Location]",
+ test_setup, test_select, &cfg_str_ac2_1, STR_AC2_1c);
+ define_test("BAP/UCL/STR/BV-560-C [UCL, AC 2, Generic, QoS, Mono]",
+ test_setup, test_select, &cfg_str_ac2_0ab, STR_AC2_0a);
+ define_test("BAP/UCL/STR/BV-561-C [UCL, AC 2, Generic, QoS, Mono, "
+ "Default Ch Count]",
+ test_setup, test_select, &cfg_str_ac2_0ab, STR_AC2_0b);
+ define_test("BAP/UCL/STR/BV-562-C [UCL, AC 2, Generic, QoS, Mono, "
+ "No PACS]",
+ test_setup, test_select, &cfg_str_ac2_0cd, STR_AC2_0c);
+ define_test("BAP/UCL/STR/BV-563-C [UCL, AC 2, Generic, QoS, Mono, "
+ "Default Ch Count, No PACS]",
+ test_setup, test_select, &cfg_str_ac2_0cd, STR_AC2_0d);
+
+ define_test("BAP/UCL/STR/BV-540-C [UCL, AC 10, Generic, QoS]",
+ test_setup, test_select, &cfg_str_ac10_2, STR_AC10_2);
+ define_test("BAP/UCL/STR/BV-583-C [UCL, AC 10, Generic, QoS, "
+ "Multi Channels]",
+ test_setup, test_select, &cfg_str_ac10_2, STR_AC10_2a);
+ define_test("BAP/UCL/STR/BV-584-C [UCL, AC 10, Generic, QoS, "
+ "Multi Location]",
+ test_setup, test_select, &cfg_str_ac10_2, STR_AC10_2b);
+ define_test("BAP/UCL/STR/BV-585-C [UCL, AC 10, Generic, QoS, "
+ "Multi Channels and Location]",
+ test_setup, test_select, &cfg_str_ac10_2, STR_AC10_2c);
+
+ define_test("BAP/UCL/STR/BV-541-C [UCL SRC, AC 1, Generic, QoS]",
+ test_setup, test_select, &cfg_str_ac1_1, STR_AC1_1);
+ define_test("BAP/UCL/STR/BV-586-C [UCL, AC 1, Generic, QoS, "
+ "Multi Channels]",
+ test_setup, test_select, &cfg_str_ac1_1, STR_AC1_1a);
+ define_test("BAP/UCL/STR/BV-587-C [UCL, AC 1, Generic, QoS, "
+ "Multi Location]",
+ test_setup, test_select, &cfg_str_ac1_1, STR_AC1_1b);
+ define_test("BAP/UCL/STR/BV-588-C [UCL, AC 1, Generic, QoS, "
+ "Multi Channels and Location]",
+ test_setup, test_select, &cfg_str_ac1_1, STR_AC1_1c);
+
+ define_test("BAP/UCL/STR/BV-564-C [UCL SRC, AC 1, Generic, QoS, Mono]",
+ test_setup, test_select, &cfg_str_ac1_0ab, STR_AC1_0a);
+ define_test("BAP/UCL/STR/BV-565-C [UCL SRC, AC 1, Generic, QoS, Mono, "
+ "Default Ch Count]",
+ test_setup, test_select, &cfg_str_ac1_0ab, STR_AC1_0b);
+ define_test("BAP/UCL/STR/BV-566-C [UCL SRC, AC 1, Generic, QoS, Mono, "
+ "No PACS]",
+ test_setup, test_select, &cfg_str_ac1_0cd, STR_AC1_0c);
+ define_test("BAP/UCL/STR/BV-567-C [UCL SRC, AC 1, Generic, QoS, Mono, "
+ "Default Ch Count, No PACS]",
+ test_setup, test_select, &cfg_str_ac1_0cd, STR_AC1_0d);
+
+ define_test("BAP/UCL/STR/BV-542-C [UCL SRC, AC 4, Generic, QoS]",
+ test_setup, test_select, &cfg_str_ac4_2, STR_AC4_2);
+ define_test("BAP/UCL/STR/BV-589-C [UCL, AC 4, Generic, QoS, "
+ "Multi Channels]",
+ test_setup, test_select, &cfg_str_ac4_2, STR_AC4_2a);
+ define_test("BAP/UCL/STR/BV-590-C [UCL, AC 4, Generic, QoS, "
+ "Multi Location]",
+ test_setup, test_select, &cfg_str_ac4_2, STR_AC4_2b);
+ define_test("BAP/UCL/STR/BV-591-C [UCL, AC 4, Generic, QoS, "
+ "Multi Channels and Location]",
+ test_setup, test_select, &cfg_str_ac4_2, STR_AC4_2c);
+
+ define_test("BAP/UCL/STR/BV-129-C [UCL SRC, AC 1, VS Codec]",
+ test_setup, test_select, &cfg_str_vs_ac1, STR_VS_AC1);
+ define_test("BAP/UCL/STR/BV-130-C [UCL SRC, AC 4, VS Codec]",
+ test_setup, test_select, &cfg_str_vs_ac4, STR_VS_AC4);
+ define_test("BAP/UCL/STR/BV-131-C [UCL, AC 2, VS Codec]",
+ test_setup, test_select, &cfg_str_vs_ac2, STR_VS_AC2);
+ define_test("BAP/UCL/STR/BV-132-C [UCL, AC 10, VS Codec]",
+ test_setup, test_select, &cfg_str_vs_ac10, STR_VS_AC10);
+
+ define_test("BAP/UCL/STR/BV-549-C [UCL, AC 3, Generic, QoS, QoS]",
+ test_setup, test_select, &cfg_str_ac3, STR_AC3);
+ define_test("BAP/UCL/STR/BV-550-C [UCL, AC 5, Generic, QoS, QoS]",
+ test_setup, test_select, &cfg_str_ac5, STR_AC5);
+ define_test("BAP/UCL/STR/BV-551-C [UCL, AC 7(i), Generic, QoS, QoS]",
+ test_setup, test_select, &cfg_str_ac7i, STR_AC7i);
+
+ define_test("BAP/UCL/STR/BV-229-C [UCL, AC 3, VS]",
+ test_setup, test_select, &cfg_str_vs_ac3, STR_VS_AC3);
+ define_test("BAP/UCL/STR/BV-230-C [UCL, AC 5, VS]",
+ test_setup, test_select, &cfg_str_vs_ac5, STR_VS_AC5);
+ define_test("BAP/UCL/STR/BV-231-C [UCL, AC 7, VS]",
+ test_setup, test_select, &cfg_str_vs_ac7, STR_VS_AC7);
+
+ /* TODO: combine these to a single test with two simultaneous BAP */
+ define_test("BAP/UCL/STR/BV-526-C [UCL, AC 7(ii), Generic] Left",
+ test_setup, test_select, &cfg_str_ac7ii_L, DISC_AC7ii_L);
+ define_test("BAP/UCL/STR/BV-526-C [UCL, AC 7(ii), Generic] Right",
+ test_setup, test_select, &cfg_str_ac7ii_R, DISC_AC7ii_R);
+
+ define_test("BAP/UCL/STR/BV-527-C [UCL, AC 6(i), Generic]",
+ test_setup, test_select, &cfg_str_ac6i, STR_AC6i);
+ define_test("BAP/UCL/STR/BV-296-C [UCL, AC 6(i), VS]",
+ test_setup, test_select, &cfg_str_vs_ac6i, STR_VS_AC6i);
+
+ /* TODO: combine these to a single test with two simultaneous BAP */
+ define_test("BAP/UCL/STR/BV-528-C [UCL, AC 6(ii), Generic] Left",
+ test_setup, test_select, &cfg_str_ac6ii_L, DISC_AC6ii_L);
+ define_test("BAP/UCL/STR/BV-528-C [UCL, AC 6(ii), Generic] Right",
+ test_setup, test_select, &cfg_str_ac6ii_R, DISC_AC6ii_R);
+
+ /* TODO: combine these to a single test with two simultaneous BAP */
+ define_test("BAP/UCL/STR/BV-329-C [UCL, AC 6(ii), VS] Left",
+ test_setup, test_select, &cfg_str_vs_ac6ii_L, DISC_VS_AC6ii_L);
+ define_test("BAP/UCL/STR/BV-329-C [UCL, AC 6(ii), VS] Right",
+ test_setup, test_select, &cfg_str_vs_ac6ii_R, DISC_VS_AC6ii_R);
+
+ define_test("BAP/UCL/STR/BV-529-C [UCL, AC 9(i), Generic]",
+ test_setup, test_select, &cfg_str_ac9i, STR_AC9i);
+
+ /* TODO: combine these to a single test with two simultaneous BAP */
+ define_test("BAP/UCL/STR/BV-530-C [UCL, AC 9(ii), Generic] Left",
+ test_setup, test_select,
+ &cfg_str_ac9ii_L, DISC_AC9ii_L);
+ define_test("BAP/UCL/STR/BV-530-C [UCL, AC 9(ii), Generic] Right",
+ test_setup, test_select,
+ &cfg_str_ac9ii_R, DISC_AC9ii_R);
+
+ define_test("BAP/UCL/STR/BV-531-C [UCL, AC 8(i), Generic]",
+ test_setup, test_select,
+ &cfg_str_ac8i, STR_AC8i);
+
+ /* TODO: combine these to a single test with two simultaneous BAP */
+ define_test("BAP/UCL/STR/BV-532-C [UCL, AC 8(ii), Generic] Left",
+ test_setup, test_select,
+ &cfg_str_ac8ii_L, DISC_AC8ii_L);
+ define_test("BAP/UCL/STR/BV-532-C [UCL, AC 8(ii), Generic] Right",
+ test_setup, test_select,
+ &cfg_str_ac8ii_R, DISC_AC8ii_R);
+
+ /* TODO: this one fails due to exceeding ATT MTU */
+ define_test("BAP/UCL/STR/BV-533-C [UCL, AC 11(i), Generic]",
+ test_setup, test_select, &cfg_str_ac11i, STR_AC11i);
+
+ /* TODO: combine these to a single test with two simultaneous BAP */
+ define_test("BAP/UCL/STR/BV-534-C [UCL, AC 11(ii), Generic] Left",
+ test_setup, test_select, &cfg_str_ac11ii_L, DISC_AC11ii_L);
+ define_test("BAP/UCL/STR/BV-534-C [UCL, AC 11(ii), Generic] Right",
+ test_setup, test_select, &cfg_str_ac11ii_R, DISC_AC11ii_R);
+
+ /* Custom tests: */
+ define_test("BAP/UCL/STR/BLUEZ-1 [UCL, Custom AC, 8 -> 2 Ch, Generic]",
+ test_setup, test_select, &cfg_str_many_2, DISC_MANY);
+ define_test("BAP/UCL/STR/BLUEZ-2 [UCL, Custom AC, 8 -> 4+4 Ch, "
+ "Generic]",
+ test_setup, test_select, &cfg_str_many_8, DISC_MANY);
+}
+
int main(int argc, char *argv[])
{
tester_init(&argc, &argv);
@@ -8802,6 +10264,7 @@ int main(int argc, char *argv[])
test_bsnk_scc();
test_bsnk_str();
test_bsrc_str();
+ test_ucl_str();
return tester_run();
}
--
2.51.1
^ permalink raw reply related [flat|nested] 8+ messages in thread
* RE: [BlueZ,v4,1/6] shared/bap: fix channel allocation logic in bt_bap_select()
2025-11-15 12:58 [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select() Pauli Virtanen
` (4 preceding siblings ...)
2025-11-15 12:58 ` [PATCH BlueZ v4 6/6] test-bap: add audio configuration selection and streaming tests Pauli Virtanen
@ 2025-11-15 14:03 ` bluez.test.bot
2025-11-17 19:10 ` [PATCH BlueZ v4 1/6] " patchwork-bot+bluetooth
6 siblings, 0 replies; 8+ messages in thread
From: bluez.test.bot @ 2025-11-15 14:03 UTC (permalink / raw)
To: linux-bluetooth, pav
[-- Attachment #1: Type: text/plain, Size: 2365 bytes --]
This is automated email and please do not reply to this email!
Dear submitter,
Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=1023839
---Test result---
Test Summary:
CheckPatch PENDING 0.29 seconds
GitLint PENDING 0.32 seconds
BuildEll PASS 20.05 seconds
BluezMake PASS 637.47 seconds
MakeCheck PASS 21.92 seconds
MakeDistcheck PASS 238.39 seconds
CheckValgrind PASS 295.57 seconds
CheckSmatch WARNING 344.68 seconds
bluezmakeextell PASS 181.02 seconds
IncrementalBuild PENDING 0.24 seconds
ScanBuild PASS 985.35 seconds
Details
##############################
Test: CheckPatch - PENDING
Desc: Run checkpatch.pl script
Output:
##############################
Test: GitLint - PENDING
Desc: Run gitlint
Output:
##############################
Test: CheckSmatch - WARNING
Desc: Run smatch tool with source
Output:
src/shared/bap.c:312:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:312:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:312:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:312:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:312:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structuressrc/shared/bap.c:312:25: warning: array of flexible structuressrc/shared/bap.c: note: in included file:./src/shared/ascs.h:88:25: warning: array of flexible structures
##############################
Test: IncrementalBuild - PENDING
Desc: Incremental build with the patches in the series
Output:
---
Regards,
Linux Bluetooth
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select()
2025-11-15 12:58 [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select() Pauli Virtanen
` (5 preceding siblings ...)
2025-11-15 14:03 ` [BlueZ,v4,1/6] shared/bap: fix channel allocation logic in bt_bap_select() bluez.test.bot
@ 2025-11-17 19:10 ` patchwork-bot+bluetooth
6 siblings, 0 replies; 8+ messages in thread
From: patchwork-bot+bluetooth @ 2025-11-17 19:10 UTC (permalink / raw)
To: Pauli Virtanen; +Cc: linux-bluetooth
Hello:
This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:
On Sat, 15 Nov 2025 14:58:28 +0200 you wrote:
> bt_bap_select() does not correctly determine the need for multi-stream
> configurations 6,7,8,9,11(i), as its result depends on whether Audio
> Locations is read before or after the PACs, doesn't work with general
> location bits, etc.
>
> Fix the procedure to be simpler: create streams for all locations, up to
> a specific number of channels. By default, limit to max 2 channels per
> direction for compatibility (BAP doesn't have explicit AC with larger
> channel counts.) Also simplify the code.
>
> [...]
Here is the summary with links:
- [BlueZ,v4,1/6] shared/bap: fix channel allocation logic in bt_bap_select()
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=f1afca6a097b
- [BlueZ,v4,2/6] shared/bap: fix packet length comparison to ATT MTU in bap_queue_req()
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=0c56d482fd20
- [BlueZ,v4,3/6] bap: don't configure endpoints of all codecs at once
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=231372ca5e15
- [BlueZ,v4,4/6] shared/tester: better debug output on io memcmp failure
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=a1f8862a38a5
- [BlueZ,v4,5/6] test-bap: make PDU macros parametrizable
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=7858675e6281
- [BlueZ,v4,6/6] test-bap: add audio configuration selection and streaming tests
https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=8a41ac3fde99
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-11-17 19:10 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-15 12:58 [PATCH BlueZ v4 1/6] shared/bap: fix channel allocation logic in bt_bap_select() Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 2/6] shared/bap: fix packet length comparison to ATT MTU in bap_queue_req() Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 3/6] bap: don't configure endpoints of all codecs at once Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 4/6] shared/tester: better debug output on io memcmp failure Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 5/6] test-bap: make PDU macros parametrizable Pauli Virtanen
2025-11-15 12:58 ` [PATCH BlueZ v4 6/6] test-bap: add audio configuration selection and streaming tests Pauli Virtanen
2025-11-15 14:03 ` [BlueZ,v4,1/6] shared/bap: fix channel allocation logic in bt_bap_select() bluez.test.bot
2025-11-17 19:10 ` [PATCH BlueZ v4 1/6] " patchwork-bot+bluetooth
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).