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:
parent
a7c011b0be
commit
57784df5f0
12 changed files with 459 additions and 305 deletions
|
@ -154,6 +154,62 @@ enum bt_bap_ascs_reason {
|
||||||
BT_BAP_ASCS_REASON_CIS = 0x0a,
|
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. */
|
/** @brief Abstract Audio Broadcast Source structure. */
|
||||||
struct bt_bap_broadcast_source;
|
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] 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
|
* @param[out] pref Pointer to a QoS preference object that shall be populated with
|
||||||
* values. Invalid values will reject the codec configuration request.
|
* 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.
|
* @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,
|
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,
|
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
|
* @brief Stream reconfig request callback
|
||||||
|
@ -598,11 +656,14 @@ struct bt_bap_unicast_server_cb {
|
||||||
* @param[in] codec Codec configuration.
|
* @param[in] codec Codec configuration.
|
||||||
* @param[out] pref Pointer to a QoS preference object that shall be populated with
|
* @param[out] pref Pointer to a QoS preference object that shall be populated with
|
||||||
* values. Invalid values will reject the codec configuration request.
|
* 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.
|
* @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,
|
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
|
* @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
|
* QoS callback is called whenever an Audio Stream Quality of
|
||||||
* Service needs to be configured.
|
* Service needs to be configured.
|
||||||
*
|
*
|
||||||
* @param stream Stream object being reconfigured.
|
* @param[in] stream Stream object being reconfigured.
|
||||||
* @param qos Quality of Service configuration.
|
* @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.
|
* @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
|
* @brief Stream Enable request callback
|
||||||
*
|
*
|
||||||
* Enable callback is called whenever an Audio Stream is requested to be enabled to stream.
|
* Enable callback is called whenever an Audio Stream is requested to be enabled to stream.
|
||||||
*
|
*
|
||||||
* @param stream Stream object being enabled.
|
* @param[in] stream Stream object being enabled.
|
||||||
* @param meta Metadata entries
|
* @param[in] meta Metadata entries
|
||||||
* @param meta_count Number of 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.
|
* @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,
|
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
|
* @brief Stream Start request callback
|
||||||
*
|
*
|
||||||
* Start callback is called whenever an Audio Stream is requested to start streaming.
|
* 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.
|
* @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
|
* @brief Stream Metadata update request callback
|
||||||
*
|
*
|
||||||
* Metadata callback is called whenever an Audio Stream is requested to update its metadata.
|
* Metadata callback is called whenever an Audio Stream is requested to update its metadata.
|
||||||
*
|
*
|
||||||
* @param stream Stream object.
|
* @param[in] stream Stream object.
|
||||||
* @param meta Metadata entries
|
* @param[in] meta Metadata entries
|
||||||
* @param meta_count Number of 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.
|
* @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,
|
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
|
* @brief Stream Disable request callback
|
||||||
*
|
*
|
||||||
* Disable callback is called whenever an Audio Stream is requested to disable the stream.
|
* 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.
|
* @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
|
* @brief Stream Stop callback
|
||||||
*
|
*
|
||||||
* Stop callback is called whenever an Audio Stream is requested to stop streaming.
|
* 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.
|
* @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
|
* @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
|
* Release callback is called whenever a new Audio Stream needs to be released and thus
|
||||||
* deallocated.
|
* 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.
|
* @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);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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,
|
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,
|
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);
|
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();
|
*stream = stream_alloc();
|
||||||
if (*stream == NULL) {
|
if (*stream == NULL) {
|
||||||
printk("No streams available\n");
|
printk("No streams available\n");
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
|
||||||
return -ENOMEM;
|
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,
|
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);
|
printk("ASE Codec Reconfig: stream %p\n", stream);
|
||||||
|
|
||||||
print_codec(codec);
|
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 */
|
/* We only support one QoS at the moment, reject changes */
|
||||||
return -ENOEXEC;
|
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);
|
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,
|
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);
|
printk("Enable: stream %p meta_count %u\n", stream, meta_count);
|
||||||
|
|
||||||
return 0;
|
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);
|
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,
|
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);
|
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
|
||||||
|
|
||||||
for (size_t i = 0; i < meta_count; i++) {
|
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",
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -324,21 +332,21 @@ static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data
|
||||||
return 0;
|
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);
|
printk("Disable: stream %p\n", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
printk("Stop: stream %p\n", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
printk("Release: stream %p\n", stream);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -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,
|
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,
|
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);
|
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);
|
*stream = stream_alloc(dir);
|
||||||
if (*stream == NULL) {
|
if (*stream == NULL) {
|
||||||
printk("No streams available\n");
|
printk("No streams available\n");
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
|
||||||
|
|
||||||
return -ENOMEM;
|
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,
|
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);
|
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;
|
lc3_decoder = NULL;
|
||||||
#endif
|
#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 */
|
/* We only support one QoS at the moment, reject changes */
|
||||||
return -ENOEXEC;
|
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);
|
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,
|
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);
|
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) {
|
if (freq < 0) {
|
||||||
printk("Error: Codec frequency not set, cannot start codec.");
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame_duration_us < 0) {
|
if (frame_duration_us < 0) {
|
||||||
printk("Error: Frame duration not set, cannot start codec.");
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,6 +360,8 @@ static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *
|
||||||
|
|
||||||
if (lc3_decoder == NULL) {
|
if (lc3_decoder == NULL) {
|
||||||
printk("ERROR: Failed to setup LC3 encoder - wrong parameters?\n");
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,7 +370,7 @@ static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *
|
||||||
return 0;
|
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);
|
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,
|
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);
|
printk("Metadata: stream %p meta_count %u\n", stream, meta_count);
|
||||||
|
|
||||||
for (size_t i = 0; i < meta_count; i++) {
|
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",
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -441,21 +456,21 @@ static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data
|
||||||
return 0;
|
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);
|
printk("Disable: stream %p\n", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
printk("Stop: stream %p\n", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
printk("Release: stream %p\n", stream);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -902,65 +902,6 @@ static void ascs_cp_rsp_add(uint8_t id, uint8_t op, uint8_t code,
|
||||||
ase_rsp->reason = reason;
|
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)
|
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);
|
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)
|
static void ase_release(struct bt_ascs_ase *ase)
|
||||||
{
|
{
|
||||||
uint8_t ase_id = ASE_ID(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;
|
int err;
|
||||||
|
|
||||||
LOG_DBG("ase %p state %s", ase, bt_bap_ep_state_str(ase->ep.status.state));
|
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) {
|
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 {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -999,6 +950,8 @@ static void ase_disable(struct bt_ascs_ase *ase)
|
||||||
{
|
{
|
||||||
struct bt_bap_stream *stream;
|
struct bt_bap_stream *stream;
|
||||||
struct bt_bap_ep *ep;
|
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;
|
int err;
|
||||||
|
|
||||||
LOG_DBG("ase %p", ase);
|
LOG_DBG("ase %p", ase);
|
||||||
|
@ -1013,23 +966,29 @@ static void ase_disable(struct bt_ascs_ase *ase)
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
|
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,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_DISABLE_OP,
|
||||||
BT_BAP_ASCS_REASON_NONE);
|
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = ep->stream;
|
stream = ep->stream;
|
||||||
|
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) {
|
if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) {
|
||||||
err = unicast_server_cb->disable(stream);
|
err = unicast_server_cb->disable(stream, &rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("Disable failed: %d", err);
|
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_DISABLE_OP, err,
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
|
||||||
BT_BAP_ASCS_REASON_NONE);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1315,6 +1274,8 @@ static bool ascs_codec_config_store(struct bt_data *data, void *user_data)
|
||||||
|
|
||||||
struct codec_lookup_id_data {
|
struct codec_lookup_id_data {
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
|
uint16_t cid;
|
||||||
|
uint16_t vid;
|
||||||
struct bt_codec *codec;
|
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;
|
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;
|
data->codec = cap->codec;
|
||||||
|
|
||||||
return false;
|
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,
|
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 net_buf_simple ad;
|
||||||
struct codec_lookup_id_data lookup_data = {
|
struct codec_lookup_id_data lookup_data = {
|
||||||
.id = id,
|
.id = id,
|
||||||
|
.cid = cid,
|
||||||
|
.vid = vid,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ep == NULL && codec == NULL) {
|
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;
|
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",
|
LOG_DBG("Codec with id %u for dir %s is not supported by our capabilities",
|
||||||
id, bt_audio_dir_str(ep->dir));
|
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;
|
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;
|
codec->path_id = lookup_data.codec->path_id;
|
||||||
|
|
||||||
if (len == 0 || buf == NULL) {
|
if (len == 0 || buf == NULL) {
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
|
||||||
return 0;
|
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) {
|
if (ad.len) {
|
||||||
LOG_ERR("Unable to parse Codec Config: len %u", ad.len);
|
LOG_ERR("Unable to parse Codec Config: len %u", ad.len);
|
||||||
(void)memset(codec, 0, sizeof(*codec));
|
(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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
|
||||||
return 0;
|
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,
|
const struct bt_ascs_config *cfg,
|
||||||
struct net_buf_simple *buf)
|
struct net_buf_simple *buf)
|
||||||
{
|
{
|
||||||
struct bt_bap_stream *stream;
|
struct bt_bap_stream *stream;
|
||||||
struct bt_codec codec;
|
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;
|
int err;
|
||||||
|
|
||||||
LOG_DBG("ase %p latency 0x%02x phy 0x%02x codec 0x%02x "
|
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 ||
|
if (cfg->latency < BT_ASCS_CONFIG_LATENCY_LOW ||
|
||||||
cfg->latency > BT_ASCS_CONFIG_LATENCY_HIGH) {
|
cfg->latency > BT_ASCS_CONFIG_LATENCY_HIGH) {
|
||||||
LOG_WRN("Invalid latency: 0x%02x", cfg->latency);
|
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);
|
BT_BAP_ASCS_REASON_LATENCY);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg->phy < BT_ASCS_CONFIG_PHY_LE_1M ||
|
if (cfg->phy < BT_ASCS_CONFIG_PHY_LE_1M ||
|
||||||
cfg->phy > BT_ASCS_CONFIG_PHY_LE_CODED) {
|
cfg->phy > BT_ASCS_CONFIG_PHY_LE_CODED) {
|
||||||
LOG_WRN("Invalid PHY: 0x%02x", cfg->phy);
|
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,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP,
|
||||||
BT_BAP_ASCS_REASON_PHY);
|
BT_BAP_ASCS_RSP_CODE_CONF_INVALID, BT_BAP_ASCS_REASON_PHY);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ase->ep.status.state) {
|
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));
|
bt_bap_ep_state_str(ase->ep.status.state));
|
||||||
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP,
|
||||||
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, 0x00);
|
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, 0x00);
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store current codec configuration to be able to restore it
|
/* 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));
|
(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.cid),
|
||||||
sys_le16_to_cpu(cfg->codec.vid),
|
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));
|
(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,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, rsp.code, rsp.reason);
|
||||||
BT_BAP_ASCS_REASON_CODEC_DATA);
|
return;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ase->ep.stream != NULL) {
|
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,
|
err = unicast_server_cb->reconfig(ase->ep.stream,
|
||||||
ase->ep.dir,
|
ase->ep.dir,
|
||||||
&ase->ep.codec,
|
&ase->ep.codec,
|
||||||
&ase->ep.qos_pref);
|
&ase->ep.qos_pref,
|
||||||
|
&rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != 0) {
|
if (err) {
|
||||||
uint8_t reason = BT_BAP_ASCS_REASON_CODEC_DATA;
|
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));
|
(void)memcpy(&ase->ep.codec, &codec, sizeof(codec));
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase),
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, rsp.code, rsp.reason);
|
||||||
BT_ASCS_CONFIG_OP,
|
|
||||||
err, reason);
|
return;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = ase->ep.stream;
|
stream = ase->ep.stream;
|
||||||
|
@ -1474,23 +1455,28 @@ static int ase_config(struct bt_ascs *ascs, struct bt_ascs_ase *ase,
|
||||||
stream = NULL;
|
stream = NULL;
|
||||||
if (unicast_server_cb != NULL &&
|
if (unicast_server_cb != NULL &&
|
||||||
unicast_server_cb->config != NULL) {
|
unicast_server_cb->config != NULL) {
|
||||||
err = unicast_server_cb->config(ascs->conn, &ase->ep,
|
err = unicast_server_cb->config(ascs->conn, &ase->ep, ase->ep.dir,
|
||||||
ase->ep.dir,
|
|
||||||
&ase->ep.codec, &stream,
|
&ase->ep.codec, &stream,
|
||||||
&ase->ep.qos_pref);
|
&ase->ep.qos_pref, &rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != 0 || stream == NULL) {
|
if (err || stream == NULL) {
|
||||||
LOG_ERR("Config failed, err: %d, stream %p", err, stream);
|
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));
|
(void)memcpy(&ase->ep.codec, &codec, sizeof(codec));
|
||||||
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_CONFIG_OP, rsp.code, rsp.reason);
|
||||||
BT_BAP_ASCS_RSP_CODE_CONF_REJECTED,
|
|
||||||
BT_BAP_ASCS_REASON_CODEC_DATA);
|
|
||||||
|
|
||||||
return err;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_bap_stream_init(stream);
|
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);
|
bt_bap_stream_attach(ascs->conn, stream, &ase->ep, &ase->ep.codec);
|
||||||
|
|
||||||
ascs_ep_set_state(&ase->ep, BT_BAP_EP_STATE_CODEC_CONFIGURED);
|
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,
|
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 *ascs;
|
||||||
struct bt_ascs_ase *ase;
|
struct bt_ascs_ase *ase;
|
||||||
struct bt_bap_ep *ep;
|
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) {
|
CHECKIF(conn == NULL || stream == NULL || codec == NULL || qos_pref == NULL) {
|
||||||
LOG_DBG("NULL value(s) supplied)");
|
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),
|
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) {
|
if (err) {
|
||||||
return 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++) {
|
for (uint8_t i = 0; i < req->num_ases; i++) {
|
||||||
struct bt_ascs_ase *ase;
|
struct bt_ascs_ase *ase;
|
||||||
int err;
|
|
||||||
|
|
||||||
cfg = net_buf_simple_pull_mem(buf, sizeof(*cfg));
|
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) {
|
if (!ase) {
|
||||||
ascs_cp_rsp_add(cfg->ase, BT_ASCS_CONFIG_OP, BT_BAP_ASCS_RSP_CODE_NO_MEM,
|
ascs_cp_rsp_add(cfg->ase, BT_ASCS_CONFIG_OP,
|
||||||
0x00);
|
BT_BAP_ASCS_RSP_CODE_NO_MEM, 0x00);
|
||||||
LOG_WRN("No free ASE found for config ASE ID 0x%02x", cfg->ase);
|
LOG_WRN("No free ASE found for config ASE ID 0x%02x", cfg->ase);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ase_config(ascs, ase, cfg, buf);
|
ase_config(ascs, ase, cfg, buf);
|
||||||
if (err != 0) {
|
|
||||||
LOG_WRN("Malformed ASE Config");
|
|
||||||
return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return buf->size;
|
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,
|
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;
|
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");
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1689,23 +1674,34 @@ static int ase_stream_qos(struct bt_bap_stream *stream, struct bt_codec_qos *qos
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
|
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;
|
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;
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->qos != NULL) {
|
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) {
|
||||||
if (err != 0) {
|
if (rsp->code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||||
LOG_DBG("Application returned error: %d", err);
|
*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;
|
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);
|
iso = bap_iso_get_or_new(ascs, cig_id, cis_id);
|
||||||
if (iso == NULL) {
|
if (iso == NULL) {
|
||||||
LOG_ERR("Could not allocate bap_iso");
|
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;
|
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",
|
LOG_ERR("iso %p already in use in dir %s",
|
||||||
&iso->chan, bt_audio_dir_str(ep->dir));
|
&iso->chan, bt_audio_dir_str(ep->dir));
|
||||||
bt_bap_iso_unref(iso);
|
bt_bap_iso_unref(iso);
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_CONF_INVALID,
|
||||||
|
BT_BAP_ASCS_REASON_CIS);
|
||||||
return -EALREADY;
|
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);
|
ascs_iso_listen(stream);
|
||||||
|
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
|
||||||
return 0;
|
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;
|
struct bt_codec_qos *cqos = &ep->qos;
|
||||||
const uint8_t cig_id = qos->cig;
|
const uint8_t cig_id = qos->cig;
|
||||||
const uint8_t cis_id = qos->cis;
|
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;
|
int err;
|
||||||
|
|
||||||
cqos->interval = sys_get_le24(qos->interval);
|
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,
|
qos->cis, cqos->interval, cqos->framing, cqos->phy, cqos->sdu,
|
||||||
cqos->rtn, cqos->latency, cqos->pd);
|
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) {
|
if (err) {
|
||||||
uint8_t reason = 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,
|
||||||
LOG_ERR("QoS failed: err %d", err);
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
} 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));
|
memset(cqos, 0, sizeof(*cqos));
|
||||||
|
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_QOS_OP,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_QOS_OP, rsp.code, rsp.reason);
|
||||||
err, reason);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1889,6 +1870,7 @@ static bool ascs_codec_store_metadata(struct bt_data *data, void *user_data)
|
||||||
|
|
||||||
struct ascs_parse_result {
|
struct ascs_parse_result {
|
||||||
int err;
|
int err;
|
||||||
|
struct bt_bap_ascs_rsp *rsp;
|
||||||
size_t count;
|
size_t count;
|
||||||
const struct bt_bap_ep *ep;
|
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) {
|
if (result->count > CONFIG_BT_CODEC_MAX_METADATA_COUNT) {
|
||||||
LOG_ERR("Not enough buffers for Codec Config Metadata: %zu > %zu", result->count,
|
LOG_ERR("Not enough buffers for Codec Config Metadata: %zu > %zu", result->count,
|
||||||
CONFIG_BT_CODEC_MAX_METADATA_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;
|
result->err = -ENOMEM;
|
||||||
|
|
||||||
return false;
|
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) {
|
if (data_len > CONFIG_BT_CODEC_MAX_METADATA_LEN) {
|
||||||
LOG_ERR("Not enough space for Codec Config Metadata: %u > %zu", data->data_len,
|
LOG_ERR("Not enough space for Codec Config Metadata: %u > %zu", data->data_len,
|
||||||
CONFIG_BT_CODEC_MAX_METADATA_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;
|
result->err = -ENOMEM;
|
||||||
|
|
||||||
return false;
|
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)) {
|
if (!bt_pacs_context_available(ep->dir, context)) {
|
||||||
LOG_WRN("Context 0x%04x is unavailable", 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;
|
result->err = -EACCES;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1963,9 +1950,11 @@ static bool ascs_parse_metadata(struct bt_data *data, void *user_data)
|
||||||
return true;
|
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 = {
|
struct ascs_parse_result result = {
|
||||||
|
.rsp = rsp,
|
||||||
.count = 0U,
|
.count = 0U,
|
||||||
.err = 0,
|
.err = 0,
|
||||||
.ep = ep
|
.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) {
|
if (meta_ltv.len > 2) {
|
||||||
/* Value of the Metadata Type field in error */
|
/* 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];
|
return meta_ltv.data[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_METADATA_INVALID,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
return -EINVAL;
|
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,
|
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;
|
struct net_buf_simple meta_ltv;
|
||||||
int err;
|
int err;
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
|
||||||
|
|
||||||
if (ep == NULL && codec == NULL) {
|
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;
|
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) {
|
if (len == 0) {
|
||||||
(void)memset(codec->meta, 0, sizeof(codec->meta));
|
(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;
|
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),
|
net_buf_simple_pull_mem(buf, len),
|
||||||
len);
|
len);
|
||||||
|
|
||||||
err = ascs_verify_metadata(&meta_ltv, ep);
|
err = ascs_verify_metadata(&meta_ltv, ep, rsp);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -2033,13 +2030,15 @@ static int ascs_ep_set_metadata(struct bt_bap_ep *ep, struct net_buf_simple *buf
|
||||||
return 0;
|
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 bt_ascs_metadata *meta,
|
||||||
struct net_buf_simple *buf)
|
struct net_buf_simple *buf)
|
||||||
{
|
{
|
||||||
struct bt_codec_data metadata_backup[CONFIG_BT_CODEC_MAX_DATA_COUNT];
|
struct bt_codec_data metadata_backup[CONFIG_BT_CODEC_MAX_DATA_COUNT];
|
||||||
struct bt_bap_stream *stream;
|
struct bt_bap_stream *stream;
|
||||||
struct bt_bap_ep *ep;
|
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;
|
uint8_t state;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -2056,10 +2055,9 @@ static int ase_metadata(struct bt_ascs_ase *ase, uint8_t op,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(state));
|
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(state));
|
||||||
err = -EBADMSG;
|
ascs_cp_rsp_add(ASE_ID(ase), op, BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE,
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase), op, err,
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
buf->len ? *buf->data : 0x00);
|
return;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!meta->len) {
|
if (!meta->len) {
|
||||||
|
@ -2068,42 +2066,40 @@ static int ase_metadata(struct bt_ascs_ase *ase, uint8_t op,
|
||||||
|
|
||||||
/* Backup existing metadata */
|
/* Backup existing metadata */
|
||||||
(void)memcpy(metadata_backup, ep->codec.meta, sizeof(metadata_backup));
|
(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) {
|
||||||
if (err < 0) {
|
ascs_cp_rsp_add(ASE_ID(ase), op, rsp.code, rsp.reason);
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase), op, err, 0x00);
|
return;
|
||||||
} else {
|
|
||||||
ascs_cp_rsp_add(ASE_ID(ase), op, BT_BAP_ASCS_RSP_CODE_METADATA_INVALID,
|
|
||||||
err);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = ep->stream;
|
stream = ep->stream;
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
|
if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
|
||||||
err = unicast_server_cb->metadata(stream, ep->codec.meta,
|
err = unicast_server_cb->metadata(stream, ep->codec.meta,
|
||||||
ep->codec.meta_count);
|
ep->codec.meta_count, &rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
/* Restore backup */
|
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||||
(void)memcpy(ep->codec.meta, metadata_backup,
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_UNSPECIFIED,
|
||||||
sizeof(metadata_backup));
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
LOG_ERR("Metadata failed: %d", err);
|
/* Restore backup */
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase), op, err,
|
(void)memcpy(ep->codec.meta, metadata_backup, sizeof(metadata_backup));
|
||||||
buf->len ? *buf->data : 0x00);
|
|
||||||
return err;
|
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 */
|
/* Set the state to the same state to trigger the notifications */
|
||||||
ascs_ep_set_state(ep, ep->status.state);
|
ascs_ep_set_state(ep, ep->status.state);
|
||||||
done:
|
done:
|
||||||
ascs_cp_rsp_success(ASE_ID(ase), op);
|
ascs_cp_rsp_success(ASE_ID(ase), op);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ase_enable(struct bt_ascs_ase *ase, struct bt_ascs_metadata *meta,
|
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_stream *stream;
|
||||||
struct bt_bap_ep *ep;
|
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;
|
int err;
|
||||||
|
|
||||||
LOG_DBG("ase %p buf->len %u", ase, buf->len);
|
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) {
|
if (ep->status.state != BT_BAP_EP_STATE_QOS_CONFIGURED) {
|
||||||
err = -EBADMSG;
|
err = -EBADMSG;
|
||||||
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
|
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;
|
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) {
|
||||||
if (err < 0) {
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_ENABLE_OP, rsp.code, rsp.reason);
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_ENABLE_OP,
|
return err;
|
||||||
err, 0x00);
|
|
||||||
} else {
|
|
||||||
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_ENABLE_OP,
|
|
||||||
BT_BAP_ASCS_RSP_CODE_METADATA_INVALID, err);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = ep->stream;
|
stream = ep->stream;
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->enable != NULL) {
|
if (unicast_server_cb != NULL && unicast_server_cb->enable != NULL) {
|
||||||
err = unicast_server_cb->enable(stream, ep->codec.meta,
|
err = unicast_server_cb->enable(stream, ep->codec.meta,
|
||||||
ep->codec.meta_count);
|
ep->codec.meta_count, &rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("Enable rejected: %d", err);
|
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_ENABLE_OP, err, BT_BAP_ASCS_REASON_NONE);
|
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;
|
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)
|
static void ase_start(struct bt_ascs_ase *ase)
|
||||||
{
|
{
|
||||||
struct bt_bap_ep *ep;
|
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;
|
int err;
|
||||||
|
|
||||||
LOG_DBG("ase %p", ase);
|
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) */
|
/* Valid for an ASE only if ASE_State field = 0x02 (QoS Configured) */
|
||||||
if (ep->status.state != BT_BAP_EP_STATE_ENABLING) {
|
if (ep->status.state != BT_BAP_EP_STATE_ENABLING) {
|
||||||
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
|
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,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP,
|
||||||
BT_BAP_ASCS_REASON_NONE);
|
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2239,8 +2242,8 @@ static void ase_start(struct bt_ascs_ase *ase)
|
||||||
*/
|
*/
|
||||||
if (ep->dir == BT_AUDIO_DIR_SINK) {
|
if (ep->dir == BT_AUDIO_DIR_SINK) {
|
||||||
LOG_WRN("Start failed: invalid operation for 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,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP,
|
||||||
BT_BAP_ASCS_REASON_NONE);
|
BT_BAP_ASCS_RSP_CODE_INVALID_DIR, BT_BAP_ASCS_REASON_NONE);
|
||||||
return;
|
return;
|
||||||
} else if (ep->iso->chan.state != BT_ISO_STATE_CONNECTED) {
|
} else if (ep->iso->chan.state != BT_ISO_STATE_CONNECTED) {
|
||||||
/* An ASE may not go into the streaming state unless the CIS
|
/* 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",
|
LOG_WRN("Start failed: CIS not connected: %u",
|
||||||
ep->iso->chan.state);
|
ep->iso->chan.state);
|
||||||
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP,
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->start != NULL) {
|
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 {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("Start failed: %d", err);
|
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||||
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_START_OP, err, BT_BAP_ASCS_REASON_NONE);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2377,6 +2388,8 @@ static void ase_stop(struct bt_ascs_ase *ase)
|
||||||
{
|
{
|
||||||
struct bt_bap_stream *stream;
|
struct bt_bap_stream *stream;
|
||||||
struct bt_bap_ep *ep;
|
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;
|
int err;
|
||||||
|
|
||||||
LOG_DBG("ase %p", ase);
|
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) {
|
if (ep->status.state != BT_BAP_EP_STATE_DISABLING) {
|
||||||
LOG_WRN("Invalid operation in state: %s", bt_bap_ep_state_str(ep->status.state));
|
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,
|
ascs_cp_rsp_add(ASE_ID(ase), BT_ASCS_STOP_OP,
|
||||||
BT_BAP_ASCS_REASON_NONE);
|
BT_BAP_ASCS_RSP_CODE_INVALID_ASE_STATE, BT_BAP_ASCS_REASON_NONE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream = ep->stream;
|
stream = ep->stream;
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->stop != NULL) {
|
if (unicast_server_cb != NULL && unicast_server_cb->stop != NULL) {
|
||||||
err = unicast_server_cb->stop(stream);
|
err = unicast_server_cb->stop(stream, &rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
|
rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NOT_SUPPORTED,
|
||||||
|
BT_BAP_ASCS_REASON_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LOG_ERR("Stop failed: %d", err);
|
if (rsp.code == BT_BAP_ASCS_RSP_CODE_SUCCESS) {
|
||||||
ascs_cp_rsp_add_errno(ASE_ID(ase), BT_ASCS_STOP_OP, err, BT_BAP_ASCS_REASON_NONE);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -540,7 +540,7 @@ static bool valid_create_param(const struct bt_bap_broadcast_source_create_param
|
||||||
return false;
|
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");
|
LOG_DBG("param->qos is invalid");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
#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 ||
|
if (qos->interval < BT_ISO_SDU_INTERVAL_MIN ||
|
||||||
qos->interval > BT_ISO_SDU_INTERVAL_MAX) {
|
qos->interval > BT_ISO_SDU_INTERVAL_MAX) {
|
||||||
LOG_DBG("Interval not within allowed range: %u (%u-%u)", qos->interval,
|
LOG_DBG("Interval not within allowed range: %u (%u-%u)", qos->interval,
|
||||||
BT_ISO_SDU_INTERVAL_MIN, BT_ISO_SDU_INTERVAL_MAX);
|
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) {
|
if (qos->framing > BT_CODEC_QOS_FRAMED) {
|
||||||
LOG_DBG("Invalid Framing 0x%02x", qos->framing);
|
LOG_DBG("Invalid Framing 0x%02x", qos->framing);
|
||||||
return false;
|
return BT_BAP_ASCS_REASON_FRAMING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qos->phy != BT_CODEC_QOS_1M &&
|
if (qos->phy != BT_CODEC_QOS_1M &&
|
||||||
qos->phy != BT_CODEC_QOS_2M &&
|
qos->phy != BT_CODEC_QOS_2M &&
|
||||||
qos->phy != BT_CODEC_QOS_CODED) {
|
qos->phy != BT_CODEC_QOS_CODED) {
|
||||||
LOG_DBG("Invalid PHY 0x%02x", qos->phy);
|
LOG_DBG("Invalid PHY 0x%02x", qos->phy);
|
||||||
return false;
|
return BT_BAP_ASCS_REASON_PHY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qos->sdu > BT_ISO_MAX_SDU) {
|
if (qos->sdu > BT_ISO_MAX_SDU) {
|
||||||
LOG_DBG("Invalid SDU %u", qos->sdu);
|
LOG_DBG("Invalid SDU %u", qos->sdu);
|
||||||
return false;
|
return BT_BAP_ASCS_REASON_SDU;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qos->latency < BT_ISO_LATENCY_MIN ||
|
if (qos->latency < BT_ISO_LATENCY_MIN ||
|
||||||
qos->latency > BT_ISO_LATENCY_MAX) {
|
qos->latency > BT_ISO_LATENCY_MAX) {
|
||||||
LOG_DBG("Invalid Latency %u", qos->latency);
|
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,
|
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));
|
(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;
|
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)) {
|
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",
|
LOG_DBG("Presentation Delay not within range: min %u max %u pd %u",
|
||||||
qos_pref->pd_min, qos_pref->pd_max, qos->pd);
|
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)
|
void bt_bap_stream_detach(struct bt_bap_stream *stream)
|
||||||
|
|
|
@ -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);
|
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);
|
struct bt_iso_chan *bt_bap_stream_iso_chan_get(struct bt_bap_stream *stream);
|
||||||
|
|
|
@ -2205,7 +2205,7 @@ static int stream_param_check(const struct bt_bap_unicast_group_stream_param *pa
|
||||||
return -EALREADY;
|
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");
|
LOG_ERR("Invalid QoS");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -2520,7 +2520,7 @@ int bt_bap_unicast_client_qos(struct bt_conn *conn, struct bt_bap_unicast_group
|
||||||
return -EINVAL;
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
int bt_bap_unicast_server_reconfig(struct bt_bap_stream *stream, const struct bt_codec *codec)
|
||||||
{
|
{
|
||||||
struct bt_bap_ep *ep;
|
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;
|
int err;
|
||||||
|
|
||||||
ep = stream->ep;
|
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 &&
|
if (unicast_server_cb != NULL &&
|
||||||
unicast_server_cb->reconfig != NULL) {
|
unicast_server_cb->reconfig != NULL) {
|
||||||
err = unicast_server_cb->reconfig(stream, ep->dir, codec,
|
err = unicast_server_cb->reconfig(stream, ep->dir, codec,
|
||||||
&ep->qos_pref);
|
&ep->qos_pref, &rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
@ -108,11 +110,13 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec
|
||||||
size_t meta_count)
|
size_t meta_count)
|
||||||
{
|
{
|
||||||
struct bt_bap_ep *ep;
|
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;
|
int err;
|
||||||
|
|
||||||
|
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->metadata != NULL) {
|
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 {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +128,7 @@ int bt_bap_unicast_server_metadata(struct bt_bap_stream *stream, struct bt_codec
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
LOG_ERR("Metadata failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
|
||||||
return err;
|
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)
|
int bt_bap_unicast_server_disable(struct bt_bap_stream *stream)
|
||||||
{
|
{
|
||||||
struct bt_bap_ep *ep;
|
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;
|
int err;
|
||||||
|
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) {
|
if (unicast_server_cb != NULL && unicast_server_cb->disable != NULL) {
|
||||||
err = unicast_server_cb->disable(stream);
|
err = unicast_server_cb->disable(stream, &rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
LOG_ERR("Disable failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
|
||||||
return err;
|
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)
|
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;
|
int err;
|
||||||
|
|
||||||
if (unicast_server_cb != NULL && unicast_server_cb->release != NULL) {
|
if (unicast_server_cb != NULL && unicast_server_cb->release != NULL) {
|
||||||
err = unicast_server_cb->release(stream);
|
err = unicast_server_cb->release(stream, &rsp);
|
||||||
} else {
|
} else {
|
||||||
err = -ENOTSUP;
|
err = -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
|
LOG_ERR("Release failed: err %d, code %u, reason %u", err, rsp.code, rsp.reason);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
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,
|
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);
|
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) {
|
if (*stream == NULL) {
|
||||||
shell_print(ctx_shell, "No unicast_streams available");
|
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;
|
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,
|
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);
|
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;
|
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);
|
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,
|
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,
|
shell_print(ctx_shell, "Enable: stream %p meta_count %zu", stream,
|
||||||
meta_count);
|
meta_count);
|
||||||
|
@ -525,7 +529,7 @@ static int lc3_enable(struct bt_bap_stream *stream, const struct bt_codec_data *
|
||||||
return 0;
|
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);
|
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,
|
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,
|
shell_print(ctx_shell, "Metadata: stream %p meta_count %zu", stream,
|
||||||
meta_count);
|
meta_count);
|
||||||
|
|
||||||
for (size_t i = 0; i < meta_count; i++) {
|
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,
|
shell_print(ctx_shell,
|
||||||
"Invalid metadata type %u or length %u",
|
"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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -597,21 +604,21 @@ static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data
|
||||||
return 0;
|
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);
|
shell_print(ctx_shell, "Disable: stream %p", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
shell_print(ctx_shell, "Stop: stream %p", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
shell_print(ctx_shell, "Release: stream %p", stream);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
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,
|
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);
|
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();
|
*stream = stream_alloc();
|
||||||
if (*stream == NULL) {
|
if (*stream == NULL) {
|
||||||
printk("No streams available\n");
|
printk("No streams available\n");
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
|
||||||
return -ENOMEM;
|
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,
|
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);
|
printk("ASE Codec Reconfig: stream %p\n", stream);
|
||||||
|
|
||||||
print_codec(codec);
|
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 */
|
/* We only support one QoS at the moment, reject changes */
|
||||||
return -ENOEXEC;
|
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);
|
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,
|
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);
|
printk("Enable: stream %p meta_count %zu\n", stream, meta_count);
|
||||||
|
|
||||||
return 0;
|
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);
|
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,
|
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);
|
printk("Metadata: stream %p meta_count %zu\n", stream, meta_count);
|
||||||
|
|
||||||
for (size_t i = 0; i < meta_count; i++) {
|
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];
|
||||||
printk("Invalid metadata type %u or length %u\n", meta->data.type,
|
|
||||||
meta->data.data_len);
|
|
||||||
|
|
||||||
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -176,21 +182,21 @@ static int lc3_metadata(struct bt_bap_stream *stream, const struct bt_codec_data
|
||||||
return 0;
|
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);
|
printk("Disable: stream %p\n", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
printk("Stop: stream %p\n", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
printk("Release: stream %p\n", stream);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
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,
|
enum bt_audio_dir dir, const struct bt_codec *codec,
|
||||||
struct bt_bap_stream **stream,
|
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);
|
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();
|
*stream = unicast_stream_alloc();
|
||||||
if (*stream == NULL) {
|
if (*stream == NULL) {
|
||||||
printk("No streams available\n");
|
printk("No streams available\n");
|
||||||
|
*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_NO_MEM, BT_BAP_ASCS_REASON_NONE);
|
||||||
|
|
||||||
return -ENOMEM;
|
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,
|
static int unicast_server_reconfig(struct bt_bap_stream *stream, enum bt_audio_dir dir,
|
||||||
const struct bt_codec *codec,
|
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);
|
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;
|
*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 */
|
/* We only support one QoS at the moment, reject changes */
|
||||||
return -ENOEXEC;
|
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);
|
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,
|
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);
|
printk("Enable: stream %p meta_count %zu\n", stream, meta_count);
|
||||||
|
|
||||||
return 0;
|
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);
|
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,
|
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);
|
printk("Metadata: stream %p meta_count %zu\n", stream, meta_count);
|
||||||
|
|
||||||
for (size_t i = 0; i < meta_count; i++) {
|
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];
|
||||||
printk("Invalid metadata type %u or length %u\n",
|
|
||||||
meta->data.type, meta->data.data_len);
|
|
||||||
|
|
||||||
|
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;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,21 +386,21 @@ static int unicast_server_metadata(struct bt_bap_stream *stream, const struct bt
|
||||||
return 0;
|
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);
|
printk("Disable: stream %p\n", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
printk("Stop: stream %p\n", stream);
|
||||||
|
|
||||||
return 0;
|
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);
|
printk("Release: stream %p\n", stream);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue