From 0a2ef78ea8a82aa84539037d17eaff9a39b8c248 Mon Sep 17 00:00:00 2001 From: Andreas Vibeto Date: Thu, 22 Feb 2024 16:01:04 +0100 Subject: [PATCH] applications: nrf5340_audio: Integrate sample rate converter - Have fixed system sample rate - Convert frames based on config from LE Audio Signed-off-by: Andreas Vibeto Signed-off-by: Alexander Svensen --- .../nrf5340_audio/broadcast_sink/main.c | 10 +- .../nrf5340_audio/broadcast_source/main.c | 6 + applications/nrf5340_audio/prj.conf | 3 + applications/nrf5340_audio/prj_release.conf | 3 + applications/nrf5340_audio/src/audio/Kconfig | 19 +- .../nrf5340_audio/src/audio/audio_datapath.c | 3 +- .../nrf5340_audio/src/audio/audio_system.c | 45 ++- .../nrf5340_audio/src/audio/audio_system.h | 17 ++ .../nrf5340_audio/src/audio/sw_codec_select.c | 231 ++++++++++++--- .../nrf5340_audio/src/audio/sw_codec_select.h | 4 +- .../nrf5340_audio/src/bluetooth/Kconfig | 33 ++- .../bt_stream/bt_le_audio_tx/bt_le_audio_tx.c | 18 +- .../src/bluetooth/bt_stream/le_audio.h | 27 +- .../src/bluetooth/bt_stream/unicast/Kconfig | 7 + .../bt_stream/unicast/unicast_client.c | 275 ++++++++++++++++-- .../bt_stream/unicast/unicast_client.h | 19 ++ .../bt_stream/unicast/unicast_server.c | 98 +++++-- .../bt_stream/unicast/unicast_server.h | 13 +- .../nrf5340_audio/unicast_client/main.c | 27 ++ .../nrf5340_audio/unicast_server/main.c | 22 +- .../releases/release-notes-changelog.rst | 1 + include/pcm_stream_channel_modifier.h | 6 +- include/sample_rate_converter.h | 3 + .../pcm_stream_channel_modifier.c | 5 +- 24 files changed, 744 insertions(+), 151 deletions(-) diff --git a/applications/nrf5340_audio/broadcast_sink/main.c b/applications/nrf5340_audio/broadcast_sink/main.c index 0ef894ecec6a..aa011a3337cd 100644 --- a/applications/nrf5340_audio/broadcast_sink/main.c +++ b/applications/nrf5340_audio/broadcast_sink/main.c @@ -222,7 +222,7 @@ static void le_audio_msg_sub_thread(void) break; case LE_AUDIO_EVT_CONFIG_RECEIVED: - LOG_DBG("Config received"); + LOG_DBG("LE audio config received"); ret = broadcast_sink_config_get(&bitrate_bps, &sampling_rate_hz, &pres_delay_us); @@ -231,8 +231,12 @@ static void le_audio_msg_sub_thread(void) break; } - LOG_DBG("Sampling rate: %d Hz", sampling_rate_hz); - LOG_DBG("Bitrate: %d bps", bitrate_bps); + LOG_DBG("\tSampling rate: %d Hz", sampling_rate_hz); + LOG_DBG("\tBitrate (compressed): %d bps", bitrate_bps); + + ret = audio_system_config_set(VALUE_NOT_SET, VALUE_NOT_SET, + sampling_rate_hz); + ERR_CHK(ret); ret = audio_datapath_pres_delay_us_set(pres_delay_us); if (ret) { diff --git a/applications/nrf5340_audio/broadcast_source/main.c b/applications/nrf5340_audio/broadcast_source/main.c index 5ed31d1290d9..86972fe81ded 100644 --- a/applications/nrf5340_audio/broadcast_source/main.c +++ b/applications/nrf5340_audio/broadcast_source/main.c @@ -6,6 +6,7 @@ #include "streamctrl.h" +#include #include #include @@ -337,6 +338,11 @@ int main(void) ret = broadcast_source_enable(); ERR_CHK_MSG(ret, "Failed to enable broadcaster"); + ret = audio_system_config_set( + bt_audio_codec_cfg_freq_to_freq_hz(CONFIG_BT_AUDIO_PREF_SAMPLE_RATE_VALUE), + CONFIG_BT_AUDIO_BITRATE_BROADCAST_SRC, VALUE_NOT_SET); + ERR_CHK_MSG(ret, "Failed to set sample- and bitrate"); + broadcast_source_adv_get(&ext_adv, &ext_adv_size, &per_adv, &per_adv_size); ret = bt_mgmt_adv_start(ext_adv, ext_adv_size, per_adv, per_adv_size, false); diff --git a/applications/nrf5340_audio/prj.conf b/applications/nrf5340_audio/prj.conf index a5027228770c..52342a9f6e3d 100644 --- a/applications/nrf5340_audio/prj.conf +++ b/applications/nrf5340_audio/prj.conf @@ -7,6 +7,9 @@ # nRF5340 Audio CONFIG_NRF5340_AUDIO=y +CONFIG_SAMPLE_RATE_CONVERTER=y +CONFIG_SAMPLE_RATE_CONVERTER_FILTER_SIMPLE=y + # General CONFIG_DEBUG=y CONFIG_DEBUG_INFO=y diff --git a/applications/nrf5340_audio/prj_release.conf b/applications/nrf5340_audio/prj_release.conf index 0b669855c6cb..1adec71c0299 100644 --- a/applications/nrf5340_audio/prj_release.conf +++ b/applications/nrf5340_audio/prj_release.conf @@ -7,6 +7,9 @@ # nRF5340 Audio CONFIG_NRF5340_AUDIO=y +CONFIG_SAMPLE_RATE_CONVERTER=y +CONFIG_SAMPLE_RATE_CONVERTER_FILTER_SIMPLE=y + # General CONFIG_DEBUG=n CONFIG_ASSERT=n diff --git a/applications/nrf5340_audio/src/audio/Kconfig b/applications/nrf5340_audio/src/audio/Kconfig index 94694099511e..f6457c0520ca 100644 --- a/applications/nrf5340_audio/src/audio/Kconfig +++ b/applications/nrf5340_audio/src/audio/Kconfig @@ -43,13 +43,12 @@ config AUDIO_MAX_PRES_DLY_US help The maximum presentation delay in micro seconds. -choice AUDIO_SAMPLE_RATE - prompt "Audio sample rate" - default AUDIO_SAMPLE_RATE_16000_HZ if BT_BAP_BROADCAST_16_2_1 || BT_BAP_BROADCAST_16_2_2 || BT_BAP_UNICAST_16_2_1 - default AUDIO_SAMPLE_RATE_24000_HZ if BT_BAP_BROADCAST_24_2_1 || BT_BAP_BROADCAST_24_2_2 || BT_BAP_UNICAST_24_2_1 +choice AUDIO_SYSTEM_SAMPLE_RATE + prompt "System audio sample rate" default AUDIO_SAMPLE_RATE_48000_HZ help - This will be selected based on the BAP settings. + This configuration reflects the system sample rate, but the audio data may be resampled to + another sample rate before encoding, and after decoding. config AUDIO_SAMPLE_RATE_16000_HZ bool "16 kHz" @@ -213,7 +212,7 @@ visible if SW_CODEC_LC3 config LC3_BITRATE_MAX int "Max bitrate for LC3" - default 124000 + default 96000 config LC3_BITRATE_MIN int "Min bitrate for LC3" @@ -343,13 +342,13 @@ menu "Stack sizes" config ENCODER_STACK_SIZE int "Stack size for encoder thread" - default 7500 if AUDIO_BIT_DEPTH_16 - default 11264 if AUDIO_BIT_DEPTH_32 + default 11000 if AUDIO_BIT_DEPTH_16 + default 21400 if AUDIO_BIT_DEPTH_32 config AUDIO_DATAPATH_STACK_SIZE int "Stack size for audio datapath thread" - default 4096 if AUDIO_BIT_DEPTH_16 - default 8192 if AUDIO_BIT_DEPTH_32 + default 7600 if AUDIO_BIT_DEPTH_16 + default 14700 if AUDIO_BIT_DEPTH_32 config BUTTON_MSG_SUB_STACK_SIZE int "Stack size for button subscriber" diff --git a/applications/nrf5340_audio/src/audio/audio_datapath.c b/applications/nrf5340_audio/src/audio/audio_datapath.c index c3199f64e741..87c9489245e5 100644 --- a/applications/nrf5340_audio/src/audio/audio_datapath.c +++ b/applications/nrf5340_audio/src/audio/audio_datapath.c @@ -980,7 +980,8 @@ void audio_datapath_stream_out(const uint8_t *buf, size_t size, uint32_t sdu_ref } if (pcm_size != (BLK_STEREO_SIZE_OCTETS * NUM_BLKS_IN_FRAME)) { - LOG_WRN("Decoded audio has wrong size"); + LOG_WRN("Decoded audio has wrong size: %d. Expected: %d", pcm_size, + (BLK_STEREO_SIZE_OCTETS * NUM_BLKS_IN_FRAME)); /* Discard frame */ return; } diff --git a/applications/nrf5340_audio/src/audio/audio_system.c b/applications/nrf5340_audio/src/audio/audio_system.c index c6e0a835ac16..2c24e3840bb2 100644 --- a/applications/nrf5340_audio/src/audio/audio_system.c +++ b/applications/nrf5340_audio/src/audio/audio_system.c @@ -50,6 +50,15 @@ static struct sw_codec_config sw_codec_cfg; static int16_t test_tone_buf[CONFIG_AUDIO_SAMPLE_RATE_HZ / 1000]; static size_t test_tone_size; +static bool sample_rate_valid(uint32_t sample_rate_hz) +{ + if (sample_rate_hz == 16000 || sample_rate_hz == 24000 || sample_rate_hz == 48000) { + return true; + } + + return false; +} + static void audio_gateway_configure(void) { if (IS_ENABLED(CONFIG_SW_CODEC_LC3)) { @@ -64,12 +73,6 @@ static void audio_gateway_configure(void) sw_codec_cfg.decoder.channel_mode = SW_CODEC_MONO; #endif /* (CONFIG_STREAM_BIDIRECTIONAL) */ - if (IS_ENABLED(CONFIG_SW_CODEC_LC3)) { - sw_codec_cfg.encoder.bitrate = CONFIG_LC3_BITRATE; - } else { - ERR_CHK_MSG(-EINVAL, "No codec selected"); - } - if (IS_ENABLED(CONFIG_MONO_TO_ALL_RECEIVERS)) { sw_codec_cfg.encoder.num_ch = 1; } else { @@ -93,12 +96,6 @@ static void audio_headset_configure(void) sw_codec_cfg.encoder.enabled = true; sw_codec_cfg.encoder.num_ch = 1; sw_codec_cfg.encoder.channel_mode = SW_CODEC_MONO; - - if (IS_ENABLED(CONFIG_SW_CODEC_LC3)) { - sw_codec_cfg.encoder.bitrate = CONFIG_LC3_BITRATE; - } else { - ERR_CHK_MSG(-EINVAL, "No codec selected"); - } #endif /* (CONFIG_STREAM_BIDIRECTIONAL) */ sw_codec_cfg.decoder.num_ch = 1; @@ -259,6 +256,30 @@ int audio_system_encode_test_tone_step(void) return 0; } +int audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bitrate, + uint32_t decoder_sample_rate_hz) +{ + if (sample_rate_valid(encoder_sample_rate_hz)) { + sw_codec_cfg.encoder.sample_rate_hz = encoder_sample_rate_hz; + } else if (encoder_sample_rate_hz) { + LOG_ERR("%d is not a valid sample rate", encoder_sample_rate_hz); + return -EINVAL; + } + + if (sample_rate_valid(decoder_sample_rate_hz)) { + sw_codec_cfg.decoder.sample_rate_hz = decoder_sample_rate_hz; + } else if (decoder_sample_rate_hz) { + LOG_ERR("%d is not a valid sample rate", decoder_sample_rate_hz); + return -EINVAL; + } + + if (encoder_bitrate) { + sw_codec_cfg.encoder.bitrate = encoder_bitrate; + } + + return 0; +} + /* This function is only used on gateway using USB as audio source and bidirectional stream */ int audio_system_decode(void const *const encoded_data, size_t encoded_data_size, bool bad_frame) { diff --git a/applications/nrf5340_audio/src/audio/audio_system.h b/applications/nrf5340_audio/src/audio/audio_system.h index d88289595c73..ba6bebf516ee 100644 --- a/applications/nrf5340_audio/src/audio/audio_system.h +++ b/applications/nrf5340_audio/src/audio/audio_system.h @@ -11,6 +11,8 @@ #include #include +#define VALUE_NOT_SET 0 + /** * @brief Start the execution of the encoder thread. */ @@ -46,6 +48,21 @@ int audio_system_encode_test_tone_set(uint32_t freq); */ int audio_system_encode_test_tone_step(void); +/** + * @brief Set the sample rates for the encoder and the decoder, and the bit rate for encoder. + * + * @note If any of the values are 0, the corresponding configuration will not be set. + * + * @param[in] encoder_sample_rate_hz Sample rate to be used by the encoder; can be 0. + * @param[in] encoder_bitrate Bit rate to be used by the encoder (bps); can be 0. + * @param[in] decoder_sample_rate_hz Sample rate to be used by the decoder; can be 0. + * + * @retval -EINVAL Invalid sample rate given. + * @retval 0 On success. + */ +int audio_system_config_set(uint32_t encoder_sample_rate_hz, uint32_t encoder_bitrate, + uint32_t decoder_sample_rate_hz); + /** * @brief Decode data and then add it to TX FIFO buffer. * diff --git a/applications/nrf5340_audio/src/audio/sw_codec_select.c b/applications/nrf5340_audio/src/audio/sw_codec_select.c index dafc1e09b6d4..ac3779330b7c 100644 --- a/applications/nrf5340_audio/src/audio/sw_codec_select.c +++ b/applications/nrf5340_audio/src/audio/sw_codec_select.c @@ -11,6 +11,7 @@ #include "channel_assignment.h" #include "pcm_stream_channel_modifier.h" +#include "sample_rate_converter.h" #if (CONFIG_SW_CODEC_LC3) #include "sw_codec_lc3.h" #endif /* (CONFIG_SW_CODEC_LC3) */ @@ -20,6 +21,64 @@ LOG_MODULE_REGISTER(sw_codec_select, CONFIG_SW_CODEC_SELECT_LOG_LEVEL); static struct sw_codec_config m_config; +static struct sample_rate_converter_ctx encoder_converters[AUDIO_CH_NUM]; +static struct sample_rate_converter_ctx decoder_converters[AUDIO_CH_NUM]; + +/** + * @brief Converts the sample rate of the uncompressed audio stream if needed. + * + * @details Two buffers must be made available for the function: the input_data buffer that + * contains the samples for the audio stream, and the conversion buffer that will be + * used to store the converted audio stream. data_ptr will point to conversion_buffer + * if a conversion took place; otherwise, it will point to input_data. + * + * @param[in] ctx Sample rate converter context. + * @param[in] input_sample_rate Input sample rate. + * @param[in] output_sample_rate Output sample rate. + * @param[in] input_data Data coming in. Buffer is assumed to be of size + * PCM_NUM_BYTES_MONO. + * @param[in] input_data_size Size of input data. + * @param[in] conversion_buffer Buffer to perform sample rate conversion. Must be of size + * PCM_NUM_BYTES_MONO. + * @param[out] data_ptr Pointer to the data to be used from this point on. + * Will point to either @p input_data or @p conversion_buffer. + * @param[out] output_size Number of bytes out. + * + * @retval -ENOTSUP Sample rates are not equal, and the sample rate conversion has not + *been enabled in the application. + * @retval 0 Success. + */ +static int sw_codec_sample_rate_convert(struct sample_rate_converter_ctx *ctx, + uint32_t input_sample_rate, uint32_t output_sample_rate, + char *input_data, size_t input_data_size, + char *conversion_buffer, char **data_ptr, + size_t *output_size) +{ + int ret; + + if (input_sample_rate == output_sample_rate) { + *data_ptr = input_data; + *output_size = input_data_size; + } else if (IS_ENABLED(CONFIG_SAMPLE_RATE_CONVERTER)) { + ret = sample_rate_converter_process(ctx, SAMPLE_RATE_FILTER_SIMPLE, input_data, + input_data_size, input_sample_rate, + conversion_buffer, PCM_NUM_BYTES_MONO, + output_size, output_sample_rate); + if (ret) { + LOG_ERR("Failed to convert sample rate: %d", ret); + return ret; + } + + *data_ptr = conversion_buffer; + } else { + LOG_ERR("Sample rates are not equal, and sample rate conversion has not been " + "enabled in the application."); + return -ENOTSUP; + } + + return 0; +} + bool sw_codec_is_initialized(void) { return m_config.initialized; @@ -27,13 +86,17 @@ bool sw_codec_is_initialized(void) int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, size_t *encoded_size) { + int ret; + /* Temp storage for split stereo PCM signal */ - char pcm_data_mono[AUDIO_CH_NUM][PCM_NUM_BYTES_MONO] = {0}; + char pcm_data_mono_system_sample_rate[AUDIO_CH_NUM][PCM_NUM_BYTES_MONO] = {0}; /* Make sure we have enough space for two frames (stereo) */ static uint8_t m_encoded_data[ENC_MAX_FRAME_SIZE * AUDIO_CH_NUM]; + char pcm_data_mono_converted_buf[AUDIO_CH_NUM][PCM_NUM_BYTES_MONO] = {0}; + + size_t pcm_block_size_mono_system_sample_rate; size_t pcm_block_size_mono; - int ret; if (!m_config.encoder.enabled) { LOG_ERR("Encoder has not been initialized"); @@ -44,20 +107,36 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz case SW_CODEC_LC3: { #if (CONFIG_SW_CODEC_LC3) uint16_t encoded_bytes_written; + char *pcm_data_mono_ptrs[m_config.encoder.channel_mode]; /* Since LC3 is a single channel codec, we must split the * stereo PCM stream */ ret = pscm_two_channel_split(pcm_data, pcm_size, CONFIG_AUDIO_BIT_DEPTH_BITS, - pcm_data_mono[AUDIO_CH_L], pcm_data_mono[AUDIO_CH_R], - &pcm_block_size_mono); + pcm_data_mono_system_sample_rate[AUDIO_CH_L], + pcm_data_mono_system_sample_rate[AUDIO_CH_R], + &pcm_block_size_mono_system_sample_rate); if (ret) { return ret; } + for (int i = 0; i < m_config.encoder.channel_mode; ++i) { + ret = sw_codec_sample_rate_convert( + &encoder_converters[i], CONFIG_AUDIO_SAMPLE_RATE_HZ, + m_config.encoder.sample_rate_hz, + pcm_data_mono_system_sample_rate[i], + pcm_block_size_mono_system_sample_rate, + pcm_data_mono_converted_buf[i], &pcm_data_mono_ptrs[i], + &pcm_block_size_mono); + if (ret) { + LOG_ERR("Sample rate conversion failed for channel %d: %d", i, ret); + return ret; + } + } + switch (m_config.encoder.channel_mode) { case SW_CODEC_MONO: { - ret = sw_codec_lc3_enc_run(pcm_data_mono[m_config.encoder.audio_ch], + ret = sw_codec_lc3_enc_run(pcm_data_mono_ptrs[AUDIO_CH_L], pcm_block_size_mono, LC3_USE_BITRATE_FROM_INIT, 0, sizeof(m_encoded_data), m_encoded_data, &encoded_bytes_written); @@ -67,19 +146,19 @@ int sw_codec_encode(void *pcm_data, size_t pcm_size, uint8_t **encoded_data, siz break; } case SW_CODEC_STEREO: { - ret = sw_codec_lc3_enc_run(pcm_data_mono[AUDIO_CH_L], pcm_block_size_mono, - LC3_USE_BITRATE_FROM_INIT, AUDIO_CH_L, - sizeof(m_encoded_data), m_encoded_data, - &encoded_bytes_written); + ret = sw_codec_lc3_enc_run(pcm_data_mono_ptrs[AUDIO_CH_L], + pcm_block_size_mono, LC3_USE_BITRATE_FROM_INIT, + AUDIO_CH_L, sizeof(m_encoded_data), + m_encoded_data, &encoded_bytes_written); if (ret) { return ret; } - ret = sw_codec_lc3_enc_run(pcm_data_mono[AUDIO_CH_R], pcm_block_size_mono, - LC3_USE_BITRATE_FROM_INIT, AUDIO_CH_R, - sizeof(m_encoded_data) - encoded_bytes_written, - m_encoded_data + encoded_bytes_written, - &encoded_bytes_written); + ret = sw_codec_lc3_enc_run( + pcm_data_mono_ptrs[AUDIO_CH_R], pcm_block_size_mono, + LC3_USE_BITRATE_FROM_INIT, AUDIO_CH_R, + sizeof(m_encoded_data) - encoded_bytes_written, + m_encoded_data + encoded_bytes_written, &encoded_bytes_written); if (ret) { return ret; } @@ -115,28 +194,44 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool } int ret; - char pcm_data_mono[PCM_NUM_BYTES_MONO] = {0}; + static char pcm_data_stereo[PCM_NUM_BYTES_STEREO]; + char decoded_data_mono[AUDIO_CH_NUM][PCM_NUM_BYTES_MONO] = {0}; + char decoded_data_mono_system_sample_rate[AUDIO_CH_NUM][PCM_NUM_BYTES_MONO] = {0}; + size_t pcm_size_stereo = 0; - uint16_t pcm_size_session = 0; + size_t pcm_size_mono = 0; + size_t decoded_data_size = 0; switch (m_config.sw_codec) { case SW_CODEC_LC3: { #if (CONFIG_SW_CODEC_LC3) - /* Typically used for right channel if stereo signal */ - char pcm_data_mono_right[PCM_NUM_BYTES_MONO] = {0}; + char *pcm_in_data_ptrs[m_config.decoder.channel_mode]; switch (m_config.decoder.channel_mode) { case SW_CODEC_MONO: { if (bad_frame && IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) { - memset(pcm_data_mono, 0, PCM_NUM_BYTES_MONO); - pcm_size_session = PCM_NUM_BYTES_MONO; + memset(decoded_data_mono[AUDIO_CH_L], 0, PCM_NUM_BYTES_MONO); + decoded_data_size = PCM_NUM_BYTES_MONO; } else { - ret = sw_codec_lc3_dec_run(encoded_data, encoded_size, - LC3_PCM_NUM_BYTES_MONO, 0, pcm_data_mono, - &pcm_size_session, bad_frame); + ret = sw_codec_lc3_dec_run( + encoded_data, encoded_size, LC3_PCM_NUM_BYTES_MONO, 0, + decoded_data_mono[AUDIO_CH_L], + (uint16_t *)&decoded_data_size, bad_frame); + if (ret) { + return ret; + } + + ret = sw_codec_sample_rate_convert( + &decoder_converters[AUDIO_CH_L], + m_config.decoder.sample_rate_hz, + CONFIG_AUDIO_SAMPLE_RATE_HZ, decoded_data_mono[AUDIO_CH_L], + decoded_data_size, + decoded_data_mono_system_sample_rate[AUDIO_CH_L], + &pcm_in_data_ptrs[AUDIO_CH_L], &pcm_size_mono); if (ret) { + LOG_ERR("Sample rate conversion failed for mono: %d", ret); return ret; } } @@ -145,7 +240,7 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool * just one channel, we need to insert 0 for the * other channel */ - ret = pscm_zero_pad(pcm_data_mono, (size_t)pcm_size_session, + ret = pscm_zero_pad(pcm_in_data_ptrs[AUDIO_CH_L], pcm_size_mono, m_config.decoder.audio_ch, CONFIG_AUDIO_BIT_DEPTH_BITS, pcm_data_stereo, &pcm_size_stereo); if (ret) { @@ -155,29 +250,50 @@ int sw_codec_decode(uint8_t const *const encoded_data, size_t encoded_size, bool } case SW_CODEC_STEREO: { if (bad_frame && IS_ENABLED(CONFIG_SW_CODEC_OVERRIDE_PLC)) { - memset(pcm_data_mono, 0, PCM_NUM_BYTES_MONO); - memset(pcm_data_mono_right, 0, PCM_NUM_BYTES_MONO); - pcm_size_session = PCM_NUM_BYTES_MONO; + memset(decoded_data_mono[AUDIO_CH_L], 0, PCM_NUM_BYTES_MONO); + memset(decoded_data_mono[AUDIO_CH_R], 0, PCM_NUM_BYTES_MONO); + decoded_data_size = PCM_NUM_BYTES_MONO; } else { /* Decode left channel */ ret = sw_codec_lc3_dec_run( encoded_data, encoded_size / 2, LC3_PCM_NUM_BYTES_MONO, - AUDIO_CH_L, pcm_data_mono, &pcm_size_session, bad_frame); + AUDIO_CH_L, decoded_data_mono[AUDIO_CH_L], + (uint16_t *)&decoded_data_size, bad_frame); if (ret) { return ret; } + /* Decode right channel */ - ret = sw_codec_lc3_dec_run((encoded_data + (encoded_size / 2)), - encoded_size / 2, LC3_PCM_NUM_BYTES_MONO, - AUDIO_CH_R, pcm_data_mono_right, - &pcm_size_session, bad_frame); + ret = sw_codec_lc3_dec_run( + (encoded_data + (encoded_size / 2)), encoded_size / 2, + LC3_PCM_NUM_BYTES_MONO, AUDIO_CH_R, + decoded_data_mono[AUDIO_CH_R], + (uint16_t *)&decoded_data_size, bad_frame); if (ret) { return ret; } + + for (int i = 0; i < m_config.decoder.channel_mode; ++i) { + ret = sw_codec_sample_rate_convert( + &decoder_converters[i], + m_config.decoder.sample_rate_hz, + CONFIG_AUDIO_SAMPLE_RATE_HZ, decoded_data_mono[i], + decoded_data_size, + decoded_data_mono_system_sample_rate[i], + &pcm_in_data_ptrs[i], &pcm_size_mono); + if (ret) { + LOG_ERR("Sample rate conversion failed for channel " + "%d : %d", + i, ret); + return ret; + } + } } - ret = pscm_combine(pcm_data_mono, pcm_data_mono_right, - (size_t)pcm_size_session, CONFIG_AUDIO_BIT_DEPTH_BITS, - pcm_data_stereo, &pcm_size_stereo); + + ret = pscm_combine(pcm_in_data_ptrs[AUDIO_CH_L], + pcm_in_data_ptrs[AUDIO_CH_R], pcm_size_mono, + CONFIG_AUDIO_BIT_DEPTH_BITS, pcm_data_stereo, + &pcm_size_stereo); if (ret) { return ret; } @@ -214,7 +330,8 @@ int sw_codec_uninit(struct sw_codec_config sw_codec_cfg) #if (CONFIG_SW_CODEC_LC3) if (sw_codec_cfg.encoder.enabled) { if (!m_config.encoder.enabled) { - LOG_ERR("Trying to uninit encoder, it has not been initialized"); + LOG_ERR("Trying to uninit encoder, it has not been " + "initialized"); return -EALREADY; } ret = sw_codec_lc3_enc_uninit_all(); @@ -226,7 +343,8 @@ int sw_codec_uninit(struct sw_codec_config sw_codec_cfg) if (sw_codec_cfg.decoder.enabled) { if (!m_config.decoder.enabled) { - LOG_WRN("Trying to uninit decoder, it has not been initialized"); + LOG_WRN("Trying to uninit decoder, it has not been " + "initialized"); return -EALREADY; } @@ -250,11 +368,11 @@ int sw_codec_uninit(struct sw_codec_config sw_codec_cfg) int sw_codec_init(struct sw_codec_config sw_codec_cfg) { + int ret; + switch (sw_codec_cfg.sw_codec) { case SW_CODEC_LC3: { #if (CONFIG_SW_CODEC_LC3) - int ret; - if (m_config.sw_codec != SW_CODEC_LC3) { /* Check if LC3 is already initialized */ ret = sw_codec_lc3_init(NULL, NULL, CONFIG_AUDIO_FRAME_DURATION_US); @@ -271,12 +389,12 @@ int sw_codec_init(struct sw_codec_config sw_codec_cfg) uint16_t pcm_bytes_req_enc; LOG_DBG("Encode: %dHz %dbits %dus %dbps %d channel(s)", - CONFIG_AUDIO_SAMPLE_RATE_HZ, CONFIG_AUDIO_BIT_DEPTH_BITS, + sw_codec_cfg.encoder.sample_rate_hz, CONFIG_AUDIO_BIT_DEPTH_BITS, CONFIG_AUDIO_FRAME_DURATION_US, sw_codec_cfg.encoder.bitrate, sw_codec_cfg.encoder.num_ch); ret = sw_codec_lc3_enc_init( - CONFIG_AUDIO_SAMPLE_RATE_HZ, CONFIG_AUDIO_BIT_DEPTH_BITS, + sw_codec_cfg.encoder.sample_rate_hz, CONFIG_AUDIO_BIT_DEPTH_BITS, CONFIG_AUDIO_FRAME_DURATION_US, sw_codec_cfg.encoder.bitrate, sw_codec_cfg.encoder.num_ch, &pcm_bytes_req_enc); @@ -292,11 +410,11 @@ int sw_codec_init(struct sw_codec_config sw_codec_cfg) } LOG_DBG("Decode: %dHz %dbits %dus %d channel(s)", - CONFIG_AUDIO_SAMPLE_RATE_HZ, CONFIG_AUDIO_BIT_DEPTH_BITS, + sw_codec_cfg.decoder.sample_rate_hz, CONFIG_AUDIO_BIT_DEPTH_BITS, CONFIG_AUDIO_FRAME_DURATION_US, sw_codec_cfg.decoder.num_ch); ret = sw_codec_lc3_dec_init( - CONFIG_AUDIO_SAMPLE_RATE_HZ, CONFIG_AUDIO_BIT_DEPTH_BITS, + sw_codec_cfg.decoder.sample_rate_hz, CONFIG_AUDIO_BIT_DEPTH_BITS, CONFIG_AUDIO_FRAME_DURATION_US, sw_codec_cfg.decoder.num_ch); if (ret) { @@ -305,7 +423,8 @@ int sw_codec_init(struct sw_codec_config sw_codec_cfg) } break; #else - LOG_ERR("LC3 is not compiled in, please open menuconfig and select LC3"); + LOG_ERR("LC3 is not compiled in, please open menuconfig and select " + "LC3"); return -ENODEV; #endif /* (CONFIG_SW_CODEC_LC3) */ } @@ -315,6 +434,30 @@ int sw_codec_init(struct sw_codec_config sw_codec_cfg) return false; } + if (sw_codec_cfg.encoder.enabled && IS_ENABLED(SAMPLE_RATE_CONVERTER)) { + for (int i = 0; i < sw_codec_cfg.encoder.channel_mode; i++) { + ret = sample_rate_converter_open(&encoder_converters[i]); + if (ret) { + LOG_ERR("Failed to initialize the sample rate converter for " + "encoding channel %d: %d", + i, ret); + return ret; + } + } + } + + if (sw_codec_cfg.decoder.enabled && IS_ENABLED(SAMPLE_RATE_CONVERTER)) { + for (int i = 0; i < sw_codec_cfg.decoder.channel_mode; i++) { + ret = sample_rate_converter_open(&decoder_converters[i]); + if (ret) { + LOG_ERR("Failed to initialize the sample rate converter for " + "decoding channel %d: %d", + i, ret); + return ret; + } + } + } + m_config = sw_codec_cfg; m_config.initialized = true; diff --git a/applications/nrf5340_audio/src/audio/sw_codec_select.h b/applications/nrf5340_audio/src/audio/sw_codec_select.h index 5d8522d09592..0941ee678273 100644 --- a/applications/nrf5340_audio/src/audio/sw_codec_select.h +++ b/applications/nrf5340_audio/src/audio/sw_codec_select.h @@ -12,7 +12,7 @@ #if (CONFIG_SW_CODEC_LC3) #define LC3_MAX_FRAME_SIZE_MS 10 -#define LC3_ENC_MONO_FRAME_SIZE (CONFIG_LC3_BITRATE * LC3_MAX_FRAME_SIZE_MS / (8 * 1000)) +#define LC3_ENC_MONO_FRAME_SIZE (CONFIG_LC3_BITRATE_MAX * LC3_MAX_FRAME_SIZE_MS / (8 * 1000)) #define LC3_PCM_NUM_BYTES_MONO \ (CONFIG_AUDIO_SAMPLE_RATE_HZ * CONFIG_AUDIO_BIT_DEPTH_OCTETS * LC3_MAX_FRAME_SIZE_MS / 1000) @@ -48,6 +48,7 @@ struct sw_codec_encoder { enum sw_codec_channel_mode channel_mode; uint8_t num_ch; enum audio_channel audio_ch; + uint32_t sample_rate_hz; }; struct sw_codec_decoder { @@ -56,6 +57,7 @@ struct sw_codec_decoder { enum sw_codec_channel_mode channel_mode; /* Mono or stereo. */ uint8_t num_ch; /* Number of decoder channels. */ enum audio_channel audio_ch; /* Used to choose which channel to use. */ + uint32_t sample_rate_hz; }; /** diff --git a/applications/nrf5340_audio/src/bluetooth/Kconfig b/applications/nrf5340_audio/src/bluetooth/Kconfig index e821b40db145..de6ff644a073 100644 --- a/applications/nrf5340_audio/src/bluetooth/Kconfig +++ b/applications/nrf5340_audio/src/bluetooth/Kconfig @@ -27,6 +27,35 @@ config BT_AUDIO_PACKING_INTERLEAVED help ISO channels can either be interleaved or sequentially packed; sequential is the default one. +config BT_AUDIO_PREF_SAMPLE_RATE_VALUE + hex + default 0x03 if BT_AUDIO_PREF_SAMPLE_RATE_16KHZ + default 0x05 if BT_AUDIO_PREF_SAMPLE_RATE_24KHZ + default 0x08 if BT_AUDIO_PREF_SAMPLE_RATE_48KHZ + +choice BT_AUDIO_PREF_SAMPLE_RATE + prompt "Preferred audio sample rate" + default BT_AUDIO_PREF_SAMPLE_RATE_24KHZ if STREAM_BIDIRECTIONAL + default BT_AUDIO_PREF_SAMPLE_RATE_48KHZ + help + Select the preferred sample rate if there are more than one to choose from. + +config BT_AUDIO_PREF_SAMPLE_RATE_48KHZ + bool "48 kHz" + help + Select 48000 Hz as the preferred sample rate. + +config BT_AUDIO_PREF_SAMPLE_RATE_24KHZ + bool "24 kHz" + help + Select 24000 Hz as the preferred sample rate. + +config BT_AUDIO_PREF_SAMPLE_RATE_16KHZ + bool "16 kHz" + help + Select 16000 Hz as the preferred sample rate. +endchoice + #----------------------------------------------------------------------------# menu "QoS" @@ -50,11 +79,11 @@ config BT_AUDIO_MAX_TRANSPORT_LATENCY_MS Max transport latency for the ISO link. config BT_AUDIO_RETRANSMITS - int "Number of retransmits" + int "Number of re-transmits" range 0 30 default 2 help - Number of retransmits for the ISO link. 2 retransmits means a total + Number of re-transmits for the ISO link. 2 re-transmits means a total of 3 packets sent per stream. endmenu # QoS diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c index 52a5c66b3c7c..b3c138838980 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/bt_le_audio_tx/bt_le_audio_tx.c @@ -157,11 +157,6 @@ int bt_le_audio_tx_send(struct bt_bap_stream **bap_streams, struct le_audio_enco return -EINVAL; } - if (data_size_pr_stream != LE_AUDIO_SDU_SIZE_OCTETS(CONFIG_LC3_BITRATE)) { - LOG_ERR("The encoded data size does not match the SDU size"); - return -EINVAL; - } - /* When sending ISO data, we always send ts = 0 to the first active transmitting channel. * The controller will populate with a ts which is fetched using bt_iso_chan_get_tx_sync. * This timestamp will be submitted to all the other channels in order to place data on all @@ -187,6 +182,19 @@ int bt_le_audio_tx_send(struct bt_bap_stream **bap_streams, struct le_audio_enco continue; } + uint32_t bitrate; + + ret = le_audio_bitrate_get(bap_streams[i]->codec_cfg, &bitrate); + if (ret) { + LOG_ERR("Failed to calculate bitrate: %d", ret); + return ret; + } + + if (data_size_pr_stream != LE_AUDIO_SDU_SIZE_OCTETS(bitrate)) { + LOG_ERR("The encoded data size does not match the SDU size"); + return -EINVAL; + } + if (common_interval != 0 && (common_interval != bap_streams[i]->qos->interval)) { LOG_ERR("Not all channels have the same ISO interval"); return -EINVAL; diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h b/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h index 8c2d84313b30..f43bdab1f8df 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/le_audio.h @@ -13,20 +13,27 @@ #define LE_AUDIO_ZBUS_EVENT_WAIT_TIME K_MSEC(5) #define LE_AUDIO_SDU_SIZE_OCTETS(bitrate) (bitrate / (1000000 / CONFIG_AUDIO_FRAME_DURATION_US) / 8) -#if (CONFIG_AUDIO_SAMPLE_RATE_48000_HZ) -#define BT_AUDIO_CODEC_CONFIG_FREQ BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ -#define BT_AUDIO_CODEC_CAPABILIY_FREQ BT_AUDIO_CODEC_LC3_FREQ_48KHZ -#elif (CONFIG_AUDIO_SAMPLE_RATE_24000_HZ) -#define BT_AUDIO_CODEC_CONFIG_FREQ BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ -#define BT_AUDIO_CODEC_CAPABILIY_FREQ BT_AUDIO_CODEC_LC3_FREQ_24KHZ -#elif (CONFIG_AUDIO_SAMPLE_RATE_16000_HZ) -#define BT_AUDIO_CODEC_CONFIG_FREQ BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ +#if CONFIG_SAMPLE_RATE_CONVERTER +#define BT_AUDIO_CODEC_CAPABILIY_FREQ \ + BT_AUDIO_CODEC_LC3_FREQ_48KHZ | BT_AUDIO_CODEC_LC3_FREQ_24KHZ | \ + BT_AUDIO_CODEC_LC3_FREQ_16KHZ + +#elif CONFIG_AUDIO_SAMPLE_RATE_16000_HZ #define BT_AUDIO_CODEC_CAPABILIY_FREQ BT_AUDIO_CODEC_LC3_FREQ_16KHZ -#endif /* (CONFIG_AUDIO_SAMPLE_RATE_48000_HZ) */ + +#elif CONFIG_AUDIO_SAMPLE_RATE_24000_HZ +#define BT_AUDIO_CODEC_CAPABILIY_FREQ BT_AUDIO_CODEC_LC3_FREQ_24KHZ + +#elif CONFIG_AUDIO_SAMPLE_RATE_48000_HZ +#define BT_AUDIO_CODEC_CAPABILIY_FREQ BT_AUDIO_CODEC_LC3_FREQ_48KHZ + +#else +#error No sample rate supported +#endif /* CONFIG_SAMPLE_RATE_CONVERTER */ #define BT_BAP_LC3_PRESET_CONFIGURABLE(_loc, _stream_context, _bitrate) \ BT_BAP_LC3_PRESET( \ - BT_AUDIO_CODEC_LC3_CONFIG(BT_AUDIO_CODEC_CONFIG_FREQ, \ + BT_AUDIO_CODEC_LC3_CONFIG(CONFIG_BT_AUDIO_PREF_SAMPLE_RATE_VALUE, \ BT_AUDIO_CODEC_CONFIG_LC3_DURATION_10, _loc, \ LE_AUDIO_SDU_SIZE_OCTETS(_bitrate), 1, _stream_context), \ BT_AUDIO_CODEC_LC3_QOS_10_UNFRAMED(LE_AUDIO_SDU_SIZE_OCTETS(_bitrate), \ diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/Kconfig b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/Kconfig index 9325705eb840..54ce3bf6ee7f 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/Kconfig +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/Kconfig @@ -36,6 +36,13 @@ config BT_BAP_UNICAST_24_2_1 help Unicast codec capability 24_2_1. 24kHz, 48kbps, 2 retransmits, 10ms transport latency, and 40ms presentation delay. + +config BT_BAP_UNICAST_48_4_1 + bool "48_4_1" + depends on TRANSPORT_CIS + help + Unicast codec capability 48_4_1. + 48kHz, 96kbps, 5 retransmits, 20ms transport latency, and 40ms presentation delay. endchoice choice BT_AUDIO_PRES_DLY_SRCH diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c index 35fae1882896..34c81c65724d 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.c @@ -97,8 +97,25 @@ static le_audio_receive_cb receive_cb; static struct bt_bap_unicast_group *unicast_group; +/* Used for group creation only */ +static struct bt_bap_lc3_preset lc3_preset_max = BT_BAP_LC3_PRESET_CONFIGURABLE( + BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA, CONFIG_LC3_BITRATE_MAX); + static struct bt_bap_lc3_preset lc3_preset_sink = BT_BAP_LC3_UNICAST_PRESET_NRF5340_AUDIO_SINK; +static struct bt_bap_lc3_preset lc3_preset_sink_48_4_1 = + BT_BAP_LC3_UNICAST_PRESET_48_4_1(BT_AUDIO_LOCATION_ANY, (BT_AUDIO_CONTEXT_TYPE_MEDIA)); +static struct bt_bap_lc3_preset lc3_preset_sink_24_2_1 = + BT_BAP_LC3_UNICAST_PRESET_24_2_1(BT_AUDIO_LOCATION_ANY, (BT_AUDIO_CONTEXT_TYPE_MEDIA)); +static struct bt_bap_lc3_preset lc3_preset_sink_16_2_1 = + BT_BAP_LC3_UNICAST_PRESET_16_2_1(BT_AUDIO_LOCATION_ANY, (BT_AUDIO_CONTEXT_TYPE_MEDIA)); + static struct bt_bap_lc3_preset lc3_preset_source = BT_BAP_LC3_UNICAST_PRESET_NRF5340_AUDIO_SOURCE; +static struct bt_bap_lc3_preset lc3_preset_source_48_4_1 = + BT_BAP_LC3_UNICAST_PRESET_48_4_1(BT_AUDIO_LOCATION_ANY, BT_AUDIO_CONTEXT_TYPE_MEDIA); +static struct bt_bap_lc3_preset lc3_preset_source_24_2_1 = + BT_BAP_LC3_UNICAST_PRESET_24_2_1(BT_AUDIO_LOCATION_ANY, BT_AUDIO_CONTEXT_TYPE_MEDIA); +static struct bt_bap_lc3_preset lc3_preset_source_16_2_1 = + BT_BAP_LC3_UNICAST_PRESET_16_2_1(BT_AUDIO_LOCATION_ANY, BT_AUDIO_CONTEXT_TYPE_MEDIA); static bool playing_state = true; @@ -306,17 +323,146 @@ static int channel_index_get(const struct bt_conn *conn, uint8_t *index) return -EINVAL; } -static bool parse_cb(struct bt_data *data, void *user_data) +static void supported_sample_rates_print(uint16_t supported_sample_rates, enum bt_audio_dir dir) +{ + char supported_str[20] = ""; + + if (supported_sample_rates & BT_AUDIO_CODEC_LC3_FREQ_48KHZ) { + strcat(supported_str, "48, "); + } + + if (supported_sample_rates & BT_AUDIO_CODEC_LC3_FREQ_24KHZ) { + strcat(supported_str, "24, "); + } + + if (supported_sample_rates & BT_AUDIO_CODEC_LC3_FREQ_16KHZ) { + strcat(supported_str, "16, "); + } + + if (dir == BT_AUDIO_DIR_SINK) { + LOG_DBG("Headset supports: %s kHz in sink direction", supported_str); + } else if (dir == BT_AUDIO_DIR_SOURCE) { + LOG_DBG("Headset supports: %s kHz in source direction", supported_str); + } +} + +static bool sink_parse_cb(struct bt_data *data, void *user_data) { if (data->type == BT_AUDIO_CODEC_LC3_FREQ) { - uint16_t temp = sys_get_le16(data->data); + uint16_t lc3_freq_bit = sys_get_le16(data->data); + + supported_sample_rates_print(lc3_freq_bit, BT_AUDIO_DIR_SINK); + + /* Try with the preferred sample rate first */ + switch (CONFIG_BT_AUDIO_PREF_SAMPLE_RATE_VALUE) { + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ: + if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_48KHZ) { + lc3_preset_sink = lc3_preset_sink_48_4_1; + *(bool *)user_data = true; + /* Found what we were looking for, stop parsing LTV */ + return false; + } + + break; + + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ: + if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_24KHZ) { + lc3_preset_sink = lc3_preset_sink_24_2_1; + *(bool *)user_data = true; + /* Found what we were looking for, stop parsing LTV */ + return false; + } - if (temp & BT_AUDIO_CODEC_CAPABILIY_FREQ) { + break; + + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ: + if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_16KHZ) { + lc3_preset_sink = lc3_preset_sink_16_2_1; + *(bool *)user_data = true; + /* Found what we were looking for, stop parsing LTV */ + return false; + } + + break; + } + + /* If no match with the preferred, revert to trying highest first */ + if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_48KHZ) { + lc3_preset_sink = lc3_preset_sink_48_4_1; + *(bool *)user_data = true; + } else if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_24KHZ) { + lc3_preset_sink = lc3_preset_sink_24_2_1; + *(bool *)user_data = true; + } else if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_16KHZ) { + lc3_preset_sink = lc3_preset_sink_16_2_1; *(bool *)user_data = true; } + + /* Found what we were looking for, stop parsing LTV */ return false; } + /* Did not find what we were looking for, continue parsing LTV */ + return true; +} + +static bool source_parse_cb(struct bt_data *data, void *user_data) +{ + if (data->type == BT_AUDIO_CODEC_LC3_FREQ) { + uint16_t lc3_freq_bit = sys_get_le16(data->data); + + supported_sample_rates_print(lc3_freq_bit, BT_AUDIO_DIR_SOURCE); + + /* Try with the preferred sample rate first */ + switch (CONFIG_BT_AUDIO_PREF_SAMPLE_RATE_VALUE) { + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_48KHZ: + if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_48KHZ) { + lc3_preset_source = lc3_preset_source_48_4_1; + *(bool *)user_data = true; + /* Found what we were looking for, stop parsing LTV */ + return false; + } + + break; + + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_24KHZ: + if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_24KHZ) { + lc3_preset_source = lc3_preset_source_24_2_1; + *(bool *)user_data = true; + /* Found what we were looking for, stop parsing LTV */ + return false; + } + + break; + + case BT_AUDIO_CODEC_CONFIG_LC3_FREQ_16KHZ: + if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_16KHZ) { + lc3_preset_source = lc3_preset_source_16_2_1; + *(bool *)user_data = true; + /* Found what we were looking for, stop parsing LTV */ + return false; + } + + break; + } + + /* If no match with the preferred, revert to trying highest first */ + if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_48KHZ) { + lc3_preset_source = lc3_preset_source_48_4_1; + *(bool *)user_data = true; + } else if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_24KHZ) { + lc3_preset_source = lc3_preset_source_24_2_1; + *(bool *)user_data = true; + } else if (lc3_freq_bit & BT_AUDIO_CODEC_LC3_FREQ_16KHZ) { + lc3_preset_source = lc3_preset_source_16_2_1; + *(bool *)user_data = true; + } + + /* Found what we were looking for, stop parsing LTV */ + return false; + } + + /* Did not find what we were looking for, continue parsing LTV */ return true; } @@ -325,19 +471,28 @@ static bool parse_cb(struct bt_data *data, void *user_data) * * @note Currently only the sampling frequency is checked. * - * @param cap_array The array of pointers to codec capabilities. - * @param num_caps The size of cap_array. + * @param[in] cap_array The array of pointers to codec capabilities. + * @param[in] num_caps The size of cap_array. + * @param[in] dir Direction of the capabilities to check. * * @return True if valid codec capability found, false otherwise. */ -static bool valid_codec_cap_check(struct bt_audio_codec_cap cap_array[], uint8_t num_caps) +static bool valid_codec_cap_check(struct bt_audio_codec_cap cap_array[], uint8_t num_caps, + enum bt_audio_dir dir) { bool valid_result = false; /* Only the sampling frequency is checked */ - for (int i = 0; i < num_caps; i++) { - (void)bt_audio_data_parse(cap_array[i].data, cap_array[i].data_len, parse_cb, - &valid_result); + if (dir == BT_AUDIO_DIR_SINK) { + for (int i = 0; i < num_caps; i++) { + (void)bt_audio_data_parse(cap_array[i].data, cap_array[i].data_len, + sink_parse_cb, &valid_result); + } + } else if (dir == BT_AUDIO_DIR_SOURCE) { + for (int i = 0; i < num_caps; i++) { + (void)bt_audio_data_parse(cap_array[i].data, cap_array[i].data_len, + source_parse_cb, &valid_result); + } } return valid_result; @@ -529,8 +684,8 @@ static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_b if (dir == BT_AUDIO_DIR_SINK) { if (ep != NULL) { if (headsets[channel_index].num_sink_eps > 0) { - LOG_WRN("More than one sink endpoint found, idx 0 is used by " - "default"); + LOG_WRN("More than one sink endpoint found, idx 0 is used " + "by default"); return; } @@ -547,8 +702,8 @@ static void endpoint_cb(struct bt_conn *conn, enum bt_audio_dir dir, struct bt_b } else if (dir == BT_AUDIO_DIR_SOURCE) { if (ep != NULL) { if (headsets[channel_index].num_source_eps > 0) { - LOG_WRN("More than one source endpoint found, idx 0 is used by " - "default"); + LOG_WRN("More than one source endpoint found, idx 0 is " + "used by default"); return; } @@ -587,9 +742,9 @@ static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) LOG_WRN("No sources found"); headsets[channel_index].waiting_for_source_disc = false; /** - * We usually wait until both sink and source has been discovered before - * configuring, but since no source was found and we have a sink, we need - * to configure that. + * We usually wait until both sink and source has been discovered + * before configuring, but since no source was found and we have a + * sink, we need to configure that. */ if (headsets[channel_index].sink_ep != NULL) { ret = bt_bap_stream_config(conn, @@ -628,7 +783,7 @@ static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) if (dir == BT_AUDIO_DIR_SINK) { if (valid_codec_cap_check(headsets[channel_index].sink_codec_cap, - temp_cap[temp_cap_index].num_caps)) { + temp_cap[temp_cap_index].num_caps, BT_AUDIO_DIR_SINK)) { if (conn == headsets[AUDIO_CH_L].headset_conn) { bt_audio_codec_allocation_set(&lc3_preset_sink.codec_cfg, BT_AUDIO_LOCATION_FRONT_LEFT); @@ -646,7 +801,7 @@ static void discover_cb(struct bt_conn *conn, int err, enum bt_audio_dir dir) } } else if (dir == BT_AUDIO_DIR_SOURCE) { if (valid_codec_cap_check(headsets[channel_index].source_codec_cap, - temp_cap[temp_cap_index].num_caps)) { + temp_cap[temp_cap_index].num_caps, BT_AUDIO_DIR_SOURCE)) { if (conn == headsets[AUDIO_CH_L].headset_conn) { bt_audio_codec_allocation_set(&lc3_preset_source.codec_cfg, BT_AUDIO_LOCATION_FRONT_LEFT); @@ -783,7 +938,11 @@ static void stream_configured_cb(struct bt_bap_stream *stream, headsets[channel_index].sink_stream.qos->pd = new_pres_dly_us; } - /* Make sure both sink and source ep (if both are discovered) are configured before QoS */ + le_audio_event_publish(LE_AUDIO_EVT_CONFIG_RECEIVED, stream->conn, stream->ep->dir); + + /* Make sure both sink and source ep (if both are discovered) are configured before + * QoS + */ if ((headsets[channel_index].sink_ep != NULL && !le_audio_ep_state_check(headsets[channel_index].sink_stream.ep, BT_BAP_EP_STATE_CODEC_CONFIGURED)) || @@ -1137,6 +1296,80 @@ static void disconnected_headset_cleanup(uint8_t chan_idx) headsets[chan_idx].num_source_eps = 0; } +int unicast_client_config_get(struct bt_conn *conn, enum bt_audio_dir dir, uint32_t *bitrate, + uint32_t *sampling_rate_hz) +{ + int ret; + uint8_t headset_idx; + + if (conn == NULL) { + LOG_ERR("No valid connection pointer received"); + return -EINVAL; + } + + if (bitrate == NULL && sampling_rate_hz == NULL) { + LOG_ERR("No valid pointers received"); + return -ENXIO; + } + + ret = channel_index_get(conn, &headset_idx); + if (ret) { + LOG_WRN("No configured streams found"); + return ret; + } + + if (dir == BT_AUDIO_DIR_SINK) { + if (headsets[headset_idx].sink_stream.codec_cfg == NULL) { + LOG_ERR("No codec found for the stream"); + + return -ENXIO; + } + + if (sampling_rate_hz != NULL) { + ret = le_audio_freq_hz_get(headsets[headset_idx].sink_stream.codec_cfg, + sampling_rate_hz); + if (ret) { + LOG_ERR("Invalid sampling frequency: %d", ret); + return -ENXIO; + } + } + + if (bitrate != NULL) { + ret = le_audio_bitrate_get(headsets[headset_idx].sink_stream.codec_cfg, + bitrate); + if (ret) { + LOG_ERR("Unable to calculate bitrate: %d", ret); + return -ENXIO; + } + } + } else if (dir == BT_AUDIO_DIR_SOURCE) { + if (headsets[headset_idx].source_stream.codec_cfg == NULL) { + LOG_ERR("No codec found for the stream"); + return -ENXIO; + } + + if (sampling_rate_hz != NULL) { + ret = le_audio_freq_hz_get(headsets[headset_idx].source_stream.codec_cfg, + sampling_rate_hz); + if (ret) { + LOG_ERR("Invalid sampling frequency: %d", ret); + return -ENXIO; + } + } + + if (bitrate != NULL) { + ret = le_audio_bitrate_get(headsets[headset_idx].source_stream.codec_cfg, + bitrate); + if (ret) { + LOG_ERR("Unable to calculate bitrate: %d", ret); + return -ENXIO; + } + } + } + + return 0; +} + void unicast_client_conn_disconnected(struct bt_conn *conn) { int ret; @@ -1332,10 +1565,10 @@ int unicast_client_enable(le_audio_receive_cb recv_cb) for (int i = 0; i < ARRAY_SIZE(group_stream_params); i++) { /* Every other stream should be sink or source */ if ((i % 2) == 0) { - group_stream_params[i].qos = &lc3_preset_sink.qos; + group_stream_params[i].qos = &lc3_preset_max.qos; group_stream_params[i].stream = &headsets[headset_iterator].sink_stream; } else { - group_stream_params[i].qos = &lc3_preset_source.qos; + group_stream_params[i].qos = &lc3_preset_max.qos; group_stream_params[i].stream = &headsets[headset_iterator].source_stream; headset_iterator++; } diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.h b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.h index 52cc92c51240..7b64e0d77e72 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.h +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_client.h @@ -40,10 +40,29 @@ enum unicast_discover_dir { #define BT_BAP_LC3_UNICAST_PRESET_NRF5340_AUDIO_SOURCE \ BT_BAP_LC3_UNICAST_PRESET_24_2_1(BT_AUDIO_LOCATION_FRONT_LEFT, BT_AUDIO_CONTEXT_TYPE_MEDIA) +#elif CONFIG_BT_BAP_UNICAST_48_4_1 +#define BT_BAP_LC3_UNICAST_PRESET_NRF5340_AUDIO_SINK \ + BT_BAP_LC3_UNICAST_PRESET_48_4_1(BT_AUDIO_LOCATION_ANY, BT_AUDIO_CONTEXT_TYPE_MEDIA) + +#define BT_BAP_LC3_UNICAST_PRESET_NRF5340_AUDIO_SOURCE \ + BT_BAP_LC3_UNICAST_PRESET_48_4_1(BT_AUDIO_LOCATION_ANY, BT_AUDIO_CONTEXT_TYPE_MEDIA) #else #error Unsupported LC3 codec preset for unicast #endif /* CONFIG_BT_BAP_UNICAST_CONFIGURABLE */ +/** + * @brief Get configuration for the audio stream. + * + * @param[in] conn Pointer to the connection to get the configuration for. + * @param[in] dir Direction to get the configuration from. + * @param[out] bitrate Pointer to the bit rate used; can be NULL. + * @param[out] sampling_rate_hz Pointer to the sampling rate used; can be NULL. + * + * @return 0 for success, error otherwise. + */ +int unicast_client_config_get(struct bt_conn *conn, enum bt_audio_dir dir, uint32_t *bitrate, + uint32_t *sampling_rate_hz); + /** * @brief Start service discovery for a Bluetooth LE Audio unicast (CIS) server. * diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c index b5535a717c2a..14c11557debf 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.c @@ -21,6 +21,8 @@ #include "bt_le_audio_tx.h" #include "le_audio.h" +#include <../subsys/bluetooth/audio/bap_endpoint.h> + #include LOG_MODULE_REGISTER(unicast_server, CONFIG_UNICAST_SERVER_LOG_LEVEL); @@ -123,11 +125,17 @@ struct bt_csip_set_member_register_param csip_param = { .cb = &csip_callbacks, }; -static struct bt_audio_codec_cap lc3_codec = BT_AUDIO_CODEC_CAP_LC3( +static struct bt_audio_codec_cap lc3_codec_sink = BT_AUDIO_CODEC_CAP_LC3( + BT_AUDIO_CODEC_CAPABILIY_FREQ, + (BT_AUDIO_CODEC_LC3_DURATION_10 | BT_AUDIO_CODEC_LC3_DURATION_PREFER_10), + BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), LE_AUDIO_SDU_SIZE_OCTETS(CONFIG_LC3_BITRATE_MIN), + LE_AUDIO_SDU_SIZE_OCTETS(CONFIG_LC3_BITRATE_MAX), 1u, AVAILABLE_SINK_CONTEXT); + +static struct bt_audio_codec_cap lc3_codec_source = BT_AUDIO_CODEC_CAP_LC3( BT_AUDIO_CODEC_CAPABILIY_FREQ, (BT_AUDIO_CODEC_LC3_DURATION_10 | BT_AUDIO_CODEC_LC3_DURATION_PREFER_10), BT_AUDIO_CODEC_LC3_CHAN_COUNT_SUPPORT(1), LE_AUDIO_SDU_SIZE_OCTETS(CONFIG_LC3_BITRATE_MIN), - LE_AUDIO_SDU_SIZE_OCTETS(CONFIG_LC3_BITRATE_MAX), 1u, BT_AUDIO_CONTEXT_TYPE_MEDIA); + LE_AUDIO_SDU_SIZE_OCTETS(CONFIG_LC3_BITRATE_MAX), 1u, AVAILABLE_SOURCE_CONTEXT); static enum bt_audio_dir caps_dirs[] = { BT_AUDIO_DIR_SINK, @@ -145,12 +153,12 @@ static const struct bt_audio_codec_qos_pref qos_pref = BT_AUDIO_CODEC_QOS_PREF( static struct bt_pacs_cap caps[] = { #if (CONFIG_BT_AUDIO_RX) { - .codec_cap = &lc3_codec, + .codec_cap = &lc3_codec_sink, }, #endif #if (CONFIG_BT_AUDIO_TX) { - .codec_cap = &lc3_codec, + .codec_cap = &lc3_codec_source, } #endif /* (CONFIG_BT_AUDIO_TX) */ }; @@ -531,8 +539,8 @@ static int adv_buf_put(struct bt_data *adv_buf, uint8_t adv_buf_vacant, int *ind return 0; } -int unicast_server_config_get(uint32_t *bitrate, uint32_t *sampling_rate_hz, - uint32_t *pres_delay_us) +int unicast_server_config_get(struct bt_conn *conn, enum bt_audio_dir dir, uint32_t *bitrate, + uint32_t *sampling_rate_hz, uint32_t *pres_delay_us) { int ret; @@ -541,34 +549,74 @@ int unicast_server_config_get(uint32_t *bitrate, uint32_t *sampling_rate_hz, return -ENXIO; } - if (audio_streams[0].codec_cfg == NULL) { - LOG_ERR("No codec found for the stream"); - return -ENXIO; - } + if (dir == BT_AUDIO_DIR_SINK) { + /* If multiple sink streams exists, they should have the same configurations, + * hence we only check the first one. + */ + if (audio_streams[0].codec_cfg == NULL) { + LOG_ERR("No codec found for the stream"); - if (sampling_rate_hz != NULL) { - ret = le_audio_freq_hz_get(audio_streams[0].codec_cfg, sampling_rate_hz); - if (ret) { - LOG_ERR("Invalid sampling frequency: %d", ret); return -ENXIO; } - } - if (bitrate != NULL) { - ret = le_audio_bitrate_get(audio_streams[0].codec_cfg, bitrate); - if (ret) { - LOG_ERR("Unable to calculate bitrate: %d", ret); - return -ENXIO; + if (sampling_rate_hz != NULL) { + ret = le_audio_freq_hz_get(audio_streams[0].codec_cfg, sampling_rate_hz); + if (ret) { + LOG_ERR("Invalid sampling frequency: %d", ret); + return -ENXIO; + } } - } - if (pres_delay_us != NULL) { - if (audio_streams[0].qos == NULL) { - LOG_ERR("No QoS found for the stream"); + if (bitrate != NULL) { + ret = le_audio_bitrate_get(audio_streams[0].codec_cfg, bitrate); + if (ret) { + LOG_ERR("Unable to calculate bitrate: %d", ret); + return -ENXIO; + } + } + + if (pres_delay_us != NULL) { + if (audio_streams[0].qos == NULL) { + LOG_ERR("No QoS found for the stream"); + return -ENXIO; + } + + *pres_delay_us = audio_streams[0].qos->pd; + } + } else if (dir == BT_AUDIO_DIR_SOURCE) { + /* If multiple source streams exists, they should have the same configurations, + * hence we only check the first one. + */ + if (bap_tx_streams[0]->codec_cfg == NULL) { + LOG_ERR("No codec found for the stream"); return -ENXIO; } - *pres_delay_us = audio_streams[0].qos->pd; + if (sampling_rate_hz != NULL) { + ret = le_audio_freq_hz_get(bap_tx_streams[0]->codec_cfg, sampling_rate_hz); + if (ret) { + LOG_ERR("Invalid sampling frequency: %d", ret); + return -ENXIO; + } + } + + if (bitrate != NULL) { + ret = le_audio_bitrate_get(bap_tx_streams[0]->codec_cfg, bitrate); + if (ret) { + LOG_ERR("Unable to calculate bitrate: %d", ret); + return -ENXIO; + } + } + + if (pres_delay_us != NULL) { + if (bap_tx_streams[0]->qos == NULL) { + LOG_ERR("No QoS found for the stream"); + return -ENXIO; + } + + *pres_delay_us = bap_tx_streams[0]->qos->pd; + LOG_ERR("pres_delay_us: %d", *pres_delay_us); + } } return 0; diff --git a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.h b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.h index d25999c3812f..bb6a98374b04 100644 --- a/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.h +++ b/applications/nrf5340_audio/src/bluetooth/bt_stream/unicast/unicast_server.h @@ -15,15 +15,18 @@ /** * @brief Get configuration for audio stream. * - * @param[out] bitrate Pointer to the bitrate used; can be NULL. + * @param[in] conn Pointer to the connection to get the configuration for. + * @param[in] dir Direction to get the configuration from. + * @param[out] bitrate Pointer to the bit rate used; can be NULL. * @param[out] sampling_rate_hz Pointer to the sampling rate used; can be NULL. - * @param[out] pres_delay_us Pointer to the presentation delay used; can be NULL. + * @param[out] pres_delay_us Pointer to the presentation delay used; can be NULL. Only + * valid for the sink direction. * * @retval 0 Operation successful. * @retval -ENXIO The feature is disabled. */ -int unicast_server_config_get(uint32_t *bitrate, uint32_t *sampling_rate_hz, - uint32_t *pres_delay_us); +int unicast_server_config_get(struct bt_conn *conn, enum bt_audio_dir dir, uint32_t *bitrate, + uint32_t *sampling_rate_hz, uint32_t *pres_delay_us); /** * @brief Put the UUIDs from this module into the buffer. @@ -44,7 +47,7 @@ int unicast_server_uuid_populate(struct net_buf_simple *uuid_buf); * @param[out] adv_buf Buffer being populated with ext adv elements. * @param[in] adv_buf_vacant Number of vacant elements in @p adv_buf. * - * @return Negative values for errors or num elements added to @p adv_buf. + * @return Negative values for errors or number of elements added to @p adv_buf. */ int unicast_server_adv_populate(struct bt_data *adv_buf, uint8_t adv_buf_vacant); diff --git a/applications/nrf5340_audio/unicast_client/main.c b/applications/nrf5340_audio/unicast_client/main.c index e9c709637782..606a21330274 100644 --- a/applications/nrf5340_audio/unicast_client/main.c +++ b/applications/nrf5340_audio/unicast_client/main.c @@ -206,6 +206,8 @@ static void button_msg_sub_thread(void) static void le_audio_msg_sub_thread(void) { int ret; + uint32_t bitrate_bps; + uint32_t sampling_rate_hz; const struct zbus_channel *chan; while (1) { @@ -266,6 +268,31 @@ static void le_audio_msg_sub_thread(void) break; + case LE_AUDIO_EVT_CONFIG_RECEIVED: + LOG_DBG("LE audio config received"); + + ret = unicast_client_config_get(msg.conn, msg.dir, &bitrate_bps, + &sampling_rate_hz); + if (ret) { + LOG_WRN("Failed to get config: %d", ret); + break; + } + + LOG_DBG("\tSampling rate: %d Hz", sampling_rate_hz); + LOG_DBG("\tBitrate (compressed): %d bps", bitrate_bps); + + if (msg.dir == BT_AUDIO_DIR_SINK) { + ret = audio_system_config_set(sampling_rate_hz, bitrate_bps, + VALUE_NOT_SET); + ERR_CHK(ret); + } else if (msg.dir == BT_AUDIO_DIR_SOURCE) { + ret = audio_system_config_set(VALUE_NOT_SET, VALUE_NOT_SET, + sampling_rate_hz); + ERR_CHK(ret); + } + + break; + default: LOG_WRN("Unexpected/unhandled le_audio event: %d", msg.event); break; diff --git a/applications/nrf5340_audio/unicast_server/main.c b/applications/nrf5340_audio/unicast_server/main.c index 5f44af58b311..01ae5bf823c2 100644 --- a/applications/nrf5340_audio/unicast_server/main.c +++ b/applications/nrf5340_audio/unicast_server/main.c @@ -223,23 +223,35 @@ static void le_audio_msg_sub_thread(void) break; case LE_AUDIO_EVT_CONFIG_RECEIVED: - LOG_DBG("Config received"); + LOG_DBG("LE audio config received"); - ret = unicast_server_config_get(&bitrate_bps, &sampling_rate_hz, NULL); + ret = unicast_server_config_get(msg.conn, msg.dir, &bitrate_bps, + &sampling_rate_hz, NULL); if (ret) { LOG_WRN("Failed to get config: %d", ret); break; } - LOG_DBG("Sampling rate: %d Hz", sampling_rate_hz); - LOG_DBG("Bitrate: %d bps", bitrate_bps); + LOG_DBG("\tSampling rate: %d Hz", sampling_rate_hz); + LOG_DBG("\tBitrate (compressed): %d bps", bitrate_bps); + + if (msg.dir == BT_AUDIO_DIR_SINK) { + ret = audio_system_config_set(VALUE_NOT_SET, VALUE_NOT_SET, + sampling_rate_hz); + ERR_CHK(ret); + } else if (msg.dir == BT_AUDIO_DIR_SOURCE) { + ret = audio_system_config_set(sampling_rate_hz, bitrate_bps, + VALUE_NOT_SET); + ERR_CHK(ret); + } break; case LE_AUDIO_EVT_PRES_DELAY_SET: LOG_DBG("Set presentation delay"); - ret = unicast_server_config_get(NULL, NULL, &pres_delay_us); + ret = unicast_server_config_get(msg.conn, BT_AUDIO_DIR_SINK, NULL, NULL, + &pres_delay_us); if (ret) { LOG_ERR("Failed to get config: %d", ret); break; diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst index d876611c069e..6c35a3d91350 100644 --- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst +++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst @@ -309,6 +309,7 @@ nRF5340 Audio * Support for Filter Accept List; enabled as default. * Metadata used in Auracast, such as ``active_state`` and ``parental_rating``. * Updated :ref:`lib_bt_ll_acs_nrf53_readme` from v3424 to v17933. + * Support for converting the audio sample rate between 48 kHz, 24 kHz, and 16 kHz. * Updated: diff --git a/include/pcm_stream_channel_modifier.h b/include/pcm_stream_channel_modifier.h index 684438101b80..b5b20c998cac 100644 --- a/include/pcm_stream_channel_modifier.h +++ b/include/pcm_stream_channel_modifier.h @@ -22,7 +22,6 @@ #include #include - /** @brief Adds a 0 after every sample from *input * and writes it to *output. * @note Use to create stereo stream from a mono source where one @@ -84,9 +83,8 @@ int pscm_combine(void const *const input_left, void const *const input_right, si * * @return 0 if success. */ -int pscm_one_channel_split(void const *const input, size_t input_size, - enum audio_channel channel, uint8_t pcm_bit_depth, void *output, - size_t *output_size); +int pscm_one_channel_split(void const *const input, size_t input_size, enum audio_channel channel, + uint8_t pcm_bit_depth, void *output, size_t *output_size); /** @brief Splits a stereo stream to two separate mono streams. * @note Use to split stereo audio stream to two separate channels. diff --git a/include/sample_rate_converter.h b/include/sample_rate_converter.h index 15eb3f0dbd5b..7e350b881a50 100644 --- a/include/sample_rate_converter.h +++ b/include/sample_rate_converter.h @@ -70,6 +70,9 @@ enum sample_rate_converter_filter { ((CONFIG_SAMPLE_RATE_CONVERTER_BLOCK_SIZE_MAX + \ SAMPLE_RATE_CONVERTER_OUTPUT_BUFFER_NUMBER_OVERFLOW_SAMPLES) * \ sizeof(uint32_t)) +#else +#define SAMPLE_RATE_CONVERTER_INPUT_BUF_SIZE 0 +#define SAMPLE_RATE_CONVERTER_RINGBUF_SIZE 0 #endif /** Buffer used for storing input bytes to the sample rate converter */ diff --git a/lib/pcm_stream_channel_modifier/pcm_stream_channel_modifier.c b/lib/pcm_stream_channel_modifier/pcm_stream_channel_modifier.c index c29ad284ab8f..0c62558f4050 100644 --- a/lib/pcm_stream_channel_modifier/pcm_stream_channel_modifier.c +++ b/lib/pcm_stream_channel_modifier/pcm_stream_channel_modifier.c @@ -142,9 +142,8 @@ int pscm_combine(void const *const input_left, void const *const input_right, si return 0; } -int pscm_one_channel_split(void const *const input, size_t input_size, - enum audio_channel channel, uint8_t pcm_bit_depth, void *output, - size_t *output_size) +int pscm_one_channel_split(void const *const input, size_t input_size, enum audio_channel channel, + uint8_t pcm_bit_depth, void *output, size_t *output_size) { uint8_t bytes_per_sample = pcm_bit_depth / 8;