LE Audio: Refactor server ASE callbacks to return rsp object

From now app layer is able to return explicit response code and
reason that will appear in ASE Control Point notification.

Fixes issues of ASCS/SR/SPE/BI-(07/08/09)-C PTS test cases, where
PTS was receiving wrong response codes and reasons.

Signed-off-by: Magdalena Kasenberg <magdalena.kasenberg@codecoup.pl>
This commit is contained in:
Magdalena Kasenberg 2023-02-15 11:22:04 +01:00 committed by Carles Cufí
commit 57784df5f0
12 changed files with 459 additions and 305 deletions

View file

@ -154,6 +154,62 @@ enum bt_bap_ascs_reason {
BT_BAP_ASCS_REASON_CIS = 0x0a,
};
/** @brief Structure storing values of fields of ASE Control Point notification. */
struct bt_bap_ascs_rsp {
/** @brief Value of the Response Code field. */
enum bt_bap_ascs_rsp_code code;
/**
* @brief Value of the Reason field.
*
* The meaning of this value depend on the Response Code field.
*/
union {
/**
* @brief Response reason
*
* If the Response Code is one of the following:
* - @ref BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED
* - @ref BT_BAP_ASCS_RSP_CODE_CONF_REJECTED
* - @ref BT_BAP_ASCS_RSP_CODE_CONF_INVALID
* all values from @ref bt_bap_ascs_reason can be used.
*
* If the Response Code is one of the following:
* - @ref BT_BAP_ASCS_RSP_CODE_SUCCESS
* - @ref BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED
* - @ref BT_BAP_ASCS_RSP_CODE_INVALID_LENGTH
* - @ref BT_BAP_ASCS_RSP_CODE_INVALID_ASE
* - @ref BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE
* - @ref BT_BAP_ASCS_RSP_CODE_INVALID_DIR
* - @ref BT_BAP_ASCS_RSP_CODE_CAP_UNSUPPORTED
* - @ref BT_BAP_ASCS_RSP_CODE_NO_MEM
* - @ref BT_BAP_ASCS_RSP_CODE_UNSPECIFIED
* only value @ref BT_BAP_ASCS_REASON_NONE shall be used.
*/
enum bt_bap_ascs_reason reason;
/**
* @brief Response metadata type
*
* If the Response Code is one of the following:
* - @ref BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED
* - @ref BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED
* - @ref BT_BAP_ASCS_RSP_CODE_METADATA_INVALID
* the value of the Metadata Type shall be used.
*/
enum bt_audio_metadata_type metadata_type;
};
};
/**
* @brief Macro used to initialise the object storing values of ASE Control Point notification.
*
* @param c Response Code field
* @param r Reason field - @ref bt_bap_ascs_reason or @ref bt_audio_metadata_type (see notes in
* @ref bt_bap_ascs_rsp).
*/
#define BT_BAP_ASCS_RSP(c, r) (struct bt_bap_ascs_rsp) { .code = c, .reason = r }
/** @brief Abstract Audio Broadcast Source structure. */
struct bt_bap_broadcast_source;
@ -580,12 +636,14 @@ struct bt_bap_unicast_server_cb {
* @param[out] stream Pointer to stream that will be configured for the endpoint.
* @param[out] pref Pointer to a QoS preference object that shall be populated with
* values. Invalid values will reject the codec configuration request.
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*config)(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_bap_stream **stream,
struct bt_codec_qos_pref *const pref);
struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp);
/**
* @brief Stream reconfig request callback
@ -598,11 +656,14 @@ struct bt_bap_unicast_server_cb {
* @param[in] codec Codec configuration.
* @param[out] pref Pointer to a QoS preference object that shall be populated with
* values. Invalid values will reject the codec configuration request.
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*reconfig)(struct bt_bap_stream *stream, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref);
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref,
struct bt_bap_ascs_rsp *rsp);
/**
* @brief Stream QoS request callback
@ -610,73 +671,86 @@ struct bt_bap_unicast_server_cb {
* QoS callback is called whenever an Audio Stream Quality of
* Service needs to be configured.
*
* @param stream Stream object being reconfigured.
* @param qos Quality of Service configuration.
* @param[in] stream Stream object being reconfigured.
* @param[in] qos Quality of Service configuration.
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*qos)(struct bt_bap_stream *stream, const struct bt_codec_qos *qos);
int (*qos)(struct bt_bap_stream *stream, const struct bt_codec_qos *qos,
struct bt_bap_ascs_rsp *rsp);
/**
* @brief Stream Enable request callback
*
* Enable callback is called whenever an Audio Stream is requested to be enabled to stream.
*
* @param stream Stream object being enabled.
* @param meta Metadata entries
* @param meta_count Number of metadata entries
* @param[in] stream Stream object being enabled.
* @param[in] meta Metadata entries
* @param[in] meta_count Number of metadata entries
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*enable)(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count);
size_t meta_count, struct bt_bap_ascs_rsp *rsp);
/**
* @brief Stream Start request callback
*
* Start callback is called whenever an Audio Stream is requested to start streaming.
*
* @param stream Stream object.
* @param[in] stream Stream object.
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*start)(struct bt_bap_stream *stream);
int (*start)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp);
/**
* @brief Stream Metadata update request callback
*
* Metadata callback is called whenever an Audio Stream is requested to update its metadata.
*
* @param stream Stream object.
* @param meta Metadata entries
* @param meta_count Number of metadata entries
* @param[in] stream Stream object.
* @param[in] meta Metadata entries
* @param[in] meta_count Number of metadata entries
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*metadata)(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count);
size_t meta_count, struct bt_bap_ascs_rsp *rsp);
/**
* @brief Stream Disable request callback
*
* Disable callback is called whenever an Audio Stream is requested to disable the stream.
*
* @param stream Stream object being disabled.
* @param[in] stream Stream object being disabled.
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*disable)(struct bt_bap_stream *stream);
int (*disable)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp);
/**
* @brief Stream Stop callback
*
* Stop callback is called whenever an Audio Stream is requested to stop streaming.
*
* @param stream Stream object.
* @param[in] stream Stream object.
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*stop)(struct bt_bap_stream *stream);
int (*stop)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp);
/**
* @brief Stream release callback
@ -684,11 +758,13 @@ struct bt_bap_unicast_server_cb {
* Release callback is called whenever a new Audio Stream needs to be released and thus
* deallocated.
*
* @param stream Stream object.
* @param[in] stream Stream object.
* @param[out] rsp Object for the ASE operation response. Only used if the return
* value is non-zero.
*
* @return 0 in case of success or negative value in case of error.
*/
int (*release)(struct bt_bap_stream *stream);
int (*release)(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp);
};
/**

View file

@ -189,7 +189,7 @@ static struct bt_bap_stream *stream_alloc(void)
static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_bap_stream **stream,
struct bt_codec_qos_pref *const pref)
struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp)
{
printk("ASE Codec Config: conn %p ep %p dir %u\n", conn, ep, dir);
@ -198,7 +198,7 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_
*stream = stream_alloc();
if (*stream == NULL) {
printk("No streams available\n");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
return -ENOMEM;
}
@ -214,17 +214,21 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_
}
static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref)
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref,
struct bt_bap_ascs_rsp *rsp)
{
printk("ASE Codec Reconfig: stream %p\n", stream);
print_codec(codec);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, BT_BAP_ASCS_REASON_NONE);
/* We only support one QoS at the moment, reject changes */
return -ENOEXEC;
}
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos,
struct bt_bap_ascs_rsp *rsp)
{
printk("QoS: stream %p qos %p\n", stream, qos);
@ -234,14 +238,14 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
}
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
return 0;
}
static int lc3_start(struct bt_bap_stream *stream)
static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Start: stream %p\n", stream);
@ -308,14 +312,18 @@ static bool valid_metadata_type(uint8_t type, uint8_t len)
}
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
for (size_t i = 0; i < meta_count; i++) {
if (!valid_metadata_type(meta->data.type, meta->data.data_len)) {
const struct bt_codec_data *data = &meta[i];
if (!valid_metadata_type(data->data.type, data->data.data_len)) {
printk("Invalid metadata type %u or length %u\n",
meta->data.type, meta->data.data_len);
data->data.type, data->data.data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
data->data.type);
return -EINVAL;
}
@ -324,21 +332,21 @@ static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data
return 0;
}
static int lc3_disable(struct bt_bap_stream *stream)
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Disable: stream %p\n", stream);
return 0;
}
static int lc3_stop(struct bt_bap_stream *stream)
static int lc3_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Stop: stream %p\n", stream);
return 0;
}
static int lc3_release(struct bt_bap_stream *stream)
static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Release: stream %p\n", stream);
return 0;

View file

@ -261,7 +261,7 @@ static struct bt_bap_stream *stream_alloc(enum bt_audio_dir dir)
static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_bap_stream **stream,
struct bt_codec_qos_pref *const pref)
struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp)
{
printk("ASE Codec Config: conn %p ep %p dir %u\n", conn, ep, dir);
@ -270,6 +270,7 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_
*stream = stream_alloc(dir);
if (*stream == NULL) {
printk("No streams available\n");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
return -ENOMEM;
}
@ -291,7 +292,8 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_
}
static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref)
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref,
struct bt_bap_ascs_rsp *rsp)
{
printk("ASE Codec Reconfig: stream %p\n", stream);
@ -302,11 +304,14 @@ static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
lc3_decoder = NULL;
#endif
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, BT_BAP_ASCS_REASON_NONE);
/* We only support one QoS at the moment, reject changes */
return -ENOEXEC;
}
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos,
struct bt_bap_ascs_rsp *rsp)
{
printk("QoS: stream %p qos %p\n", stream, qos);
@ -323,7 +328,7 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
}
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
@ -334,11 +339,15 @@ static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *
if (freq < 0) {
printk("Error: Codec frequency not set, cannot start codec.");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CODEC_DATA);
return -1;
}
if (frame_duration_us < 0) {
printk("Error: Frame duration not set, cannot start codec.");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CODEC_DATA);
return -1;
}
@ -351,6 +360,8 @@ static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *
if (lc3_decoder == NULL) {
printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CODEC_DATA);
return -1;
}
}
@ -359,7 +370,7 @@ static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *
return 0;
}
static int lc3_start(struct bt_bap_stream *stream)
static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Start: stream %p\n", stream);
@ -425,14 +436,18 @@ static bool valid_metadata_type(uint8_t type, uint8_t len)
}
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
for (size_t i = 0; i < meta_count; i++) {
if (!valid_metadata_type(meta->data.type, meta->data.data_len)) {
const struct bt_codec_data *data = &meta[i];
if (!valid_metadata_type(data->data.type, data->data.data_len)) {
printk("Invalid metadata type %u or length %u\n",
meta->data.type, meta->data.data_len);
data->data.type, data->data.data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
data->data.type);
return -EINVAL;
}
@ -441,21 +456,21 @@ static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data
return 0;
}
static int lc3_disable(struct bt_bap_stream *stream)
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Disable: stream %p\n", stream);
return 0;
}
static int lc3_stop(struct bt_bap_stream *stream)
static int lc3_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Stop: stream %p\n", stream);
return 0;
}
static int lc3_release(struct bt_bap_stream *stream)
static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Release: stream %p\n", stream);
return 0;

View file

@ -902,65 +902,6 @@ static void ascs_cp_rsp_add(uint8_t id, uint8_t op, uint8_t code,
ase_rsp->reason = reason;
}
static void ascs_cp_rsp_add_errno(uint8_t id, uint8_t op, int err,
uint8_t reason)
{
LOG_DBG("id %u op %u err %d reason %u", id, op, err, reason);
switch (err) {
case -ENOBUFS:
case -ENOMEM:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_NO_MEM,
BT_BAP_ASCS_REASON_NONE);
case -EINVAL:
switch (op) {
case BT_ASCS_CONFIG_OP:
/* Fallthrough */
case BT_ASCS_QOS_OP:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_CONF_INVALID, reason);
case BT_ASCS_ENABLE_OP:
/* Fallthrough */
case BT_ASCS_METADATA_OP:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_METADATA_INVALID,
reason);
default:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
case -ENOTSUP:
switch (op) {
case BT_ASCS_CONFIG_OP:
/* Fallthrough */
case BT_ASCS_QOS_OP:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED,
reason);
case BT_ASCS_ENABLE_OP:
/* Fallthrough */
case BT_ASCS_METADATA_OP:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_METADATA_UNSUPPORTED,
reason);
default:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
case -EBADMSG:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE,
BT_BAP_ASCS_REASON_NONE);
case -EACCES:
switch (op) {
case BT_ASCS_METADATA_OP:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
reason);
default:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
default:
return ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
}
static void ascs_cp_rsp_success(uint8_t id, uint8_t op)
{
ascs_cp_rsp_add(id, op, BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
@ -969,6 +910,8 @@ static void ascs_cp_rsp_success(uint8_t id, uint8_t op)
static void ase_release(struct bt_ascs_ase *ase)
{
uint8_t ase_id = ASE_ID(ase);
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
LOG_DBG("ase %p state %s", ase, bt_bap_ep_state_str(ase->ep.status.state));
@ -979,13 +922,21 @@ static void ase_release(struct bt_ascs_ase *ase)
}
if (unicast_server_cb != NULL && unicast_server_cb->release != NULL) {
err = unicast_server_cb->release(ase->ep.stream);
err = unicast_server_cb->release(ase->ep.stream, &rsp);
} else {
err = -ENOTSUP;
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
if (err) {
ascs_cp_rsp_add_errno(ase_id, BT_ASCS_RELEASE_OP, err, BT_BAP_ASCS_REASON_NONE);
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_ERR("Release failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
ascs_cp_rsp_add(ase_id, BT_ASCS_RELEASE_OP, rsp.code, rsp.reason);
return;
}
@ -999,6 +950,8 @@ static void ase_disable(struct bt_ascs_ase *ase)
{
struct bt_bap_stream *stream;
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
LOG_DBG("ase %p", ase);
@ -1013,23 +966,29 @@ static void ase_disable(struct bt_ascs_ase *ase)
break;
default:
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_DISABLE_OP, -EBADMSG,
BT_BAP_ASCS_REASON_NONE);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_DISABLE_OP,
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE);
return;
}
stream = ep->stream;
if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) {
err = unicast_server_cb->disable(stream);
err = unicast_server_cb->disable(stream, &rsp);
} else {
err = -ENOTSUP;
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
if (err) {
LOG_ERR("Disable failed: %d", err);
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_DISABLE_OP, err,
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_ERR("Disable failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_DISABLE_OP, rsp.code, rsp.reason);
return;
}
@ -1315,6 +1274,8 @@ static bool ascs_codec_config_store(struct bt_data *data, void *user_data)
struct codec_lookup_id_data {
uint8_t id;
uint16_t cid;
uint16_t vid;
struct bt_codec *codec;
};
@ -1322,7 +1283,8 @@ static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data)
{
struct codec_lookup_id_data *data = user_data;
if (cap->codec->id == data->id) {
if (cap->codec->id == data->id && cap->codec->cid == data->cid &&
cap->codec->vid == data->vid) {
data->codec = cap->codec;
return false;
@ -1332,14 +1294,19 @@ static bool codec_lookup_id(const struct bt_pacs_cap *cap, void *user_data)
}
static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uint16_t vid,
struct net_buf_simple *buf, uint8_t len, struct bt_codec *codec)
struct net_buf_simple *buf, uint8_t len, struct bt_codec *codec,
struct bt_bap_ascs_rsp *rsp)
{
struct net_buf_simple ad;
struct codec_lookup_id_data lookup_data = {
.id = id,
.cid = cid,
.vid = vid,
};
if (ep == NULL && codec == NULL) {
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CODEC_DATA);
return -EINVAL;
}
@ -1352,6 +1319,8 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin
LOG_DBG("Codec with id %u for dir %s is not supported by our capabilities",
id, bt_audio_dir_str(ep->dir));
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CODEC);
return -ENOENT;
}
@ -1366,6 +1335,7 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin
codec->path_id = lookup_data.codec->path_id;
if (len == 0 || buf == NULL) {
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
return 0;
}
@ -1379,19 +1349,23 @@ static int ascs_ep_set_codec(struct bt_bap_ep *ep, uint8_t id, uint16_t cid, uin
if (ad.len) {
LOG_ERR("Unable to parse Codec Config: len %u", ad.len);
(void)memset(codec, 0, sizeof(*codec));
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CODEC_DATA);
return -EINVAL;
}
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
return 0;
}
static int ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
static void ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
const struct bt_ascs_config *cfg,
struct net_buf_simple *buf)
{
struct bt_bap_stream *stream;
struct bt_codec codec;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
LOG_DBG("ase %p latency 0x%02x phy 0x%02x codec 0x%02x "
@ -1402,17 +1376,18 @@ static int ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
if (cfg->latency < BT_ASCS_CONFIG_LATENCY_LOW ||
cfg->latency > BT_ASCS_CONFIG_LATENCY_HIGH) {
LOG_WRN("Invalid latency: 0x%02x", cfg->latency);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP,
BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_LATENCY);
return 0;
return;
}
if (cfg->phy < BT_ASCS_CONFIG_PHY_LE_1M ||
cfg->phy > BT_ASCS_CONFIG_PHY_LE_CODED) {
LOG_WRN("Invalid PHY: 0x%02x", cfg->phy);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_PHY);
return 0;
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP,
BT_BAP_ASCS_RSP_CODE_CONF_INVALID, BT_BAP_ASCS_REASON_PHY);
return;
}
switch (ase->ep.status.state) {
@ -1428,7 +1403,7 @@ static int ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
bt_bap_ep_state_str(ase->ep.status.state));
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP,
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, 0x00);
return 0;
return;
}
/* Store current codec configuration to be able to restore it
@ -1436,14 +1411,14 @@ static int ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
*/
(void)memcpy(&codec, &ase->ep.codec, sizeof(codec));
if (ascs_ep_set_codec(&ase->ep, cfg->codec.id,
err = ascs_ep_set_codec(&ase->ep, cfg->codec.id,
sys_le16_to_cpu(cfg->codec.cid),
sys_le16_to_cpu(cfg->codec.vid),
buf, cfg->cc_len, &ase->ep.codec)) {
buf, cfg->cc_len, &ase->ep.codec, &rsp);
if (err) {
(void)memcpy(&ase->ep.codec, &codec, sizeof(codec));
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CODEC_DATA);
return 0;
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, rsp.code, rsp.reason);
return;
}
if (ase->ep.stream != NULL) {
@ -1452,21 +1427,27 @@ static int ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
err = unicast_server_cb->reconfig(ase->ep.stream,
ase->ep.dir,
&ase->ep.codec,
&ase->ep.qos_pref);
&ase->ep.qos_pref,
&rsp);
} else {
err = -ENOTSUP;
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
if (err != 0) {
uint8_t reason = BT_BAP_ASCS_REASON_CODEC_DATA;
if (err) {
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_ERR("Reconfig failed: %d", err);
LOG_ERR("Reconfig failed: err %d, code %u, reason %u",
err, rsp.code, rsp.reason);
(void)memcpy(&ase->ep.codec, &codec, sizeof(codec));
ascs_cp_rsp_add_errno(ASE_ID(ase),
BT_ASCS_CONFIG_OP,
err, reason);
return 0;
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, rsp.code, rsp.reason);
return;
}
stream = ase->ep.stream;
@ -1474,23 +1455,28 @@ static int ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
stream = NULL;
if (unicast_server_cb != NULL &&
unicast_server_cb->config != NULL) {
err = unicast_server_cb->config(ascs->conn, &ase->ep,
ase->ep.dir,
err = unicast_server_cb->config(ascs->conn, &ase->ep, ase->ep.dir,
&ase->ep.codec, &stream,
&ase->ep.qos_pref);
&ase->ep.qos_pref, &rsp);
} else {
err = -ENOTSUP;
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
if (err != 0 || stream == NULL) {
LOG_ERR("Config failed, err: %d, stream %p", err, stream);
if (err || stream == NULL) {
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_ERR("Config failed: err %d, stream %p, code %u, reason %u",
err, stream, rsp.code, rsp.reason);
(void)memcpy(&ase->ep.codec, &codec, sizeof(codec));
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP,
BT_BAP_ASCS_RSP_CODE_CONF_REJECTED,
BT_BAP_ASCS_REASON_CODEC_DATA);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, rsp.code, rsp.reason);
return err;
return;
}
bt_bap_stream_init(stream);
@ -1501,8 +1487,6 @@ static int ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
bt_bap_stream_attach(ascs->conn, stream, &ase->ep, &ase->ep.codec);
ascs_ep_set_state(&ase->ep, BT_BAP_EP_STATE_CODEC_CONFIGURED);
return 0;
}
int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struct bt_codec *codec,
@ -1512,6 +1496,8 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struc
struct bt_ascs *ascs;
struct bt_ascs_ase *ase;
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
CHECKIF(conn == NULL || stream == NULL || codec == NULL || qos_pref == NULL) {
LOG_DBG("NULL value(s) supplied)");
@ -1549,7 +1535,7 @@ int bt_ascs_config_ase(struct bt_conn *conn, struct bt_bap_stream *stream, struc
}
err = ascs_ep_set_codec(ep, codec->id, sys_le16_to_cpu(codec->cid),
sys_le16_to_cpu(codec->vid), NULL, 0, &ep->codec);
sys_le16_to_cpu(codec->vid), NULL, 0, &ep->codec, &rsp);
if (err) {
return err;
}
@ -1623,7 +1609,6 @@ static ssize_t ascs_config(struct bt_ascs *ascs, struct net_buf_simple *buf)
for (uint8_t i = 0; i < req->num_ases; i++) {
struct bt_ascs_ase *ase;
int err;
cfg = net_buf_simple_pull_mem(buf, sizeof(*cfg));
@ -1639,17 +1624,13 @@ static ssize_t ascs_config(struct bt_ascs *ascs, struct net_buf_simple *buf)
}
if (!ase) {
ascs_cp_rsp_add(cfg->ase, BT_ASCS_CONFIG_OP, BT_BAP_ASCS_RSP_CODE_NO_MEM,
0x00);
ascs_cp_rsp_add(cfg->ase, BT_ASCS_CONFIG_OP,
BT_BAP_ASCS_RSP_CODE_NO_MEM, 0x00);
LOG_WRN("No free ASE found for config ASE ID 0x%02x", cfg->ase);
continue;
}
err = ase_config(ascs, ase, cfg, buf);
if (err != 0) {
LOG_WRN("Malformed ASE Config");
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
}
ase_config(ascs, ase, cfg, buf);
}
return buf->size;
@ -1668,12 +1649,16 @@ void bt_ascs_foreach_ep(struct bt_conn *conn, bt_bap_ep_func_t func, void *user_
}
static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_codec_qos *qos,
struct bt_ascs *ascs, uint8_t cig_id, uint8_t cis_id)
struct bt_ascs *ascs, uint8_t cig_id, uint8_t cis_id,
struct bt_bap_ascs_rsp *rsp)
{
struct bt_bap_ep *ep;
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
if (stream == NULL || stream->ep == NULL || qos == NULL) {
CHECKIF(stream == NULL || stream->ep == NULL || qos == NULL) {
LOG_DBG("Invalid input stream, ep or qos pointers");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE,
BT_BAP_ASCS_REASON_NONE);
return -EINVAL;
}
@ -1689,23 +1674,34 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_codec_qos *qos
break;
default:
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE,
BT_BAP_ASCS_REASON_NONE);
return -EBADMSG;
}
if (!bt_audio_valid_qos(qos)) {
rsp->reason = bt_audio_verify_qos(qos);
if (rsp->reason != BT_BAP_ASCS_REASON_NONE) {
rsp->code = BT_BAP_ASCS_RSP_CODE_CONF_INVALID;
return -EINVAL;
}
if (!bt_bap_stream_valid_qos(stream, qos)) {
rsp->reason = bt_bap_stream_verify_qos(stream, qos);
if (rsp->reason != BT_BAP_ASCS_REASON_NONE) {
rsp->code = BT_BAP_ASCS_RSP_CODE_CONF_INVALID;
return -EINVAL;
}
if (unicast_server_cb != NULL && unicast_server_cb->qos != NULL) {
int err;
int err = unicast_server_cb->qos(stream, qos, rsp);
err = unicast_server_cb->qos(stream, qos);
if (err != 0) {
LOG_DBG("Application returned error: %d", err);
if (err) {
if (rsp->code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_DBG("Application returned error: err %d status %u reason %u",
err, rsp->code, rsp->reason);
return err;
}
}
@ -1721,6 +1717,8 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_codec_qos *qos
iso = bap_iso_get_or_new(ascs, cig_id, cis_id);
if (iso == NULL) {
LOG_ERR("Could not allocate bap_iso");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM,
BT_BAP_ASCS_REASON_NONE);
return -ENOMEM;
}
@ -1728,6 +1726,8 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_codec_qos *qos
LOG_ERR("iso %p already in use in dir %s",
&iso->chan, bt_audio_dir_str(ep->dir));
bt_bap_iso_unref(iso);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
BT_BAP_ASCS_REASON_CIS);
return -EALREADY;
}
@ -1754,6 +1754,7 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_codec_qos *qos
ascs_iso_listen(stream);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
return 0;
}
@ -1764,6 +1765,8 @@ static void ase_qos(struct bt_ascs_ase *ase, const struct bt_ascs_qos *qos)
struct bt_codec_qos *cqos = &ep->qos;
const uint8_t cig_id = qos->cig;
const uint8_t cis_id = qos->cis;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
cqos->interval = sys_get_le24(qos->interval);
@ -1779,38 +1782,16 @@ static void ase_qos(struct bt_ascs_ase *ase, const struct bt_ascs_qos *qos)
qos->cis, cqos->interval, cqos->framing, cqos->phy, cqos->sdu,
cqos->rtn, cqos->latency, cqos->pd);
err = ase_stream_qos(stream, cqos, ase->ascs, cig_id, cis_id);
err = ase_stream_qos(stream, cqos, ase->ascs, cig_id, cis_id, &rsp);
if (err) {
uint8_t reason = BT_BAP_ASCS_REASON_NONE;
LOG_ERR("QoS failed: err %d", err);
if (err == -ENOTSUP) {
if (cqos->interval == 0) {
reason = BT_BAP_ASCS_REASON_INTERVAL;
} else if (cqos->framing == 0xff) {
reason = BT_BAP_ASCS_REASON_FRAMING;
} else if (cqos->phy == 0) {
reason = BT_BAP_ASCS_REASON_PHY;
} else if (cqos->sdu == 0xffff) {
reason = BT_BAP_ASCS_REASON_SDU;
} else if (cqos->latency == 0) {
reason = BT_BAP_ASCS_REASON_LATENCY;
} else if (cqos->pd == 0) {
reason = BT_BAP_ASCS_REASON_PD;
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
} else if (err == -EALREADY) {
reason = BT_BAP_ASCS_REASON_CIS;
/* FIXME: Ugly workaround to send Response_Code
* 0x09 = Invalid Configuration Parameter Value
*/
err = -EINVAL;
}
LOG_ERR("QoS failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
memset(cqos, 0, sizeof(*cqos));
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_QOS_OP,
err, reason);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_QOS_OP, rsp.code, rsp.reason);
return;
}
@ -1889,6 +1870,7 @@ static bool ascs_codec_store_metadata(struct bt_data *data, void *user_data)
struct ascs_parse_result {
int err;
struct bt_bap_ascs_rsp *rsp;
size_t count;
const struct bt_bap_ep *ep;
};
@ -1908,6 +1890,8 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data)
if (result->count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) {
LOG_ERR("Not enough buffers for Codec Config Metadata: %zu > %zu", result->count,
CONFIG_BT_CODEC_MAX_METADATA_LEN);
*result->rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM,
BT_BAP_ASCS_REASON_NONE);
result->err = -ENOMEM;
return false;
@ -1916,6 +1900,8 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data)
if (data_len > CONFIG_BT_CODEC_MAX_METADATA_LEN) {
LOG_ERR("Not enough space for Codec Config Metadata: %u > %zu", data->data_len,
CONFIG_BT_CODEC_MAX_METADATA_LEN);
*result->rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM,
BT_BAP_ASCS_REASON_NONE);
result->err = -ENOMEM;
return false;
@ -1930,7 +1916,8 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data)
if (!bt_pacs_context_available(ep->dir, context)) {
LOG_WRN("Context 0x%04x is unavailable", context);
*result->rsp = BT_BAP_ASCS_RSP(
BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED, data_type);
result->err = -EACCES;
return false;
@ -1963,9 +1950,11 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data)
return true;
}
static int ascs_verify_metadata(const struct net_buf_simple *buf, struct bt_bap_ep *ep)
static int ascs_verify_metadata(const struct net_buf_simple *buf, struct bt_bap_ep *ep,
struct bt_bap_ascs_rsp *rsp)
{
struct ascs_parse_result result = {
.rsp = rsp,
.count = 0U,
.err = 0,
.ep = ep
@ -1984,9 +1973,13 @@ static int ascs_verify_metadata(const struct net_buf_simple *buf, struct bt_bap_
if (meta_ltv.len > 2) {
/* Value of the Metadata Type field in error */
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_INVALID,
meta_ltv.data[2]);
return meta_ltv.data[2];
}
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_INVALID,
BT_BAP_ASCS_REASON_NONE);
return -EINVAL;
}
@ -1994,12 +1987,15 @@ static int ascs_verify_metadata(const struct net_buf_simple *buf, struct bt_bap_
}
static int ascs_ep_set_metadata(struct bt_bap_ep *ep, struct net_buf_simple *buf, uint8_t len,
struct bt_codec *codec)
struct bt_codec *codec, struct bt_bap_ascs_rsp *rsp)
{
struct net_buf_simple meta_ltv;
int err;
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
if (ep == NULL && codec == NULL) {
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE,
BT_BAP_ASCS_REASON_NONE);
return -EINVAL;
}
@ -2007,6 +2003,7 @@ static int ascs_ep_set_metadata(struct bt_bap_ep *ep, struct net_buf_simple *buf
if (len == 0) {
(void)memset(codec->meta, 0, sizeof(codec->meta));
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
return 0;
}
@ -2019,7 +2016,7 @@ static int ascs_ep_set_metadata(struct bt_bap_ep *ep, struct net_buf_simple *buf
net_buf_simple_pull_mem(buf, len),
len);
err = ascs_verify_metadata(&meta_ltv, ep);
err = ascs_verify_metadata(&meta_ltv, ep, rsp);
if (err != 0) {
return err;
}
@ -2033,13 +2030,15 @@ static int ascs_ep_set_metadata(struct bt_bap_ep *ep, struct net_buf_simple *buf
return 0;
}
static int ase_metadata(struct bt_ascs_ase *ase, uint8_t op,
static void ase_metadata(struct bt_ascs_ase *ase, uint8_t op,
struct bt_ascs_metadata *meta,
struct net_buf_simple *buf)
{
struct bt_codec_data metadata_backup[CONFIG_BT_CODEC_MAX_DATA_COUNT];
struct bt_bap_stream *stream;
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
uint8_t state;
int err;
@ -2056,10 +2055,9 @@ static int ase_metadata(struct bt_ascs_ase *ase, uint8_t op,
break;
default:
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(state));
err = -EBADMSG;
ascs_cp_rsp_add_errno(ASE_ID(ase), op, err,
buf->len ? *buf->data : 0x00);
return err;
ascs_cp_rsp_add(ASE_ID(ase), op, BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE,
BT_BAP_ASCS_REASON_NONE);
return;
}
if (!meta->len) {
@ -2068,42 +2066,40 @@ static int ase_metadata(struct bt_ascs_ase *ase, uint8_t op,
/* Backup existing metadata */
(void)memcpy(metadata_backup, ep->codec.meta, sizeof(metadata_backup));
err = ascs_ep_set_metadata(ep, buf, meta->len, &ep->codec);
err = ascs_ep_set_metadata(ep, buf, meta->len, &ep->codec, &rsp);
if (err) {
if (err < 0) {
ascs_cp_rsp_add_errno(ASE_ID(ase), op, err, 0x00);
} else {
ascs_cp_rsp_add(ASE_ID(ase), op, BT_BAP_ASCS_RSP_CODE_METADATA_INVALID,
err);
}
return 0;
ascs_cp_rsp_add(ASE_ID(ase), op, rsp.code, rsp.reason);
return;
}
stream = ep->stream;
if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
err = unicast_server_cb->metadata(stream, ep->codec.meta,
ep->codec.meta_count);
ep->codec.meta_count, &rsp);
} else {
err = -ENOTSUP;
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
if (err) {
/* Restore backup */
(void)memcpy(ep->codec.meta, metadata_backup,
sizeof(metadata_backup));
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_ERR("Metadata failed: %d", err);
ascs_cp_rsp_add_errno(ASE_ID(ase), op, err,
buf->len ? *buf->data : 0x00);
return err;
/* Restore backup */
(void)memcpy(ep->codec.meta, metadata_backup, sizeof(metadata_backup));
LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
ascs_cp_rsp_add(ASE_ID(ase), op, rsp.code, rsp.reason);
return;
}
/* Set the state to the same state to trigger the notifications */
ascs_ep_set_state(ep, ep->status.state);
done:
ascs_cp_rsp_success(ASE_ID(ase), op);
return 0;
}
static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta,
@ -2111,6 +2107,8 @@ static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta,
{
struct bt_bap_stream *stream;
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
LOG_DBG("ase %p buf->len %u", ase, buf->len);
@ -2121,33 +2119,36 @@ static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta,
if (ep->status.state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
err = -EBADMSG;
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_ENABLE_OP, err, BT_BAP_ASCS_REASON_NONE);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_ENABLE_OP,
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE);
return err;
}
err = ascs_ep_set_metadata(ep, buf, meta->len, &ep->codec);
err = ascs_ep_set_metadata(ep, buf, meta->len, &ep->codec, &rsp);
if (err) {
if (err < 0) {
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_ENABLE_OP,
err, 0x00);
} else {
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_ENABLE_OP,
BT_BAP_ASCS_RSP_CODE_METADATA_INVALID, err);
}
return 0;
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_ENABLE_OP, rsp.code, rsp.reason);
return err;
}
stream = ep->stream;
if (unicast_server_cb != NULL && unicast_server_cb->enable != NULL) {
err = unicast_server_cb->enable(stream, ep->codec.meta,
ep->codec.meta_count);
ep->codec.meta_count, &rsp);
} else {
err = -ENOTSUP;
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
if (err) {
LOG_ERR("Enable rejected: %d", err);
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_ENABLE_OP, err, BT_BAP_ASCS_REASON_NONE);
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_ERR("Enable rejected: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_ENABLE_OP, rsp.code, rsp.reason);
return -EFAULT;
}
@ -2217,6 +2218,8 @@ static ssize_t ascs_enable(struct bt_ascs *ascs, struct net_buf_simple *buf)
static void ase_start(struct bt_ascs_ase *ase)
{
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
LOG_DBG("ase %p", ase);
@ -2226,8 +2229,8 @@ static void ase_start(struct bt_ascs_ase *ase)
/* Valid for an ASE only if ASE_State field = 0x02 (QoS Configured) */
if (ep->status.state != BT_BAP_EP_STATE_ENABLING) {
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_START_OP, -EBADMSG,
BT_BAP_ASCS_REASON_NONE);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP,
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE);
return;
}
@ -2239,8 +2242,8 @@ static void ase_start(struct bt_ascs_ase *ase)
*/
if (ep->dir == BT_AUDIO_DIR_SINK) {
LOG_WRN("Start failed: invalid operation for Sink");
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP, BT_BAP_ASCS_RSP_CODE_INVALID_DIR,
BT_BAP_ASCS_REASON_NONE);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP,
BT_BAP_ASCS_RSP_CODE_INVALID_DIR, BT_BAP_ASCS_REASON_NONE);
return;
} else if (ep->iso->chan.state != BT_ISO_STATE_CONNECTED) {
/* An ASE may not go into the streaming state unless the CIS
@ -2249,19 +2252,27 @@ static void ase_start(struct bt_ascs_ase *ase)
LOG_WRN("Start failed: CIS not connected: %u",
ep->iso->chan.state);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP,
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE);
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE,
BT_BAP_ASCS_REASON_NONE);
return;
}
if (unicast_server_cb != NULL && unicast_server_cb->start != NULL) {
err = unicast_server_cb->start(ep->stream);
err = unicast_server_cb->start(ep->stream, &rsp);
} else {
err = -ENOTSUP;
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
if (err) {
LOG_ERR("Start failed: %d", err);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP, err, BT_BAP_ASCS_REASON_NONE);
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_ERR("Start failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP, rsp.code, rsp.reason);
return;
}
@ -2377,6 +2388,8 @@ static void ase_stop(struct bt_ascs_ase *ase)
{
struct bt_bap_stream *stream;
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
LOG_DBG("ase %p", ase);
@ -2398,21 +2411,28 @@ static void ase_stop(struct bt_ascs_ase *ase)
if (ep->status.state != BT_BAP_EP_STATE_DISABLING) {
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_STOP_OP, -EBADMSG,
BT_BAP_ASCS_REASON_NONE);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_STOP_OP,
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE);
return;
}
stream = ep->stream;
if (unicast_server_cb != NULL && unicast_server_cb->stop != NULL) {
err = unicast_server_cb->stop(stream);
err = unicast_server_cb->stop(stream, &rsp);
} else {
err = -ENOTSUP;
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
BT_BAP_ASCS_REASON_NONE);
}
if (err) {
LOG_ERR("Stop failed: %d", err);
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_STOP_OP, err, BT_BAP_ASCS_REASON_NONE);
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
BT_BAP_ASCS_REASON_NONE);
}
LOG_ERR("Stop failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_STOP_OP, rsp.code, rsp.reason);
return;
}

View file

@ -540,7 +540,7 @@ static bool valid_create_param(const struct bt_bap_broadcast_source_create_param
return false;
}
CHECKIF(!bt_audio_valid_qos(qos)) {
CHECKIF(bt_audio_verify_qos(qos) != BT_BAP_ASCS_REASON_NONE) {
LOG_DBG("param->qos is invalid");
return false;
}

View file

@ -136,39 +136,39 @@ int bt_bap_ep_get_info(const struct bt_bap_ep *ep, struct bt_bap_ep_info *info)
}
#if defined(CONFIG_BT_BAP_UNICAST) || defined(CONFIG_BT_BAP_BROADCAST_SOURCE)
bool bt_audio_valid_qos(const struct bt_codec_qos *qos)
enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_codec_qos *qos)
{
if (qos->interval < BT_ISO_SDU_INTERVAL_MIN ||
qos->interval > BT_ISO_SDU_INTERVAL_MAX) {
LOG_DBG("Interval not within allowed range: %u (%u-%u)", qos->interval,
BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX);
return false;
return BT_BAP_ASCS_REASON_INTERVAL;
}
if (qos->framing > BT_CODEC_QOS_FRAMED) {
LOG_DBG("Invalid Framing 0x%02x", qos->framing);
return false;
return BT_BAP_ASCS_REASON_FRAMING;
}
if (qos->phy != BT_CODEC_QOS_1M &&
qos->phy != BT_CODEC_QOS_2M &&
qos->phy != BT_CODEC_QOS_CODED) {
LOG_DBG("Invalid PHY 0x%02x", qos->phy);
return false;
return BT_BAP_ASCS_REASON_PHY;
}
if (qos->sdu > BT_ISO_MAX_SDU) {
LOG_DBG("Invalid SDU %u", qos->sdu);
return false;
return BT_BAP_ASCS_REASON_SDU;
}
if (qos->latency < BT_ISO_LATENCY_MIN ||
qos->latency > BT_ISO_LATENCY_MAX) {
LOG_DBG("Invalid Latency %u", qos->latency);
return false;
return BT_BAP_ASCS_REASON_LATENCY;
}
return true;
return BT_BAP_ASCS_REASON_NONE;
}
int bt_bap_stream_send(struct bt_bap_stream *stream, struct net_buf *buf,
@ -203,7 +203,8 @@ static bool bt_bap_stream_is_broadcast(const struct bt_bap_stream *stream)
(IS_ENABLED(CONFIG_BT_BAP_BROADCAST_SINK) && bt_bap_ep_is_broadcast_snk(stream->ep));
}
bool bt_bap_stream_valid_qos(const struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
enum bt_bap_ascs_reason bt_bap_stream_verify_qos(const struct bt_bap_stream *stream,
const struct bt_codec_qos *qos)
{
const struct bt_codec_qos_pref *qos_pref = &stream->ep->qos_pref;
@ -215,10 +216,10 @@ bool bt_bap_stream_valid_qos(const struct bt_bap_stream *stream, const struct bt
if (!IN_RANGE(qos->pd, qos_pref->pd_min, qos_pref->pd_max)) {
LOG_DBG("Presentation Delay not within range: min %u max %u pd %u",
qos_pref->pd_min, qos_pref->pd_max, qos->pd);
return false;
return BT_BAP_ASCS_REASON_PD;
}
return true;
return BT_BAP_ASCS_REASON_NONE;
}
void bt_bap_stream_detach(struct bt_bap_stream *stream)

View file

@ -24,8 +24,9 @@ void bt_audio_codec_qos_to_iso_qos(struct bt_iso_chan_io_qos *io,
void bt_bap_stream_detach(struct bt_bap_stream *stream);
bool bt_audio_valid_qos(const struct bt_codec_qos *qos);
enum bt_bap_ascs_reason bt_audio_verify_qos(const struct bt_codec_qos *qos);
bool bt_bap_stream_valid_qos(const struct bt_bap_stream *stream, const struct bt_codec_qos *qos);
enum bt_bap_ascs_reason bt_bap_stream_verify_qos(const struct bt_bap_stream *stream,
const struct bt_codec_qos *qos);
struct bt_iso_chan *bt_bap_stream_iso_chan_get(struct bt_bap_stream *stream);

View file

@ -2205,7 +2205,7 @@ static int stream_param_check(const struct bt_bap_unicast_group_stream_param *pa
return -EALREADY;
}
CHECKIF(!bt_audio_valid_qos(param->qos))
CHECKIF(bt_audio_verify_qos(param->qos) != BT_BAP_ASCS_REASON_NONE)
{
LOG_ERR("Invalid QoS");
return -EINVAL;
@ -2520,7 +2520,7 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group
return -EINVAL;
}
if (!bt_bap_stream_valid_qos(stream, stream->qos)) {
if (bt_bap_stream_verify_qos(stream, stream->qos) != BT_BAP_ASCS_REASON_NONE) {
return -EINVAL;
}

View file

@ -58,6 +58,8 @@ int bt_bap_unicast_server_unregister_cb(const struct bt_bap_unicast_server_cb *c
int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, const struct bt_codec *codec)
{
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
ep = stream->ep;
@ -65,7 +67,7 @@ int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, const struct bt
if (unicast_server_cb != NULL &&
unicast_server_cb->reconfig != NULL) {
err = unicast_server_cb->reconfig(stream, ep->dir, codec,
&ep->qos_pref);
&ep->qos_pref, &rsp);
} else {
err = -ENOTSUP;
}
@ -108,11 +110,13 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec
size_t meta_count)
{
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
err = unicast_server_cb->metadata(stream, meta, meta_count);
err = unicast_server_cb->metadata(stream, meta, meta_count, &rsp);
} else {
err = -ENOTSUP;
}
@ -124,6 +128,7 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec
}
if (err) {
LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
return err;
}
@ -136,15 +141,18 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec
int bt_bap_unicast_server_disable(struct bt_bap_stream *stream)
{
struct bt_bap_ep *ep;
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) {
err = unicast_server_cb->disable(stream);
err = unicast_server_cb->disable(stream, &rsp);
} else {
err = -ENOTSUP;
}
if (err != 0) {
LOG_ERR("Disable failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
return err;
}
@ -164,15 +172,18 @@ int bt_bap_unicast_server_disable(struct bt_bap_stream *stream)
int bt_bap_unicast_server_release(struct bt_bap_stream *stream)
{
struct bt_bap_ascs_rsp rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS,
BT_BAP_ASCS_REASON_NONE);
int err;
if (unicast_server_cb != NULL && unicast_server_cb->release != NULL) {
err = unicast_server_cb->release(stream);
err = unicast_server_cb->release(stream, &rsp);
} else {
err = -ENOTSUP;
}
if (err != 0) {
LOG_ERR("Release failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
return err;
}

View file

@ -469,7 +469,7 @@ static struct bt_bap_stream *stream_alloc(void)
static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_bap_stream **stream,
struct bt_codec_qos_pref *const pref)
struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "ASE Codec Config: conn %p ep %p dir %u", conn, ep, dir);
@ -479,6 +479,8 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_
if (*stream == NULL) {
shell_print(ctx_shell, "No unicast_streams available");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
return -ENOMEM;
}
@ -492,7 +494,8 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_
}
static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref)
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref,
struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "ASE Codec Reconfig: stream %p", stream);
@ -507,7 +510,8 @@ static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
return 0;
}
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos,
struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "QoS: stream %p %p", stream, qos);
@ -517,7 +521,7 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
}
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "Enable: stream %p meta_count %zu", stream,
meta_count);
@ -525,7 +529,7 @@ static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *
return 0;
}
static int lc3_start(struct bt_bap_stream *stream)
static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "Start: stream %p", stream);
@ -579,17 +583,20 @@ static bool valid_metadata_type(uint8_t type, uint8_t len)
}
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "Metadata: stream %p meta_count %zu", stream,
meta_count);
for (size_t i = 0; i < meta_count; i++) {
if (!valid_metadata_type(meta->data.type, meta->data.data_len)) {
const struct bt_codec_data *data = &meta[i];
if (!valid_metadata_type(data->data.type, data->data.data_len)) {
shell_print(ctx_shell,
"Invalid metadata type %u or length %u",
meta->data.type, meta->data.data_len);
data->data.type, data->data.data_len);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_REJECTED,
data->data.type);
return -EINVAL;
}
}
@ -597,21 +604,21 @@ static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data
return 0;
}
static int lc3_disable(struct bt_bap_stream *stream)
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "Disable: stream %p", stream);
return 0;
}
static int lc3_stop(struct bt_bap_stream *stream)
static int lc3_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "Stop: stream %p", stream);
return 0;
}
static int lc3_release(struct bt_bap_stream *stream)
static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
shell_print(ctx_shell, "Release: stream %p", stream);

View file

@ -57,7 +57,7 @@ static struct bt_bap_stream *stream_alloc(void)
static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_bap_stream **stream,
struct bt_codec_qos_pref *const pref)
struct bt_codec_qos_pref *const pref, struct bt_bap_ascs_rsp *rsp)
{
printk("ASE Codec Config: conn %p ep %p dir %u\n", conn, ep, dir);
@ -66,7 +66,7 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_
*stream = stream_alloc();
if (*stream == NULL) {
printk("No streams available\n");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
return -ENOMEM;
}
@ -82,17 +82,20 @@ static int lc3_config(struct bt_conn *conn, const struct bt_bap_ep *ep, enum bt_
}
static int lc3_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref)
const struct bt_codec *codec, struct bt_codec_qos_pref *const pref,
struct bt_bap_ascs_rsp *rsp)
{
printk("ASE Codec Reconfig: stream %p\n", stream);
print_codec(codec);
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, BT_BAP_ASCS_REASON_NONE);
/* We only support one QoS at the moment, reject changes */
return -ENOEXEC;
}
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos,
struct bt_bap_ascs_rsp *rsp)
{
printk("QoS: stream %p qos %p\n", stream, qos);
@ -102,14 +105,14 @@ static int lc3_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
}
static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
printk("Enable: stream %p meta_count %zu\n", stream, meta_count);
return 0;
}
static int lc3_start(struct bt_bap_stream *stream)
static int lc3_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Start: stream %p\n", stream);
@ -160,15 +163,18 @@ static bool valid_metadata_type(uint8_t type, uint8_t len)
}
static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
printk("Metadata: stream %p meta_count %zu\n", stream, meta_count);
for (size_t i = 0; i < meta_count; i++) {
if (!valid_metadata_type(meta->data.type, meta->data.data_len)) {
printk("Invalid metadata type %u or length %u\n", meta->data.type,
meta->data.data_len);
const struct bt_codec_data *data = &meta[i];
if (!valid_metadata_type(data->data.type, data->data.data_len)) {
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;
}
}
@ -176,21 +182,21 @@ static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data
return 0;
}
static int lc3_disable(struct bt_bap_stream *stream)
static int lc3_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Disable: stream %p\n", stream);
return 0;
}
static int lc3_stop(struct bt_bap_stream *stream)
static int lc3_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Stop: stream %p\n", stream);
return 0;
}
static int lc3_release(struct bt_bap_stream *stream)
static int lc3_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Release: stream %p\n", stream);

View file

@ -257,7 +257,8 @@ static struct bt_bap_stream *unicast_stream_alloc(void)
static int unicast_server_config(struct bt_conn *conn, const struct bt_bap_ep *ep,
enum bt_audio_dir dir, const struct bt_codec *codec,
struct bt_bap_stream **stream,
struct bt_codec_qos_pref *const pref)
struct bt_codec_qos_pref *const pref,
struct bt_bap_ascs_rsp *rsp)
{
printk("ASE Codec Config: conn %p ep %p dir %u\n", conn, ep, dir);
@ -266,6 +267,7 @@ static int unicast_server_config(struct bt_conn *conn, const struct bt_bap_ep *e
*stream = unicast_stream_alloc();
if (*stream == NULL) {
printk("No streams available\n");
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
return -ENOMEM;
}
@ -281,7 +283,8 @@ static int unicast_server_config(struct bt_conn *conn, const struct bt_bap_ep *e
static int unicast_server_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
const struct bt_codec *codec,
struct bt_codec_qos_pref *const pref)
struct bt_codec_qos_pref *const pref,
struct bt_bap_ascs_rsp *rsp)
{
printk("ASE Codec Reconfig: stream %p\n", stream);
@ -289,11 +292,14 @@ static int unicast_server_reconfig(struct bt_bap_stream *stream, enum bt_audio_d
*pref = unicast_qos_pref;
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_UNSUPPORTED, BT_BAP_ASCS_REASON_NONE);
/* We only support one QoS at the moment, reject changes */
return -ENOEXEC;
}
static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos)
static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_codec_qos *qos,
struct bt_bap_ascs_rsp *rsp)
{
printk("QoS: stream %p qos %p\n", stream, qos);
@ -303,14 +309,14 @@ static int unicast_server_qos(struct bt_bap_stream *stream, const struct bt_code
}
static int unicast_server_enable(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
printk("Enable: stream %p meta_count %zu\n", stream, meta_count);
return 0;
}
static int unicast_server_start(struct bt_bap_stream *stream)
static int unicast_server_start(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Start: stream %p\n", stream);
@ -361,15 +367,18 @@ static bool valid_metadata_type(uint8_t type, uint8_t len)
}
static int unicast_server_metadata(struct bt_bap_stream *stream, const struct bt_codec_data *meta,
size_t meta_count)
size_t meta_count, struct bt_bap_ascs_rsp *rsp)
{
printk("Metadata: stream %p meta_count %zu\n", stream, meta_count);
for (size_t i = 0; i < meta_count; i++) {
if (!valid_metadata_type(meta->data.type, meta->data.data_len)) {
printk("Invalid metadata type %u or length %u\n",
meta->data.type, meta->data.data_len);
const struct bt_codec_data *data = &meta[i];
if (!valid_metadata_type(data->data.type, data->data.data_len)) {
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;
}
}
@ -377,21 +386,21 @@ static int unicast_server_metadata(struct bt_bap_stream *stream, const struct bt
return 0;
}
static int unicast_server_disable(struct bt_bap_stream *stream)
static int unicast_server_disable(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Disable: stream %p\n", stream);
return 0;
}
static int unicast_server_stop(struct bt_bap_stream *stream)
static int unicast_server_stop(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Stop: stream %p\n", stream);
return 0;
}
static int unicast_server_release(struct bt_bap_stream *stream)
static int unicast_server_release(struct bt_bap_stream *stream, struct bt_bap_ascs_rsp *rsp)
{
printk("Release: stream %p\n", stream);