diff --git a/samples/bluetooth/bap_broadcast_sink/CMakeLists.txt b/samples/bluetooth/bap_broadcast_sink/CMakeLists.txt index 5137eba4cb24..3efc14377b1f 100644 --- a/samples/bluetooth/bap_broadcast_sink/CMakeLists.txt +++ b/samples/bluetooth/bap_broadcast_sink/CMakeLists.txt @@ -2,14 +2,16 @@ cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) -project(bap_unicast_server) +project(bap_unicast_sink) target_sources(app PRIVATE src/main.c src/stream_rx.c ) -zephyr_sources_ifdef(CONFIG_LIBLC3 src/lc3.c) -zephyr_sources_ifdef(CONFIG_USB_DEVICE_AUDIO src/usb.c) +target_sources_ifdef(CONFIG_ENABLE_LC3 app PRIVATE src/lc3.c) -zephyr_library_include_directories(${ZEPHYR_BASE}/samples/bluetooth) +if (CONFIG_USE_USB_AUDIO_OUTPUT) + include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake) + target_sources(app PRIVATE src/usb.c) +endif() diff --git a/samples/bluetooth/bap_broadcast_sink/Kconfig b/samples/bluetooth/bap_broadcast_sink/Kconfig index 430d3bb7227b..5ad90225c191 100644 --- a/samples/bluetooth/bap_broadcast_sink/Kconfig +++ b/samples/bluetooth/bap_broadcast_sink/Kconfig @@ -55,8 +55,8 @@ config ENABLE_LC3 config USE_USB_AUDIO_OUTPUT bool "Use USB Audio as output" depends on ENABLE_LC3 - select USB_DEVICE_STACK - select USB_DEVICE_AUDIO + select USB_DEVICE_STACK_NEXT + select USBD_AUDIO2_CLASS select RING_BUFFER help Enables USB audio as output as a USB peripheral. This does not support providing USB @@ -87,4 +87,9 @@ config INFO_REPORTING_INTERVAL Determines how often information about received data is logged. Set to 0 to disable reporting. +# Source common USB sample options used to initialize new experimental USB device stack. +# The scope of these options is limited to USB samples in project tree, +# you cannot use them in your own application. +source "samples/subsys/usb/common/Kconfig.sample_usbd" + source "Kconfig.zephyr" diff --git a/samples/bluetooth/bap_broadcast_sink/app.overlay b/samples/bluetooth/bap_broadcast_sink/app.overlay new file mode 100644 index 000000000000..78a08d530d81 --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/app.overlay @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +/ { + uac2_microphone: usb_audio2 { + compatible = "zephyr,uac2"; + status = "okay"; + full-speed; + audio-function = ; + + /* Clock supporting 48KHz + * + * Since the incoming audio may be between 8 and 48 KHz, we always upsample to 48KHz + */ + uac_aclk: aclk { + compatible = "zephyr,uac2-clock-source"; + clock-type = "internal-programmable"; + frequency-control = "read-only"; + sampling-frequencies = <48000>; + }; + + /* The out_terminal supports the incoming Bluetooth LE Audio over ISO + * and treats it as a microphone towards the USB host + */ + out_terminal: out_terminal { + compatible = "zephyr,uac2-input-terminal"; + clock-source = <&uac_aclk>; + terminal-type = ; + front-left; + front-right; + }; + + /* USB Audio terminal from USB device to USB host */ + in_terminal: in_terminal { + compatible = "zephyr,uac2-output-terminal"; + data-source = <&out_terminal>; + clock-source = <&uac_aclk>; + terminal-type = ; + }; + + as_iso_in: in_interface { + compatible = "zephyr,uac2-audio-streaming"; + linked-terminal = <&in_terminal>; + subslot-size = <2>; + bit-resolution = <16>; + }; + }; +}; diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf52833dk_nrf52833.conf b/samples/bluetooth/bap_broadcast_sink/boards/nrf52833dk_nrf52833.conf index 69b3cc51473c..a37005f3bca3 100644 --- a/samples/bluetooth/bap_broadcast_sink/boards/nrf52833dk_nrf52833.conf +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf52833dk_nrf52833.conf @@ -1,3 +1,3 @@ # Use USB Audio as audio sink CONFIG_USE_USB_AUDIO_OUTPUT=y -CONFIG_USB_DEVICE_PRODUCT="USB Broadcast Sink" +CONFIG_SAMPLE_USBD_PRODUCT="USB Broadcast Sink sample" diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf52833dk_nrf52833.overlay b/samples/bluetooth/bap_broadcast_sink/boards/nrf52833dk_nrf52833.overlay index b8e72f1b61c5..94b67c37c705 100644 --- a/samples/bluetooth/bap_broadcast_sink/boards/nrf52833dk_nrf52833.overlay +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf52833dk_nrf52833.overlay @@ -1,15 +1,7 @@ -zephyr_udc0: &usbd { - compatible = "nordic,nrf-usbd"; - status = "okay"; +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ - hs_0: hs_0 { - compatible = "usb-audio-hs"; - mic-feature-mute; - mic-channel-l; - mic-channel-r; - - hp-feature-mute; - hp-channel-l; - hp-channel-r; - }; -}; +#include "../app.overlay" diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dk_nrf52840.conf b/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dk_nrf52840.conf new file mode 100644 index 000000000000..a37005f3bca3 --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dk_nrf52840.conf @@ -0,0 +1,3 @@ +# Use USB Audio as audio sink +CONFIG_USE_USB_AUDIO_OUTPUT=y +CONFIG_SAMPLE_USBD_PRODUCT="USB Broadcast Sink sample" diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dk_nrf52840.overlay b/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dk_nrf52840.overlay new file mode 100644 index 000000000000..94b67c37c705 --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dk_nrf52840.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../app.overlay" diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dongle_nrf52840.conf b/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dongle_nrf52840.conf index 69b3cc51473c..61db369175b2 100644 --- a/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dongle_nrf52840.conf +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dongle_nrf52840.conf @@ -1,3 +1,5 @@ # Use USB Audio as audio sink CONFIG_USE_USB_AUDIO_OUTPUT=y -CONFIG_USB_DEVICE_PRODUCT="USB Broadcast Sink" +CONFIG_SAMPLE_USBD_PRODUCT="USB Broadcast Sink sample" + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dongle_nrf52840.overlay b/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dongle_nrf52840.overlay index b8e72f1b61c5..94b67c37c705 100644 --- a/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dongle_nrf52840.overlay +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf52840dongle_nrf52840.overlay @@ -1,15 +1,7 @@ -zephyr_udc0: &usbd { - compatible = "nordic,nrf-usbd"; - status = "okay"; +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ - hs_0: hs_0 { - compatible = "usb-audio-hs"; - mic-feature-mute; - mic-channel-l; - mic-channel-r; - - hp-feature-mute; - hp-channel-l; - hp-channel-r; - }; -}; +#include "../app.overlay" diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf b/samples/bluetooth/bap_broadcast_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf index 69b3cc51473c..a37005f3bca3 100644 --- a/samples/bluetooth/bap_broadcast_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.conf @@ -1,3 +1,3 @@ # Use USB Audio as audio sink CONFIG_USE_USB_AUDIO_OUTPUT=y -CONFIG_USB_DEVICE_PRODUCT="USB Broadcast Sink" +CONFIG_SAMPLE_USBD_PRODUCT="USB Broadcast Sink sample" diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.overlay b/samples/bluetooth/bap_broadcast_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.overlay new file mode 100644 index 000000000000..94b67c37c705 --- /dev/null +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf5340_audio_dk_nrf5340_cpuapp.overlay @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "../app.overlay" diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf5340dk_nrf5340_cpuapp.conf b/samples/bluetooth/bap_broadcast_sink/boards/nrf5340dk_nrf5340_cpuapp.conf index 69b3cc51473c..a37005f3bca3 100644 --- a/samples/bluetooth/bap_broadcast_sink/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -1,3 +1,3 @@ # Use USB Audio as audio sink CONFIG_USE_USB_AUDIO_OUTPUT=y -CONFIG_USB_DEVICE_PRODUCT="USB Broadcast Sink" +CONFIG_SAMPLE_USBD_PRODUCT="USB Broadcast Sink sample" diff --git a/samples/bluetooth/bap_broadcast_sink/boards/nrf5340dk_nrf5340_cpuapp.overlay b/samples/bluetooth/bap_broadcast_sink/boards/nrf5340dk_nrf5340_cpuapp.overlay index b8e72f1b61c5..94b67c37c705 100644 --- a/samples/bluetooth/bap_broadcast_sink/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/samples/bluetooth/bap_broadcast_sink/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -1,15 +1,7 @@ -zephyr_udc0: &usbd { - compatible = "nordic,nrf-usbd"; - status = "okay"; +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ - hs_0: hs_0 { - compatible = "usb-audio-hs"; - mic-feature-mute; - mic-channel-l; - mic-channel-r; - - hp-feature-mute; - hp-channel-l; - hp-channel-r; - }; -}; +#include "../app.overlay" diff --git a/samples/bluetooth/bap_broadcast_sink/src/lc3.c b/samples/bluetooth/bap_broadcast_sink/src/lc3.c index 9aba8a1508b0..c05de47d355e 100644 --- a/samples/bluetooth/bap_broadcast_sink/src/lc3.c +++ b/samples/bluetooth/bap_broadcast_sink/src/lc3.c @@ -65,7 +65,6 @@ static K_FIFO_DEFINE(lc3_in_fifo); */ static struct stream_rx *usb_left_stream; static struct stream_rx *usb_right_stream; -static size_t rx_streaming_cnt; static int init_lc3_decoder(struct stream_rx *stream, uint32_t lc3_frame_duration_us, uint32_t lc3_freq_hz) @@ -92,7 +91,7 @@ static int init_lc3_decoder(struct stream_rx *stream, uint32_t lc3_frame_duratio /* Create the decoder instance. This shall complete before stream_started() is called. */ stream->lc3_decoder = lc3_setup_decoder(lc3_frame_duration_us, lc3_freq_hz, - IS_ENABLED(CONFIG_USB_DEVICE_AUDIO) ? USB_SAMPLE_RATE_HZ : 0, + IS_ENABLED(CONFIG_USE_USB_AUDIO_OUTPUT) ? USB_SAMPLE_RATE_HZ : 0, &stream->lc3_decoder_mem); if (stream->lc3_decoder == NULL) { LOG_ERR("Failed to setup LC3 decoder - wrong parameters?\n"); @@ -100,7 +99,6 @@ static int init_lc3_decoder(struct stream_rx *stream, uint32_t lc3_frame_duratio } LOG_INF("Initialized LC3 decoder for %p", stream); - rx_streaming_cnt++; return 0; } @@ -152,7 +150,7 @@ static bool decode_frame(struct lc3_data *data, size_t frame_cnt) static int get_lc3_chan_alloc_from_index(const struct stream_rx *stream, uint8_t index, enum bt_audio_location *chan_alloc) { -#if defined(CONFIG_USB_DEVICE_AUDIO) +#if defined(CONFIG_USE_USB_AUDIO_OUTPUT) const bool has_left = (stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0; const bool has_right = (stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_RIGHT) != 0; const bool is_mono = stream->lc3_chan_allocation == BT_AUDIO_LOCATION_MONO_AUDIO; @@ -174,9 +172,9 @@ static int get_lc3_chan_alloc_from_index(const struct stream_rx *stream, uint8_t } return 0; -#else /* !CONFIG_USB_DEVICE_AUDIO */ +#else /* !CONFIG_USE_USB_AUDIO_OUTPUT */ return -EINVAL; -#endif /* CONFIG_USB_DEVICE_AUDIO */ +#endif /* CONFIG_USE_USB_AUDIO_OUTPUT */ } static size_t decode_frame_block(struct lc3_data *data, size_t frame_cnt) @@ -192,7 +190,7 @@ static size_t decode_frame_block(struct lc3_data *data, size_t frame_cnt) if (decode_frame(data, frame_cnt + decoded_frames)) { decoded_frames++; - if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + if (IS_ENABLED(CONFIG_USE_USB_AUDIO_OUTPUT)) { enum bt_audio_location chan_alloc; int err; @@ -223,7 +221,7 @@ static size_t decode_frame_block(struct lc3_data *data, size_t frame_cnt) /* If decoding failed, we clear the data to USB as it would contain * invalid data */ - if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + if (IS_ENABLED(CONFIG_USE_USB_AUDIO_OUTPUT)) { usb_clear_frames_to_usb(); } @@ -379,7 +377,7 @@ int lc3_enable(struct stream_rx *stream) } } - if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + if (IS_ENABLED(CONFIG_USE_USB_AUDIO_OUTPUT)) { if ((stream->lc3_chan_allocation & BT_AUDIO_LOCATION_FRONT_LEFT) != 0) { if (usb_left_stream == NULL) { LOG_INF("Setting USB left stream to %p", stream); @@ -404,12 +402,11 @@ int lc3_enable(struct stream_rx *stream) int lc3_disable(struct stream_rx *stream) { - if (rx_streaming_cnt == 0 || stream->lc3_decoder == NULL) { + if (stream->lc3_decoder == NULL) { return -EINVAL; } stream->lc3_decoder = NULL; - rx_streaming_cnt--; if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { if (usb_left_stream == stream) { @@ -488,8 +485,3 @@ int lc3_init(void) return 0; } - -size_t lc3_get_rx_streaming_cnt(void) -{ - return rx_streaming_cnt; -} diff --git a/samples/bluetooth/bap_broadcast_sink/src/lc3.h b/samples/bluetooth/bap_broadcast_sink/src/lc3.h index 2b9ef3ff0c90..21de18212ee2 100644 --- a/samples/bluetooth/bap_broadcast_sink/src/lc3.h +++ b/samples/bluetooth/bap_broadcast_sink/src/lc3.h @@ -35,19 +35,12 @@ #include "stream_rx.h" -#define LC3_MAX_SAMPLE_RATE_HZ 48000U +#define LC3_MAX_SAMPLE_RATE_HZ 48000U /* Limit to 16KHz for now */ #define LC3_MAX_FRAME_DURATION_US 10000U #define LC3_MAX_NUM_SAMPLES_MONO \ ((LC3_MAX_FRAME_DURATION_US * LC3_MAX_SAMPLE_RATE_HZ) / USEC_PER_SEC) #define LC3_MAX_NUM_SAMPLES_STEREO (LC3_MAX_NUM_SAMPLES_MONO * 2U) -/** - * @brief Returns the number of active streams using an LC3 codec - * - * @return the number of active streams using an LC3 codec - */ -size_t lc3_get_rx_streaming_cnt(void); - /** * @brief Enables LC3 for a stream * diff --git a/samples/bluetooth/bap_broadcast_sink/src/main.c b/samples/bluetooth/bap_broadcast_sink/src/main.c index 9ea7a2e08565..bfa04b848653 100644 --- a/samples/bluetooth/bap_broadcast_sink/src/main.c +++ b/samples/bluetooth/bap_broadcast_sink/src/main.c @@ -890,7 +890,7 @@ static int init(void) lc3_init(); } - if (IS_ENABLED(CONFIG_USB_DEVICE_AUDIO)) { + if (IS_ENABLED(CONFIG_USE_USB_AUDIO_OUTPUT)) { usb_init(); } diff --git a/samples/bluetooth/bap_broadcast_sink/src/usb.c b/samples/bluetooth/bap_broadcast_sink/src/usb.c index dbe5ec16a62b..5baea0f70571 100644 --- a/samples/bluetooth/bap_broadcast_sink/src/usb.c +++ b/samples/bluetooth/bap_broadcast_sink/src/usb.c @@ -28,11 +28,12 @@ #include #include #include -#include -#include +#include +#include + +#include #include "lc3.h" -#include "stream_rx.h" #include "usb.h" LOG_MODULE_REGISTER(usb, CONFIG_LOG_DEFAULT_LEVEL); @@ -47,6 +48,8 @@ LOG_MODULE_REGISTER(usb, CONFIG_LOG_DEFAULT_LEVEL); #define USB_OUT_RING_BUF_SIZE (CONFIG_BT_ISO_RX_BUF_COUNT * LC3_MAX_NUM_SAMPLES_STEREO) #define USB_IN_RING_BUF_SIZE (USB_MONO_FRAME_SIZE * USB_ENQUEUE_COUNT) +#define IN_TERMINAL_ID UAC2_ENTITY_ID(DT_NODELABEL(in_terminal)) + struct decoded_sdu { int16_t right_frames[CONFIG_MAX_CODEC_FRAMES_PER_SDU][LC3_MAX_NUM_SAMPLES_MONO]; int16_t left_frames[CONFIG_MAX_CODEC_FRAMES_PER_SDU][LC3_MAX_NUM_SAMPLES_MONO]; @@ -57,66 +60,84 @@ struct decoded_sdu { } decoded_sdu; RING_BUF_DECLARE(usb_out_ring_buf, USB_OUT_RING_BUF_SIZE); -NET_BUF_POOL_DEFINE(usb_out_buf_pool, USB_ENQUEUE_COUNT, USB_STEREO_FRAME_SIZE, 0, net_buf_destroy); +K_MEM_SLAB_DEFINE_STATIC(usb_out_buf_pool, USB_STEREO_FRAME_SIZE, USB_ENQUEUE_COUNT, 4); +static bool terminal_enabled; /* USB consumer callback, called every 1ms, consumes data from ring-buffer */ -static void usb_data_request_cb(const struct device *dev) +static void uac2_sof_cb(const struct device *dev, void *user_data) { - uint8_t usb_audio_data[USB_STEREO_FRAME_SIZE] = {0}; - struct net_buf *pcm_buf; + void *pcm_buf; uint32_t size; int err; - if (lc3_get_rx_streaming_cnt() == 0) { - /* no-op as we have no streams that receive data */ + if (!terminal_enabled) { + /* Simply discard the data then */ + (void)ring_buf_get(&usb_out_ring_buf, NULL, USB_STEREO_FRAME_SIZE); return; } - pcm_buf = net_buf_alloc(&usb_out_buf_pool, K_NO_WAIT); - if (pcm_buf == NULL) { + err = k_mem_slab_alloc(&usb_out_buf_pool, &pcm_buf, K_NO_WAIT); + if (err != 0) { LOG_WRN("Could not allocate pcm_buf"); return; } - /* This may fail without causing issues since usb_audio_data is 0-initialized */ - size = ring_buf_get(&usb_out_ring_buf, usb_audio_data, sizeof(usb_audio_data)); - - net_buf_add_mem(pcm_buf, usb_audio_data, sizeof(usb_audio_data)); + size = ring_buf_get(&usb_out_ring_buf, pcm_buf, USB_STEREO_FRAME_SIZE); + if (size != USB_STEREO_FRAME_SIZE) { + /* If we could not fill the buffer, zero-fill the rest (possibly all) */ + memset(((uint8_t *)pcm_buf) + size, 0, USB_STEREO_FRAME_SIZE - size); + } - if (size != 0) { - static size_t cnt; + if (CONFIG_INFO_REPORTING_INTERVAL > 0) { + if (size != 0) { + static size_t cnt; - if (CONFIG_INFO_REPORTING_INTERVAL > 0 && - (++cnt % (CONFIG_INFO_REPORTING_INTERVAL * 10)) == 0U) { - LOG_INF("[%zu]: Sending USB audio", cnt); - } - } else { - static size_t cnt; + if (++cnt % (CONFIG_INFO_REPORTING_INTERVAL * 10) == 0U) { + LOG_INF("[%zu]: Sending USB audio", cnt); + } + } else { + static size_t cnt; - if (CONFIG_INFO_REPORTING_INTERVAL > 0 && - (++cnt % (CONFIG_INFO_REPORTING_INTERVAL * 10)) == 0U) { - LOG_INF("[%zu]: Sending empty USB audio", cnt); + if (++cnt % (CONFIG_INFO_REPORTING_INTERVAL * 10) == 0U) { + LOG_INF("[%zu]: Sending empty USB audio", cnt); + } } } - err = usb_audio_send(dev, pcm_buf, sizeof(usb_audio_data)); + err = usbd_uac2_send(dev, IN_TERMINAL_ID, pcm_buf, USB_STEREO_FRAME_SIZE); if (err != 0) { - static size_t cnt; + if (CONFIG_INFO_REPORTING_INTERVAL > 0) { + static size_t cnt; - cnt++; - if (CONFIG_INFO_REPORTING_INTERVAL > 0 && - (cnt % (CONFIG_INFO_REPORTING_INTERVAL * 10)) == 0) { - LOG_ERR("Failed to send USB audio: %d (%zu)", err, cnt); + if (cnt++ % (CONFIG_INFO_REPORTING_INTERVAL * 10) == 0) { + LOG_ERR("[%zu]: Failed to send USB audio: %d", cnt, err); + } } - net_buf_unref(pcm_buf); + /* usbd_uac2_send is inconsistent about when it takes ownership + * The following cases may happen where it does not take ownership + */ + if (err == -ENOENT || err == -EAGAIN) { + k_mem_slab_free(&usb_out_buf_pool, pcm_buf); + } + } /* USB owns the buffer which will be released in uac2_buf_release_cb */ +} + +static void uac2_buf_release_cb(const struct device *dev, uint8_t terminal, void *buf, + void *user_data) +{ + /* buf may be NULL sometimes for some reason + * https://github.com/zephyrproject-rtos/zephyr/issues/84664 + */ + if (buf != NULL) { + k_mem_slab_free(&usb_out_buf_pool, buf); } } -static void usb_data_written_cb(const struct device *dev, struct net_buf *buf, size_t size) +static void terminal_update_cb(const struct device *dev, uint8_t terminal, bool enabled, + bool microframes, void *user_data) { - /* Unreference the buffer now that the USB is done with it */ - net_buf_unref(buf); + terminal_enabled = enabled; } static void usb_send_frames_to_usb(void) @@ -215,6 +236,12 @@ int usb_add_frame_to_usb(enum bt_audio_location chan_allocation, const int16_t * const uint8_t ts_jitter_us = 100; /* timestamps may have jitter */ static size_t cnt; + if (!terminal_enabled) { + /* Simply discard the data then */ + /* TODO: Consider if we still want to decode the incoming audio */ + return 0; + } + if (CONFIG_INFO_REPORTING_INTERVAL > 0 && (++cnt % CONFIG_INFO_REPORTING_INTERVAL) == 0U) { LOG_INF("[%zu]: Adding USB audio frame", cnt); } @@ -319,11 +346,13 @@ void usb_clear_frames_to_usb(void) int usb_init(void) { - const struct device *hs_dev = DEVICE_DT_GET(DT_NODELABEL(hs_0)); - static const struct usb_audio_ops usb_ops = { - .data_request_cb = usb_data_request_cb, - .data_written_cb = usb_data_written_cb, + const struct device *mic_dev = DEVICE_DT_GET(DT_NODELABEL(uac2_microphone)); + static struct uac2_ops usb_audio_ops = { + .sof_cb = uac2_sof_cb, + .buf_release_cb = uac2_buf_release_cb, + .terminal_update_cb = terminal_update_cb, }; + struct usbd_context *sample_usbd; static bool initialized; int err; @@ -331,15 +360,20 @@ int usb_init(void) return -EALREADY; } - if (!device_is_ready(hs_dev)) { - LOG_ERR("Cannot get USB Headset Device"); + if (!device_is_ready(mic_dev)) { + LOG_ERR("Cannot get USB Microphone Device"); return -EIO; } - usb_audio_register(hs_dev, &usb_ops); - err = usb_enable(NULL); + usbd_uac2_set_ops(mic_dev, &usb_audio_ops, NULL); + + sample_usbd = sample_usbd_init_device(NULL); + if (sample_usbd == NULL) { + return -ENODEV; + } + + err = usbd_enable(sample_usbd); if (err != 0) { - LOG_ERR("Failed to enable USB"); return err; }