diff --git a/include/audio_defines.h b/include/audio_defines.h index d9e0b8d795af..2e554611a850 100644 --- a/include/audio_defines.h +++ b/include/audio_defines.h @@ -57,7 +57,7 @@ struct audio_metadata { * bits_per_sample = 24 * carrier_size = 32 */ - uint8_t carried_bits_pr_sample; + uint8_t carried_bits_per_sample; /* A 32 bit mask indicating which channel(s)/locations are active within * the data. A bit set indicates the location is active and diff --git a/include/audio_module/audio_module.h b/include/audio_module/audio_module.h index 640772cab2c6..8aa6452d6ec0 100644 --- a/include/audio_module/audio_module.h +++ b/include/audio_module/audio_module.h @@ -23,6 +23,19 @@ extern "C" { #include "audio_defines.h" +/** + * @brief Helper macro to configure the modules parameters. + */ +#define AUDIO_MODULE_PARAMETERS(p, dest, stk, stk_size, pri, fifo_rx, fifo_tx, slab, slab_size) \ + (p).description = (dest); \ + (p).thread.stack = (stk); \ + (p).thread.stack_size = (stk_size); \ + (p).thread.priority = (pri); \ + (p).thread.msg_rx = (fifo_rx); \ + (p).thread.msg_tx = (fifo_tx); \ + (p).thread.data_slab = (slab); \ + (p).thread.data_size = (slab_size); + /** * @brief Number of valid location bits. */ @@ -409,6 +422,10 @@ int audio_module_stop(struct audio_module_handle *handle); /** * @brief Send an audio data item to an audio module, all data is consumed by the module. * + * @note: The data pointer and its associated size that are passed via the audio data + * pointer, can be NULL and/or 0. It is the responsibility of the low level module functions + * to handle this correctly. + * * @param handle [in/out] The handle for the receiving module instance. * @param audio_data [in] Pointer to the audio data to send to the module. * @param response_cb [in] Pointer to a callback to run when the buffer is @@ -423,6 +440,10 @@ int audio_module_data_tx(struct audio_module_handle *handle, /** * @brief Retrieve an audio data item from an audio module. * + * @note: The data pointer and its associated size that are passed via the audio data + * pointer, can be NULL and/or 0. It is the responsibility of the low level module functions + * to handle this correctly. + * * @param handle [in/out] The handle to the module instance. * @param audio_data [out] Pointer to the audio data from the module. * @param timeout [in] Non-negative waiting period to wait for operation to complete @@ -441,6 +462,10 @@ int audio_module_data_rx(struct audio_module_handle *handle, struct audio_data * * returned via the module or final module's output FIFO. All the input data is consumed * within the call and thus the input data buffer maybe released once the function returns. * + * @note: The data I/O pointers and their associated sizes that are passed via the audio data + * pointers, can be NULL and/or 0. It is the responsibility of the low level module functions + * to handle this correctly. + * * @param handle_tx [in/out] The handle to the module to send the input audio data to. * @param handle_rx [in/out] The handle to the module to receive audio data from. * @param audio_data_tx [in] Pointer to the audio data to send. diff --git a/include/audio_modules/audio_module_template.h b/include/audio_modules/audio_module_template.h new file mode 100644 index 000000000000..6142ddf4b8bb --- /dev/null +++ b/include/audio_modules/audio_module_template.h @@ -0,0 +1,50 @@ +/* + * Copyright(c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#ifndef _AUDIO_MODULE_TEMPLATE_H_ +#define _AUDIO_MODULE_TEMPLATE_H_ + +#include +#include +#include +#include "audio_defines.h" +#include "audio_module.h" + +#define AUDIO_MODULE_TEMPLATE_LAST_BYTES (10) + +/** + * @brief Private pointer to the module's parameters. + * + */ +extern struct audio_module_description *audio_module_template_description; + +/** + * @brief The module configuration structure. + * + */ +struct audio_module_template_configuration { + /* The rate. */ + uint32_t sample_rate_hz; + + /* the depth. */ + uint32_t bit_depth; + + /* A string .*/ + char *some_text; +}; + +/** + * @brief Private module context. + * + */ +struct audio_module_template_context { + /* Array of data to illustrate the data process function. */ + uint8_t audio_module_template_data[AUDIO_MODULE_TEMPLATE_LAST_BYTES]; + + /* The template configuration. */ + struct audio_module_template_configuration config; +}; + +#endif /* _AUDIO_MODULE_TEMPLATE_H_ */ diff --git a/include/audio_modules/lc3_decoder.h b/include/audio_modules/lc3_decoder.h new file mode 100644 index 000000000000..430cd29d3bd4 --- /dev/null +++ b/include/audio_modules/lc3_decoder.h @@ -0,0 +1,83 @@ +/* + * Copyright(c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#ifndef _LC3_DECODER_H_ +#define _LC3_DECODER_H_ + +#include "audio_defines.h" +#include "audio_module.h" + +#define LC3_DECODER_PCM_NUM_BYTES_MONO \ + ((CONFIG_LC3_DECODER_SAMPLE_RATE_HZ * CONFIG_LC3_DECODER_BIT_DEPTH_OCTETS * \ + CONFIG_LC3_DECODER_FRAME_DURATION_US) / \ + 1000000) + +/** + * @brief Private pointer to the module's parameters. + */ +extern struct audio_module_description *lc3_decoder_description; + +/** + * @brief Private pointer to the decoders handle. + */ +struct lc3_decoder_handle; + +/** + * @brief The module configuration structure. + */ +struct lc3_decoder_configuration { + /* Sample rate for the decoder instance. */ + uint32_t sample_rate_hz; + + /* Number of valid bits for a sample (bit depth). + * Typically 16 or 24. + */ + uint8_t bits_per_sample; + + /* Number of bits used to carry a sample of size bits_per_sample. + * For example, say we have a 24 bit sample stored in a 32 bit + * word (int32_t), then: + * bits_per_sample = 24 + * carrier_size = 32 + */ + uint32_t carried_bits_per_sample; + + /* Frame duration for this decoder instance. */ + uint32_t data_len_us; + + /* A flag indicating if the decoded buffer is sample interleaved or not. */ + bool interleaved; + + /* Channel locations for this decoder instance. */ + uint32_t locations; + + /* Maximum bitrate supported by the decoder. */ + uint32_t bitrate_bps_max; +}; + +/** + * @brief Private module context. + */ +struct lc3_decoder_context { + /* Array of decoder channel handles. */ + struct lc3_decoder_handle *lc3_dec_channel[CONFIG_LC3_DEC_CHANNELS_MAX]; + + /* Number of decoder channel handles. */ + uint32_t dec_handles_count; + + /* The decoder configuration. */ + struct lc3_decoder_configuration config; + + /* Minimum coded bytes required for this decoder instance. */ + uint16_t coded_bytes_req; + + /* Audio sample bytes per frame. */ + size_t sample_frame_bytes; + + /* Number of successive frames to which PLC has been applied. */ + uint16_t plc_count; +}; + +#endif /* _LC3_DECODER_H_ */ diff --git a/include/data_fifo.h b/include/data_fifo.h index 258e359d2ac1..a4a71dd506ca 100644 --- a/include/data_fifo.h +++ b/include/data_fifo.h @@ -42,10 +42,10 @@ struct data_fifo { }; #define DATA_FIFO_DEFINE(name, elements_max_in, block_size_max_in) \ - char __aligned(WB_UP(1)) \ - _msgq_buffer_##name[(elements_max_in) * sizeof(struct data_fifo_msgq)] = {0}; \ - char __aligned(WB_UP(1)) \ - _slab_buffer_##name[(elements_max_in) * (block_size_max_in)] = {0}; \ + char __aligned(WB_UP( \ + 1)) _msgq_buffer_##name[(elements_max_in) * sizeof(struct data_fifo_msgq)] = {0}; \ + char __aligned(WB_UP(1)) _slab_buffer_##name[(elements_max_in) * (block_size_max_in)] = { \ + 0}; \ struct data_fifo name = {.msgq_buffer = _msgq_buffer_##name, \ .slab_buffer = _slab_buffer_##name, \ .block_size_max = block_size_max_in, \ @@ -163,7 +163,7 @@ int data_fifo_empty(struct data_fifo *data_fifo); int data_fifo_uninit(struct data_fifo *data_fifo); /** - * @brief Initialise the data_fifo. + * @brief Initialize the data_fifo. * * @param data_fifo Pointer to the data_fifo structure. * @@ -172,6 +172,16 @@ int data_fifo_uninit(struct data_fifo *data_fifo); */ int data_fifo_init(struct data_fifo *data_fifo); +/** + * @brief Test if the data_fifo state. + * + * @param data_fifo Pointer to the data_fifo structure. + * + * @retval false Uninitialized. + * @retval true Initialized. + */ +bool data_fifo_state(struct data_fifo *data_fifo); + /** * @} */ diff --git a/lib/data_fifo/data_fifo.c b/lib/data_fifo/data_fifo.c index 4a865b15bbed..c0ef1cec683e 100644 --- a/lib/data_fifo/data_fifo.c +++ b/lib/data_fifo/data_fifo.c @@ -206,3 +206,13 @@ int data_fifo_init(struct data_fifo *data_fifo) return ret; } + +bool data_fifo_state(struct data_fifo *data_fifo) +{ + __ASSERT_NO_MSG(data_fifo != NULL); + __ASSERT_NO_MSG(data_fifo->elements_max != 0); + __ASSERT_NO_MSG(data_fifo->block_size_max != 0); + __ASSERT_NO_MSG((data_fifo->block_size_max % WB_UP(1)) == 0); + + return data_fifo->initialized; +} diff --git a/subsys/CMakeLists.txt b/subsys/CMakeLists.txt index 7afba217388b..7f551edfa21c 100644 --- a/subsys/CMakeLists.txt +++ b/subsys/CMakeLists.txt @@ -70,6 +70,8 @@ add_subdirectory_ifdef(CONFIG_NRF_DM dm) add_subdirectory_ifdef(CONFIG_EMDS emds) add_subdirectory_ifdef(CONFIG_NET_CORE_MONITOR net_core_monitor) add_subdirectory_ifdef(CONFIG_AUDIO_MODULE audio_module) +add_subdirectory_ifdef(CONFIG_AUDIO_MODULE_TEMPLATE audio_modules/audio_module_template) +add_subdirectory_ifdef(CONFIG_AUDIO_MODULE_T2_LC3_DECODER audio_modules/lc3/t2/decoder) add_subdirectory_ifdef(CONFIG_UART_ASYNC_ADAPTER uart_async_adapter) add_subdirectory_ifdef(CONFIG_SDFW_SERVICES_ENABLED sdfw_services) add_subdirectory(suit) diff --git a/subsys/Kconfig b/subsys/Kconfig index 04ba79518fee..e60c31881484 100644 --- a/subsys/Kconfig +++ b/subsys/Kconfig @@ -34,6 +34,8 @@ rsource "dm/Kconfig" rsource "nrf_security/Kconfig" rsource "net_core_monitor/Kconfig" rsource "audio_module/Kconfig" +rsource "audio_modules/audio_module_template/Kconfig" +rsource "audio_modules/lc3/t2/decoder/Kconfig" rsource "uart_async_adapter/Kconfig" rsource "trusted_storage/Kconfig" rsource "logging/Kconfig" diff --git a/subsys/audio_module/CMakeLists.txt b/subsys/audio_module/CMakeLists.txt index 674c375ff352..f0fa0d2532d1 100644 --- a/subsys/audio_module/CMakeLists.txt +++ b/subsys/audio_module/CMakeLists.txt @@ -4,4 +4,4 @@ # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # -target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/audio_module.c) +zephyr_sources_ifdef(CONFIG_AUDIO_MODULE audio_module.c) diff --git a/subsys/audio_module/Kconfig b/subsys/audio_module/Kconfig index f0ea1d118a3b..1a52346bd278 100644 --- a/subsys/audio_module/Kconfig +++ b/subsys/audio_module/Kconfig @@ -3,8 +3,7 @@ # # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause # - -menu "Audio Module" +menu "Audio Modules" config AUDIO_MODULE tristate "Enable the audio module" @@ -20,8 +19,12 @@ config AUDIO_MODULE_NAME_SIZE int "Maximum size for module naming in characters" default 20 +#----------------------------------------------------------------------------# +menu "Log levels" + module = AUDIO_MODULE module-str = audio_module source "subsys/logging/Kconfig.template.log_config" -endmenu # Audio Module +endmenu # Log levels +endmenu # Audio Modules diff --git a/subsys/audio_module/audio_module.c b/subsys/audio_module/audio_module.c index 846a0fb4d3b7..67b39c1a1d84 100644 --- a/subsys/audio_module/audio_module.c +++ b/subsys/audio_module/audio_module.c @@ -153,8 +153,10 @@ static void audio_data_release_cb(struct audio_module_handle_private *handle, } if (k_sem_count_get(&hdl->sem) == 0) { + LOG_DBG("Audio data has been consumed in module %s", hdl->name); + /* Audio data has been consumed by all modules so now can free the data memory. */ - k_mem_slab_free(hdl->thread.data_slab, (void **)&audio_data->data); + k_mem_slab_free(hdl->thread.data_slab, (void *)audio_data->data); } } @@ -185,14 +187,14 @@ static int data_tx(struct audio_module_handle *tx_handle, struct audio_module_ha } /* Copy. The audio data itself will remain in its original location. */ - memcpy(&data_msg_rx->audio_data, audio_data, sizeof(struct audio_data)); + memcpy(&(data_msg_rx->audio_data), audio_data, sizeof(struct audio_data)); data_msg_rx->tx_handle = tx_handle; data_msg_rx->response_cb = data_in_response_cb; ret = data_fifo_block_lock(rx_handle->thread.msg_rx, (void **)&data_msg_rx, sizeof(struct audio_module_message)); if (ret) { - data_fifo_block_free(rx_handle->thread.msg_rx, (void **)&data_msg_rx); + data_fifo_block_free(rx_handle->thread.msg_rx, (void *)data_msg_rx); LOG_WRN("Module %s failed to queue audio data, ret %d", rx_handle->name, ret); @@ -244,7 +246,7 @@ static int tx_fifo_put(struct audio_module_handle *handle, LOG_ERR("Failed to send audio data to output of module %s, ret %d", handle->name, ret); - data_fifo_block_free(handle->thread.msg_tx, (void **)&data_msg_tx); + data_fifo_block_free(handle->thread.msg_tx, (void *)data_msg_tx); ret = k_sem_take(&handle->sem, K_NO_WAIT); if (ret) { @@ -254,6 +256,8 @@ static int tx_fifo_put(struct audio_module_handle *handle, return ret; } + LOG_DBG("Sent audio data to output of module %s", handle->name); + return 0; } @@ -275,7 +279,7 @@ static int send_to_connected_modules(struct audio_module_handle *handle, LOG_WRN("Nowhere to send the audio data from module %s so releasing it", handle->name); - k_mem_slab_free(handle->thread.data_slab, (void **)audio_data->data); + k_mem_slab_free(handle->thread.data_slab, (void *)audio_data->data); return 0; } @@ -332,6 +336,8 @@ static int send_to_connected_modules(struct audio_module_handle *handle, return ret; } + + LOG_DBG("Sent audio data to TX message queue for module %s", handle->name); } return 0; @@ -367,7 +373,7 @@ static void module_thread_input(struct audio_module_handle *handle, void *p2, vo * will control the data flow. */ ret = k_mem_slab_alloc(handle->thread.data_slab, (void **)&data, K_NO_WAIT); - __ASSERT(ret, "No free data for module %s, ret %d", handle->name, ret); + __ASSERT(ret == 0, "No free data for module %s, ret %d", handle->name, ret); /* Configure new audio data. */ audio_data.data = data; @@ -377,7 +383,7 @@ static void module_thread_input(struct audio_module_handle *handle, void *p2, vo ret = handle->description->functions->data_process( (struct audio_module_handle_private *)handle, NULL, &audio_data); if (ret) { - k_mem_slab_free(handle->thread.data_slab, (void **)(&data)); + k_mem_slab_free(handle->thread.data_slab, (void *)(data)); LOG_ERR("Data process error in module %s, ret %d", handle->name, ret); continue; @@ -426,7 +432,7 @@ static void module_thread_output(struct audio_module_handle *handle, void *p2, v */ ret = data_fifo_pointer_last_filled_get(handle->thread.msg_rx, (void **)&msg_rx, &size, K_FOREVER); - __ASSERT(ret, "Module %s error in getting last filled", handle->name); + __ASSERT(ret == 0, "Module %s error in getting last filled", handle->name); LOG_DBG("Module %s new audio data received", handle->name); @@ -449,7 +455,7 @@ static void module_thread_output(struct audio_module_handle *handle, void *p2, v &msg_rx->audio_data); } - data_fifo_block_free(handle->thread.msg_rx, (void **)&msg_rx); + data_fifo_block_free(handle->thread.msg_rx, (void *)msg_rx); } CODE_UNREACHABLE; @@ -481,21 +487,17 @@ static void module_thread_in_out(struct audio_module_handle *handle, void *p2, v while (1) { data = NULL; - LOG_DBG("Module %s is waiting for audio data", handle->name); - /* Get a new input message. * Since this input message is queued outside the module, this will then control the * data flow. */ ret = data_fifo_pointer_last_filled_get(handle->thread.msg_rx, (void **)&msg_rx, &size, K_FOREVER); - __ASSERT(ret, "Module %s error in getting last filled", handle->name); - - LOG_DBG("Module %s new audio data received", handle->name); + __ASSERT(ret == 0, "Module %s error in getting last filled %d", handle->name, ret); /* Get a new output buffer. */ ret = k_mem_slab_alloc(handle->thread.data_slab, (void **)&data, K_NO_WAIT); - __ASSERT(ret, "No free data buffer for module %s, dropping input, ret %d", + __ASSERT(ret == 0, "No free data buffer for module %s, dropping input, ret %d", handle->name, ret); /* Configure new audio audio_data. */ @@ -513,9 +515,9 @@ static void module_thread_in_out(struct audio_module_handle *handle, void *p2, v &msg_rx->audio_data); } - data_fifo_block_free(handle->thread.msg_rx, (void **)(&msg_rx)); + data_fifo_block_free(handle->thread.msg_rx, (void *)(msg_rx)); - k_mem_slab_free(handle->thread.data_slab, (void **)(&data)); + k_mem_slab_free(handle->thread.data_slab, (void *)(data)); LOG_ERR("Data process error in module %s, ret %d", handle->name, ret); continue; @@ -529,7 +531,7 @@ static void module_thread_in_out(struct audio_module_handle *handle, void *p2, v &msg_rx->audio_data); } - data_fifo_block_free(handle->thread.msg_rx, (void **)&msg_rx); + data_fifo_block_free(handle->thread.msg_rx, (void *)msg_rx); } CODE_UNREACHABLE; @@ -562,7 +564,7 @@ int audio_module_open(struct audio_module_parameters const *const parameters, /* Clear handle to known state. */ memset(handle, 0, sizeof(struct audio_module_handle)); - /* Allocate the context memory. */ + /* Store pointer to the context. */ handle->context = context; memcpy(handle->name, name, CONFIG_AUDIO_MODULE_NAME_SIZE); @@ -610,6 +612,30 @@ int audio_module_open(struct audio_module_parameters const *const parameters, return -EINVAL; } + if (handle->thread.msg_rx != NULL && !data_fifo_state(handle->thread.msg_rx)) { + ret = data_fifo_init(handle->thread.msg_rx); + if (ret) { + LOG_ERR("Failed to initialize the RX FIFO for module %s, ret %d", + handle->name, ret); + + /* Clean up the handle. */ + memset(handle, 0, sizeof(struct audio_module_handle)); + return ret; + } + } + + if (handle->thread.msg_tx != NULL && !data_fifo_state(handle->thread.msg_tx)) { + ret = data_fifo_init(handle->thread.msg_tx); + if (ret) { + LOG_ERR("Failed to initialize the TX FIFO for module %s, ret %d", + handle->name, ret); + + /* Clean up the handle. */ + memset(handle, 0, sizeof(struct audio_module_handle)); + return ret; + } + } + sys_slist_init(&handle->handle_dest_list); k_mutex_init(&handle->dest_mutex); @@ -659,12 +685,12 @@ int audio_module_close(struct audio_module_handle *handle) } } - if (handle->thread.msg_rx != NULL) { - data_fifo_empty(handle->thread.msg_rx); + if (handle->thread.msg_rx != NULL && data_fifo_state(handle->thread.msg_rx)) { + data_fifo_uninit(handle->thread.msg_rx); } - if (handle->thread.msg_tx != NULL) { - data_fifo_empty(handle->thread.msg_tx); + if (handle->thread.msg_tx != NULL && data_fifo_state(handle->thread.msg_tx)) { + data_fifo_uninit(handle->thread.msg_tx); } /* @@ -674,6 +700,9 @@ int audio_module_close(struct audio_module_handle *handle) k_thread_abort(handle->thread_id); + /* Ensure module handle data is fully cleared. */ + memset(handle, 0, sizeof(struct audio_module_handle)); + LOG_DBG("Closed module %s", handle->name); return 0; @@ -829,6 +858,8 @@ int audio_module_connect(struct audio_module_handle *handle_from, return ret; } + LOG_DBG("Connection(s) created"); + return 0; } @@ -1011,8 +1042,8 @@ int audio_module_data_tx(struct audio_module_handle *handle, return -ECANCELED; } - if (audio_data == NULL || audio_data->data == NULL || audio_data->data_size == 0) { - LOG_ERR("Data parameter error for module %s", handle->name); + if (audio_data == NULL) { + LOG_ERR("Output audio data for module %s has a NULL pointer", handle->name); return -EINVAL; } @@ -1024,11 +1055,11 @@ int audio_module_data_rx(struct audio_module_handle *handle, struct audio_data * { int ret; - struct audio_module_message *msg_tx; - size_t msg_tx_size; + struct audio_module_message *msg_rx = NULL; + size_t msg_rx_size = 0; - if (handle == NULL) { - LOG_ERR("Module handle is NULL"); + if (handle == NULL || audio_data == NULL) { + LOG_ERR("Module handle or audio data pointer are NULL"); return -EINVAL; } @@ -1048,31 +1079,41 @@ int audio_module_data_rx(struct audio_module_handle *handle, struct audio_data * return -ECANCELED; } - if (audio_data == NULL || audio_data->data == NULL || audio_data->data_size == 0) { - LOG_ERR("Input audio data for module %s has NULL pointer or a zero size buffer", - handle->name); - return -EINVAL; - } - - ret = data_fifo_pointer_last_filled_get(handle->thread.msg_tx, (void **)&msg_tx, - &msg_tx_size, timeout); + ret = data_fifo_pointer_last_filled_get(handle->thread.msg_tx, (void **)&msg_rx, + &msg_rx_size, timeout); if (ret) { LOG_ERR("Failed to retrieve data from module %s, ret %d", handle->name, ret); return ret; } - if (msg_tx->audio_data.data == NULL || - msg_tx->audio_data.data_size > audio_data->data_size) { - LOG_ERR("Data output pointer NULL or not enough room for buffer from module %s", - handle->name); - ret = -EINVAL; + if (msg_rx == NULL) { + LOG_ERR("Failed to retrieve message from %s", handle->name); + return -ECANCELED; + } + + if (audio_data->data_size != 0) { + if (msg_rx->audio_data.data_size > audio_data->data_size) { + LOG_ERR("Not enough room for buffer from module %s", handle->name); + ret = -ECANCELED; + } else if (audio_data->data == NULL) { + LOG_WRN("Data pointer to buffer is NULL"); + } else { + memcpy(&audio_data->meta, &msg_rx->audio_data.meta, + sizeof(struct audio_metadata)); + memcpy((uint8_t *)audio_data->data, (uint8_t *)msg_rx->audio_data.data, + msg_rx->audio_data.data_size); + audio_data->data_size = msg_rx->audio_data.data_size; + } } else { - memcpy(&audio_data->meta, &msg_tx->audio_data.meta, sizeof(struct audio_metadata)); - memcpy((uint8_t *)audio_data->data, (uint8_t *)msg_tx->audio_data.data, - msg_tx->audio_data.data_size); + LOG_WRN("Data buffer size is 0"); + } + + if (msg_rx->response_cb != NULL) { + msg_rx->response_cb((struct audio_module_handle_private *)msg_rx->tx_handle, + &msg_rx->audio_data); } - data_fifo_block_free(handle->thread.msg_tx, (void **)&msg_tx); + data_fifo_block_free(handle->thread.msg_tx, (void *)msg_rx); return ret; } @@ -1117,41 +1158,43 @@ int audio_module_data_tx_rx(struct audio_module_handle *handle_tx, return -EINVAL; } - if (audio_data_tx->data == NULL || audio_data_tx->data_size == 0 || - audio_data_rx->data == NULL || audio_data_rx->data_size == 0) { - LOG_ERR("One or both of the have invalid output audio data"); - return -EINVAL; - } - - ret = data_tx(NULL, handle_tx, audio_data_tx, NULL); + ret = data_tx(NULL, handle_rx, audio_data_tx, NULL); if (ret) { LOG_ERR("Failed to send audio data to module %s, ret %d", handle_tx->name, ret); return ret; } - LOG_DBG("Wait for message on module %s TX queue", handle_rx->name); - - ret = data_fifo_pointer_last_filled_get(handle_rx->thread.msg_rx, (void **)&msg_rx, + ret = data_fifo_pointer_last_filled_get(handle_rx->thread.msg_tx, (void **)&msg_rx, &msg_rx_size, timeout); if (ret) { - LOG_ERR("Failed to retrieve audio data from module %s, ret %d", handle_rx->name, + LOG_ERR("Failed to retrieve audio data from module %s, ret %d", handle_tx->name, ret); return ret; } - if (msg_rx->audio_data.data == NULL || msg_rx->audio_data.data_size == 0) { - LOG_ERR("Data output buffer too small for received buffer from module %s " - "(%d)", - handle_rx->name, msg_rx->audio_data.data_size); - ret = -EINVAL; + if (audio_data_rx->data_size != 0) { + if (msg_rx->audio_data.data_size > audio_data_rx->data_size) { + LOG_ERR("Not enough room for buffer from module %s", handle_rx->name); + ret = -ECANCELED; + } else if (audio_data_rx->data == NULL) { + LOG_WRN("Data pointer to buffer is NULL"); + } else { + memcpy(&audio_data_rx->meta, &msg_rx->audio_data.meta, + sizeof(struct audio_metadata)); + memcpy((uint8_t *)audio_data_rx->data, (uint8_t *)msg_rx->audio_data.data, + msg_rx->audio_data.data_size); + audio_data_rx->data_size = msg_rx->audio_data.data_size; + } } else { - memcpy(&audio_data_rx->meta, &msg_rx->audio_data.meta, - sizeof(struct audio_metadata)); - memcpy((uint8_t *)audio_data_rx->data, (uint8_t *)msg_rx->audio_data.data, - msg_rx->audio_data.data_size); + LOG_WRN("Data buffer size is 0"); + } + + if (msg_rx->response_cb != NULL) { + msg_rx->response_cb((struct audio_module_handle_private *)msg_rx->tx_handle, + &msg_rx->audio_data); } - data_fifo_block_free(handle_rx->thread.msg_rx, (void **)&msg_rx); + data_fifo_block_free(handle_rx->thread.msg_tx, (void *)msg_rx); return ret; }; diff --git a/subsys/audio_modules/audio_module_template/CMakeLists.txt b/subsys/audio_modules/audio_module_template/CMakeLists.txt new file mode 100644 index 000000000000..41d86a5587ce --- /dev/null +++ b/subsys/audio_modules/audio_module_template/CMakeLists.txt @@ -0,0 +1,10 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/audio_module_template.c) + +target_include_directories(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/include/audio_module + ${ZEPHYR_NRF_MODULE_DIR}/include/audio_modules) diff --git a/subsys/audio_modules/audio_module_template/Kconfig b/subsys/audio_modules/audio_module_template/Kconfig new file mode 100644 index 000000000000..e055063a721e --- /dev/null +++ b/subsys/audio_modules/audio_module_template/Kconfig @@ -0,0 +1,27 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +menu "Audio Modules" + +config AUDIO_MODULE_TEMPLATE + bool "Audio module template" + help + Enable the audio module template, the + starting point for a new audio module + +if AUDIO_MODULE_TEMPLATE + +#----------------------------------------------------------------------------# +menu "Log levels" + +module = AUDIO_MODULE_TEMPLATE +module-str = audio_module +source "subsys/logging/Kconfig.template.log_config" + +endmenu # Log levels + +endif # AUDIO_MODULE_TEMPLATE + +endmenu # Audio Modules diff --git a/subsys/audio_modules/audio_module_template/audio_module_template.c b/subsys/audio_modules/audio_module_template/audio_module_template.c new file mode 100644 index 000000000000..18b55c28a98c --- /dev/null +++ b/subsys/audio_modules/audio_module_template/audio_module_template.c @@ -0,0 +1,200 @@ +/* + * Copyright(c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include "audio_module_template.h" + +#include +#include +#include +#include +#include +#include +#include "audio_defines.h" +#include "audio_module.h" + +#include +LOG_MODULE_REGISTER(audio_module_template, CONFIG_AUDIO_MODULE_TEMPLATE_LOG_LEVEL); + +static int audio_module_template_open(struct audio_module_handle_private *handle, + struct audio_module_configuration const *const configuration) + +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)hdl->context; + struct audio_module_template_configuration *config = + (struct audio_module_template_configuration *)configuration; + + /* Perform any other functions required to open the module. */ + + /* For example: Clear the module's context. + * Save the initial configuration to the module context. + */ + memset(ctx, 0, sizeof(struct audio_module_template_context)); + memcpy(&ctx->config, config, sizeof(struct audio_module_template_configuration)); + + LOG_DBG("Open %s module", hdl->name); + + return 0; +} + +static int audio_module_template_close(struct audio_module_handle_private *handle) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)hdl->context; + + /* Perform any other functions required to close the module. */ + + /* For example: Clear the context data */ + memset(ctx, 0, sizeof(struct audio_module_template_context)); + + LOG_DBG("Close %s module", hdl->name); + + return 0; +} + +static int audio_module_template_configuration_set( + struct audio_module_handle_private *handle, + struct audio_module_configuration const *const configuration) +{ + struct audio_module_template_configuration *config = + (struct audio_module_template_configuration *)configuration; + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)hdl->context; + + /* Perform any other functions to configure the module. */ + + /* For example: Copy the configuration into the context. */ + memcpy(&ctx->config, config, sizeof(struct audio_module_template_configuration)); + + LOG_DBG("Set the configuration for %s module: rate = %d depth = %d string = %s", + hdl->name, ctx->config.sample_rate_hz, ctx->config.bit_depth, + ctx->config.some_text); + + return 0; +} + +static int +audio_module_template_configuration_get(struct audio_module_handle_private const *const handle, + struct audio_module_configuration *configuration) +{ + struct audio_module_template_configuration *config = + (struct audio_module_template_configuration *)configuration; + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)hdl->context; + + /* Perform any other functions to extract the configuration of the module. */ + + /* For example: Copy the configuration from the context into the output configuration. */ + memcpy(config, &ctx->config, sizeof(struct audio_module_template_configuration)); + + LOG_DBG("Get the configuration for %s module: rate = %d depth = %d string = %s", + hdl->name, config->sample_rate_hz, config->bit_depth, config->some_text); + + return 0; +} + +static int audio_module_template_start(struct audio_module_handle_private *handle) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + + /* Perform any other functions to start the module. */ + + LOG_DBG("Start the %s module", hdl->name); + + return 0; +} + +static int audio_module_template_stop(struct audio_module_handle_private *handle) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + + /* Perform any other functions to stop the module. */ + + LOG_DBG("Stop the %s module", hdl->name); + + return 0; +} + +static int audio_module_template_data_process(struct audio_module_handle_private *handle, + struct audio_data const *const audio_data_in, + struct audio_data *audio_data_out) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + + /* Perform any other functions to process the data within the module. */ + + /* For example: Copy the input to the output. */ + { + size_t size = audio_data_in->data_size < audio_data_out->data_size + ? audio_data_in->data_size + : audio_data_out->data_size; + + memcpy(&audio_data_out->meta, &audio_data_in->meta, sizeof(struct audio_metadata)); + memcpy((uint8_t *)audio_data_out->data, (uint8_t *)audio_data_in->data, size); + audio_data_out->data_size = size; + } + + LOG_DBG("Process the input audio data into the output audio data item for %s module", + hdl->name); + + return 0; +} + +/** + * @brief Table of the dummy module functions. + */ +const struct audio_module_functions audio_module_template_functions = { + /** + * @brief Function to an open the dummy module. + */ + .open = audio_module_template_open, + + /** + * @brief Function to close the dummy module. + */ + .close = audio_module_template_close, + + /** + * @brief Function to set the configuration of the dummy module. + */ + .configuration_set = audio_module_template_configuration_set, + + /** + * @brief Function to get the configuration of the dummy module. + */ + .configuration_get = audio_module_template_configuration_get, + + /** + * @brief Start a module processing data. + */ + .start = audio_module_template_start, + + /** + * @brief Pause a module processing data. + */ + .stop = audio_module_template_stop, + + /** + * @brief The core data processing function in the dummy module. + */ + .data_process = audio_module_template_data_process, +}; + +/** + * @brief The set-up description for the LC3 decoder. + */ +struct audio_module_description audio_module_template_dept = { + .name = "Audio Module Temp", + .type = AUDIO_MODULE_TYPE_IN_OUT, + .functions = &audio_module_template_functions}; + +/** + * @brief A private pointer to the LC3 decoder set-up parameters. + */ +struct audio_module_description *audio_module_template_description = &audio_module_template_dept; diff --git a/subsys/audio_modules/lc3/t2/decoder/CMakeLists.txt b/subsys/audio_modules/lc3/t2/decoder/CMakeLists.txt new file mode 100644 index 000000000000..4a2fb38fafc2 --- /dev/null +++ b/subsys/audio_modules/lc3/t2/decoder/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright (c) 2023 Nordic Semiconductor +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +target_sources(app PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/lc3_decoder.c) + +target_include_directories(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/include/audio_module + ${ZEPHYR_NRF_MODULE_DIR}/include/audio_modules) + +zephyr_include_directories( + ${ZEPHYR_BASE}/../nrfxlib/lc3/codec/inc + ${ZEPHYR_BASE}/../nrfxlib/lc3/platform/os/inc + ${ZEPHYR_BASE}/../nrfxlib/lc3/platform/os/baremetal/inc +) diff --git a/subsys/audio_modules/lc3/t2/decoder/Kconfig b/subsys/audio_modules/lc3/t2/decoder/Kconfig new file mode 100644 index 000000000000..6f8da59f9e7b --- /dev/null +++ b/subsys/audio_modules/lc3/t2/decoder/Kconfig @@ -0,0 +1,146 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +menu "Audio Modules" + +config AUDIO_MODULE_T2_LC3_DECODER + bool "Enable the T2 LC3 decoder" + default y + help + Enable the T2 LC3 decoder audio module in test mode. + +config AUDIO_MODULE_T2_LC3_DECODER_TEST + bool "Enable the T2 LC3 decoder" + default n + help + Enable the T2 LC3 decoder audio module in test mode. + +config LC3_DEC_CHANNELS_MAX + int "Maximum audio channels" + default 2 + help + The maximum audio channels the decoder can support. + +choice LC3_DECODER_FRAME_DURATION + prompt "Select frame duration - 7.5 ms frame duration is not tested" + default LC3_DECODER_FRAME_DURATION_10_MS + help + LC3 supports frame duration of 7.5 and 10 ms. + +config LC3_DECODER_FRAME_DURATION_7_5_MS + bool "7.5 ms" + +config LC3_DECODER_FRAME_DURATION_10_MS + bool "10 ms" +endchoice + +config LC3_DECODER_FRAME_DURATION_US + int + default 7500 if LC3_DECODER_FRAME_DURATION_7_5_MS + default 10000 if LC3_DECODER_FRAME_DURATION_10_MS + help + Audio frame duration in µs. + +choice LC3_DECODER_SYSTEM_SAMPLE_RATE + prompt "System audio sample rate" + default LC3_DECODER_SAMPLE_RATE_48000_HZ + help + This configuration reflects the decoding sample rate. + +config LC3_DECODER_SAMPLE_RATE_8000_HZ + bool "8 kHz" + help + Sample rate of 16kHz. + +config LC3_DECODER_SAMPLE_RATE_16000_HZ + bool "16 kHz" + help + Sample rate of 16kHz. + +config LC3_DECODER_SAMPLE_RATE_24000_HZ + bool "24 kHz" + help + Sample rate of 24kHz. + +config LC3_DECODER_SAMPLE_RATE_32000_HZ + bool "32 kHz" + help + Sample rate of 16kHz. + +config LC3_DECODER_SAMPLE_RATE_44100_HZ + bool "44.1 kHz" + help + Sample rate of 16kHz. + +config LC3_DECODER_SAMPLE_RATE_48000_HZ + bool "48 kHz" + help + Sample rate of 48kHz. +endchoice + +config LC3_DECODER_SAMPLE_RATE_HZ + int + default 8000 if LC3_DECODER_SAMPLE_RATE_8000_HZ + default 16000 if LC3_DECODER_SAMPLE_RATE_16000_HZ + default 24000 if LC3_DECODER_SAMPLE_RATE_24000_HZ + default 32000 if LC3_DECODER_SAMPLE_RATE_32000_HZ + default 44100 if LC3_DECODER_SAMPLE_RATE_44100_HZ + default 48000 if LC3_DECODER_SAMPLE_RATE_48000_HZ + help + I2S supports 16, 24, and 48 kHz sample rates for both input and output. + USB supports only 48 kHz for input. + +choice LC3_DECODER_BIT_DEPTH + prompt "Audio bit depth" + default LC3_DECODER_BIT_DEPTH_16 + help + Select the bit depth for audio. + +config LC3_DECODER_BIT_DEPTH_16 + bool "16 bit audio" + +config LC3_DECODER_BIT_DEPTH_32 + bool "32 bit audio" +endchoice + +config LC3_DECODER_BIT_DEPTH_BITS + int + default 16 if LC3_DECODER_BIT_DEPTH_16 + default 32 if LC3_DECODER_BIT_DEPTH_32 + help + Bit depth of one sample in storage. + +config LC3_DECODER_BIT_DEPTH_OCTETS + int + default 2 if LC3_DECODER_BIT_DEPTH_16 + default 4 if LC3_DECODER_BIT_DEPTH_32 + help + Bit depth of one sample in storage given in octets. + +config LC3_DECODER_THREAD_PRIO + int "Priority for the decoder thread" + default 3 + help + This is a preemptible thread. + +config LC3_DECODER_STACK_SIZE + int "Stack size for the decoder thread" + default 4092 if LC3_DECODER_BIT_DEPTH_16 + default 5115 if LC3_DECODER_BIT_DEPTH_32 + help + The modules thread stack size. + +osource "../nrfxlib/lc3/Kconfig" + +#----------------------------------------------------------------------------# +menu "Log levels" + +module = AUDIO_MODULE_LC3_DECODER +module-str = t2_lc3_decoder +source "subsys/logging/Kconfig.template.log_config" + +endmenu # Log levels +endmenu # Audio Modules diff --git a/subsys/audio_modules/lc3/t2/decoder/lc3_decoder.c b/subsys/audio_modules/lc3/t2/decoder/lc3_decoder.c new file mode 100644 index 000000000000..99a5b721d53b --- /dev/null +++ b/subsys/audio_modules/lc3/t2/decoder/lc3_decoder.c @@ -0,0 +1,435 @@ +/* + * Copyright(c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "audio_modules/lc3_decoder.h" + +#include +#include +#include + +#include "audio_defines.h" +#include "audio_module/audio_module.h" +#include "LC3API.h" + +#include +LOG_MODULE_REGISTER(t2_lc3_decoder, CONFIG_AUDIO_MODULE_LC3_DECODER_LOG_LEVEL); + +/** + * @brief Number of micro seconds in a second. + * + */ +#define LC3_DECODER_US_IN_A_SECOND (1000000) + +/** + * @brief Interleave a channel into a buffer of N channels of PCM + * + * @note: The interleaver can not be executed inplace (i.e. input != output) + * + * @param[in] input Pointer to the single channel input buffer. + * @param[in] input_size Number of bytes in input. Must be divisible by two. + * @param[in] channel Channel to interleave into. + * @param[in] pcm_bit_depth Bit depth of PCM samples (8, 16, 24, or 32). + * @param[out] output Pointer to the output start of the multi-channel output. + * @param[in] output_size Number of bytes in output. Must be divisible by two and + * at least (input_size * bytes_per_sample * output_channels). + * @param[in] output_channels Number of output channels in the output buffer. + * + * @return 0 if successful, error value + */ +static int interleave(void const *const input, size_t input_size, uint8_t channel, + uint8_t pcm_bit_depth, void *output, size_t output_size, + uint8_t output_channels) +{ + uint8_t bytes_per_sample = pcm_bit_depth / 8; + size_t step; + uint8_t *pointer_input; + uint8_t *pointer_output; + + if (input == NULL || input_size == 0 || channel > output_channels || pcm_bit_depth == 0 || + output == NULL || output_size == 0 || output_channels == 0) { + return -EINVAL; + } + + if (output_size < (input_size * output_channels)) { + LOG_DBG("Output buffer too small to interleave input into"); + return -EINVAL; + } + + step = bytes_per_sample * (output_channels - 1); + pointer_input = (uint8_t *)input; + pointer_output = (uint8_t *)output + (step * channel); + + for (size_t i = 0; i < input_size; i += bytes_per_sample) { + for (size_t j = 0; j < bytes_per_sample; j++) { + *pointer_output++ = *pointer_input++; + } + + pointer_output += step; + } + + return 0; +} + +/** + * @brief Open the LC3 module. + * + * @param handle A pointer to the audio module's handle. + * @param configuration A pointer to the audio module's configuration to set. + * + * @return 0 if successful, error value + */ +static int lc3_dec_t2_open(struct audio_module_handle_private *handle, + struct audio_module_configuration const *const configuration) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct lc3_decoder_context *ctx = (struct lc3_decoder_context *)hdl->context; + + /* Clear the context */ + memset(ctx, 0, sizeof(struct lc3_decoder_context)); + + LOG_DBG("Open LC3 decoder module"); + + return 0; +} + +/** + * @brief Close the LC3 audio module. + * + * @param handle A pointer to the audio module's handle. + * + * @return 0 if successful, error value + */ +static int lc3_dec_t2_close(struct audio_module_handle_private *handle) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct lc3_decoder_context *ctx = (struct lc3_decoder_context *)hdl->context; + LC3DecoderHandle_t *dec_handles = (LC3DecoderHandle_t *)&ctx->lc3_dec_channel[0]; + int8_t number_channels; + + audio_module_number_channels_calculate(ctx->config.locations, &number_channels); + + /* Close decoder sessions */ + for (uint8_t i = 0; i < number_channels; i++) { + if (dec_handles[i] != NULL) { + LC3DecodeSessionClose(dec_handles[i]); + dec_handles[i] = NULL; + } + } + + return 0; +} + +/** + * @brief Set the configuration of an audio module. + * + * @param handle A pointer to the audio module's handle. + * @param configuration A pointer to the audio module's configuration to set. + * + * @return 0 if successful, error value + */ +static int +lc3_dec_t2_configuration_set(struct audio_module_handle_private *handle, + struct audio_module_configuration const *const configuration) +{ + int ret; + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct lc3_decoder_context *ctx = (struct lc3_decoder_context *)hdl->context; + struct lc3_decoder_configuration *config = + (struct lc3_decoder_configuration *)configuration; + LC3DecoderHandle_t *dec_handles = (LC3DecoderHandle_t *)&ctx->lc3_dec_channel[0]; + LC3FrameSize_t framesize; + uint16_t coded_bytes_req; + int8_t number_channels; + + /* Need to validate the config parameters here before proceeding */ + + audio_module_number_channels_calculate(config->locations, &number_channels); + + /* Free previous decoder memory */ + for (uint8_t i = 0; i < number_channels; i++) { + if (dec_handles[i] != NULL) { + LC3DecodeSessionClose(dec_handles[i]); + dec_handles[i] = NULL; + } + } + + switch (config->data_len_us) { + case 7500: + framesize = LC3FrameSize7_5Ms; + break; + case 10000: + framesize = LC3FrameSize10Ms; + break; + default: + LOG_ERR("Unsupported framesize: %d", config->data_len_us); + return -EINVAL; + } + + coded_bytes_req = LC3BitstreamBuffersize(config->sample_rate_hz, config->bitrate_bps_max, + framesize, &ret); + if (coded_bytes_req == 0) { + LOG_ERR("Required coded bytes to LC3 instance %s is zero", hdl->name); + return -EPERM; + } + + for (uint8_t i = 0; i < number_channels; i++) { + dec_handles[i] = + LC3DecodeSessionOpen(config->sample_rate_hz, config->bits_per_sample, + framesize, NULL, NULL, &ret); + if (ret) { + LOG_ERR("LC3 decoder channel %d failed to initialise for module %s", i, + hdl->name); + return ret; + } + + LOG_DBG("LC3 decode module %s session %d: %dus %dbits", hdl->name, i, + config->data_len_us, config->bits_per_sample); + + ctx->dec_handles_count += 1; + } + + memcpy(&ctx->config, config, sizeof(struct lc3_decoder_configuration)); + + ctx->coded_bytes_req = coded_bytes_req; + ctx->sample_frame_bytes = ((ctx->config.data_len_us * ctx->config.sample_rate_hz) / + LC3_DECODER_US_IN_A_SECOND) * + (ctx->config.carried_bits_per_sample / 8); + + LOG_DBG("LC3 decode module %s requires %d coded bytes to produce %d decoded sample bytes", + hdl->name, ctx->coded_bytes_req, ctx->sample_frame_bytes); + + /* Configure decoder */ + LOG_DBG("LC3 decode module %s configuration: %d Hz %d bits (sample bits %d) " + "%d us %d " + "channel(s)", + hdl->name, ctx->config.sample_rate_hz, ctx->config.carried_bits_per_sample, + ctx->config.bits_per_sample, ctx->config.data_len_us, number_channels); + + return 0; +} + +/** + * @brief Get the current configuration of an audio module. + * + * @param handle A pointer to the audio module's handle. + * @param configuration A pointer to the audio module's current configuration. + * + * @return 0 if successful, error value + */ +static int lc3_dec_t2_configuration_get(struct audio_module_handle_private const *const handle, + struct audio_module_configuration *configuration) +{ + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct lc3_decoder_context *ctx = (struct lc3_decoder_context *)hdl->context; + struct lc3_decoder_configuration *config = + (struct lc3_decoder_configuration *)configuration; + memcpy(config, &ctx->config, sizeof(struct lc3_decoder_configuration)); + + /* Configure decoder */ + LOG_DBG("LC3 decode module %s configuration: %dHz %dbits (sample bits %d) %dus channel(s) " + "mapped as 0x%X", + hdl->name, config->sample_rate_hz, config->carried_bits_per_sample, + config->bits_per_sample, config->data_len_us, config->locations); + + return 0; +} + +/** + * @brief This processes the input audio data into the output audio data. + * + * @param handle A handle to this audio module's instance + * @param audio_data_in Pointer to the input audio data or NULL for an input module + * @param audio_data_out Pointer to the output audio data or NULL for an output module + * + * @return 0 if successful, error value + */ +static int lc3_dec_t2_data_process(struct audio_module_handle_private *handle, + struct audio_data const *const audio_data_in, + struct audio_data *audio_data_out) +{ + int ret; + struct audio_module_handle *hdl = (struct audio_module_handle *)handle; + struct lc3_decoder_context *ctx = (struct lc3_decoder_context *)hdl->context; + LC3DecoderHandle_t *dec_handles = (LC3DecoderHandle_t *)&ctx->lc3_dec_channel[0]; + LC3BFI_t frame_status; + uint16_t plc_counter = 0; + size_t data_out_size; + size_t session_in_size; + uint8_t *data_in; + uint8_t *data_out; + uint8_t temp_pcm[LC3_DECODER_PCM_NUM_BYTES_MONO]; + int8_t number_channels; + + LOG_DBG("LC3 decoder module %s start process", hdl->name); + + if (audio_data_in->meta.data_coding != LC3) { + LOG_DBG("LC3 decoder module %s has incorrect input data type: %d", hdl->name, + audio_data_in->meta.data_coding); + return -EINVAL; + } + + if (ctx->config.locations != audio_data_in->meta.locations) { + LOG_DBG("LC3 decoder module %s has incorrect channel map in the new audio_data: %d", + hdl->name, audio_data_in->meta.locations); + return -EINVAL; + } + + if (audio_data_in->meta.bad_data) { + frame_status = BadFrame; + } else { + frame_status = GoodFrame; + ctx->plc_count = 0; + } + + audio_module_number_channels_calculate(ctx->config.locations, &number_channels); + + if (audio_data_in->data_size) { + session_in_size = audio_data_in->data_size / number_channels; + if (session_in_size < ctx->coded_bytes_req) { + LOG_ERR("Too few coded bytes to decode. Bytes required- %d, input " + "framesize " + "is %d", + ctx->coded_bytes_req, session_in_size); + return -EINVAL; + } + } else { + session_in_size = 0; + } + + if (audio_data_out->data_size < ctx->sample_frame_bytes * number_channels) { + LOG_ERR("Output buffer too small. Bytes required %d, output buffer is %d", + (ctx->sample_frame_bytes * number_channels), audio_data_out->data_size); + return -EINVAL; + } + + if (ctx->config.interleaved) { + data_out = temp_pcm; + } else { + data_out = (uint8_t *)audio_data_out->data; + } + + data_out_size = 0; + + /* Should be able to decode only the channel(s) of interest here. + * These will be put in the first channel or channels and the location + * will indicate which channel(s) they are. Prior to playout (I2S or TDM) + * all other channels can be zeroed. + */ + for (uint8_t chan = 0; chan < number_channels; chan++) { + data_in = (uint8_t *)audio_data_in->data + (session_in_size * chan); + + LC3DecodeInput_t LC3DecodeInput = { + .inputData = data_in, .inputDataLength = session_in_size, frame_status}; + LC3DecodeOutput_t LC3DecodeOutput = {.PCMData = data_out, + .PCMDataLength = ctx->sample_frame_bytes, + .bytesWritten = 0, + .PLCCounter = plc_counter}; + + if (dec_handles[chan] == NULL) { + LOG_DBG("LC3 dec ch: %d is not initialized", chan); + return -EINVAL; + } + + ret = LC3DecodeSessionData(dec_handles[chan], &LC3DecodeInput, &LC3DecodeOutput); + if (ret) { + /* handle error */ + LOG_DBG("Error in decoder, ret: %d", ret); + return ret; + } + + if (LC3DecodeOutput.bytesWritten != ctx->sample_frame_bytes) { + /* handle error */ + LOG_DBG("Error in decoder, output incorrect size %d when should " + "be %d", + LC3DecodeOutput.bytesWritten, ctx->sample_frame_bytes); + + /* Clear this channel as it is not correct */ + memset(data_out, 0, LC3DecodeOutput.bytesWritten); + + return -EFAULT; + } + + /* Could also perform the resampling here, while we are operating + * on this area of memory. + */ + if (ctx->config.interleaved) { + ret = interleave(LC3DecodeOutput.PCMData, LC3DecodeOutput.bytesWritten, + chan, ctx->config.bits_per_sample, audio_data_out->data, + audio_data_out->data_size, number_channels); + + if (ret) { + LOG_DBG("Failed to interleave output"); + return ret; + } + + LOG_DBG("Completed decoders PCM interleaving for ch: %d", chan); + } else { + data_out += LC3DecodeOutput.bytesWritten; + } + + data_out_size += LC3DecodeOutput.bytesWritten; + + LOG_DBG("Completed LC3 decode of ch: %d", chan); + } + + ctx->plc_count = plc_counter; + + audio_data_out->data_size = data_out_size; + + return 0; +} + +/** + * @brief Table of the LC3 decoder module functions. + */ +struct audio_module_functions lc3_dec_t2_functions = { + /** + * @brief Function to an open the LC3 decoder module. + */ + .open = lc3_dec_t2_open, + + /** + * @brief Function to close the LC3 decoder module. + */ + .close = lc3_dec_t2_close, + + /** + * @brief Function to set the configuration of the LC3 decoder module. + */ + .configuration_set = lc3_dec_t2_configuration_set, + + /** + * @brief Function to get the configuration of the LC3 decoder module. + */ + .configuration_get = lc3_dec_t2_configuration_get, + + /** + * @brief Start a module processing data. + */ + .start = NULL, + + /** + * @brief Pause a module processing data. + */ + .stop = NULL, + + /** + * @brief The core data processing function in the LC3 decoder module. + */ + .data_process = lc3_dec_t2_data_process}; + +/** + * @brief The set-up parameters for the LC3 decoder. + */ +struct audio_module_description lc3_dec_t2_dept = { + .name = "LC3 Decoder (T2)", + .type = AUDIO_MODULE_TYPE_IN_OUT, + .functions = (struct audio_module_functions *)&lc3_dec_t2_functions}; + +/** + * @brief A private pointer to the LC3 decoder set-up parameters. + */ +struct audio_module_description *lc3_decoder_description = &lc3_dec_t2_dept; diff --git a/tests/subsys/audio_module/CMakeLists.txt b/tests/subsys/audio_module/CMakeLists.txt index 1c05b1024015..12183fa65a27 100644 --- a/tests/subsys/audio_module/CMakeLists.txt +++ b/tests/subsys/audio_module/CMakeLists.txt @@ -11,7 +11,7 @@ project("Audio module") target_sources(app PRIVATE src/main.c - src/fakes.c + src/audio_module_test_fakes.c src/audio_module_test_common.c src/bad_param_test.c src/functional_test.c diff --git a/tests/subsys/audio_module/src/audio_module_test_common.c b/tests/subsys/audio_module/src/audio_module_test_common.c index 00964ac66768..6c98b50913bd 100644 --- a/tests/subsys/audio_module/src/audio_module_test_common.c +++ b/tests/subsys/audio_module/src/audio_module_test_common.c @@ -6,9 +6,10 @@ #include #include +#include "audio_module/audio_module.h" #include "audio_module_test_common.h" -#include "audio_module/audio_module.h" +#include "audio_module_test_fakes.h" const char *TEST_INSTANCE_NAME = "Test instance"; const char *TEST_STRING = "This is a test string"; @@ -19,6 +20,7 @@ void test_context_set(struct mod_context *ctx, struct mod_config const *const co memcpy(&ctx->test_string, TEST_STRING, sizeof(TEST_STRING)); ctx->test_uint32 = TEST_UINT32; memcpy(&ctx->config, config, sizeof(struct mod_config)); + fake_fifo_counter_reset(); } int test_open_function(struct audio_module_handle_private *handle, @@ -96,8 +98,14 @@ int test_data_process_function(struct audio_module_handle_private *handle, ARG_UNUSED(handle); memcpy(audio_data_tx, audio_data_rx, sizeof(struct audio_data)); - memcpy(audio_data_tx->data, audio_data_rx->data, audio_data_rx->data_size); - audio_data_tx->data_size = audio_data_rx->data_size; + + if (audio_data_rx->data != NULL && audio_data_tx->data != NULL) { + memcpy(audio_data_tx->data, audio_data_rx->data, audio_data_rx->data_size); + + audio_data_tx->data_size = audio_data_rx->data_size; + } else { + printk("The input and output data pointers are NULL"); + } return 0; } diff --git a/tests/subsys/audio_module/src/audio_module_test_common.h b/tests/subsys/audio_module/src/audio_module_test_common.h index 61c8c847895b..d978f1b1fb07 100644 --- a/tests/subsys/audio_module/src/audio_module_test_common.h +++ b/tests/subsys/audio_module/src/audio_module_test_common.h @@ -18,6 +18,7 @@ #define TEST_CONNECTIONS_NUM (5) #define TEST_MODULES_NUM (TEST_CONNECTIONS_NUM - 1) #define TEST_MOD_DATA_SIZE (40) +#define TEST_AUDIO_DATA_ITEMS_NUM (20) struct mod_config { int test_int1; diff --git a/tests/subsys/audio_module/src/fakes.c b/tests/subsys/audio_module/src/audio_module_test_fakes.c similarity index 74% rename from tests/subsys/audio_module/src/fakes.c rename to tests/subsys/audio_module/src/audio_module_test_fakes.c index a00a269bdb61..3dad57c239b7 100644 --- a/tests/subsys/audio_module/src/fakes.c +++ b/tests/subsys/audio_module/src/audio_module_test_fakes.c @@ -9,16 +9,16 @@ #include #include "audio_module_test_common.h" -#include "fakes.h" +#include "audio_module_test_fakes.h" /* Overload the message buffer pointer with a point to one of the an arrays below */ -static int fifo_num; +int fifo_num; struct test_slab_queue { size_t head; size_t tail; size_t size; - size_t locked; + struct k_sem sem; void **data[FAKE_FIFO_MSG_QUEUE_SIZE]; struct audio_module_message msg[FAKE_FIFO_MSG_QUEUE_SIZE]; @@ -28,26 +28,17 @@ struct test_msg_fifo_queue { size_t head; size_t tail; size_t size; - size_t locked; + struct k_sem sem; void **data[FAKE_FIFO_MSG_QUEUE_SIZE]; }; +/* FIFO "slab" */ static struct test_slab_queue test_fifo_slab[FAKE_FIFO_NUM]; +/* FIFO "message" queue */ static struct test_msg_fifo_queue test_fifo_msg_queue[FAKE_FIFO_NUM]; -void data_fifo_deinit(struct data_fifo *data_fifo) -{ - data_fifo->msgq_buffer = (char *)NULL; - data_fifo->slab_buffer = (char *)NULL; - data_fifo->elements_max = 0; - data_fifo->block_size_max = 0; - data_fifo->initialized = false; - - fifo_num = 0; -} - /* * Stubs are defined here, so that multiple *.c files can share them * without having linker issues. @@ -62,20 +53,30 @@ DEFINE_FAKE_VALUE_FUNC(int, data_fifo_pointer_last_filled_get, struct data_fifo DEFINE_FAKE_VOID_FUNC2(data_fifo_block_free, struct data_fifo *, void *); DEFINE_FAKE_VALUE_FUNC(int, data_fifo_num_used_get, struct data_fifo *, uint32_t *, uint32_t *); DEFINE_FAKE_VALUE_FUNC(int, data_fifo_empty, struct data_fifo *); +DEFINE_FAKE_VALUE_FUNC(int, data_fifo_uninit, struct data_fifo *); DEFINE_FAKE_VALUE_FUNC(int, data_fifo_init, struct data_fifo *); +DEFINE_FAKE_VALUE_FUNC(bool, data_fifo_state, struct data_fifo *); +void fake_fifo_counter_reset(void) +{ + fifo_num = 0; +} + +/* Custom fakes implementation */ int fake_data_fifo_pointer_first_vacant_get__succeeds(struct data_fifo *data_fifo, void **data, k_timeout_t timeout) { + int ret; struct test_slab_queue *test_fifo_slab_data = (struct test_slab_queue *)data_fifo->slab_buffer; - if (test_fifo_slab_data->head == test_fifo_slab_data->tail) { - return -EINVAL; - } + zassert_not_equal(data_fifo, NULL, "Data FIFO pointer is NULL"); - *data = &test_fifo_slab_data->msg[test_fifo_slab_data->tail % test_fifo_slab_data->size]; - test_fifo_slab_data->tail = (test_fifo_slab_data->tail + 1) % test_fifo_slab_data->size; + ret = k_sem_take(&test_fifo_slab_data->sem, timeout); + zassert_equal(ret, 0, "Failed to take the slab semaphore: ret %d", ret); + + *data = &test_fifo_slab_data->msg[test_fifo_slab_data->head]; + test_fifo_slab_data->head = (test_fifo_slab_data->head + 1) % test_fifo_slab_data->size; return 0; } @@ -116,15 +117,13 @@ int fake_data_fifo_block_lock__succeeds(struct data_fifo *data_fifo, void **data struct test_msg_fifo_queue *test_fifo_msg = (struct test_msg_fifo_queue *)data_fifo->msgq_buffer; - if (((test_fifo_msg->head + 1) % test_fifo_msg->size) == test_fifo_msg->tail) { - return -EINVAL; - } + zassert_not_equal(data_fifo, NULL, "Data FIFO pointer is NULL"); + + k_sem_give(&test_fifo_msg->sem); test_fifo_msg->data[test_fifo_msg->head] = *data; test_fifo_msg->head = (test_fifo_msg->head + 1) % test_fifo_msg->size; - test_fifo_msg->locked++; - return 0; } @@ -158,13 +157,15 @@ int fake_data_fifo_block_lock__put_fails(struct data_fifo *data_fifo, void **dat int fake_data_fifo_pointer_last_filled_get__succeeds(struct data_fifo *data_fifo, void **data, size_t *size, k_timeout_t timeout) { + int ret; struct audio_module_message *msg; struct test_msg_fifo_queue *test_fifo_msg = (struct test_msg_fifo_queue *)data_fifo->msgq_buffer; - if (test_fifo_msg->tail == test_fifo_msg->head) { - return -EINVAL; - } + zassert_not_equal(data_fifo, NULL, "Data FIFO pointer is NULL"); + + ret = k_sem_take(&test_fifo_msg->sem, timeout); + zassert_equal(ret, 0, "Failed to take the message semaphore: ret %d", ret); msg = (struct audio_module_message *)test_fifo_msg->data[test_fifo_msg->tail]; @@ -174,8 +175,6 @@ int fake_data_fifo_pointer_last_filled_get__succeeds(struct data_fifo *data_fifo *data = msg; *size = sizeof(struct audio_module_message); - test_fifo_msg->locked--; - return 0; } @@ -205,14 +204,13 @@ void fake_data_fifo_block_free__succeeds(struct data_fifo *data_fifo, void *data { ARG_UNUSED(data); + zassert_not_equal(data_fifo, NULL, "Data FIFO pointer is NULL"); + struct test_slab_queue *test_fifo_slab_data = (struct test_slab_queue *)data_fifo->slab_buffer; - if (test_fifo_slab_data->tail == test_fifo_slab_data->head) { - return; - } - - test_fifo_slab_data->head = (test_fifo_slab_data->head + 1) % test_fifo_slab_data->size; + k_sem_give(&test_fifo_slab_data->sem); + test_fifo_slab_data->tail = (test_fifo_slab_data->tail + 1) % test_fifo_slab_data->size; } int fake_data_fifo_num_used_get__succeeds(struct data_fifo *data_fifo, uint32_t *alloced_num, @@ -222,7 +220,7 @@ int fake_data_fifo_num_used_get__succeeds(struct data_fifo *data_fifo, uint32_t (struct test_msg_fifo_queue *)data_fifo->msgq_buffer; *alloced_num = test_fifo_msg->head - test_fifo_msg->tail; - *locked_num = test_fifo_msg->locked; + *locked_num = k_sem_count_get(&test_fifo_msg->sem); return 0; } @@ -239,19 +237,25 @@ int fake_data_fifo_num_used_get__fails(struct data_fifo *data_fifo, uint32_t *al int fake_data_fifo_empty__succeeds(struct data_fifo *data_fifo) { + int ret; struct test_msg_fifo_queue *test_fifo_msg = (struct test_msg_fifo_queue *)data_fifo->msgq_buffer; struct test_slab_queue *test_fifo_slab_data = (struct test_slab_queue *)data_fifo->slab_buffer; + zassert_not_equal(data_fifo, NULL, "Data FIFO pointer is NULL"); + test_fifo_msg->head = 0; test_fifo_msg->tail = 0; test_fifo_msg->size = FAKE_FIFO_MSG_QUEUE_SIZE; - test_fifo_msg->locked = 0; + k_sem_reset(&test_fifo_msg->sem); test_fifo_slab_data->head = 0; test_fifo_slab_data->tail = 0; test_fifo_slab_data->size = FAKE_FIFO_MSG_QUEUE_SIZE; + ret = k_sem_init(&test_fifo_slab_data->sem, FAKE_FIFO_MSG_QUEUE_SIZE, + FAKE_FIFO_MSG_QUEUE_SIZE); + zassert_equal(ret, 0, "Failed to initialize the slab semaphore: ret %d", ret); return 0; } @@ -284,13 +288,42 @@ int fake_data_fifo_empty__timeout_fails(struct data_fifo *data_fifo) return -EAGAIN; } +int fake_data_fifo_uninit__succeeds(struct data_fifo *data_fifo) +{ + int ret; + + zassert_not_equal(data_fifo, NULL, "Data FIFO pointer is NULL"); + + if (data_fifo->initialized) { + ret = data_fifo_empty(data_fifo); + if (ret) { + return ret; + } + + data_fifo->initialized = false; + } + + return 0; +} + +int fake_data_fifo_uninit__fails(struct data_fifo *data_fifo) +{ + ARG_UNUSED(data_fifo); + + return -EINVAL; +} + int fake_data_fifo_init__succeeds(struct data_fifo *data_fifo) { + int ret; struct test_msg_fifo_queue *test_fifo_msg = &test_fifo_msg_queue[fifo_num]; struct test_slab_queue *test_fifo_slab_data = &test_fifo_slab[fifo_num]; + zassert_not_equal(data_fifo, NULL, "Data FIFO pointer is NULL"); + data_fifo->msgq_buffer = (char *)test_fifo_msg; data_fifo->slab_buffer = (char *)test_fifo_slab_data; + data_fifo->elements_max = FAKE_FIFO_MSG_QUEUE_SIZE; data_fifo->block_size_max = TEST_MOD_DATA_SIZE; data_fifo->initialized = true; @@ -300,23 +333,22 @@ int fake_data_fifo_init__succeeds(struct data_fifo *data_fifo) test_fifo_msg->head = 0; test_fifo_msg->tail = 0; test_fifo_msg->size = FAKE_FIFO_MSG_QUEUE_SIZE; - test_fifo_msg->locked = 0; + ret = k_sem_init(&test_fifo_msg->sem, 0, FAKE_FIFO_MSG_QUEUE_SIZE); + zassert_equal(ret, 0, "Failed to initialize the message semaphore: ret %d", ret); test_fifo_slab_data->head = 0; test_fifo_slab_data->tail = 0; test_fifo_slab_data->size = FAKE_FIFO_MSG_QUEUE_SIZE; + ret = k_sem_init(&test_fifo_slab_data->sem, FAKE_FIFO_MSG_QUEUE_SIZE, + FAKE_FIFO_MSG_QUEUE_SIZE); + zassert_equal(ret, 0, "Failed to initialize the slab semaphore: ret %d", ret); for (int i = 0; i < FAKE_FIFO_MSG_QUEUE_SIZE; i++) { - if (((test_fifo_slab_data->head + 1) % test_fifo_slab_data->size) == - test_fifo_slab_data->tail) { - return -ENOMSG; - } - test_fifo_slab_data->data[test_fifo_slab_data->head] = - (void **)&test_fifo_slab_data->msg[i]; - test_fifo_slab_data->head = - (test_fifo_slab_data->head + 1) % test_fifo_slab_data->size; + test_fifo_slab_data->data[i] = (void **)&test_fifo_slab_data->msg[i]; } + data_fifo->initialized = true; + return 0; } @@ -326,3 +358,10 @@ int fake_data_fifo_init__fails(struct data_fifo *data_fifo) return -EINVAL; } + +bool fake_data_fifo_state__succeeds(struct data_fifo *data_fifo) +{ + zassert_not_equal(data_fifo, NULL, "Data FIFO pointer is NULL"); + + return data_fifo->initialized; +} diff --git a/tests/subsys/audio_module/src/fakes.h b/tests/subsys/audio_module/src/audio_module_test_fakes.h similarity index 87% rename from tests/subsys/audio_module/src/fakes.h rename to tests/subsys/audio_module/src/audio_module_test_fakes.h index 52bdcfc1aeae..b38c870e8eae 100644 --- a/tests/subsys/audio_module/src/fakes.h +++ b/tests/subsys/audio_module/src/audio_module_test_fakes.h @@ -13,13 +13,6 @@ #include "audio_module_test_common.h" -/** - * @brief Deinitialize data FIFO structure. - * - * @param data_fifo [in/out] The data FIFO instance. - */ -void data_fifo_deinit(struct data_fifo *data_fifo); - /* Fake functions declaration. */ DECLARE_FAKE_VALUE_FUNC(int, data_fifo_pointer_first_vacant_get, struct data_fifo *, void **, k_timeout_t); @@ -29,7 +22,9 @@ DECLARE_FAKE_VALUE_FUNC(int, data_fifo_pointer_last_filled_get, struct data_fifo DECLARE_FAKE_VOID_FUNC2(data_fifo_block_free, struct data_fifo *, void *); DECLARE_FAKE_VALUE_FUNC(int, data_fifo_num_used_get, struct data_fifo *, uint32_t *, uint32_t *); DECLARE_FAKE_VALUE_FUNC(int, data_fifo_empty, struct data_fifo *); +DECLARE_FAKE_VALUE_FUNC(int, data_fifo_uninit, struct data_fifo *); DECLARE_FAKE_VALUE_FUNC(int, data_fifo_init, struct data_fifo *); +DECLARE_FAKE_VALUE_FUNC(bool, data_fifo_state, struct data_fifo *); /* List of fakes used by this unit tester */ #define DO_FOREACH_FAKE(FUNC) \ @@ -40,9 +35,13 @@ DECLARE_FAKE_VALUE_FUNC(int, data_fifo_init, struct data_fifo *); FUNC(data_fifo_block_free) \ FUNC(data_fifo_num_used_get) \ FUNC(data_fifo_empty) \ + FUNC(data_fifo_uninit) \ FUNC(data_fifo_init) \ + FUNC(data_fifo_state) \ } while (0) +void fake_fifo_counter_reset(void); + int fake_data_fifo_pointer_first_vacant_get__succeeds(struct data_fifo *data_fifo, void **data, k_timeout_t timeout); int fake_data_fifo_pointer_first_vacant_get__timeout_fails(struct data_fifo *data_fifo, void **data, @@ -71,7 +70,10 @@ int fake_data_fifo_empty__count_fails(struct data_fifo *data_fifo); int fake_data_fifo_empty__no_wait_fails(struct data_fifo *data_fifo); int fake_data_fifo_empty__slab_init_fails(struct data_fifo *data_fifo); int fake_data_fifo_empty__timeout_fails(struct data_fifo *data_fifo); +int fake_data_fifo_uninit__succeeds(struct data_fifo *data_fifo); +int fake_data_fifo_uninit__fails(struct data_fifo *data_fifo); int fake_data_fifo_init__succeeds(struct data_fifo *data_fifo); int fake_data_fifo_init__fails(struct data_fifo *data_fifo); +bool fake_data_fifo_state__succeeds(struct data_fifo *data_fifo); #endif /* _FAKES_H_ */ diff --git a/tests/subsys/audio_module/src/bad_param_test.c b/tests/subsys/audio_module/src/bad_param_test.c index 1439aae03332..abce776a77c5 100644 --- a/tests/subsys/audio_module/src/bad_param_test.c +++ b/tests/subsys/audio_module/src/bad_param_test.c @@ -6,9 +6,9 @@ #include #include - -#include "fakes.h" #include "audio_module/audio_module.h" + +#include "audio_module_test_fakes.h" #include "audio_module_test_common.h" static struct audio_module_functions mod_1_functions = {.open = NULL, @@ -26,7 +26,7 @@ static struct audio_module_configuration *config = (struct audio_module_configuration *)&configuration; static struct audio_module_handle handle, handle_tx, handle_rx; static struct mod_context context; -static uint8_t test_data[FAKE_FIFO_MSG_QUEUE_DATA_SIZE]; +static uint8_t test_data[TEST_MOD_DATA_SIZE]; static struct data_fifo mod_fifo_tx, mod_fifo_rx; static struct audio_data test_block, test_block_tx, test_block_rx; static char mod_thread_stack[TEST_MOD_THREAD_STACK_SIZE]; @@ -155,7 +155,7 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_bad_state) NULL, &mod_fifo_rx); test_block.data = &test_data[0]; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx(&handle, &test_block, NULL); zassert_equal(ret, -ECANCELED, "Data TX function did not return -EALREADY (%d): ret %d", @@ -199,11 +199,7 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_null) NULL, NULL); test_block.data = &test_data[0]; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; - - ret = audio_module_data_tx(NULL, &test_block, NULL); - zassert_equal(ret, -EINVAL, "Data TX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx(&handle, &test_block, NULL); zassert_equal(ret, -ECANCELED, "Data TX function did not return -ECANCELED (%d): ret %d", @@ -214,20 +210,6 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_null) ret = audio_module_data_tx(&handle, NULL, NULL); zassert_equal(ret, -EINVAL, "Data TX function did not return -EINVAL (%d): ret %d", -EINVAL, ret); - - test_block.data = NULL; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; - - ret = audio_module_data_tx(&handle, &test_block, NULL); - zassert_equal(ret, -EINVAL, "Data TX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); - - test_block.data = &test_data[0]; - test_block.data_size = 0; - - ret = audio_module_data_tx(&handle, &test_block, NULL); - zassert_equal(ret, -EINVAL, "Data TX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); } ZTEST(suite_audio_module_bad_param, test_data_rx_bad_state) @@ -241,7 +223,7 @@ ZTEST(suite_audio_module_bad_param, test_data_rx_bad_state) &mod_fifo_tx, NULL); test_block.data = &test_data[0]; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_rx(&handle, &test_block, K_NO_WAIT); zassert_equal(ret, -ECANCELED, "Data RX function did not return -ECANCELED (%d): ret %d", @@ -285,7 +267,7 @@ ZTEST(suite_audio_module_bad_param, test_data_rx_null) NULL, NULL); test_block.data = &test_data[0]; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_rx(NULL, &test_block, K_NO_WAIT); zassert_equal(ret, -EINVAL, "Data RX function did not return -EINVAL (%d): ret %d", -EINVAL, @@ -302,18 +284,18 @@ ZTEST(suite_audio_module_bad_param, test_data_rx_null) ret); test_block.data = NULL; - test_block.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_rx(&handle, &test_block, K_NO_WAIT); - zassert_equal(ret, -EINVAL, "Data RX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); + zassert_equal(ret, -ECANCELED, "Data RX function did not return -ECANCELED (%d): ret %d", + -ECANCELED, ret); test_block.data = &test_data[0]; test_block.data_size = 0; ret = audio_module_data_rx(&handle, &test_block, K_NO_WAIT); - zassert_equal(ret, -EINVAL, "Data RX function did not return -EINVAL (%d): ret %d", -EINVAL, - ret); + zassert_equal(ret, -ECANCELED, "Data RX function did not return -ECANCELED (%d): ret %d", + -ECANCELED, ret); } ZTEST(suite_audio_module_bad_param, test_data_tx_rx_bad_state) @@ -331,9 +313,9 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_rx_bad_state) AUDIO_MODULE_STATE_RUNNING, &mod_fifo_tx, &mod_fifo_rx); test_block_tx.data = &test_data[0]; - test_block_tx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_tx.data_size = TEST_MOD_DATA_SIZE; test_block_rx.data = &test_data[0]; - test_block_rx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_rx.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx_rx(&handle_tx, &handle_rx, &test_block_tx, &test_block_rx, K_NO_WAIT); @@ -424,9 +406,9 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_rx_null) AUDIO_MODULE_STATE_RUNNING, NULL, NULL); test_block_tx.data = &test_data[0]; - test_block_tx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_tx.data_size = TEST_MOD_DATA_SIZE; test_block_rx.data = &test_data[0]; - test_block_rx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_rx.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx_rx(NULL, &handle_rx, &test_block_tx, &test_block_rx, K_NO_WAIT); zassert_equal(ret, -EINVAL, "Data TX/RX function did not return -EINVAL (%d): ret %d", @@ -459,7 +441,7 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_rx_null) -EINVAL, ret); test_block_tx.data = NULL; - test_block_tx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_tx.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx_rx(&handle_tx, &handle_rx, &test_block_tx, &test_block_rx, K_NO_WAIT); @@ -475,9 +457,9 @@ ZTEST(suite_audio_module_bad_param, test_data_tx_rx_null) -EINVAL, ret); test_block_tx.data = &test_data[0]; - test_block_tx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_tx.data_size = TEST_MOD_DATA_SIZE; test_block_rx.data = NULL; - test_block_rx.data_size = FAKE_FIFO_MSG_QUEUE_DATA_SIZE; + test_block_rx.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx_rx(&handle_tx, &handle_rx, &test_block_tx, &test_block_rx, K_NO_WAIT); diff --git a/tests/subsys/audio_module/src/functional_test.c b/tests/subsys/audio_module/src/functional_test.c index fa6e459a9061..0df0a51f49ba 100644 --- a/tests/subsys/audio_module/src/functional_test.c +++ b/tests/subsys/audio_module/src/functional_test.c @@ -7,11 +7,13 @@ #include #include #include - -#include "fakes.h" #include "audio_module/audio_module.h" + +#include "audio_module_test_fakes.h" #include "audio_module_test_common.h" +#define FAKE_FIFO_CALL_TX_RX_TEST_COUNT (3) + K_THREAD_STACK_DEFINE(mod_stack, TEST_MOD_THREAD_STACK_SIZE); K_MEM_SLAB_DEFINE(data_slab, TEST_MOD_DATA_SIZE, FAKE_FIFO_MSG_QUEUE_SIZE, 4); @@ -45,9 +47,7 @@ static struct audio_module_parameters mod_parameters = { .data_slab = &data_slab, .data_size = TEST_MOD_DATA_SIZE}}; struct audio_module_parameters test_mod_parameters; -static struct audio_module_handle handle; static struct mod_context *handle_context; -static struct data_fifo mod_fifo_tx, mod_fifo_rx; /** * @brief Set the minimum for a handle. @@ -217,10 +217,12 @@ static void test_close(const struct audio_module_functions *test_fnct, enum audio_module_state test_state) { int ret; - int empty_call_count = 0; char *test_inst_name = "TEST instance 1"; struct audio_module_description test_mod_description; struct audio_module_functions test_mod_functions; + struct data_fifo fifo_tx; + struct data_fifo fifo_rx; + struct audio_module_handle handle; /* Register resets */ DO_FOREACH_FAKE(RESET_FAKE); @@ -253,21 +255,19 @@ static void test_close(const struct audio_module_functions *test_fnct, data_fifo_empty_fake.custom_fake = fake_data_fifo_empty__succeeds; if (fifo_rx_set) { - data_fifo_deinit(&mod_fifo_rx); - data_fifo_init(&mod_fifo_rx); - handle.thread.msg_rx = &mod_fifo_rx; + ret = data_fifo_init(&fifo_rx); + zassert_equal(ret, 0, "Failed to initialise the RX data FIFO: ret %d", ret); - empty_call_count++; + handle.thread.msg_rx = &fifo_rx; } else { handle.thread.msg_rx = NULL; } if (fifo_tx_set) { - data_fifo_deinit(&mod_fifo_tx); - data_fifo_init(&mod_fifo_tx); - handle.thread.msg_tx = &mod_fifo_tx; + ret = data_fifo_init(&fifo_tx); + zassert_equal(ret, 0, "Failed to initialise the TX data FIFO: ret %d", ret); - empty_call_count++; + handle.thread.msg_tx = &fifo_tx; } else { handle.thread.msg_tx = NULL; } @@ -279,9 +279,6 @@ static void test_close(const struct audio_module_functions *test_fnct, ret = audio_module_close(&handle); zassert_equal(ret, 0, "Close function did not return successfully: ret %d", ret); - zassert_equal(data_fifo_empty_fake.call_count, empty_call_count, - "Failed close, data FIFO empty called %d times", - data_fifo_empty_fake.call_count); zassert_mem_equal(&mod_description, &test_mod_description, sizeof(struct audio_module_description), "Failed close, modified the modules description"); @@ -310,26 +307,28 @@ static void test_open(enum audio_module_type test_type, bool fifo_rx_set, bool f { int ret; char *test_inst_name = "TEST instance 1"; + struct data_fifo fifo_tx = {0}; + struct data_fifo fifo_rx = {0}; + struct audio_module_handle handle; /* Fake internal empty data FIFO success */ data_fifo_init_fake.custom_fake = fake_data_fifo_init__succeeds; + data_fifo_state_fake.custom_fake = fake_data_fifo_state__succeeds; mod_description.functions = &ft_pop; test_context_set(&test_mod_context, &mod_config); if (fifo_rx_set) { - data_fifo_deinit(&mod_fifo_rx); - data_fifo_init(&mod_fifo_rx); - mod_parameters.thread.msg_rx = &mod_fifo_rx; + data_fifo_init(&fifo_rx); + mod_parameters.thread.msg_rx = &fifo_rx; } else { mod_parameters.thread.msg_rx = NULL; } if (fifo_tx_set) { - data_fifo_deinit(&mod_fifo_tx); - data_fifo_init(&mod_fifo_tx); - mod_parameters.thread.msg_tx = &mod_fifo_tx; + data_fifo_init(&fifo_tx); + mod_parameters.thread.msg_tx = &fifo_tx; } else { mod_parameters.thread.msg_tx = NULL; } @@ -459,6 +458,7 @@ static void test_start_stop(bool start, const struct audio_module_functions *tes enum audio_module_state return_state, int ret_expected) { int ret; + struct audio_module_handle handle; mod_description.functions = test_fnct; test_initialize_handle(&handle, &mod_description, &mod_context, NULL); @@ -562,6 +562,7 @@ ZTEST(suite_audio_module_functional, test_names_get_fnct) int ret; char *base_name; char instance_name[CONFIG_AUDIO_MODULE_NAME_SIZE] = {0}; + struct audio_module_handle handle; char *test_base_name_empty = ""; char *test_base_name_long = "Test base name that is longer than the size of CONFIG_AUDIO_MODULE_NAME_SIZE"; @@ -629,6 +630,7 @@ ZTEST(suite_audio_module_functional, test_names_get_fnct) ZTEST(suite_audio_module_functional, test_reconfigure_fnct) { int ret; + struct audio_module_handle handle; mod_description.functions = &ft_pop; test_initialize_handle(&handle, &mod_description, &mod_context, &mod_config); @@ -659,6 +661,7 @@ ZTEST(suite_audio_module_functional, test_reconfigure_fnct) ZTEST(suite_audio_module_functional, test_configuration_get_fnct) { int ret; + struct audio_module_handle handle; mod_description.functions = &ft_pop; test_initialize_handle(&handle, &mod_description, &mod_context, &mod_config); @@ -919,25 +922,28 @@ ZTEST(suite_audio_module_functional, test_data_tx_fnct) char test_data[TEST_MOD_DATA_SIZE]; struct audio_data audio_data = {0}; struct audio_module_message *msg_rx; + struct data_fifo fifo_rx; + struct audio_module_handle handle; test_context_set(&mod_context, &mod_config); /* Fake internal empty data FIFO success */ data_fifo_init_fake.custom_fake = fake_data_fifo_init__succeeds; + data_fifo_uninit_fake.custom_fake = fake_data_fifo_uninit__succeeds; + data_fifo_empty_fake.custom_fake = fake_data_fifo_empty__succeeds; data_fifo_pointer_first_vacant_get_fake.custom_fake = fake_data_fifo_pointer_first_vacant_get__succeeds; data_fifo_block_lock_fake.custom_fake = fake_data_fifo_block_lock__succeeds; data_fifo_pointer_last_filled_get_fake.custom_fake = fake_data_fifo_pointer_last_filled_get__succeeds; data_fifo_block_free_fake.custom_fake = fake_data_fifo_block_free__succeeds; + data_fifo_state_fake.custom_fake = fake_data_fifo_state__succeeds; - data_fifo_deinit(&mod_fifo_rx); - - data_fifo_init(&mod_fifo_rx); + fake_data_fifo_init__succeeds(&fifo_rx); memcpy(&handle.name, test_inst_name, sizeof(*test_inst_name)); handle.description = &mod_description; - handle.thread.msg_rx = &mod_fifo_rx; + handle.thread.msg_rx = &fifo_rx; handle.thread.msg_tx = NULL; handle.thread.data_slab = &data_slab; handle.thread.data_size = TEST_MOD_DATA_SIZE; @@ -948,22 +954,40 @@ ZTEST(suite_audio_module_functional, test_data_tx_fnct) test_data[i] = TEST_MOD_DATA_SIZE - i; } - audio_data.data = &test_data[0]; + audio_data.data = NULL; audio_data.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_tx(&handle, &audio_data, NULL); zassert_equal(ret, 0, "Data TX function did not return successfully: ret %d", ret); - ret = data_fifo_pointer_last_filled_get(&mod_fifo_rx, (void **)&msg_rx, &size, K_NO_WAIT); + ret = data_fifo_pointer_last_filled_get(&fifo_rx, (void **)&msg_rx, &size, K_NO_WAIT); zassert_equal(ret, 0, "Data TX function did not return 0: ret %d", 0, ret); - zassert_mem_equal(msg_rx->audio_data.data, &test_data[0], TEST_MOD_DATA_SIZE, - "Failed open, module contexts differ"); + + audio_data.data = test_data; + audio_data.data_size = 0; + + ret = audio_module_data_tx(&handle, &audio_data, NULL); + zassert_equal(ret, 0, "Data TX function did not return successfully: ret %d", ret); + + data_fifo_empty(&fifo_rx); + + audio_data.data = test_data; + audio_data.data_size = TEST_MOD_DATA_SIZE; + + ret = audio_module_data_tx(&handle, &audio_data, NULL); + zassert_equal(ret, 0, "Data TX function did not return successfully: ret %d", ret); + + ret = data_fifo_pointer_last_filled_get(&fifo_rx, (void **)&msg_rx, &size, K_NO_WAIT); + zassert_equal(ret, 0, "Data TX function did not return 0: ret %d", 0, ret); + zassert_mem_equal(msg_rx->audio_data.data, test_data, TEST_MOD_DATA_SIZE, + "Failed Data TX, data differs"); zassert_equal(msg_rx->audio_data.data_size, TEST_MOD_DATA_SIZE, "Failed Data TX function, data sizes differs"); - zassert_equal(data_fifo_pointer_first_vacant_get_fake.call_count, 1, + zassert_equal(data_fifo_pointer_first_vacant_get_fake.call_count, + FAKE_FIFO_CALL_TX_RX_TEST_COUNT, "Data TX failed to get item, data FIFO get called %d times", data_fifo_pointer_first_vacant_get_fake.call_count); - zassert_equal(data_fifo_block_lock_fake.call_count, 1, + zassert_equal(data_fifo_block_lock_fake.call_count, FAKE_FIFO_CALL_TX_RX_TEST_COUNT, "Failed to send item, data FIFO send called %d times", data_fifo_pointer_first_vacant_get_fake.call_count); } @@ -974,64 +998,106 @@ ZTEST(suite_audio_module_functional, test_data_rx_fnct) char *test_inst_name = "TEST instance 1"; char test_data[TEST_MOD_DATA_SIZE]; char data[TEST_MOD_DATA_SIZE] = {0}; - struct audio_data audio_data_in; struct audio_data audio_data_out = {0}; struct audio_module_message *data_msg_tx; + struct data_fifo fifo_tx = {0}; + struct audio_module_handle handle; test_context_set(&mod_context, &mod_config); /* Fake internal empty data FIFO success */ data_fifo_init_fake.custom_fake = fake_data_fifo_init__succeeds; + data_fifo_uninit_fake.custom_fake = fake_data_fifo_uninit__succeeds; + data_fifo_empty_fake.custom_fake = fake_data_fifo_empty__succeeds; data_fifo_pointer_first_vacant_get_fake.custom_fake = fake_data_fifo_pointer_first_vacant_get__succeeds; data_fifo_block_lock_fake.custom_fake = fake_data_fifo_block_lock__succeeds; data_fifo_pointer_last_filled_get_fake.custom_fake = fake_data_fifo_pointer_last_filled_get__succeeds; data_fifo_block_free_fake.custom_fake = fake_data_fifo_block_free__succeeds; + data_fifo_state_fake.custom_fake = fake_data_fifo_state__succeeds; - data_fifo_deinit(&mod_fifo_tx); - - data_fifo_init(&mod_fifo_tx); + fake_data_fifo_init__succeeds(&fifo_tx); memcpy(&handle.name, test_inst_name, sizeof(*test_inst_name)); handle.description = &mod_description; handle.thread.msg_rx = NULL; - handle.thread.msg_tx = &mod_fifo_tx; + handle.thread.msg_tx = &fifo_tx; handle.thread.data_slab = &data_slab; handle.thread.data_size = TEST_MOD_DATA_SIZE; handle.state = AUDIO_MODULE_STATE_RUNNING; handle.context = (struct audio_module_context *)&mod_context; - ret = data_fifo_pointer_first_vacant_get(handle.thread.msg_tx, (void **)&data_msg_tx, - K_NO_WAIT); /* fill data */ for (int i = 0; i < TEST_MOD_DATA_SIZE; i++) { test_data[i] = TEST_MOD_DATA_SIZE - i; } - audio_data_in.data = &test_data[0]; - audio_data_in.data_size = TEST_MOD_DATA_SIZE; + ret = data_fifo_pointer_first_vacant_get(handle.thread.msg_tx, (void **)&data_msg_tx, + K_NO_WAIT); + zassert_equal(ret, 0, "FIFO get function did not return successfully: ret %d", ret); + + data_msg_tx->audio_data.data = test_data; + data_msg_tx->audio_data.data_size = TEST_MOD_DATA_SIZE; + data_msg_tx->tx_handle = NULL; + data_msg_tx->response_cb = NULL; + + ret = data_fifo_block_lock(handle.thread.msg_tx, (void **)&data_msg_tx, + sizeof(struct audio_module_message)); + zassert_equal(ret, 0, "FIFO lock function did not return successfully: ret %d", ret); + + audio_data_out.data = NULL; + audio_data_out.data_size = TEST_MOD_DATA_SIZE; + + ret = audio_module_data_rx(&handle, &audio_data_out, K_NO_WAIT); + zassert_equal(ret, 0, "Data RX function did not return successfully: ret %d", ret); + + ret = data_fifo_pointer_first_vacant_get(handle.thread.msg_tx, (void **)&data_msg_tx, + K_NO_WAIT); + zassert_equal(ret, 0, "FIFO get function did not return successfully: ret %d", ret); + + data_msg_tx->audio_data.data = test_data; + data_msg_tx->audio_data.data_size = TEST_MOD_DATA_SIZE; + data_msg_tx->tx_handle = NULL; + data_msg_tx->response_cb = NULL; + + ret = data_fifo_block_lock(handle.thread.msg_tx, (void **)&data_msg_tx, + sizeof(struct audio_module_message)); + zassert_equal(ret, 0, "FIFO lock function did not return successfully: ret %d", ret); + + audio_data_out.data = data; + audio_data_out.data_size = 0; + + ret = audio_module_data_rx(&handle, &audio_data_out, K_NO_WAIT); + zassert_equal(ret, 0, "Data RX function did not return successfully: ret %d", ret); + + ret = data_fifo_pointer_first_vacant_get(handle.thread.msg_tx, (void **)&data_msg_tx, + K_NO_WAIT); + zassert_equal(ret, 0, "FIFO get function did not return successfully: ret %d", ret); - memcpy(&data_msg_tx->audio_data, &audio_data_in, sizeof(struct audio_data)); + data_msg_tx->audio_data.data = test_data; + data_msg_tx->audio_data.data_size = TEST_MOD_DATA_SIZE; data_msg_tx->tx_handle = NULL; data_msg_tx->response_cb = NULL; ret = data_fifo_block_lock(handle.thread.msg_tx, (void **)&data_msg_tx, sizeof(struct audio_module_message)); + zassert_equal(ret, 0, "FIFO lock function did not return successfully: ret %d", ret); - audio_data_out.data = &data[0]; + audio_data_out.data = data; audio_data_out.data_size = TEST_MOD_DATA_SIZE; ret = audio_module_data_rx(&handle, &audio_data_out, K_NO_WAIT); zassert_equal(ret, 0, "Data RX function did not return successfully: ret %d", ret); - zassert_mem_equal(&test_data[0], audio_data_out.data, TEST_MOD_DATA_SIZE, + zassert_mem_equal(test_data, audio_data_out.data, TEST_MOD_DATA_SIZE, "Failed Data RX function, data differs"); - zassert_equal(audio_data_in.data_size, audio_data_out.data_size, + zassert_equal(audio_data_out.data_size, TEST_MOD_DATA_SIZE, "Failed Data RX function, data sizes differs"); - zassert_equal(data_fifo_pointer_last_filled_get_fake.call_count, 1, + zassert_equal(data_fifo_pointer_last_filled_get_fake.call_count, + FAKE_FIFO_CALL_TX_RX_TEST_COUNT, "Data RX function failed to get item, data FIFO get called %d times", data_fifo_pointer_last_filled_get_fake.call_count); - zassert_equal(data_fifo_block_free_fake.call_count, 1, + zassert_equal(data_fifo_block_free_fake.call_count, FAKE_FIFO_CALL_TX_RX_TEST_COUNT, "Data RX function failed to free item, data FIFO free called %d times", data_fifo_block_free_fake.call_count); } diff --git a/tests/subsys/audio_module/src/main.c b/tests/subsys/audio_module/src/main.c index 72e80831e58e..708a7c01dca5 100644 --- a/tests/subsys/audio_module/src/main.c +++ b/tests/subsys/audio_module/src/main.c @@ -7,8 +7,7 @@ #include #include #include - -#include "fakes.h" +#include "audio_module_test_fakes.h" /* This function runs before each test */ static void run_before(void *fixture) @@ -22,5 +21,5 @@ static void run_before(void *fixture) FFF_RESET_HISTORY(); } -ZTEST_SUITE(suite_audio_module_bad_param, NULL, NULL, NULL, NULL, NULL); +ZTEST_SUITE(suite_audio_module_bad_param, NULL, NULL, run_before, NULL, NULL); ZTEST_SUITE(suite_audio_module_functional, NULL, NULL, run_before, NULL, NULL); diff --git a/tests/subsys/audio_module/testcase.yaml b/tests/subsys/audio_module/testcase.yaml index 35ad5da21c38..d4dc1b9d13f3 100644 --- a/tests/subsys/audio_module/testcase.yaml +++ b/tests/subsys/audio_module/testcase.yaml @@ -1,7 +1,7 @@ tests: nrf5340_audio.audio_module_test: sysbuild: true - platform_allow: qemu_cortex_m3 nrf5340dk/nrf5340/cpuapp + platform_allow: qemu_cortex_m3 integration_platforms: - qemu_cortex_m3 - nrf5340dk/nrf5340/cpuapp diff --git a/tests/subsys/audio_modules/audio_module_template/CMakeLists.txt b/tests/subsys/audio_modules/audio_module_template/CMakeLists.txt new file mode 100644 index 000000000000..18cf31748ead --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Copyright (c) 20234 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project("Audio module Template") + +target_sources(app PRIVATE + src/main.c + src/template_test.c +) + +target_include_directories(app PRIVATE ${ZEPHYR_NRF_MODULE_DIR}/subsys/audio_modules/audio_module_template) diff --git a/tests/subsys/audio_modules/audio_module_template/prj.conf b/tests/subsys/audio_modules/audio_module_template/prj.conf new file mode 100644 index 000000000000..5aa1308f4a9e --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/prj.conf @@ -0,0 +1,17 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +CONFIG_ZTEST=y +CONFIG_ZTEST_STACK_SIZE=8196 +CONFIG_IRQ_OFFLOAD=y +CONFIG_DATA_FIFO=y +CONFIG_AUDIO_MODULE=y +CONFIG_AUDIO_MODULE_TEMPLATE=y + +# The large stack size can be optimized +CONFIG_MAIN_STACK_SIZE=16000 + +CONFIG_STACK_SENTINEL=y diff --git a/tests/subsys/audio_modules/audio_module_template/src/main.c b/tests/subsys/audio_modules/audio_module_template/src/main.c new file mode 100644 index 000000000000..fe0369f7b663 --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/src/main.c @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +ZTEST_SUITE(suite_audio_module_template, NULL, NULL, NULL, NULL, NULL); diff --git a/tests/subsys/audio_modules/audio_module_template/src/template_test.c b/tests/subsys/audio_modules/audio_module_template/src/template_test.c new file mode 100644 index 000000000000..7f9914579f32 --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/src/template_test.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include + +#include "audio_module.h" +#include "audio_module_template.h" + +/* Define a timeout to prevent system locking */ +#define TEST_TX_RX_TIMEOUT_US (K_FOREVER) + +#define CONFIG_TEXT "Template config" +#define RECONFIG_TEXT "Template reconfig" + +#define TEST_MSG_QUEUE_SIZE (4) +#define TEST_MOD_THREAD_STACK_SIZE (2048) +#define TEST_MOD_THREAD_PRIORITY (4) +#define TEST_CONNECTIONS_NUM (5) +#define TEST_MODULES_NUM (TEST_CONNECTIONS_NUM - 1) +#define TEST_MOD_DATA_SIZE (40) +#define TEST_MSG_SIZE (sizeof(struct audio_module_message)) +#define TEST_AUDIO_DATA_ITEMS_NUM (20) + +struct mod_config { + int test_int1; + int test_int2; + int test_int3; + int test_int4; +}; + +struct mod_context { + const char *test_string; + uint32_t test_uint32; + + struct mod_config config; +}; + +const char *test_instance_name = "Test instance"; +struct audio_metadata test_metadata = {.data_coding = LC3, + .data_len_us = 10000, + .sample_rate_hz = 48000, + .bits_per_sample = 16, + .carried_bits_per_sample = 16, + .locations = 0x00000003, + .reference_ts_us = 0, + .data_rx_ts_us = 0, + .bad_data = false}; + +K_THREAD_STACK_ARRAY_DEFINE(mod_temp_stack, TEST_MODULES_NUM, TEST_MOD_THREAD_STACK_SIZE); +DATA_FIFO_DEFINE(msg_fifo_tx, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_rx, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_tx1, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_rx1, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_tx2, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_rx2, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_tx3, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +DATA_FIFO_DEFINE(msg_fifo_rx3, TEST_MSG_QUEUE_SIZE, TEST_MSG_SIZE); +K_MEM_SLAB_DEFINE(mod_data_slab, TEST_MOD_DATA_SIZE, TEST_MSG_QUEUE_SIZE, 4); + +struct data_fifo *msg_fifo_tx_array[TEST_MODULES_NUM] = {&msg_fifo_tx, &msg_fifo_tx1, &msg_fifo_tx2, + &msg_fifo_tx3}; +struct data_fifo *msg_fifo_rx_array[TEST_MODULES_NUM] = {&msg_fifo_rx, &msg_fifo_rx1, &msg_fifo_rx2, + &msg_fifo_rx3}; + +ZTEST(suite_audio_module_template, test_module_template) +{ + int ret; + int i; + char *base_name, instance_name[CONFIG_AUDIO_MODULE_NAME_SIZE]; + + struct audio_data audio_data_tx; + struct audio_data audio_data_rx; + + struct audio_module_parameters mod_parameters; + + struct audio_module_template_configuration configuration = { + .sample_rate_hz = 48000, .bit_depth = 12345, .some_text = CONFIG_TEXT}; + struct audio_module_template_configuration reconfiguration = { + .sample_rate_hz = 16000, .bit_depth = 54321, .some_text = RECONFIG_TEXT}; + struct audio_module_template_configuration return_configuration; + + struct audio_module_template_context context = {0}; + + uint8_t test_data_in[TEST_MOD_DATA_SIZE * TEST_AUDIO_DATA_ITEMS_NUM]; + uint8_t test_data_out[TEST_MOD_DATA_SIZE * TEST_AUDIO_DATA_ITEMS_NUM]; + + struct audio_module_handle handle; + + mod_parameters.description = audio_module_template_description; + mod_parameters.thread.stack = mod_temp_stack[0]; + mod_parameters.thread.stack_size = TEST_MOD_THREAD_STACK_SIZE; + mod_parameters.thread.priority = TEST_MOD_THREAD_PRIORITY; + mod_parameters.thread.data_slab = &mod_data_slab; + mod_parameters.thread.data_size = TEST_MOD_DATA_SIZE; + mod_parameters.thread.msg_rx = &msg_fifo_rx; + mod_parameters.thread.msg_tx = &msg_fifo_tx; + + ret = audio_module_open( + &mod_parameters, (struct audio_module_configuration const *const)&configuration, + test_instance_name, (struct audio_module_context *)&context, &handle); + zassert_equal(ret, 0, "Open function did not return successfully (0): ret %d", ret); + + { + struct audio_module_template_context *ctx = + (struct audio_module_template_context *)handle.context; + struct audio_module_template_configuration *test_config = &ctx->config; + + zassert_equal(test_config->bit_depth, configuration.bit_depth, + "Failed to configure module in the open function"); + zassert_equal(test_config->sample_rate_hz, configuration.sample_rate_hz, + "Failed to configure module in the open function"); + zassert_mem_equal(test_config->some_text, configuration.some_text, + sizeof(CONFIG_TEXT), + "Failed to configure module in the open function"); + } + + zassert_equal_ptr(handle.description->name, audio_module_template_description->name, + "Failed open for names, base name should be %s, but is %s", + audio_module_template_description->name, handle.description->name); + zassert_mem_equal(&handle.name[0], test_instance_name, strlen(test_instance_name), + "Failed open for names, instance name should be %s, but is %s", + test_instance_name, handle.name); + zassert_equal(handle.state, AUDIO_MODULE_STATE_CONFIGURED, + "Not in configured state after call to open the audio module"); + + ret = audio_module_names_get(&handle, &base_name, &instance_name[0]); + zassert_equal(ret, 0, "Get names function did not return successfully (0): ret %d", ret); + zassert_mem_equal(base_name, audio_module_template_description->name, + strlen(audio_module_template_description->name), + "Failed get names, base name should be %s, but is %s", + audio_module_template_description->name, base_name); + zassert_mem_equal(&instance_name[0], test_instance_name, strlen(test_instance_name), + "Failed get names, instance name should be %s, but is %s", handle.name, + &instance_name[0]); + + ret = audio_module_configuration_get( + &handle, (struct audio_module_configuration *)&return_configuration); + zassert_equal(ret, 0, "Configuration get function did not return successfully (0): ret %d", + ret); + zassert_equal(return_configuration.bit_depth, configuration.bit_depth, + "Failed to get configuration"); + zassert_equal(return_configuration.sample_rate_hz, configuration.sample_rate_hz, + "Failed to get configuration"); + zassert_mem_equal(return_configuration.some_text, configuration.some_text, + sizeof(CONFIG_TEXT), "Failed to get configuration"); + + ret = audio_module_connect(&handle, NULL, true); + zassert_equal(ret, 0, "Connect function did not return successfully (0): ret %d", ret); + zassert_equal(handle.use_tx_queue, 1, "Connect queue size is not %d, but is %d", 1, + handle.use_tx_queue); + + ret = audio_module_start(&handle); + zassert_equal(ret, 0, "Start function did not return successfully (0): ret %d", ret); + zassert_equal(handle.state, AUDIO_MODULE_STATE_RUNNING, + "Not in running state after call to start the audio module"); + + for (i = 0; i < TEST_AUDIO_DATA_ITEMS_NUM; i++) { + audio_data_tx.data = (void *)&test_data_in[i * TEST_MOD_DATA_SIZE]; + audio_data_tx.data_size = TEST_MOD_DATA_SIZE; + memcpy(&audio_data_tx.meta, &test_metadata, sizeof(struct audio_metadata)); + + audio_data_rx.data = (void *)&test_data_out[i * TEST_MOD_DATA_SIZE]; + audio_data_rx.data_size = TEST_MOD_DATA_SIZE; + + ret = audio_module_data_tx_rx(&handle, &handle, &audio_data_tx, &audio_data_rx, + TEST_TX_RX_TIMEOUT_US); + zassert_equal(ret, 0, "Data TX-RX function did not return successfully (0): ret %d", + ret); + zassert_mem_equal(audio_data_tx.data, audio_data_rx.data, TEST_MOD_DATA_SIZE, + "Failed to process data"); + zassert_equal(audio_data_tx.data_size, audio_data_rx.data_size, + "Failed to process data, sizes differ"); + zassert_mem_equal(&audio_data_tx.meta, &audio_data_rx.meta, + sizeof(struct audio_metadata), + "Failed to process data, meta data differs"); + + if (i == TEST_AUDIO_DATA_ITEMS_NUM / 2) { + ret = audio_module_stop(&handle); + zassert_equal(ret, 0, + "Stop function did not return successfully (0): ret %d", ret); + + ret = audio_module_reconfigure( + &handle, + (const struct audio_module_configuration *const)&reconfiguration); + zassert_equal( + ret, 0, + "Reconfigure function did not return successfully (0): ret %d", + ret); + zassert_equal(reconfiguration.bit_depth, reconfiguration.bit_depth, + "Failed to reconfigure module"); + zassert_equal(reconfiguration.sample_rate_hz, + reconfiguration.sample_rate_hz, + "Failed to reconfigure module"); + zassert_mem_equal(reconfiguration.some_text, reconfiguration.some_text, + sizeof(RECONFIG_TEXT), "Failed to reconfigure module"); + + ret = audio_module_start(&handle); + zassert_equal(ret, 0, + "Start function did not return successfully (0): ret %d", + ret); + zassert_equal(handle.state, AUDIO_MODULE_STATE_RUNNING, + "Not in running state after call to start the audio module"); + } + } + + ret = audio_module_disconnect(&handle, NULL, true); + zassert_equal(ret, 0, "Disconnect function did not return successfully (0): ret %d", ret); + zassert_equal(handle.use_tx_queue, 0, "Disconnect queue size is not %d, but is %d", 0, + handle.use_tx_queue); + + ret = audio_module_stop(&handle); + zassert_equal(ret, 0, "Stop function did not return successfully (0): ret %d", ret); + zassert_equal(handle.state, AUDIO_MODULE_STATE_STOPPED, + "Not in stopped state after call to stop the audio module"); + + ret = audio_module_close(&handle); + zassert_equal(ret, 0, "Close function did not return successfully (0): ret %d", ret); +} + +ZTEST(suite_audio_module_template, test_module_template_stream) +{ + int ret; + int i; + char inst_name[CONFIG_AUDIO_MODULE_NAME_SIZE]; + + struct audio_data audio_data_tx; + struct audio_data audio_data_rx; + + struct audio_module_parameters mod_parameters; + + struct audio_module_template_configuration configuration = { + .sample_rate_hz = 48000, .bit_depth = 12345, .some_text = CONFIG_TEXT}; + + struct audio_module_template_context context = {0}; + + uint8_t test_data_in[TEST_MOD_DATA_SIZE * TEST_AUDIO_DATA_ITEMS_NUM]; + uint8_t test_data_out[TEST_MOD_DATA_SIZE * TEST_AUDIO_DATA_ITEMS_NUM]; + + struct audio_module_handle handle[TEST_MODULES_NUM]; + + for (i = 0; i < TEST_MODULES_NUM; i++) { + + memset(&handle[i], 0, sizeof(struct audio_module_handle)); + + mod_parameters.description = audio_module_template_description; + mod_parameters.thread.stack = mod_temp_stack[i]; + mod_parameters.thread.stack_size = TEST_MOD_THREAD_STACK_SIZE; + mod_parameters.thread.priority = TEST_MOD_THREAD_PRIORITY; + mod_parameters.thread.data_slab = &mod_data_slab; + mod_parameters.thread.data_size = TEST_MOD_DATA_SIZE; + mod_parameters.thread.msg_rx = msg_fifo_rx_array[i]; + mod_parameters.thread.msg_tx = msg_fifo_tx_array[i]; + + ret = audio_module_open( + &mod_parameters, + (const struct audio_module_configuration *const)&configuration, + &inst_name[0], (struct audio_module_context *)&context, &handle[i]); + zassert_equal(ret, 0, "Open function did not return successfully (0): ret %d", ret); + } + + for (i = 1; i < TEST_MODULES_NUM; i++) { + ret = audio_module_connect(&handle[i - 1], &handle[i], false); + zassert_equal(ret, 0, "Connect function did not return successfully (0): ret %d", + ret); + } + + ret = audio_module_connect(&handle[TEST_MODULES_NUM - 1], NULL, true); + zassert_equal(ret, 0, "Connect function did not return successfully (0): ret %d", ret); + + for (i = 0; i < TEST_MODULES_NUM; i++) { + ret = audio_module_start(&handle[i]); + zassert_equal(ret, 0, "Start function did not return successfully (0): ret %d", + ret); + } + + for (i = 0; i < TEST_AUDIO_DATA_ITEMS_NUM; i++) { + audio_data_tx.data = (void *)&test_data_in[i * TEST_MOD_DATA_SIZE]; + audio_data_tx.data_size = TEST_MOD_DATA_SIZE; + memcpy(&audio_data_tx.meta, &test_metadata, sizeof(struct audio_metadata)); + + audio_data_rx.data = (void *)&test_data_out[i * TEST_MOD_DATA_SIZE]; + audio_data_rx.data_size = TEST_MOD_DATA_SIZE; + + ret = audio_module_data_tx_rx(&handle[0], &handle[TEST_MODULES_NUM - 1], + &audio_data_tx, &audio_data_rx, + TEST_TX_RX_TIMEOUT_US); + zassert_equal(ret, 0, "Data TX-RX function did not return successfully (0): ret %d", + ret); + zassert_mem_equal(audio_data_tx.data, audio_data_rx.data, TEST_MOD_DATA_SIZE, + "Failed to process data"); + zassert_equal(audio_data_tx.data_size, audio_data_rx.data_size, + "Failed to process data, sizes differ"); + zassert_mem_equal(&audio_data_tx.meta, &audio_data_rx.meta, + sizeof(struct audio_metadata), + "Failed to process data, meta data differs"); + } + + for (i = 1; i < TEST_MODULES_NUM; i++) { + ret = audio_module_stop(&handle[i]); + zassert_equal(ret, 0, "Stop function did not return successfully (0): ret %d", ret); + + ret = audio_module_close(&handle[i]); + zassert_equal(ret, 0, "Close function did not return successfully (0): ret %d", + ret); + } +} diff --git a/tests/subsys/audio_modules/audio_module_template/testcase.yaml b/tests/subsys/audio_modules/audio_module_template/testcase.yaml new file mode 100644 index 000000000000..75f6f3f693e4 --- /dev/null +++ b/tests/subsys/audio_modules/audio_module_template/testcase.yaml @@ -0,0 +1,7 @@ +tests: + nrf5340_audio.audio_module_template: + sysbuild: true + platform_allow: qemu_cortex_m3 + integration_platforms: + - qemu_cortex_m3 + tags: audio_module audio_module_template nrf5340_audio_unit_tests sysbuild diff --git a/tests/subsys/audio_modules/lc3_module/CMakeLists.txt b/tests/subsys/audio_modules/lc3_module/CMakeLists.txt new file mode 100644 index 000000000000..06facc33b826 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# Copyright (c) 2023 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project("Audio LC3 module") + +target_sources(app PRIVATE + src/main.c + src/lc3_test_fakes.c + src/sweep21ms_16b48khz_mono_lc3.c + src/sweep21ms_16b48khz_mono_wav.c + src/lc3_test_common.c + src/decoder_test.c +) + +zephyr_include_directories( + ${NRFXLIB_DIR}/lc3/codec/inc + ${NRFXLIB_DIR}/lc3/platform/os/inc + ${NRFXLIB_DIR}/lc3/platform/os/baremetal/inc +) + +target_include_directories(app PRIVATE + ${ZEPHYR_NRF_MODULE_DIR}/include/audio_module + ${ZEPHYR_NRF_MODULE_DIR}/subsys/audio_modules/lc3/t2/decoder +) diff --git a/tests/subsys/audio_modules/lc3_module/prj.conf b/tests/subsys/audio_modules/lc3_module/prj.conf new file mode 100644 index 000000000000..003459cf632f --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/prj.conf @@ -0,0 +1,22 @@ +# +# Copyright (c) 2024 Nordic Semiconductor ASA +# +# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause +# +CONFIG_ZTEST=y +CONFIG_ZTEST_STACK_SIZE=8000 +CONFIG_IRQ_OFFLOAD=y +CONFIG_DATA_FIFO=y +CONFIG_AUDIO_MODULE=y +CONFIG_AUDIO_MODULE_T2_LC3_DECODER_TEST=y +CONFIG_AUDIO_MODULE_T2_LC3_DECODER=y + +# Added large stack sizes. Can be optimized. +CONFIG_MAIN_STACK_SIZE=18000 + +# Decoder settings +CONFIG_LC3_DECODER_FRAME_DURATION_10_MS=y +CONFIG_LC3_DECODER_SAMPLE_RATE_48000_HZ=y +CONFIG_LC3_DECODER_BIT_DEPTH_16=y + +CONFIG_STACK_SENTINEL=y diff --git a/tests/subsys/audio_modules/lc3_module/src/decoder_test.c b/tests/subsys/audio_modules/lc3_module/src/decoder_test.c new file mode 100644 index 000000000000..feae866c1f20 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/decoder_test.c @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include + +#include "lc3_test_fakes.h" +#include "audio_module.h" +#include "lc3_test_common.h" +#include "lc3_decoder.h" +#include "sweep21ms_16b48khz_mono_lc3.h" +#include "sweep21ms_16b48khz_mono_wav.h" + +#define TEST_LC3_DECODER_MSG_QUEUE_SIZE (4) +#define TEST_LC3_DECODER_DATA_OBJECTS_NUM (2) +#define TEST_LC3_DECODER_MODULES_NUM (TEST_AUDIO_CHANNELS_MAX) +#define TEST_LC3_DECODER_MSG_SIZE (sizeof(struct audio_module_message)) +#define TEST_LC3_DECODER_AUDIO_DATA_ITEMS_NUM (4) + +enum test_lc3_decoder_module_id { + TEST_MODULE_ID_DECODER_1 = 0, + TEST_MODULE_ID_DECODER_2, + TEST_MODULE_ID_DECODER_NUM +}; + +static struct audio_module_handle handle[TEST_LC3_DECODER_MODULES_NUM]; +static struct lc3_decoder_context decoder_ctx[TEST_LC3_DECODER_MODULES_NUM]; + +K_THREAD_STACK_ARRAY_DEFINE(lc3_dec_thread_stack, TEST_LC3_DECODER_MODULES_NUM, + CONFIG_LC3_DECODER_STACK_SIZE); +DATA_FIFO_DEFINE(lc3_dec_msg_fifo_tx, TEST_LC3_DECODER_MSG_QUEUE_SIZE, TEST_LC3_DECODER_MSG_SIZE); +DATA_FIFO_DEFINE(lc3_dec_msg_fifo_rx, TEST_LC3_DECODER_MSG_QUEUE_SIZE, TEST_LC3_DECODER_MSG_SIZE); +DATA_FIFO_DEFINE(lc3_dec_msg_fifo_tx1, TEST_LC3_DECODER_MSG_QUEUE_SIZE, TEST_LC3_DECODER_MSG_SIZE); +DATA_FIFO_DEFINE(lc3_dec_msg_fifo_rx1, TEST_LC3_DECODER_MSG_QUEUE_SIZE, TEST_LC3_DECODER_MSG_SIZE); + +static struct data_fifo *lc3_dec_msg_fifo_tx_array[] = {&lc3_dec_msg_fifo_tx, + &lc3_dec_msg_fifo_tx1}; +static struct data_fifo *lc3_dec_msg_fifo_rx_array[] = {&lc3_dec_msg_fifo_rx, + &lc3_dec_msg_fifo_rx1}; + +static char audio_data_memory[TEST_DEC_MULTI_BUF_SIZE * TEST_LC3_DECODER_DATA_OBJECTS_NUM]; +static struct k_mem_slab audio_data_slab; + +static struct audio_data audio_data = {.meta = {.data_coding = LC3, + .data_len_us = TEST_LC3_FRAME_SIZE_US, + .sample_rate_hz = TEST_PCM_SAMPLE_RATE, + .bits_per_sample = TEST_PCM_BIT_DEPTH, + .carried_bits_per_sample = TEST_PCM_BIT_DEPTH, + .reference_ts_us = 0, + .data_rx_ts_us = 0, + .bad_data = false}}; + +static void test_lc3_decoder_mono_multi_init(uint32_t locations) +{ + int ret; + struct audio_module_parameters test_decoder_param; + struct lc3_decoder_configuration test_decoder_config; + uint8_t number_channels; + + for (int i = 0; i < TEST_LC3_DECODER_MODULES_NUM; i++) { + memset(&handle[i], 0, sizeof(struct audio_module_handle)); + } + + audio_module_number_channels_calculate(locations, &number_channels); + + ret = k_mem_slab_init(&audio_data_slab, &audio_data_memory[0], + TEST_DEC_MONO_BUF_SIZE * number_channels, + TEST_LC3_DECODER_DATA_OBJECTS_NUM); + zassert_equal(ret, 0, "Failed to allocate the data slab: ret = %d", ret); + + test_decoder_config.sample_rate_hz = TEST_PCM_SAMPLE_RATE; + test_decoder_config.bits_per_sample = TEST_SAMPLE_BIT_DEPTH; + test_decoder_config.carried_bits_per_sample = TEST_PCM_BIT_DEPTH; + test_decoder_config.data_len_us = TEST_LC3_FRAME_SIZE_US; + test_decoder_config.interleaved = false; + test_decoder_config.bitrate_bps_max = TEST_LC3_BITRATE; + + for (int i = 0; i < number_channels; i++) { + test_decoder_config.locations = 1 << i; + + test_decoder_param.description = lc3_decoder_description; + test_decoder_param.thread.stack_size = CONFIG_LC3_DECODER_STACK_SIZE; + test_decoder_param.thread.priority = CONFIG_LC3_DECODER_THREAD_PRIO; + test_decoder_param.thread.data_slab = &audio_data_slab; + test_decoder_param.thread.data_size = TEST_DEC_MONO_BUF_SIZE; + test_decoder_param.thread.stack = lc3_dec_thread_stack[i], + test_decoder_param.thread.msg_rx = lc3_dec_msg_fifo_rx_array[i]; + test_decoder_param.thread.msg_tx = lc3_dec_msg_fifo_tx_array[i]; + + ret = audio_module_open(&test_decoder_param, + (struct audio_module_configuration *)&test_decoder_config, + "Dec Multi-channel", + (struct audio_module_context *)&decoder_ctx[i], &handle[i]); + zassert_equal(ret, 0, "Decoder left module open did not return zero"); + zassert_equal(LC3Initialize_fake.call_count, 1, + "Failed to call LC3 initialize %d times", + LC3Initialize_fake.call_count); + zassert_equal(LC3DecodeSessionClose_fake.call_count, 0, + "Called LC3 close decoder session %d times", + LC3DecodeSessionClose_fake.call_count); + zassert_equal(LC3BitstreamBuffersize_fake.call_count, (i + 1), + "Failed to call LC3 get buffer size %d times", + LC3BitstreamBuffersize_fake.call_count); + zassert_equal(LC3DecodeSessionOpen_fake.call_count, (i + 1), + "Failed to call LC3 open decoder session %d times", + LC3DecodeSessionOpen_fake.call_count); + + ret = audio_module_connect(&handle[i], NULL, true); + zassert_equal(ret, 0, "Decoder connect did not return zero"); + + ret = audio_module_start(&handle[i]); + zassert_equal(ret, 0, "Decoder left module start did not return zero"); + } +} + +static void test_lc3_decoder_multi_init(bool pcm_format, uint32_t locations) +{ + int ret; + struct audio_module_parameters test_decoder_param; + struct lc3_decoder_configuration test_decoder_config; + uint8_t number_channels; + + for (int i = 0; i < TEST_LC3_DECODER_MODULES_NUM; i++) { + memset(&handle[i], 0, sizeof(struct audio_module_handle)); + } + + audio_module_number_channels_calculate(locations, &number_channels); + + ret = k_mem_slab_init(&audio_data_slab, &audio_data_memory[0], + TEST_DEC_MONO_BUF_SIZE * number_channels, + TEST_LC3_DECODER_DATA_OBJECTS_NUM); + zassert_equal(ret, 0, "Failed to allocate the data slab: ret = %d", ret); + + test_decoder_config.sample_rate_hz = TEST_PCM_SAMPLE_RATE; + test_decoder_config.bits_per_sample = TEST_SAMPLE_BIT_DEPTH; + test_decoder_config.carried_bits_per_sample = TEST_PCM_BIT_DEPTH; + test_decoder_config.data_len_us = TEST_LC3_FRAME_SIZE_US; + test_decoder_config.interleaved = pcm_format; + test_decoder_config.locations = locations; + test_decoder_config.bitrate_bps_max = TEST_LC3_BITRATE; + + test_decoder_param.description = lc3_decoder_description; + test_decoder_param.thread.stack_size = CONFIG_LC3_DECODER_STACK_SIZE; + test_decoder_param.thread.priority = CONFIG_LC3_DECODER_THREAD_PRIO; + test_decoder_param.thread.data_slab = &audio_data_slab; + test_decoder_param.thread.data_size = TEST_DEC_MONO_BUF_SIZE * number_channels; + test_decoder_param.thread.stack = lc3_dec_thread_stack[0], + test_decoder_param.thread.msg_rx = lc3_dec_msg_fifo_rx_array[0]; + test_decoder_param.thread.msg_tx = lc3_dec_msg_fifo_tx_array[0]; + + ret = audio_module_open( + &test_decoder_param, (struct audio_module_configuration *)&test_decoder_config, + "Dec Multi-channel", (struct audio_module_context *)&decoder_ctx[0], &handle[0]); + zassert_equal(ret, 0, "Decoder left module open did not return zero"); + zassert_equal(LC3Initialize_fake.call_count, 1, "Failed to call LC3 initialize %d times", + LC3Initialize_fake.call_count); + zassert_equal(LC3DecodeSessionClose_fake.call_count, 0, + "Called LC3 close decoder session %d times", + LC3DecodeSessionClose_fake.call_count); + zassert_equal(LC3BitstreamBuffersize_fake.call_count, 1, + "Failed to call LC3 get buffer size %d times", + LC3BitstreamBuffersize_fake.call_count); + zassert_equal(LC3DecodeSessionOpen_fake.call_count, number_channels, + "Failed to call LC3 open decoder session %d times", + LC3DecodeSessionOpen_fake.call_count); + + ret = audio_module_connect(&handle[0], NULL, true); + zassert_equal(ret, 0, "Decoder connect did not return zero"); + + ret = audio_module_start(&handle[0]); + zassert_equal(ret, 0, "Decoder left module start did not return zero"); +} + +ZTEST(suite_lc3_decoder_functional, test_lc3_decode_mono) +{ + int ret; + int dec_call_count = 0; + uint8_t *data_in = &lc3_mono[0]; + uint8_t *data_ref = (uint8_t *)&wav_mono[0]; + uint8_t pcm_out[TEST_DEC_MONO_BUF_SIZE]; + struct audio_data audio_data_tx, audio_data_rx; + + /* Fake internal empty data FIFO success */ + ref_in = (uint8_t *)&wav_mono[0]; + ref_in_size = sizeof(wav_mono); + ref_in_read_size = TEST_DEC_MONO_BUF_SIZE; + LC3Initialize_fake.custom_fake = fake_LC3Initialize__succeeds; + LC3DecodeSessionClose_fake.custom_fake = fake_LC3DecodeSessionClose__succeeds; + LC3BitstreamBuffersize_fake.custom_fake = fake_LC3BitstreamBuffersize__succeeds; + LC3DecodeSessionOpen_fake.custom_fake = fake_LC3DecodeSessionOpen__succeeds; + LC3DecodeSessionData_fake.custom_fake = fake_LC3DecodeSessionData__succeeds; + LC3Deinitialize_fake.custom_fake = fake_LC3Deinitialize__succeeds; + LC3PCMBuffersize_fake.custom_fake = fake_LC3PCMBuffersize__succeeds; + + lc3_initialize(TEST_LC3_FRAME_SIZE_US); + zassert_equal(LC3Initialize_fake.call_count, 1, "Failed, called LC3 initialize %d times", + LC3Initialize_fake.call_count); + + test_lc3_decoder_mono_multi_init(TEST_AUDIO_MONO_LEFT_LOCATIONS); + + do { + memcpy(&audio_data_tx, &audio_data, sizeof(struct audio_data)); + memcpy(&audio_data_rx, &audio_data, sizeof(struct audio_data)); + + audio_data_tx.data = (void *)data_in; + audio_data_tx.data_size = TEST_ENC_MONO_BUF_SIZE; + audio_data_tx.meta.data_coding = LC3; + audio_data_tx.meta.locations = TEST_AUDIO_MONO_LEFT_LOCATIONS; + + audio_data_rx.data = pcm_out; + audio_data_rx.data_size = TEST_DEC_MONO_BUF_SIZE; + audio_data_rx.meta.data_coding = PCM; + + ret = audio_module_data_tx_rx(&handle[TEST_MODULE_ID_DECODER_1], + &handle[TEST_MODULE_ID_DECODER_1], &audio_data_tx, + &audio_data_rx, K_FOREVER); + zassert_equal(ret, 0, "Data TX-RX did not return zero for the decoder: %d", ret); + zassert_equal(audio_data_rx.data_size, TEST_DEC_MONO_BUF_SIZE, + "Decoded number of bytes incorrect: %d", audio_data_rx.data_size); + zassert_mem_equal(&pcm_out[0], data_ref, TEST_DEC_MONO_BUF_SIZE, + "Decoded PCM data does not match reference PCM data"); + zassert_equal(LC3DecodeSessionData_fake.call_count, dec_call_count + 1, + "Failed to call LC3 decode %d times", + LC3DecodeSessionData_fake.call_count); + + data_in += TEST_DEC_MONO_BUF_SIZE; + data_ref += TEST_DEC_MONO_BUF_SIZE; + + dec_call_count += 1; + + } while ((dec_call_count < (LC3_MONO_SIZE / TEST_ENC_MONO_BUF_SIZE) && + dec_call_count < (WAV_MONO_SIZE / TEST_DEC_MONO_BUF_SAMPLES))); + + ret = audio_module_stop(&handle[TEST_MODULE_ID_DECODER_1]); + zassert_equal(ret, 0, "Failed to stop module did not return zero: ret = %d", ret); + + ret = audio_module_close(&handle[TEST_MODULE_ID_DECODER_1]); + zassert_equal(ret, 0, "Failed to close module did not return zero: ret = %d", ret); + + lc3_deinitialize(); + zassert_equal(LC3Deinitialize_fake.call_count, 1, + "Failed, called LC3 deinitialize %d times", LC3Deinitialize_fake.call_count); +} + +ZTEST(suite_lc3_decoder_functional, test_lc3_decode_dual_mono) +{ + int ret; + int dec_call_count = 0; + uint8_t *data_l_in = (uint8_t *)&lc3_mono[0]; + uint8_t *data_r_in = (uint8_t *)&lc3_mono[0]; + uint8_t *data_l_ref = (uint8_t *)&wav_mono[0]; + uint8_t *data_r_ref = (uint8_t *)&wav_mono[0]; + uint8_t data_l[TEST_DEC_MONO_BUF_SIZE], data_r[TEST_DEC_MONO_BUF_SIZE]; + struct audio_data audio_data_l_tx, audio_data_l_rx; + struct audio_data audio_data_r_tx, audio_data_r_rx; + + /* Fake internal empty data FIFO success */ + ref_in = (uint8_t *)&wav_mono[0]; + ref_in_size = sizeof(wav_mono); + ref_in_read_size = TEST_DEC_MONO_BUF_SIZE; + LC3Initialize_fake.custom_fake = fake_LC3Initialize__succeeds; + LC3DecodeSessionClose_fake.custom_fake = fake_LC3DecodeSessionClose__succeeds; + LC3BitstreamBuffersize_fake.custom_fake = fake_LC3BitstreamBuffersize__succeeds; + LC3DecodeSessionOpen_fake.custom_fake = fake_LC3DecodeSessionOpen__succeeds; + LC3DecodeSessionData_fake.custom_fake = fake_LC3DecodeSessionData__succeeds; + LC3Deinitialize_fake.custom_fake = fake_LC3Deinitialize__succeeds; + LC3PCMBuffersize_fake.custom_fake = fake_LC3PCMBuffersize__succeeds; + + lc3_initialize(TEST_LC3_FRAME_SIZE_US); + zassert_equal(LC3Initialize_fake.call_count, 1, "Failed, called LC3 initialize %d times", + LC3Initialize_fake.call_count); + + test_lc3_decoder_mono_multi_init(TEST_AUDIO_MONO_LEFT_LOCATIONS + + TEST_AUDIO_MONO_RIGHT_LOCATIONS); + + do { + memcpy(&audio_data_l_tx, &audio_data, sizeof(struct audio_data)); + memcpy(&audio_data_l_rx, &audio_data, sizeof(struct audio_data)); + + audio_data_l_tx.data = (void *)data_l_in; + audio_data_l_tx.data_size = TEST_ENC_MONO_BUF_SIZE; + audio_data_l_tx.meta.data_coding = LC3; + audio_data_l_tx.meta.locations = TEST_AUDIO_MONO_LEFT_LOCATIONS; + + memset(&data_l[0], 0, TEST_DEC_MONO_BUF_SIZE); + audio_data_l_rx.data = (void *)&data_l[0]; + audio_data_l_rx.data_size = TEST_DEC_MONO_BUF_SIZE; + + ret = audio_module_data_tx_rx(&handle[TEST_MODULE_ID_DECODER_1], + &handle[TEST_MODULE_ID_DECODER_1], &audio_data_l_tx, + &audio_data_l_rx, K_FOREVER); + zassert_equal(ret, 0, "Data TX-RX did not return zero for left decoder: %d", ret); + zassert_equal(audio_data_l_rx.data_size, TEST_DEC_MONO_BUF_SIZE, + "Decoded number of bytes for right incorrect: %d", + audio_data_l_rx.data_size); + zassert_mem_equal(&data_l[0], data_l_ref, TEST_DEC_MONO_BUF_SIZE, + "Decoded left PCM data does not match reference PCM data"); + zassert_equal(LC3DecodeSessionData_fake.call_count, dec_call_count + 1, + "Failed to call LC3 decode %d times", + LC3DecodeSessionData_fake.call_count); + + data_l_in += TEST_ENC_MONO_BUF_SIZE; + data_l_ref += TEST_DEC_MONO_BUF_SIZE; + + dec_call_count += 1; + + memcpy(&audio_data_r_tx, &audio_data, sizeof(struct audio_data)); + memcpy(&audio_data_r_rx, &audio_data, sizeof(struct audio_data)); + + audio_data_r_tx.data = (void *)data_r_in; + audio_data_r_tx.data_size = TEST_ENC_MONO_BUF_SIZE; + audio_data_r_tx.meta.data_coding = LC3; + audio_data_r_tx.meta.locations = TEST_AUDIO_MONO_RIGHT_LOCATIONS; + + memset(&data_r[0], 0, TEST_DEC_MONO_BUF_SIZE); + audio_data_r_rx.data = (void *)&data_r[0]; + audio_data_r_rx.data_size = TEST_DEC_MONO_BUF_SIZE; + + ret = audio_module_data_tx_rx(&handle[TEST_MODULE_ID_DECODER_2], + &handle[TEST_MODULE_ID_DECODER_2], &audio_data_r_tx, + &audio_data_r_rx, K_FOREVER); + zassert_equal(ret, 0, "Data TX-RX did not return zero for right decoder: %d", ret); + zassert_equal(audio_data_r_rx.data_size, TEST_DEC_MONO_BUF_SIZE, + "Decoded number of bytes for left incorrect: %d", + audio_data_r_rx.data_size); + zassert_mem_equal(&data_r[0], data_r_ref, TEST_DEC_MONO_BUF_SIZE, + "Decoded right PCM data does not match reference PCM data"); + zassert_equal(LC3DecodeSessionData_fake.call_count, dec_call_count + 1, + "Failed to call LC3 decode %d times", + LC3DecodeSessionData_fake.call_count); + + data_r_in += TEST_ENC_MONO_BUF_SIZE; + data_r_ref += TEST_DEC_MONO_BUF_SIZE; + + dec_call_count += 1; + + } while (((dec_call_count >> 1) < (LC3_MONO_SIZE / TEST_ENC_MONO_BUF_SIZE) && + (dec_call_count >> 1) < (WAV_MONO_SIZE / TEST_DEC_MONO_BUF_SAMPLES))); + + ret = audio_module_stop(&handle[TEST_MODULE_ID_DECODER_1]); + zassert_equal(ret, 0, "Failed to stop module did not return zero: ret = %d", ret); + ret = audio_module_stop(&handle[TEST_MODULE_ID_DECODER_2]); + zassert_equal(ret, 0, "Failed to stop module did not return zero: ret = %d", ret); + + ret = audio_module_close(&handle[TEST_MODULE_ID_DECODER_1]); + zassert_equal(ret, 0, "Failed to close module did not return zero: ret = %d", ret); + ret = audio_module_close(&handle[TEST_MODULE_ID_DECODER_2]); + zassert_equal(ret, 0, "Failed to close module did not return zero: ret = %d", ret); + + lc3_deinitialize(); + zassert_equal(LC3Deinitialize_fake.call_count, 1, + "Failed, called LC3 deinitialize %d times", LC3Deinitialize_fake.call_count); +} + +ZTEST(suite_lc3_decoder_functional, test_lc3_decode_multi_deint) +{ + int ret; + int dec_call_count = 0; + uint8_t *data_source = (uint8_t *)&lc3_mono[0]; + uint8_t *data_reference = (uint8_t *)&wav_mono[0]; + uint8_t data_in[TEST_ENC_STEREO_BUF_SIZE]; + uint8_t data_out[TEST_DEC_STEREO_BUF_SIZE]; + uint8_t data_ref[TEST_DEC_STEREO_BUF_SIZE]; + struct audio_data audio_data_tx, audio_data_rx; + + /* Fake internal empty data FIFO success */ + ref_in = (uint8_t *)&wav_mono[0]; + ref_in_size = sizeof(wav_mono); + ref_in_read_size = TEST_DEC_MONO_BUF_SIZE; + LC3Initialize_fake.custom_fake = fake_LC3Initialize__succeeds; + LC3DecodeSessionClose_fake.custom_fake = fake_LC3DecodeSessionClose__succeeds; + LC3BitstreamBuffersize_fake.custom_fake = fake_LC3BitstreamBuffersize__succeeds; + LC3DecodeSessionOpen_fake.custom_fake = fake_LC3DecodeSessionOpen__succeeds; + LC3DecodeSessionData_fake.custom_fake = fake_LC3DecodeSessionData__succeeds; + LC3Deinitialize_fake.custom_fake = fake_LC3Deinitialize__succeeds; + LC3PCMBuffersize_fake.custom_fake = fake_LC3PCMBuffersize__succeeds; + + lc3_initialize(TEST_LC3_FRAME_SIZE_US); + zassert_equal(LC3Initialize_fake.call_count, 1, "Failed to call LC3 initialize %d times", + LC3Initialize_fake.call_count); + + test_lc3_decoder_multi_init(false, TEST_AUDIO_STEREO_LOCATIONS); + + do { + memcpy(&data_in[0], data_source, TEST_ENC_MONO_BUF_SIZE); + memcpy(&data_in[TEST_ENC_MONO_BUF_SIZE], data_source, TEST_ENC_MONO_BUF_SIZE); + memcpy(&data_ref[0], data_reference, TEST_DEC_MONO_BUF_SIZE); + memcpy(&data_ref[TEST_DEC_MONO_BUF_SIZE], data_reference, TEST_DEC_MONO_BUF_SIZE); + + memcpy(&audio_data_tx, &audio_data, sizeof(struct audio_data)); + memcpy(&audio_data_rx, &audio_data, sizeof(struct audio_data)); + + audio_data_tx.data = &data_in[0]; + audio_data_tx.data_size = TEST_ENC_STEREO_BUF_SIZE; + audio_data_tx.meta.data_coding = LC3; + audio_data_tx.meta.locations = TEST_AUDIO_STEREO_LOCATIONS; + + audio_data_rx.data = (void *)&data_out[0]; + audio_data_rx.data_size = TEST_DEC_STEREO_BUF_SIZE; + + ret = audio_module_data_tx_rx(&handle[0], &handle[0], &audio_data_tx, + &audio_data_rx, K_FOREVER); + zassert_equal(ret, 0, "Data TX-RX did not return zero for left decoder: %d", ret); + zassert_equal(audio_data_rx.data_size, TEST_DEC_STEREO_BUF_SIZE, + "Decoded number of bytes incorrect: %d", audio_data_rx.data_size); + zassert_mem_equal(&data_out[0], &data_ref[0], TEST_DEC_STEREO_BUF_SIZE, + "Decoded PCM data does not match reference PCM data"); + zassert_equal(LC3DecodeSessionData_fake.call_count, dec_call_count + 2, + "Failed to call LC3 decode %d times", + LC3DecodeSessionData_fake.call_count); + + data_source += TEST_ENC_MONO_BUF_SIZE; + data_reference += TEST_DEC_MONO_BUF_SIZE; + + dec_call_count += 2; + + } while (((dec_call_count >> 1) < (LC3_MONO_SIZE / TEST_ENC_MONO_BUF_SIZE) && + (dec_call_count >> 1) < (WAV_MONO_SIZE / TEST_DEC_MONO_BUF_SAMPLES))); + + ret = audio_module_stop(&handle[TEST_MODULE_ID_DECODER_1]); + zassert_equal(ret, 0, "Failed to stop module did not return zero: ret = %d", ret); + + ret = audio_module_close(&handle[TEST_MODULE_ID_DECODER_1]); + zassert_equal(ret, 0, "Failed to close module did not return zero: ret = %d", ret); + + lc3_deinitialize(); + zassert_equal(LC3Deinitialize_fake.call_count, 1, + "Failed to call LC3 deinitialize %d times", LC3Deinitialize_fake.call_count); +} + +ZTEST(suite_lc3_decoder_functional, test_lc3_decode_multi_int) +{ + int ret; + int dec_call_count = 0; + uint8_t *data_source = (uint8_t *)&lc3_mono[0]; + uint8_t *data_reference = (uint8_t *)&wav_mono[0]; + uint8_t data_in[TEST_ENC_STEREO_BUF_SIZE]; + uint8_t data_out[TEST_DEC_STEREO_BUF_SIZE]; + uint8_t data_ref[TEST_DEC_STEREO_BUF_SIZE]; + uint8_t *ref; + struct audio_data audio_data_tx, audio_data_rx; + size_t input_remaining = sizeof(lc3_mono); + size_t ref_remaining = sizeof(wav_mono); + + /* Fake internal empty data FIFO success */ + ref_in = (uint8_t *)&wav_mono[0]; + ref_in_size = sizeof(wav_mono); + ref_in_read_size = TEST_DEC_MONO_BUF_SIZE; + LC3Initialize_fake.custom_fake = fake_LC3Initialize__succeeds; + LC3DecodeSessionClose_fake.custom_fake = fake_LC3DecodeSessionClose__succeeds; + LC3BitstreamBuffersize_fake.custom_fake = fake_LC3BitstreamBuffersize__succeeds; + LC3DecodeSessionOpen_fake.custom_fake = fake_LC3DecodeSessionOpen__succeeds; + LC3DecodeSessionData_fake.custom_fake = fake_LC3DecodeSessionData__succeeds; + LC3Deinitialize_fake.custom_fake = fake_LC3Deinitialize__succeeds; + LC3PCMBuffersize_fake.custom_fake = fake_LC3PCMBuffersize__succeeds; + + lc3_initialize(TEST_LC3_FRAME_SIZE_US); + zassert_equal(LC3Initialize_fake.call_count, 1, "Failed to call LC3 initialize %d times", + LC3Initialize_fake.call_count); + + test_lc3_decoder_multi_init(true, TEST_AUDIO_STEREO_LOCATIONS); + + while (input_remaining > TEST_ENC_MONO_BUF_SIZE && ref_remaining > TEST_DEC_MONO_BUF_SIZE) { + + memcpy(&data_in[0], data_source, TEST_ENC_MONO_BUF_SIZE); + memcpy(&data_in[TEST_ENC_MONO_BUF_SIZE], data_source, TEST_ENC_MONO_BUF_SIZE); + + /* Interleave the channel samples */ + ref = &data_ref[0]; + for (uint32_t i = 0; i < TEST_DEC_MONO_BUF_SIZE; + i += CONFIG_LC3_DECODER_BIT_DEPTH_OCTETS) { + for (uint8_t j = 0; j < TEST_AUDIO_CHANNELS_STEREO; j++) { + for (uint8_t k = 0; k < CONFIG_LC3_DECODER_BIT_DEPTH_OCTETS; k++) { + *ref++ = data_reference[k]; + } + } + + data_reference += CONFIG_LC3_DECODER_BIT_DEPTH_OCTETS; + } + + memcpy(&audio_data_tx, &audio_data, sizeof(struct audio_data)); + memcpy(&audio_data_rx, &audio_data, sizeof(struct audio_data)); + + audio_data_tx.data = &data_in[0]; + audio_data_tx.data_size = TEST_ENC_STEREO_BUF_SIZE; + audio_data_tx.meta.data_coding = LC3; + audio_data_tx.meta.locations = TEST_AUDIO_STEREO_LOCATIONS; + + audio_data_rx.data = (void *)&data_out[0]; + audio_data_rx.data_size = TEST_DEC_STEREO_BUF_SIZE; + + ret = audio_module_data_tx_rx(&handle[0], &handle[0], &audio_data_tx, + &audio_data_rx, K_FOREVER); + zassert_equal(ret, 0, "Data TX-RX did not return zero for left decoder: %d", ret); + zassert_equal(audio_data_rx.data_size, TEST_DEC_STEREO_BUF_SIZE, + "Decoded number of bytes incorrect: %d", audio_data_rx.data_size); + zassert_mem_equal(audio_data_rx.data, data_ref, TEST_DEC_STEREO_BUF_SIZE, + "Decoded PCM data does not match reference PCM data"); + zassert_equal(LC3DecodeSessionData_fake.call_count, dec_call_count + 2, + "Failed to call LC3 decode %d times", + LC3DecodeSessionData_fake.call_count); + + dec_call_count += 2; + + data_source += TEST_ENC_MONO_BUF_SIZE; + + input_remaining -= TEST_ENC_MONO_BUF_SIZE; + ref_remaining -= TEST_DEC_MONO_BUF_SIZE; + } + + ret = audio_module_stop(&handle[TEST_MODULE_ID_DECODER_1]); + zassert_equal(ret, 0, "Failed to stop module did not return zero: ret = %d", ret); + + ret = audio_module_close(&handle[TEST_MODULE_ID_DECODER_1]); + zassert_equal(ret, 0, "Failed to close module did not return zero: ret = %d", ret); + + lc3_deinitialize(); + zassert_equal(LC3Deinitialize_fake.call_count, 1, + "Failed to call LC3 deinitialize %d times", LC3Deinitialize_fake.call_count); +} diff --git a/tests/subsys/audio_modules/lc3_module/src/lc3_test_common.c b/tests/subsys/audio_modules/lc3_module/src/lc3_test_common.c new file mode 100644 index 000000000000..7b0eaf25f2ea --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/lc3_test_common.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include + +#include "lc3_test_fakes.h" +#include "audio_module.h" +#include "lc3_test_common.h" + +void lc3_initialize(int duration_us) +{ + int ret; + uint8_t enc_sample_rates = 0; + uint8_t dec_sample_rates = 0; + uint8_t unique_session = 0; + LC3FrameSize_t framesize; + + /* Set unique session to 0 for using the default sharing memory setting. + * + * This could lead to higher heap consumption, but is able to manipulate + * different sample rate setting between encoder/decoder. + */ + + /* Check supported sample rates for encoder */ + if (IS_ENABLED(CONFIG_LC3_ENC_SAMPLE_RATE_8KHZ_SUPPORT)) { + enc_sample_rates |= LC3_SAMPLE_RATE_8_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_ENC_SAMPLE_RATE_16KHZ_SUPPORT)) { + enc_sample_rates |= LC3_SAMPLE_RATE_16_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_ENC_SAMPLE_RATE_24KHZ_SUPPORT)) { + enc_sample_rates |= LC3_SAMPLE_RATE_24_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_ENC_SAMPLE_RATE_32KHZ_SUPPORT)) { + enc_sample_rates |= LC3_SAMPLE_RATE_32_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_ENC_SAMPLE_RATE_441KHZ_SUPPORT)) { + enc_sample_rates |= LC3_SAMPLE_RATE_441_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_ENC_SAMPLE_RATE_48KHZ_SUPPORT)) { + enc_sample_rates |= LC3_SAMPLE_RATE_48_KHZ; + } + + /* Check supported sample rates for encoder */ + if (IS_ENABLED(CONFIG_LC3_DEC_SAMPLE_RATE_8KHZ_SUPPORT)) { + dec_sample_rates |= LC3_SAMPLE_RATE_8_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_DEC_SAMPLE_RATE_16KHZ_SUPPORT)) { + dec_sample_rates |= LC3_SAMPLE_RATE_16_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_DEC_SAMPLE_RATE_24KHZ_SUPPORT)) { + dec_sample_rates |= LC3_SAMPLE_RATE_24_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_DEC_SAMPLE_RATE_32KHZ_SUPPORT)) { + dec_sample_rates |= LC3_SAMPLE_RATE_32_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_DEC_SAMPLE_RATE_441KHZ_SUPPORT)) { + dec_sample_rates |= LC3_SAMPLE_RATE_441_KHZ; + } + if (IS_ENABLED(CONFIG_LC3_DEC_SAMPLE_RATE_48KHZ_SUPPORT)) { + dec_sample_rates |= LC3_SAMPLE_RATE_48_KHZ; + } + + switch (duration_us) { + case 7500: + framesize = LC3FrameSize7_5Ms; + break; + case 10000: + framesize = LC3FrameSize10Ms; + break; + default: + return; + } + + ret = LC3Initialize(enc_sample_rates, dec_sample_rates, framesize, unique_session, NULL, + NULL); + zassert_equal(ret, 0, "LC3 initialize did not return zero"); +} + +void lc3_deinitialize(void) +{ + int ret; + + ret = LC3Deinitialize(); + zassert_equal(ret, 0, "LC3 codec failed initialization"); +} diff --git a/tests/subsys/audio_modules/lc3_module/src/lc3_test_common.h b/tests/subsys/audio_modules/lc3_module/src/lc3_test_common.h new file mode 100644 index 000000000000..6c886a0f72c4 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/lc3_test_common.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef _COMMON_H_ +#define _COMMON_H_ + +#include "audio_module.h" + +#define TEST_AUDIO_CHANNELS_MONO 1 +#define TEST_AUDIO_CHANNELS_DUAL_MONO 2 +#define TEST_AUDIO_CHANNELS_STEREO 2 +#define TEST_AUDIO_CHANNELS_MAX 2 + +#define TEST_SAMPLE_BIT_DEPTH 16 +#define TEST_PCM_BIT_DEPTH 16 +#define TEST_DEC_MONO_BUF_SIZE 960 +#define TEST_DEC_MONO_BUF_SAMPLES (TEST_DEC_MONO_BUF_SIZE / (TEST_PCM_BIT_DEPTH / 8)) +#define TEST_DEC_STEREO_BUF_SIZE (TEST_DEC_MONO_BUF_SIZE * TEST_AUDIO_CHANNELS_STEREO) +#define TEST_DEC_STEREO_BUF_SAMPLES (TEST_DEC_STEREO_BUF_SIZE / (TEST_PCM_BIT_DEPTH / 8)) +#define TEST_DEC_MULTI_BUF_SIZE (TEST_DEC_MONO_BUF_SIZE * TEST_AUDIO_CHANNELS_MAX) +#define TEST_DEC_MULTI_BUF_SAMPLES (TEST_DEC_MULTI_BUF_SIZE / (TEST_PCM_BIT_DEPTH / 8)) + +#define TEST_ENC_MONO_BUF_SIZE 120 +#define TEST_ENC_STEREO_BUF_SIZE (TEST_ENC_MONO_BUF_SIZE * TEST_AUDIO_CHANNELS_STEREO) +#define TEST_ENC_MULTI_BUF_SIZE (TEST_ENC_MONO_BUF_SIZE * TEST_AUDIO_CHANNELS_MAX) + +#define TEST_PCM_SAMPLE_RATE 48000 +#define TEST_LC3_BITRATE 96000 +#define TEST_LC3_FRAME_SIZE_US 10000 + +#define TEST_AUDIO_MONO_LEFT_LOCATIONS (1 << AUDIO_CH_L) +#define TEST_AUDIO_MONO_RIGHT_LOCATIONS (1 << AUDIO_CH_R) +#define TEST_AUDIO_STEREO_LOCATIONS ((1 << AUDIO_CH_L) | (1 << AUDIO_CH_R)) +#define TEST_AUDIO_MULTI_CHANNEL_LOCATIONS ((1 << AUDIO_CH_L) | (1 << AUDIO_CH_R)) + +enum test_module_id { + TEST_MODULE_LC3_DECODER = 0, + TEST_MODULE_LC3_ENCODER, + TEST_MODULES_NUM +}; + +/** + * @brief Initialize the LC3 codec. + * + * @note This function is called only once and configures both + * the encoder and decoder. + * + * @param duration_us [in] The duration of a frame of LC3 in micro seconds. + */ +void lc3_initialize(int duration_us); + +/** + * @brief Uninitialize the LC3 codec. + * + * @note This function is called only once and unintializes both + * the encoder and decoder. + */ +void lc3_deinitialize(void); + +#endif /* _COMMON_H_ */ diff --git a/tests/subsys/audio_modules/lc3_module/src/lc3_test_fakes.c b/tests/subsys/audio_modules/lc3_module/src/lc3_test_fakes.c new file mode 100644 index 000000000000..422c60b3c161 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/lc3_test_fakes.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include + +#include "LC3API.h" +#include "lc3_test_fakes.h" +#include "lc3_test_common.h" + +#include +LOG_MODULE_REGISTER(module_fakes, 4); + +#define TEST_ENC_SESSIONS_NUM (5) +#define TEST_DEC_SESSIONS_NUM (10) + +struct lc3_session { + bool session_init; + uint8_t *ref_data; + int ref_read_size; + int ref_remaining; +}; + +uint8_t *ref_in; +int ref_in_size; +int ref_in_read_size; + +static int enc_count; +static int dec_count; + +struct lc3_session dec_session_ctx[TEST_DEC_SESSIONS_NUM]; +struct lc3_session enc_session_ctx[TEST_ENC_SESSIONS_NUM]; + +/* + * Stubs are defined here, so that multiple .C files can share them + * without having linker issues. + */ +DEFINE_FFF_GLOBALS; + +DEFINE_FAKE_VALUE_FUNC(int32_t OSALCALL, LC3Initialize, uint8_t, uint8_t, LC3FrameSizeConfig_t, + uint8_t, uint8_t *, uint32_t *); +DEFINE_FAKE_VALUE_FUNC(int32_t OSALCALL, LC3Deinitialize); +DEFINE_FAKE_VALUE_FUNC(LC3EncoderHandle_t OSALCALL, LC3EncodeSessionOpen, uint16_t, uint8_t, + LC3FrameSize_t, uint8_t *, uint16_t *, int32_t *); +DEFINE_FAKE_VALUE_FUNC(int32_t OSALCALL, LC3EncodeSessionData, LC3EncoderHandle_t, + LC3EncodeInput_t *, LC3EncodeOutput_t *); +DEFINE_FAKE_VOID_FUNC1(LC3EncodeSessionClose, LC3EncoderHandle_t); +DEFINE_FAKE_VALUE_FUNC(LC3DecoderHandle_t, LC3DecodeSessionOpen, uint16_t, uint8_t, LC3FrameSize_t, + uint8_t *, uint16_t *, int32_t *); +DEFINE_FAKE_VALUE_FUNC(int32_t, LC3DecodeSessionData, LC3DecoderHandle_t, LC3DecodeInput_t *, + LC3DecodeOutput_t *); +DEFINE_FAKE_VOID_FUNC1(LC3DecodeSessionClose, LC3DecoderHandle_t); +DEFINE_FAKE_VALUE_FUNC(uint16_t, LC3BitstreamBuffersize, uint16_t, uint32_t, LC3FrameSize_t, + int32_t *); +DEFINE_FAKE_VALUE_FUNC(uint16_t, LC3PCMBuffersize, uint16_t, uint8_t, LC3FrameSize_t, int32_t *); + +/* Custom fakes implementation */ +int32_t fake_LC3Initialize__succeeds(uint8_t encoderSampleRates, uint8_t decoderSampleRates, + LC3FrameSizeConfig_t frameSizeConfig, uint8_t uniqueSessions, + uint8_t *buffer, uint32_t *bufferSize) +{ + ARG_UNUSED(encoderSampleRates); + ARG_UNUSED(decoderSampleRates); + ARG_UNUSED(frameSizeConfig); + ARG_UNUSED(uniqueSessions); + ARG_UNUSED(buffer); + ARG_UNUSED(bufferSize); + + enc_count = 0; + dec_count = 0; + + for (int i = 0; i < TEST_ENC_SESSIONS_NUM; i++) { + enc_session_ctx[i].session_init = false; + enc_session_ctx[i].ref_data = NULL; + enc_session_ctx[i].ref_read_size = 0; + enc_session_ctx[i].ref_remaining = 0; + } + + for (int i = 0; i < TEST_DEC_SESSIONS_NUM; i++) { + dec_session_ctx[i].session_init = false; + dec_session_ctx[i].ref_data = NULL; + dec_session_ctx[i].ref_read_size = 0; + dec_session_ctx[i].ref_remaining = 0; + } + + return 0; +} + +/* Custom fakes implementation */ +int32_t fake_LC3Initialize__fails(uint8_t encoderSampleRates, uint8_t decoderSampleRates, + LC3FrameSizeConfig_t frameSizeConfig, uint8_t uniqueSessions, + uint8_t *buffer, uint32_t *bufferSize) +{ + ARG_UNUSED(encoderSampleRates); + ARG_UNUSED(decoderSampleRates); + ARG_UNUSED(frameSizeConfig); + ARG_UNUSED(uniqueSessions); + ARG_UNUSED(buffer); + ARG_UNUSED(bufferSize); + + return -1; +} + +/* Custom fakes implementation */ +int32_t fake_LC3Deinitialize__succeeds(void) +{ + enc_count = 0; + dec_count = 0; + + for (int i = 0; i < TEST_ENC_SESSIONS_NUM; i++) { + enc_session_ctx[i].session_init = false; + enc_session_ctx[i].ref_data = NULL; + enc_session_ctx[i].ref_read_size = 0; + enc_session_ctx[i].ref_remaining = 0; + } + + for (int i = 0; i < TEST_DEC_SESSIONS_NUM; i++) { + dec_session_ctx[i].session_init = false; + dec_session_ctx[i].ref_data = NULL; + dec_session_ctx[i].ref_read_size = 0; + dec_session_ctx[i].ref_remaining = 0; + } + + return 0; +} + +/* Custom fakes implementation */ +int32_t fake_LC3Deinitialize__fails(void) +{ + return -1; +} + +/* Custom fakes implementation */ +LC3EncoderHandle_t fake_LC3EncodeSessionOpen__succeeds(uint16_t sampleRate, uint8_t bitsPerSample, + LC3FrameSize_t frameSize, uint8_t *buffer, + uint16_t *bufferSize, int32_t *result) +{ + ARG_UNUSED(sampleRate); + ARG_UNUSED(bitsPerSample); + ARG_UNUSED(frameSize); + ARG_UNUSED(buffer); + ARG_UNUSED(bufferSize); + struct lc3_session *session = (struct lc3_session *)&enc_session_ctx[enc_count]; + + session->session_init = true; + session->ref_data = ref_in; + session->ref_read_size = ref_in_read_size; + session->ref_remaining = ref_in_size; + + enc_count++; + + *result = 0; + + return (void *)session; +} + +/* Custom fakes implementation */ +LC3EncoderHandle_t fake_LC3EncodeSessionOpen__fails(uint16_t sampleRate, uint8_t bitsPerSample, + LC3FrameSize_t frameSize, uint8_t *buffer, + uint16_t *bufferSize, int32_t *result) +{ + ARG_UNUSED(sampleRate); + ARG_UNUSED(bitsPerSample); + ARG_UNUSED(frameSize); + ARG_UNUSED(buffer); + ARG_UNUSED(bufferSize); + + *result = -1; + + return NULL; +} + +int32_t fake_LC3EncodeSessionData__succeeds(LC3EncoderHandle_t encodeHandle, + LC3EncodeInput_t *encodeInput, + LC3EncodeOutput_t *encodeOutput) +{ + ARG_UNUSED(encodeInput); + struct lc3_session *session = (struct lc3_session *)encodeHandle; + uint8_t *data_out = (uint8_t *)encodeOutput->outputData; + uint8_t *ref_data = session->ref_data; + int size; + + if (session->ref_read_size > session->ref_remaining) { + size = session->ref_remaining; + session->ref_remaining = 0; + } else { + size = session->ref_read_size; + session->ref_remaining -= session->ref_read_size; + } + + for (int i = 0; i < size; i++) { + *data_out++ = *ref_data++; + } + + session->ref_data = ref_data; + + encodeOutput->bytesWritten = size; + + return 0; +} + +int32_t fake_LC3EncodeSessionData__fails(LC3EncoderHandle_t encodeHandle, + LC3EncodeInput_t *encodeInput, + LC3EncodeOutput_t *encodeOutput) +{ + ARG_UNUSED(encodeHandle); + ARG_UNUSED(encodeInput); + ARG_UNUSED(encodeOutput); + + return -1; +} + +void fake_LC3EncodeSessionClose__succeeds(LC3EncoderHandle_t encodeHandle) +{ + struct lc3_session *session = (struct lc3_session *)encodeHandle; + + session->session_init = false; + session->ref_data = NULL; + session->ref_read_size = 0; +} + +void fake_LC3EncodeSessionClose__fails(LC3EncoderHandle_t encodeHandle) +{ + ARG_UNUSED(encodeHandle); +} + +LC3DecoderHandle_t fake_LC3DecodeSessionOpen__succeeds(uint16_t sampleRate, uint8_t bitsPerSample, + LC3FrameSize_t frameSize, uint8_t *buffer, + uint16_t *bufferSize, int32_t *result) +{ + ARG_UNUSED(sampleRate); + ARG_UNUSED(bitsPerSample); + ARG_UNUSED(frameSize); + ARG_UNUSED(buffer); + ARG_UNUSED(bufferSize); + struct lc3_session *session = (struct lc3_session *)&dec_session_ctx[dec_count]; + + session->session_init = true; + session->ref_data = ref_in; + session->ref_read_size = ref_in_read_size; + session->ref_remaining = ref_in_size; + + dec_count++; + + *result = 0; + + return (void *)session; +} + +LC3DecoderHandle_t fake_LC3DecodeSessionOpen__fails(uint16_t sampleRate, uint8_t bitsPerSample, + LC3FrameSize_t frameSize, uint8_t *buffer, + uint16_t *bufferSize, int32_t *result) +{ + ARG_UNUSED(sampleRate); + ARG_UNUSED(bitsPerSample); + ARG_UNUSED(frameSize); + ARG_UNUSED(buffer); + ARG_UNUSED(bufferSize); + + *result = -1; + + return NULL; +} + +int32_t fake_LC3DecodeSessionData__succeeds(LC3DecoderHandle_t decodeHandle, + LC3DecodeInput_t *decodeInput, + LC3DecodeOutput_t *decodeOutput) +{ + ARG_UNUSED(decodeInput); + struct lc3_session *session = (struct lc3_session *)decodeHandle; + uint8_t *data_out = (uint8_t *)decodeOutput->PCMData; + uint8_t *ref_data = session->ref_data; + int size; + + if (session->ref_read_size > session->ref_remaining) { + size = session->ref_remaining; + session->ref_remaining = 0; + } else { + size = session->ref_read_size; + session->ref_remaining -= session->ref_read_size; + } + + for (int i = 0; i < size; i++) { + *data_out++ = *ref_data++; + } + + session->ref_data = ref_data; + + decodeOutput->bytesWritten = size; + + return 0; +} + +int32_t fake_LC3DecodeSessionData__fails(LC3DecoderHandle_t decodeHandle, + LC3DecodeInput_t *decodeInput, + LC3DecodeOutput_t *decodeOutput) +{ + ARG_UNUSED(decodeHandle); + ARG_UNUSED(decodeInput); + ARG_UNUSED(decodeOutput); + + return -1; +} + +void fake_LC3DecodeSessionClose__succeeds(LC3DecoderHandle_t decodeHandle) +{ + struct lc3_session *session = (struct lc3_session *)decodeHandle; + + session->session_init = false; + session->ref_data = NULL; + session->ref_read_size = 0; +} + +void fake_LC3DecodeSessionClose__fails(LC3DecoderHandle_t decodeHandle) +{ + ARG_UNUSED(decodeHandle); +} + +uint16_t fake_LC3BitstreamBuffersize__succeeds(uint16_t sampleRate, uint32_t maxBitRate, + LC3FrameSize_t frameSize, int32_t *result) +{ + ARG_UNUSED(sampleRate); + + *result = 0; + + return TEST_ENC_MONO_BUF_SIZE; +} + +uint16_t fake_LC3BitstreamBuffersize__fails(uint16_t sampleRate, uint32_t maxBitRate, + LC3FrameSize_t frameSize, int32_t *result) +{ + ARG_UNUSED(sampleRate); + ARG_UNUSED(maxBitRate); + ARG_UNUSED(frameSize); + + *result = -1; + + return 0; +} + +uint16_t fake_LC3PCMBuffersize__succeeds(uint16_t sampleRate, uint8_t bitDepth, + LC3FrameSize_t frameSize, int32_t *result) +{ + ARG_UNUSED(sampleRate); + ARG_UNUSED(bitDepth); + ARG_UNUSED(frameSize); + + *result = 0; + + return TEST_DEC_MONO_BUF_SIZE; +} + +uint16_t fake_LC3PCMBuffersize__fails(uint16_t sampleRate, uint8_t bitDepth, + LC3FrameSize_t frameSize, int32_t *result) +{ + ARG_UNUSED(sampleRate); + ARG_UNUSED(bitDepth); + ARG_UNUSED(frameSize); + + *result = -1; + + return -1; +} diff --git a/tests/subsys/audio_modules/lc3_module/src/lc3_test_fakes.h b/tests/subsys/audio_modules/lc3_module/src/lc3_test_fakes.h new file mode 100644 index 000000000000..bfe7b824d101 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/lc3_test_fakes.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef _FAKES_H_ +#define _FAKES_H_ + +#include +#include +#include +#include + +#include "LC3API.h" + +/* Fake functions declaration */ +DECLARE_FAKE_VALUE_FUNC(int32_t, LC3Initialize, uint8_t, uint8_t, LC3FrameSizeConfig_t, uint8_t, + uint8_t *, uint32_t *); +DECLARE_FAKE_VALUE_FUNC(int32_t OSALCALL, LC3Deinitialize); +DECLARE_FAKE_VALUE_FUNC(LC3EncoderHandle_t OSALCALL, LC3EncodeSessionOpen, uint16_t, uint8_t, + LC3FrameSize_t, uint8_t *, uint16_t *, int32_t *); +DECLARE_FAKE_VALUE_FUNC(int32_t, LC3EncodeSessionData, LC3EncoderHandle_t, LC3EncodeInput_t *, + LC3EncodeOutput_t *); +DECLARE_FAKE_VOID_FUNC1(LC3EncodeSessionClose, LC3EncoderHandle_t); +DECLARE_FAKE_VALUE_FUNC(LC3DecoderHandle_t, LC3DecodeSessionOpen, uint16_t, uint8_t, LC3FrameSize_t, + uint8_t *, uint16_t *, int32_t *); +DECLARE_FAKE_VALUE_FUNC(int32_t, LC3DecodeSessionData, LC3DecoderHandle_t, LC3DecodeInput_t *, + LC3DecodeOutput_t *); +DECLARE_FAKE_VOID_FUNC1(LC3DecodeSessionClose, LC3DecoderHandle_t); +DECLARE_FAKE_VALUE_FUNC(uint16_t, LC3BitstreamBuffersize, uint16_t, uint32_t, LC3FrameSize_t, + int32_t *); +DECLARE_FAKE_VALUE_FUNC(uint16_t, LC3PCMBuffersize, uint16_t, uint8_t, LC3FrameSize_t, int32_t *); + +/* List of fakes used by this unit tester */ +#define DO_FOREACH_FAKE(FUNC) \ + do { \ + FUNC(LC3Initialize) \ + FUNC(LC3Deinitialize) \ + FUNC(LC3EncodeSessionOpen) \ + FUNC(LC3EncodeSessionData) \ + FUNC(LC3EncodeSessionClose) \ + FUNC(LC3DecodeSessionOpen) \ + FUNC(LC3DecodeSessionData) \ + FUNC(LC3DecodeSessionClose) \ + FUNC(LC3BitstreamBuffersize) \ + FUNC(LC3PCMBuffersize) \ + } while (0) + +int32_t fake_LC3Initialize__succeeds(uint8_t encoderSampleRates, uint8_t decoderSampleRates, + LC3FrameSizeConfig_t frameSizeConfig, uint8_t uniqueSessions, + uint8_t *buffer, uint32_t *bufferSize); +int32_t fake_LC3Initialize__fails(uint8_t encoderSampleRates, uint8_t decoderSampleRates, + LC3FrameSizeConfig_t frameSizeConfig, uint8_t uniqueSessions, + uint8_t *buffer, uint32_t *bufferSize); +int32_t fake_LC3Deinitialize__succeeds(void); +int32_t fake_LC3Deinitialize__fails(void); +LC3EncoderHandle_t fake_LC3EncodeSessionOpen__succeeds(uint16_t sampleRate, uint8_t bitsPerSample, + LC3FrameSize_t frameSize, uint8_t *buffer, + uint16_t *bufferSize, int32_t *result); +LC3EncoderHandle_t fake_LC3EncodeSessionOpen__fails(uint16_t sampleRate, uint8_t bitsPerSample, + LC3FrameSize_t frameSize, uint8_t *buffer, + uint16_t *bufferSize, int32_t *result); +int32_t fake_LC3EncodeSessionData__succeeds(LC3EncoderHandle_t encodeHandle, + LC3EncodeInput_t *encodeInput, + LC3EncodeOutput_t *encodeOutput); +int32_t fake_LC3EncodeSessionData__fails(LC3EncoderHandle_t encodeHandle, + LC3EncodeInput_t *encodeInput, + LC3EncodeOutput_t *encodeOutput); +void fake_LC3EncodeSessionClose__succeeds(LC3EncoderHandle_t encodeHandle); +void fake_LC3EncodeSessionClose__fails(LC3EncoderHandle_t encodeHandle); +LC3DecoderHandle_t fake_LC3DecodeSessionOpen__succeeds(uint16_t sampleRate, uint8_t bitsPerSample, + LC3FrameSize_t frameSize, uint8_t *buffer, + uint16_t *bufferSize, int32_t *result); +LC3DecoderHandle_t fake_LC3DecodeSessionOpen__fails(uint16_t sampleRate, uint8_t bitsPerSample, + LC3FrameSize_t frameSize, uint8_t *buffer, + uint16_t *bufferSize, int32_t *result); +int32_t fake_LC3DecodeSessionData__succeeds(LC3DecoderHandle_t decodeHandle, + LC3DecodeInput_t *decodeInput, + LC3DecodeOutput_t *decodeOutput); +int32_t fake_LC3DecodeSessionData__fails(LC3DecoderHandle_t decodeHandle, + LC3DecodeInput_t *decodeInput, + LC3DecodeOutput_t *decodeOutput); +void fake_LC3DecodeSessionClose__succeeds(LC3DecoderHandle_t decodeHandle); +void fake_LC3DecodeSessionClose__fails(LC3DecoderHandle_t decodeHandle); +uint16_t fake_LC3BitstreamBuffersize__succeeds(uint16_t sampleRate, uint32_t maxBitRate, + LC3FrameSize_t frameSize, int32_t *result); +uint16_t fake_LC3BitstreamBuffersize__fails(uint16_t sampleRate, uint32_t maxBitRate, + LC3FrameSize_t frameSize, int32_t *result); +uint16_t fake_LC3PCMBuffersize__succeeds(uint16_t sampleRate, uint8_t bitDepth, + LC3FrameSize_t frameSize, int32_t *result); +uint16_t fake_LC3PCMBuffersize__fails(uint16_t sampleRate, uint8_t bitDepth, + LC3FrameSize_t frameSize, int32_t *result); + +extern uint8_t *ref_in; +extern int ref_in_size; +extern int ref_in_read_size; + +#endif /* _FAKES_H_ */ diff --git a/tests/subsys/audio_modules/lc3_module/src/main.c b/tests/subsys/audio_modules/lc3_module/src/main.c new file mode 100644 index 000000000000..840857420e17 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/main.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include +#include +#include +#include "lc3_test_fakes.h" + +/* This function runs before each test */ +static void run_before(void *fixture) +{ + ARG_UNUSED(fixture); + + /* Register resets */ + DO_FOREACH_FAKE(RESET_FAKE); + + /* Reset common FFF internal structures */ + FFF_RESET_HISTORY(); +} + +ZTEST_SUITE(suite_lc3_decoder_functional, NULL, NULL, run_before, NULL, NULL); +ZTEST_SUITE(suite_lc3_encoder_functional, NULL, NULL, run_before, NULL, NULL); diff --git a/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_lc3.c b/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_lc3.c new file mode 100644 index 000000000000..cfa978af2114 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_lc3.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#include "sweep21ms_16b48khz_mono_lc3.h" + +#include + +uint8_t lc3_mono[LC3_MONO_SIZE] = { + 0x1C, 0xCC, 0x12, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x01, 0x00, 0xE8, 0x03, 0x00, 0x00, 0xE8, + 0x03, 0x00, 0x00, 0x78, 0x00, 0x45, 0x0B, 0x24, 0xBE, 0x5E, 0xAC, 0xFA, 0x38, 0xEE, 0x5B, + 0xFD, 0x7C, 0x8B, 0x9E, 0xF8, 0xC9, 0xF7, 0xED, 0xB9, 0x2C, 0x2A, 0xB3, 0x73, 0x7A, 0x1B, + 0x99, 0x1B, 0x65, 0x5E, 0x44, 0x7D, 0x5A, 0x3A, 0xDE, 0x9F, 0x2F, 0xD8, 0x1B, 0x65, 0xE4, + 0x2E, 0x21, 0x8D, 0x82, 0x21, 0x03, 0x35, 0x00, 0x15, 0xA9, 0xDE, 0x67, 0xA1, 0xF0, 0x00, + 0x00, 0x05, 0x5A, 0x78, 0xE2, 0x7F, 0x08, 0xAB, 0xFE, 0x0B, 0x91, 0xEA, 0x8B, 0x7E, 0x9B, + 0x1E, 0xB4, 0xFE, 0xBE, 0x7C, 0xAC, 0xC7, 0x0B, 0xE8, 0x2F, 0xA0, 0x86, 0x31, 0x5F, 0x5F, + 0x47, 0x2A, 0xF0, 0x3C, 0x47, 0x06, 0x52, 0xFB, 0x08, 0x14, 0xF2, 0x36, 0x17, 0xB2, 0x16, + 0x1F, 0x65, 0x08, 0x3B, 0x23, 0x72, 0x3C, 0x16, 0x01, 0x71, 0xC2, 0xA2, 0xBF, 0x14, 0xAA, + 0x33, 0x9C, 0x3A, 0xA6, 0x3C, 0x78, 0x00, 0x6A, 0x58, 0x75, 0x1A, 0x61, 0x1E, 0xBE, 0xE5, + 0xE8, 0x7A, 0x7D, 0xB0, 0x4D, 0x06, 0x71, 0x53, 0xB9, 0x60, 0xF3, 0x10, 0x1A, 0x03, 0xFB, + 0x47, 0x29, 0x23, 0x12, 0x5A, 0x05, 0x01, 0xA5, 0xB4, 0x20, 0x6F, 0xEA, 0xEF, 0x11, 0x39, + 0xE1, 0x0E, 0x13, 0x21, 0x45, 0x62, 0x4F, 0x18, 0xD8, 0xF9, 0x04, 0xD9, 0x70, 0xCA, 0xF0, + 0xF1, 0x61, 0xC7, 0xD2, 0x3D, 0x2D, 0xF6, 0x87, 0xC8, 0xC6, 0x43, 0x16, 0xCD, 0xD5, 0xAB, + 0xF0, 0x4D, 0xBF, 0xFF, 0x00, 0x00, 0x1F, 0xFC, 0x03, 0xF8, 0x1F, 0x83, 0xE1, 0xE0, 0x74, + 0x7F, 0xC4, 0xB9, 0x42, 0x73, 0x22, 0xCC, 0xD6, 0xD0, 0xDC, 0x06, 0xB4, 0xB2, 0x27, 0x4B, + 0xF2, 0x35, 0x3E, 0x21, 0xC2, 0xE5, 0x83, 0x59, 0x65, 0x69, 0x29, 0x8D, 0x65, 0x92, 0xE0, + 0xF9, 0x9C, 0x08, 0xD6, 0x3F, 0x93, 0x84, 0x78, 0x00, 0xA3, 0xDB, 0xB6, 0x61, 0x33, 0x77, + 0xF9, 0x63, 0x88, 0x1B, 0xC6, 0x03, 0x73, 0x20, 0x04, 0xFF, 0xEF, 0xE8, 0x38, 0x01, 0x35, + 0x97, 0x6A, 0x6D, 0x93, 0xDF, 0x1C, 0x26, 0x0E, 0x99, 0x82, 0x14, 0xCB, 0x08, 0xCF, 0x19, + 0x95, 0x4A, 0x6D, 0x13, 0xCD, 0xDF, 0xEF, 0x17, 0xF1, 0xF6, 0xC5, 0xFA, 0x41, 0xA0, 0x9B, + 0x45, 0x6E, 0xCE, 0xD6, 0x87, 0xCF, 0x9E, 0x05, 0x1C, 0x31, 0x38, 0x7B, 0xAB, 0x9B, 0x60, + 0x8F, 0xA2, 0x18, 0xC8, 0x70, 0x81, 0xEA, 0xAE, 0x06, 0xF6, 0x11, 0x45, 0xA2, 0xBA, 0x17, + 0xA5, 0x72, 0x02, 0xAF, 0x2A, 0xA5, 0x56, 0x35, 0x4A, 0x8A, 0x6D, 0x0F, 0xC5, 0x51, 0xA9, + 0x25, 0x5B, 0x1A, 0x94, 0xF1, 0xB7, 0xF1, 0x0C, 0xC0, 0xD4, 0xFB, 0x1D, 0x6B, 0x62, 0xF9, + 0x61, 0x83, 0xB9, 0x3F, 0xE9, 0xF1, 0x3D, 0x75, 0x2C, +}; diff --git a/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_lc3.h b/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_lc3.h new file mode 100644 index 000000000000..c5266ba1d331 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_lc3.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef _LC3_H_ +#define _LC3_H_ + +#include + +#define LC3_MONO_SIZE (384) + +extern uint8_t lc3_mono[LC3_MONO_SIZE]; + +#endif /* _LC3_H_ */ diff --git a/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_wav.c b/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_wav.c new file mode 100644 index 000000000000..a5ac75bf491b --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_wav.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ +#include "sweep21ms_16b48khz_mono_wav.h" + +#include + +uint16_t wav_mono[WAV_MONO_SIZE] = { + 0xFFFF, 0x0047, 0x0087, 0x00D1, 0x0116, 0x0159, 0x01A7, 0x01E7, 0x0234, 0x027C, 0x02C2, + 0x030F, 0x0357, 0x03A2, 0x03EE, 0x0437, 0x0487, 0x04CE, 0x0522, 0x056A, 0x05B9, 0x060B, + 0x0657, 0x06A7, 0x06FA, 0x0746, 0x079C, 0x07EB, 0x0840, 0x0890, 0x08E6, 0x0939, 0x098C, + 0x09E6, 0x0A36, 0x0A91, 0x0AE4, 0x0B3F, 0x0B95, 0x0BEE, 0x0C49, 0x0C9D, 0x0D01, 0x0D51, + 0x0DB7, 0x0E0B, 0x0E6C, 0x0EC9, 0x0F26, 0x0F84, 0x0FE4, 0x1045, 0x10A2, 0x1109, 0x1162, + 0x11CC, 0x1229, 0x1291, 0x12F1, 0x135B, 0x13B8, 0x1427, 0x1486, 0x14F2, 0x1559, 0x15BE, + 0x162D, 0x168F, 0x1702, 0x1765, 0x17D7, 0x183E, 0x18AE, 0x191B, 0x1987, 0x19F9, 0x1A66, + 0x1AD7, 0x1B47, 0x1BB9, 0x1C2B, 0x1C9C, 0x1D13, 0x1D81, 0x1DFB, 0x1E6E, 0x1EE2, 0x1F5D, + 0x1FCF, 0x204A, 0x20C1, 0x213B, 0x21B2, 0x2231, 0x22A6, 0x2328, 0x239D, 0x2421, 0x2497, + 0x251C, 0x2596, 0x2617, 0x2697, 0x2716, 0x2799, 0x281A, 0x289B, 0x2920, 0x29A1, 0x2A29, + 0x2AA8, 0x2B33, 0x2BB3, 0x2C3F, 0x2CC3, 0x2D4A, 0x2DD3, 0x2E5B, 0x2EE5, 0x2F6F, 0x2FF7, + 0x3084, 0x310D, 0x319B, 0x3226, 0x32B1, 0x3344, 0x33C8, 0x3460, 0x34E7, 0x357B, 0x3608, + 0x3698, 0x3727, 0x37BB, 0x3848, 0x38DF, 0x3969, 0x3A02, 0x3A8F, 0x3B26, 0x3BB7, 0x3C4A, + 0x3CDF, 0x3D71, 0x3E06, 0x3E9B, 0x3F2E, 0x3FC4, 0x4057, 0x40EF, 0x4181, 0x4218, 0x42AE, + 0x433F, 0x43DC, 0x4469, 0x4505, 0x4597, 0x462F, 0x46C1, 0x475A, 0x47EB, 0x4884, 0x4916, + 0x49AC, 0x4A41, 0x4AD3, 0x4B69, 0x4BFA, 0x4C90, 0x4D21, 0x4DB4, 0x4E45, 0x4ED8, 0x4F67, + 0x4FFA, 0x5087, 0x5117, 0x51A7, 0x5231, 0x52C5, 0x5348, 0x53DE, 0x545C, 0x54F2, 0x5572, + 0x55FE, 0x5684, 0x5707, 0x578F, 0x5810, 0x5891, 0x5915, 0x5990, 0x5A13, 0x5A8B, 0x5B07, + 0x5B83, 0x5BF6, 0x5C71, 0x5CE2, 0x5D55, 0x5DC7, 0x5E35, 0x5EA0, 0x5F0E, 0x5F73, 0x5FDD, + 0x603C, 0x60A4, 0x60FE, 0x615F, 0x61B6, 0x6210, 0x6263, 0x62B8, 0x6305, 0x6352, 0x639D, + 0x63E2, 0x6425, 0x6467, 0x64A1, 0x64DC, 0x6512, 0x6543, 0x6573, 0x659C, 0x65C5, 0x65E7, + 0x6605, 0x6622, 0x6636, 0x664B, 0x6657, 0x6661, 0x6665, 0x6667, 0x6660, 0x6659, 0x6648, + 0x6634, 0x661E, 0x65FD, 0x65DC, 0x65B2, 0x6580, 0x6552, 0x6512, 0x64D5, 0x648F, 0x6440, + 0x63F1, 0x6395, 0x6339, 0x62D0, 0x6266, 0x61F0, 0x617A, 0x60F5, 0x6070, 0x5FDF, 0x5F49, + 0x5EAC, 0x5E05, 0x5D5B, 0x5CA4, 0x5BE9, 0x5B25, 0x5A58, 0x5987, 0x58A8, 0x57C6, 0x56D8, + 0x55E4, 0x54E7, 0x53E2, 0x52D2, 0x51BE, 0x509D, 0x4F74, 0x4E46, 0x4D07, 0x4BCB, 0x4A79, + 0x492B, 0x47C6, 0x4667, 0x44EF, 0x437F, 0x41F5, 0x4070, 0x3ED9, 0x3D3C, 0x3B97, 0x39E6, + 0x382F, 0x366D, 0x34A2, 0x32D1, 0x30F2, 0x2F10, 0x2D20, 0x2B2B, 0x292C, 0x2726, 0x2515, + 0x22FE, 0x20E0, 0x1EB4, 0x1C8D, 0x1A4C, 0x1818, 0x15CB, 0x1383, 0x1130, 0x0ED5, 0x0C76, + 0x0A12, 0x07A3, 0x0537, 0x02BE, 0x0045, 0xFDC6, 0xFB41, 0xF8BD, 0xF631, 0xF3A5, 0xF116, + 0xEE82, 0xEBF1, 0xE95B, 0xE6C7, 0xE431, 0xE19C, 0xDF08, 0xDC76, 0xD9E4, 0xD757, 0xD4CA, + 0xD245, 0xCFC1, 0xCD43, 0xCACC, 0xC857, 0xC5F1, 0xC38B, 0xC131, 0xBEE2, 0xBC98, 0xBA5F, + 0xB82B, 0xB60B, 0xB3EE, 0xB1EC, 0xAFEC, 0xAE05, 0xAC29, 0xAA60, 0xA8AA, 0xA706, 0xA578, + 0xA3FA, 0xA297, 0xA147, 0xA00F, 0x9EF1, 0x9DEA, 0x9CFD, 0x9C2C, 0x9B76, 0x9AD9, 0x9A62, + 0x99FC, 0x99C2, 0x999D, 0x999D, 0x99BD, 0x99FF, 0x9A5F, 0x9AE9, 0x9B8E, 0x9C5B, 0x9D4E, + 0x9E5E, 0x9F9C, 0xA0F8, 0xA27C, 0xA426, 0xA5F4, 0xA7E9, 0xAA04, 0xAC42, 0xAEA9, 0xB131, + 0xB3E2, 0xB6B3, 0xB9AE, 0xBCC5, 0xC005, 0xC360, 0xC6E6, 0xCA80, 0xCE45, 0xD21B, 0xD619, + 0xDA2C, 0xDE58, 0xE2A1, 0xE6F8, 0xEB6D, 0xEFEC, 0xF481, 0xF920, 0xFDD0, 0x0281, 0x0746, + 0x0BFF, 0x10CA, 0x1587, 0x1A48, 0x1EFE, 0x23AC, 0x284A, 0x2CDC, 0x3156, 0x35BB, 0x3A05, + 0x3E32, 0x423B, 0x4624, 0x49DF, 0x4D71, 0x50D5, 0x5403, 0x56FE, 0x59BD, 0x5C41, 0x5E83, + 0x6085, 0x623B, 0x63B2, 0x64D0, 0x65AF, 0x662E, 0x6669, 0x6644, 0x65CE, 0x6502, 0x63D7, + 0x625C, 0x607C, 0x5E4B, 0x5BBB, 0x58D2, 0x5593, 0x51FA, 0x4E0D, 0x49CC, 0x453B, 0x405A, + 0x3B34, 0x35C1, 0x3010, 0x2A23, 0x23F7, 0x1DA5, 0x171A, 0x1072, 0x09A8, 0x02C7, 0xFBD9, + 0xF4DE, 0xEDEE, 0xE6FA, 0xE027, 0xD965, 0xD2CC, 0xCC65, 0xC630, 0xC041, 0xBA9C, 0xB549, + 0xB05A, 0xABCB, 0xA7B0, 0xA40B, 0xA0E7, 0x9E49, 0x9C3A, 0x9ABF, 0x99DC, 0x999B, 0x99F9, + 0x9AFD, 0x9CA7, 0x9EF6, 0xA1F2, 0xA58D, 0xA9CD, 0xAEAC, 0xB420, 0xBA2A, 0xC0BD, 0xC7CF, + 0xCF57, 0xD74B, 0xDF97, 0xE836, 0xF111, 0xFA17, 0x0340, 0x0C69, 0x1591, 0x1E97, 0x276A, + 0x2FFD, 0x382D, 0x3FF3, 0x4734, 0x4DDE, 0x53DD, 0x5922, 0x5D98, 0x6133, 0x63E7, 0x65A0, + 0x6661, 0x6617, 0x64C3, 0x6267, 0x5EF6, 0x5A88, 0x550C, 0x4EA6, 0x4748, 0x3F1F, 0x3621, + 0x2C80, 0x2240, 0x178A, 0x0C77, 0x012B, 0xF5C6, 0xEA6F, 0xDF48, 0xD47C, 0xCA2B, 0xC083, + 0xB79F, 0xAFAA, 0xA8C4, 0xA307, 0x9E97, 0x9B7E, 0x99DF, 0x99B8, 0x9B22, 0x9E0E, 0xA28A, + 0xA87C, 0xAFE1, 0xB89A, 0xC28E, 0xCD96, 0xD988, 0xE63A, 0xF36F, 0x00FB, 0x0E91, 0x1C04, + 0x2907, 0x3564, 0x40D1, 0x4B1F, 0x5407, 0x5B5F, 0x60F8, 0x64A1, 0x6652, 0x65DE, 0x6351, + 0x5EA3, 0x57E3, 0x4F31, 0x44AE, 0x388D, 0x2B18, 0x1C7D, 0x0D33, 0xFD68, 0xEDA6, 0xDE2A, + 0xCF73, 0xC1D3, 0xB5AE, 0xAB61, 0xA32E, 0x9D6A, 0x9A33, 0x99C4, 0x9C1E, 0xA147, 0xA928, + 0xB392, 0xC048, 0xCEF5, 0xDF33, 0xF08B, 0x027E, 0x1477, 0x25F0, 0x364E, 0x4505, 0x5193, + 0x5B7B, 0x625E, 0x65F0, 0x65F8, 0x626C, 0x5B54, 0x50DF, 0x4363, 0x3346, 0x2126, 0x0D99, + 0xF969, 0xE555, 0xD22E, 0xC0C0, 0xB1CE, 0xA5FF, 0x9DE9, 0x99F6, 0x9A66, 0x9F51, 0xA890, + 0xB5D4, 0xC693, 0xDA1B, 0xEF8F, 0x05EE, 0x1C2D, 0x312F, 0x43E8, 0x534D, 0x5E97, 0x64FF, + 0x6631, 0x61EA, 0x5857, 0x49DD, 0x372D, 0x2144, 0x094C, 0xF0A6, 0xD8B5, 0xC2F8, 0xB0BA, + 0xA33E, 0x9B62, 0x99D2, 0x9EBA, 0xA9FA, 0xBAE8, 0xD08F, 0xE98A, 0x0439, 0x1ECD, 0x3764, + 0x4C36, 0x5BAF, 0x648F, 0x660B, 0x5FE0, 0x525C, 0x3E68, 0x256D, 0x0950, 0xEC3F, 0xD09E, + 0xB8B3, 0xA69F, 0x9BFB, 0x99EC, 0xA0BD, 0xB00E, 0xC6A4, 0xE297, 0x0178, 0x2061, 0x3C78, + 0x52E4, 0x616C, 0x6664, 0x612B, 0x5204, 0x3A57, 0x1C66, 0xFB44, 0xDA69, 0xBD6E, 0xA798, + 0x9B7D, 0x9AB3, 0xA586, 0xBAFD, 0xD8B2, 0xFB5D, 0x1EC4, 0x3EA9, 0x56EF, 0x6461, 0x6511, + 0x589C, 0x406C, 0x1F73, 0xFA05, 0xD529, 0xB602, 0xA119, 0x9999, 0xA0E7, 0xB634, 0xD6AA, + 0xFD8A, 0x2517, 0x471B, 0x5E31, 0x6666, 0x5E1D, 0x465F, 0x22C3, 0xF919, 0xD04F, 0xAF88, + 0x9CA2, 0x9B47, 0xAC15, 0xCC48, 0xF653, 0x2265, 0x4843, 0x6065, 0x65DC, 0x572C, 0x36E0, + 0x0B30, 0xDCEF, 0xB5AE, 0x9DFB, 0x9B2B, 0xAE55, 0xD3A6, 0x0323, 0x3239, 0x560A, 0x660B, + 0x5E00, 0x3F6B, 0x1134, 0xDE7F, 0xB3CD, 0x9C1E, 0x9DE5, 0xB92A, 0xE744, 0x1C44, 0x49F0, + 0x63A2, 0x61C9, 0x4460, 0x1342, 0xDC45, 0xAF65, 0x9A40, 0xA397, 0xC942, 0x0012, 0x373C, + 0x5D21, 0x654B, 0x4C5C, 0x1A0C, 0xDEA3, 0xAE41, 0x99B8, 0xA8CF, 0xD6D9, 0x13F0, 0x4A24, + 0x655C, 0x5ADD, 0x2DF0, 0xEF18, 0xB67A, 0x9A75, 0xA6D7, 0xD75B, 0x18D6, 0x5060, 0x6666, + 0x50D9, 0x1837, 0xD4A3, 0xA3EA, 0x9C5E, 0xC22F, 0x04D4, 0x458D, 0x65B0, 0x5510, 0x1AF1, + 0xD328, 0xA169, 0x9F57, 0xCEE6, 0x1849, 0x5548, 0x6508, 0x3E31, 0xF4FC, 0xB187, 0x99DF, + 0xBC60, 0x062D, 0x4CBB, 0x662B, 0x4246, 0xF5D5, 0xAF3F, 0x9AC9, 0xC656, 0x1724, 0x594D, + 0x6102, 0x27FC, 0xD3AC, 0x9D3E, 0xAB18, 0xF4A9, 0x46B0, 0x6628, 0x3B1F, 0xE424, 0xA19A, + 0xA66A, 0xF02C, 0x469E, 0x65BF, 0x33B4, 0xD78D, 0x9C22, 0xB362, 0x0B35, 0x59DF, 0x5B60, + 0x0CFE, 0xB2C9, 0x9D5B, 0xE16B, 0x41DC, 0x6574, 0x2980, 0xC5B3, 0x99D1, 0xD1CE, 0x37D5, + 0x6638, 0x2CE9, 0xC51D, 0x9A4B, 0xDA9C, 0x4326, 0x6371, 0x16F6, 0xB0B4, 0xA31C, 0xFF04, + 0x5C6B, 0x4E7C, 0xE3F8, 0x9A87, 0xCB74, 0x3CD2, 0x6344, 0x0D6D, 0xA648, 0xB200, 0x231F, + 0x6667, 0x218F, 0xAF4F, 0xAABD, 0x1BD0, 0x665C, 0x2076, 0xABFB, 0xB0BD, 0x2998, 0x6518, + 0x0938, 0x9F26, 0xC973, 0x4886, 0x55F8, 0xDAD7, 0x9B37, 0xFF55, 0x64BA, 0x22B8, 0xA62F, + 0xC254, 0x48AE, 0x50A9, 0xCAA6, 0xA377, 0x22E5, 0x62E1, 0xECDE, 0x9A62, 0x0725, 0x665E, + 0x00A3, 0x99A5, 0xFBEF, 0x6650, 0x0312, 0x9999, 0x026F, 0x662A, 0xF38F, 0x9B67, 0x1AD0, + 0x6011, 0xD31A, 0xA98E, 0x4118, 0x458E, 0xAB76, 0xD451, 0x62B0, 0x08E6, 0x9A31, 0x1FC9, + 0x5812, 0xB8EC, 0xC9B2, 0x61C8, 0x0342, 0x9CCF, 0x352E, 0x433D, 0xA17A, 0xF9D4, 0x6233, + 0xC227, 0xCAAA, 0x6516, 0xE786, 0xAEE1, 0x5A97, 0x0457, 0xA245, 0x4F40, 0x146C, 0x9E1F, + 0x4A51, 0x176B, 0x9E8B, 0x4E30, 0x0D45, 0xA41C, 0x5940, 0xF550, 0xB425, 0x649D, 0xD11C, + 0xD687, 0x627F, 0xAAA1, 0x0E52, 0x4121, 0x99D6, 0x4C52, 0xF9E3, 0xBDA1, 0x65B2, 0xAC59, + 0x186E, 0x2D39, 0xA302, 0x63A6, 0xBEB7, 0x064A, 0x359C, 0xA2B5, 0x6535, 0xB27C, +}; diff --git a/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_wav.h b/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_wav.h new file mode 100644 index 000000000000..addeb05e592c --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/src/sweep21ms_16b48khz_mono_wav.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause + */ + +#ifndef _WAV_H_ +#define _WAV_H_ + +#include + +#define WAV_MONO_SIZE (1000) + +extern uint16_t wav_mono[WAV_MONO_SIZE]; + +#endif /* _WAV_H_ */ diff --git a/tests/subsys/audio_modules/lc3_module/testcase.yaml b/tests/subsys/audio_modules/lc3_module/testcase.yaml new file mode 100644 index 000000000000..573480765441 --- /dev/null +++ b/tests/subsys/audio_modules/lc3_module/testcase.yaml @@ -0,0 +1,7 @@ +tests: + nrf5340_audio.lc3_module_test: + sysbuild: true + platform_allow: qemu_cortex_m3 + integration_platforms: + - qemu_cortex_m3 + tags: lc3_module audio_module nrf5340_audio_unit_tests sysbuild