Bluetooth: Audio: Refactor bt_audio_codec_cfg to flat arrays

Refactor the bt_audio_codec_cfg to use flat arrays to store
metadata and codec specific configurations.

The purpose of this is to make it easier to copy the data
between layers, but also to support non-LTV data for non-LC3
codec configurations.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2023-05-22 15:08:57 +02:00 committed by Carles Cufí
commit 6ccd112c56
50 changed files with 1181 additions and 1824 deletions

View file

@ -108,7 +108,7 @@ static int setup_broadcast_source(struct bt_bap_broadcast_source **source)
for (size_t j = 0U; j < ARRAY_SIZE(stream_params); j++) {
stream_params[j].stream = &streams[j];
stream_params[j].data = NULL;
stream_params[j].data_count = 0U;
stream_params[j].data_len = 0U;
bt_bap_stream_cb_register(stream_params[j].stream, &stream_ops);
}

View file

@ -58,24 +58,29 @@ static void print_hex(const uint8_t *ptr, size_t len)
}
}
static bool print_cb(struct bt_data *data, void *user_data)
{
const char *str = (const char *)user_data;
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
print_hex(data->data, data->data_len);
printk("\n");
return true;
}
static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
{
printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid,
codec_cfg->vid, codec_cfg->data_count);
for (size_t i = 0; i < codec_cfg->data_count; i++) {
printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type,
codec_cfg->data[i].data.data_len);
print_hex(codec_cfg->data[i].data.data,
codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type));
printk("\n");
}
codec_cfg->vid, codec_cfg->data_len);
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
/* LC3 uses the generic LTV format - other codecs might do as well */
enum bt_audio_location chan_allocation;
bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data");
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg));
printk(" Frame Duration: %d us\n",
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
@ -87,15 +92,11 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
bt_audio_codec_cfg_get_octets_per_frame(codec_cfg));
printk(" Frames per SDU: %d\n",
bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
} else {
print_hex(codec_cfg->data, codec_cfg->data_len);
}
for (size_t i = 0; i < codec_cfg->meta_count; i++) {
printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type,
codec_cfg->meta[i].data.data_len);
print_hex(codec_cfg->meta[i].data.data,
codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type));
printk("\n");
}
bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta");
}
static void print_qos(const struct bt_audio_codec_qos *qos)
@ -233,10 +234,10 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos
return 0;
}
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
struct bt_bap_ascs_rsp *rsp)
{
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
return 0;
}
@ -264,25 +265,26 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
return 0;
}
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
static bool data_func_cb(struct bt_data *data, void *user_data)
{
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
for (size_t i = 0; i < meta_count; i++) {
const struct bt_audio_codec_data *data = &meta[i];
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
printk("Invalid metadata type %u or length %u\n",
data->data.type, data->data.data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
data->data.type);
return -EINVAL;
}
return -EINVAL;
}
return 0;
return true;
}
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
struct bt_bap_ascs_rsp *rsp)
{
printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
}
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)

View file

@ -16,7 +16,7 @@
#include <zephyr/bluetooth/audio/tmap.h>
#define BROADCAST_ENQUEUE_COUNT 2U
#define MOCK_CCID 0x1234
#define MOCK_CCID 0xAB
NET_BUF_POOL_FIXED_DEFINE(tx_pool,
(BROADCAST_ENQUEUE_COUNT * CONFIG_BT_BAP_BROADCAST_SRC_STREAM_COUNT),
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_TX_MTU), 8, NULL);
@ -27,16 +27,13 @@ static K_SEM_DEFINE(sem_broadcast_stopped, 0, 1);
static struct bt_cap_stream broadcast_source_stream;
static struct bt_cap_stream *broadcast_stream;
struct bt_audio_codec_data bis_codec_data = BT_AUDIO_CODEC_DATA(
BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ);
static uint8_t bis_codec_data[] = {BT_AUDIO_CODEC_DATA(
BT_AUDIO_CODEC_CONFIG_LC3_FREQ, BT_BYTES_LIST_LE16(BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ))};
const struct bt_audio_codec_data new_metadata[] = {
static const uint8_t new_metadata[] = {
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
(BT_AUDIO_CONTEXT_TYPE_MEDIA & 0xFFU),
((BT_AUDIO_CONTEXT_TYPE_MEDIA >> 8) & 0xFFU)),
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST,
(MOCK_CCID & 0xFFU),
((MOCK_CCID >> 8) & 0xFFU))
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, MOCK_CCID),
};
static struct bt_bap_lc3_preset broadcast_preset_48_2_1 =
@ -252,8 +249,8 @@ void cap_initiator_setup(void)
int err;
stream_params.stream = &broadcast_source_stream;
stream_params.data_count = 1U;
stream_params.data = &bis_codec_data;
stream_params.data_len = ARRAY_SIZE(bis_codec_data);
stream_params.data = bis_codec_data;
subgroup_param.stream_count = 1U;
subgroup_param.stream_params = &stream_params;

View file

@ -180,27 +180,15 @@ static void print_hex(const uint8_t *ptr, size_t len)
}
}
static void print_ltv_elem(const char *str, uint8_t type, uint8_t value_len, const uint8_t *value,
size_t cnt)
static bool print_cb(struct bt_data *data, void *user_data)
{
printk("%s #%zu: type 0x%02x value_len %u\n", str, cnt, type, value_len);
print_hex(value, value_len);
const char *str = (const char *)user_data;
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
print_hex(data->data, data->data_len);
printk("\n");
}
static void print_ltv_array(const char *str, const uint8_t *ltv_data, size_t ltv_data_len)
{
size_t cnt = 0U;
for (size_t i = 0U; i < ltv_data_len; i++) {
const uint8_t len = ltv_data[i++];
const uint8_t type = ltv_data[i++];
const uint8_t *value = &ltv_data[i];
const uint8_t value_len = len - sizeof(type);
print_ltv_elem(str, type, value_len, value, cnt++);
i += value_len;
}
return true;
}
static void print_remote_codec(const struct bt_audio_codec_cap *codec_cap, enum bt_audio_dir dir)
@ -209,14 +197,14 @@ static void print_remote_codec(const struct bt_audio_codec_cap *codec_cap, enum
codec_cap->vid, codec_cap->data_len);
if (codec_cap->id == BT_AUDIO_CODEC_LC3_ID) {
print_ltv_array("data", codec_cap->data, codec_cap->data_len);
bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data");
} else { /* If not LC3, we cannot assume it's LTV */
printk("data: ");
print_hex(codec_cap->data, codec_cap->data_len);
printk("\n");
}
print_ltv_array("meta", codec_cap->meta, codec_cap->meta_len);
bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta");
}
static void add_remote_sink(struct bt_bap_ep *ep)

View file

@ -48,23 +48,28 @@ static void print_hex(const uint8_t *ptr, size_t len)
}
}
static bool print_cb(struct bt_data *data, void *user_data)
{
const char *str = (const char *)user_data;
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
print_hex(data->data, data->data_len);
printk("\n");
return true;
}
static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
{
printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid,
codec_cfg->vid, codec_cfg->data_count);
for (size_t i = 0; i < codec_cfg->data_count; i++) {
printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type,
codec_cfg->data[i].data.data_len);
print_hex(codec_cfg->data[i].data.data,
codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type));
printk("\n");
}
codec_cfg->vid, codec_cfg->data_len);
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
/* LC3 uses the generic LTV format - other codecs might do as well */
uint32_t chan_allocation;
enum bt_audio_location chan_allocation;
bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data");
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg));
printk(" Frame Duration: %d us\n",
@ -77,15 +82,11 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
bt_audio_codec_cfg_get_octets_per_frame(codec_cfg));
printk(" Frames per SDU: %d\n",
bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
} else {
print_hex(codec_cfg->data, codec_cfg->data_len);
}
for (size_t i = 0; i < codec_cfg->meta_count; i++) {
printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type,
codec_cfg->meta[i].data.data_len);
print_hex(codec_cfg->meta[i].data.data,
codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type));
printk("\n");
}
bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta");
}
static void print_qos(const struct bt_audio_codec_qos *qos)
@ -158,10 +159,10 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos
return 0;
}
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
struct bt_bap_ascs_rsp *rsp)
{
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
return 0;
}
@ -173,46 +174,63 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
return 0;
}
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
struct data_func_param {
struct bt_bap_ascs_rsp *rsp;
bool stream_context_present;
};
static bool data_func_cb(struct bt_data *data, void *user_data)
{
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
bool stream_context_present = false;
struct data_func_param *func_param = (struct data_func_param *)user_data;
for (size_t i = 0; i < meta_count; i++) {
const struct bt_audio_codec_data *data = &meta[i];
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
*func_param->rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
data->type);
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
printk("Invalid metadata type %u or length %u\n",
data->data.type, data->data.data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
data->data.type);
return false;
}
return -EINVAL;
}
if (data->type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
func_param->stream_context_present = true;
}
if (data->data.type == BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT) {
stream_context_present = true;
}
if (data->type == BT_AUDIO_METADATA_TYPE_CCID_LIST) {
for (uint8_t j = 0; j < data->data_len; j++) {
const uint8_t ccid = data->data[j];
if (data->data.type == BT_AUDIO_METADATA_TYPE_CCID_LIST) {
for (uint8_t j = 0; j < data->data.data_len; j++) {
const uint8_t ccid = data->data.data[j];
if (!(IS_ENABLED(CONFIG_BT_TBS_CLIENT_CCID) &&
bt_tbs_client_get_by_ccid(default_conn, ccid) != NULL)) {
printk("CCID %u is unknown", ccid);
*func_param->rsp =
BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
BT_BAP_ASCS_REASON_NONE);
if (!(IS_ENABLED(CONFIG_BT_TBS_CLIENT_CCID) &&
bt_tbs_client_get_by_ccid(default_conn, ccid) != NULL)) {
printk("CCID %u is unknown", ccid);
*rsp = BT_BAP_ASCS_RSP(
BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
BT_BAP_ASCS_REASON_NONE);
return -EINVAL;
}
return false;
}
}
}
if (stream_context_present == false) {
return true;
}
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
struct bt_bap_ascs_rsp *rsp)
{
struct data_func_param func_param = {
.rsp = rsp,
.stream_context_present = false,
};
int err;
printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
err = bt_audio_data_parse(meta, meta_len, data_func_cb, &func_param);
if (err != 0) {
return err;
}
if (!func_param.stream_context_present) {
printk("Stream audio context not present on peer!");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
BT_BAP_ASCS_REASON_NONE);

View file

@ -353,27 +353,15 @@ static void print_hex(const uint8_t *ptr, size_t len)
}
}
static void print_ltv_elem(const char *str, uint8_t type, uint8_t value_len, const uint8_t *value,
size_t cnt)
static bool print_cb(struct bt_data *data, void *user_data)
{
printk("%s #%zu: type 0x%02x value_len %u\n", str, cnt, type, value_len);
print_hex(value, value_len);
const char *str = (const char *)user_data;
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
print_hex(data->data, data->data_len);
printk("\n");
}
static void print_ltv_array(const char *str, const uint8_t *ltv_data, size_t ltv_data_len)
{
size_t cnt = 0U;
for (size_t i = 0U; i < ltv_data_len; i++) {
const uint8_t len = ltv_data[i++];
const uint8_t type = ltv_data[i++];
const uint8_t *value = &ltv_data[i];
const uint8_t value_len = len - sizeof(type);
print_ltv_elem(str, type, value_len, value, cnt++);
i += value_len;
}
return true;
}
static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
@ -382,14 +370,14 @@ static void print_codec_cap(const struct bt_audio_codec_cap *codec_cap)
codec_cap->vid, codec_cap->data_len);
if (codec_cap->id == BT_AUDIO_CODEC_LC3_ID) {
print_ltv_array("data", codec_cap->data, codec_cap->data_len);
bt_audio_data_parse(codec_cap->data, codec_cap->data_len, print_cb, "data");
} else { /* If not LC3, we cannot assume it's LTV */
printk("data: ");
print_hex(codec_cap->data, codec_cap->data_len);
printk("\n");
}
print_ltv_array("meta", codec_cap->meta, codec_cap->meta_len);
bt_audio_data_parse(codec_cap->meta, codec_cap->meta_len, print_cb, "meta");
}
static bool check_audio_support_and_connect(struct bt_data *data,
@ -998,7 +986,7 @@ static int enable_streams(void)
int err;
err = bt_bap_stream_enable(&streams[i], codec_configuration.codec_cfg.meta,
codec_configuration.codec_cfg.meta_count);
codec_configuration.codec_cfg.meta_len);
if (err != 0) {
printk("Unable to enable stream: %d\n", err);
return err;

View file

@ -118,24 +118,29 @@ void print_hex(const uint8_t *ptr, size_t len)
}
}
static bool print_cb(struct bt_data *data, void *user_data)
{
const char *str = (const char *)user_data;
printk("%s: type 0x%02x value_len %u\n", str, data->type, data->data_len);
print_hex(data->data, data->data_len);
printk("\n");
return true;
}
static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
{
printk("codec_cfg 0x%02x cid 0x%04x vid 0x%04x count %u\n", codec_cfg->id, codec_cfg->cid,
codec_cfg->vid, codec_cfg->data_count);
for (size_t i = 0; i < codec_cfg->data_count; i++) {
printk("data #%zu: type 0x%02x len %u\n", i, codec_cfg->data[i].data.type,
codec_cfg->data[i].data.data_len);
print_hex(codec_cfg->data[i].data.data,
codec_cfg->data[i].data.data_len - sizeof(codec_cfg->data[i].data.type));
printk("\n");
}
codec_cfg->vid, codec_cfg->data_len);
if (codec_cfg->id == BT_AUDIO_CODEC_LC3_ID) {
/* LC3 uses the generic LTV format - other codecs might do as well */
enum bt_audio_location chan_allocation;
bt_audio_data_parse(codec_cfg->data, codec_cfg->data_len, print_cb, "data");
printk(" Frequency: %d Hz\n", bt_audio_codec_cfg_get_freq(codec_cfg));
printk(" Frame Duration: %d us\n",
bt_audio_codec_cfg_get_frame_duration_us(codec_cfg));
@ -147,15 +152,11 @@ static void print_codec_cfg(const struct bt_audio_codec_cfg *codec_cfg)
bt_audio_codec_cfg_get_octets_per_frame(codec_cfg));
printk(" Frames per SDU: %d\n",
bt_audio_codec_cfg_get_frame_blocks_per_sdu(codec_cfg, true));
} else {
print_hex(codec_cfg->data, codec_cfg->data_len);
}
for (size_t i = 0; i < codec_cfg->meta_count; i++) {
printk("meta #%zu: type 0x%02x len %u\n", i, codec_cfg->meta[i].data.type,
codec_cfg->meta[i].data.data_len);
print_hex(codec_cfg->meta[i].data.data,
codec_cfg->meta[i].data.data_len - sizeof(codec_cfg->meta[i].data.type));
printk("\n");
}
bt_audio_data_parse(codec_cfg->meta, codec_cfg->meta_len, print_cb, "meta");
}
static void print_qos(const struct bt_audio_codec_qos *qos)
@ -341,10 +342,10 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_audio_codec_qos
return 0;
}
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
static int lc3_enable(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
struct bt_bap_ascs_rsp *rsp)
{
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
printk("Enable: stream %p meta_len %zu\n", stream, meta_len);
#if defined(CONFIG_LIBLC3)
{
@ -408,25 +409,26 @@ static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
return 0;
}
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_audio_codec_data *meta,
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
static bool data_func_cb(struct bt_data *data, void *user_data)
{
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
struct bt_bap_ascs_rsp *rsp = (struct bt_bap_ascs_rsp *)user_data;
for (size_t i = 0; i < meta_count; i++) {
const struct bt_audio_codec_data *data = &meta[i];
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->type)) {
printk("Invalid metadata type %u or length %u\n", data->type, data->data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data->type);
if (!BT_AUDIO_METADATA_TYPE_IS_KNOWN(data->data.type)) {
printk("Invalid metadata type %u or length %u\n",
data->data.type, data->data.data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
data->data.type);
return -EINVAL;
}
return -EINVAL;
}
return 0;
return true;
}
static int lc3_metadata(struct bt_bap_stream *stream, const uint8_t meta[], size_t meta_len,
struct bt_bap_ascs_rsp *rsp)
{
printk("Metadata: stream %p meta_len %zu\n", stream, meta_len);
return bt_audio_data_parse(meta, meta_len, data_func_cb, rsp);
}
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)