diff --git a/include/zephyr/bluetooth/audio/cap.h b/include/zephyr/bluetooth/audio/cap.h index 2782b5fac12..41771d8d65e 100644 --- a/include/zephyr/bluetooth/audio/cap.h +++ b/include/zephyr/bluetooth/audio/cap.h @@ -136,6 +136,21 @@ union bt_cap_set_member { struct bt_csis_client_set_member *csip; }; +struct bt_cap_stream { + struct bt_audio_stream bap_stream; + struct bt_audio_stream_ops *ops; +}; + +/** @brief Register Audio operations for a Common Audio Profile stream. + * + * Register Audio operations for a stream. + * + * @param stream Stream object. + * @param ops Stream operations structure. + */ +void bt_cap_stream_ops_register(struct bt_cap_stream *stream, + struct bt_audio_stream_ops *ops); + struct bt_cap_unicast_audio_start_param { /** The type of the set. */ enum bt_cap_set_type type; @@ -151,7 +166,7 @@ struct bt_cap_unicast_audio_start_param { * stream[i] will be associated with members[i] if not already * initialized, else the stream will be verified against the member. */ - struct bt_audio_stream **streams; + struct bt_cap_stream **streams; /** * @brief Codec configuration. @@ -233,7 +248,7 @@ struct bt_cap_broadcast_audio_start_param { size_t count; /** Streams for broadcast source. */ - struct bt_audio_stream **streams; + struct bt_cap_stream **streams; /** * @brief Codec configuration. diff --git a/subsys/bluetooth/audio/CMakeLists.txt b/subsys/bluetooth/audio/CMakeLists.txt index 3bfb897f564..a7c4aaf6ba2 100644 --- a/subsys/bluetooth/audio/CMakeLists.txt +++ b/subsys/bluetooth/audio/CMakeLists.txt @@ -57,5 +57,6 @@ zephyr_library_sources_ifdef(CONFIG_BT_BASS bass.c) zephyr_library_sources_ifdef(CONFIG_BT_BASS_CLIENT bass_client.c) zephyr_library_sources_ifdef(CONFIG_BT_HAS has.c) zephyr_library_sources_ifdef(CONFIG_BT_HAS_CLIENT has_client.c) +zephyr_library_sources_ifdef(CONFIG_BT_CAP cap_stream.c) zephyr_library_sources_ifdef(CONFIG_BT_CAP_ACCEPTOR cap_acceptor.c) zephyr_library_sources_ifdef(CONFIG_BT_CAP_INITIATOR cap_initiator.c) diff --git a/subsys/bluetooth/audio/Kconfig.cap b/subsys/bluetooth/audio/Kconfig.cap index 71d7f586670..7232de3fefc 100644 --- a/subsys/bluetooth/audio/Kconfig.cap +++ b/subsys/bluetooth/audio/Kconfig.cap @@ -5,6 +5,9 @@ # SPDX-License-Identifier: Apache-2.0 # +config BT_CAP + def_bool BT_CAP_ACCEPTOR || BT_CAP_INITIATOR + config BT_CAP_ACCEPTOR bool "Common Audio Profile Acceptor Role Support [EXPERIMENTAL]" depends on BT_AUDIO_UNICAST_SERVER || (BT_AUDIO_BROADCAST_SINK && BT_BASS) diff --git a/subsys/bluetooth/audio/cap_stream.c b/subsys/bluetooth/audio/cap_stream.c new file mode 100644 index 00000000000..a40f6c5ae56 --- /dev/null +++ b/subsys/bluetooth/audio/cap_stream.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#if defined(CONFIG_BT_AUDIO_UNICAST) +static void cap_stream_configured_cb(struct bt_audio_stream *bap_stream, + const struct bt_codec_qos_pref *pref) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->configured != NULL) { + ops->configured(bap_stream, pref); + } +} + +static void cap_stream_qos_set_cb(struct bt_audio_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->qos_set != NULL) { + ops->qos_set(bap_stream); + } +} + +static void cap_stream_enabled_cb(struct bt_audio_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->enabled != NULL) { + ops->enabled(bap_stream); + } +} + +static void cap_stream_metadata_updated_cb(struct bt_audio_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->metadata_updated != NULL) { + ops->metadata_updated(bap_stream); + } +} + +static void cap_stream_disabled_cb(struct bt_audio_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->disabled != NULL) { + ops->disabled(bap_stream); + } +} + +static void cap_stream_released_cb(struct bt_audio_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->released != NULL) { + ops->released(bap_stream); + } +} + +#endif /* CONFIG_BT_AUDIO_UNICAST */ + +static void cap_stream_started_cb(struct bt_audio_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->started != NULL) { + ops->started(bap_stream); + } +} + +static void cap_stream_stopped_cb(struct bt_audio_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->stopped != NULL) { + ops->stopped(bap_stream); + } +} + +#if defined(CONFIG_BT_AUDIO_UNICAST) || defined(CONFIG_BT_AUDIO_BROADCAST_SINK) +static void cap_stream_recv_cb(struct bt_audio_stream *bap_stream, + const struct bt_iso_recv_info *info, + struct net_buf *buf) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->recv != NULL) { + ops->recv(bap_stream, info, buf); + } +} +#endif /* CONFIG_BT_AUDIO_UNICAST || CONFIG_BT_AUDIO_BROADCAST_SINK */ + +#if defined(CONFIG_BT_AUDIO_UNICAST) || defined(CONFIG_BT_AUDIO_BROADCAST_SOURCE) +static void cap_stream_sent_cb(struct bt_audio_stream *bap_stream) +{ + struct bt_cap_stream *cap_stream = CONTAINER_OF(bap_stream, + struct bt_cap_stream, + bap_stream); + struct bt_audio_stream_ops *ops = cap_stream->ops; + + if (ops != NULL && ops->sent != NULL) { + ops->sent(bap_stream); + } +} +#endif /* CONFIG_BT_AUDIO_UNICAST || CONFIG_BT_AUDIO_BROADCAST_SOURCE */ + +static struct bt_audio_stream_ops bap_stream_ops = { +#if defined(CONFIG_BT_AUDIO_UNICAST) + .configured = cap_stream_configured_cb, + .qos_set = cap_stream_qos_set_cb, + .enabled = cap_stream_enabled_cb, + .metadata_updated = cap_stream_metadata_updated_cb, + .disabled = cap_stream_disabled_cb, + .released = cap_stream_released_cb, +#endif /* CONFIG_BT_AUDIO_UNICAST */ + .started = cap_stream_started_cb, + .stopped = cap_stream_stopped_cb, +#if defined(CONFIG_BT_AUDIO_UNICAST) || defined(CONFIG_BT_AUDIO_BROADCAST_SINK) + .recv = cap_stream_recv_cb, +#endif /* CONFIG_BT_AUDIO_UNICAST || CONFIG_BT_AUDIO_BROADCAST_SINK */ +#if defined(CONFIG_BT_AUDIO_UNICAST) || defined(CONFIG_BT_AUDIO_BROADCAST_SOURCE) + .sent = cap_stream_sent_cb, +#endif /* CONFIG_BT_AUDIO_UNICAST || CONFIG_BT_AUDIO_BROADCAST_SOURCE */ +}; + +void bt_cap_stream_ops_register(struct bt_cap_stream *stream, + struct bt_audio_stream_ops *ops) +{ + stream->ops = ops; + bt_audio_stream_cb_register(&stream->bap_stream, &bap_stream_ops); +}