From f15eab0548839cc40d028232eeac9c1c1f6bb47b Mon Sep 17 00:00:00 2001 From: Eddy Hsu Date: Wed, 31 Jan 2024 15:03:49 -0800 Subject: [PATCH] comp: Add initial Google CTC component Introduce a new component to perform crosstalk-cancellation on the playback path. Signed-off-by: Eddy Hsu --- app/overlays/mtl/ctc_overlay.conf | 4 + src/arch/host/configs/library_defconfig | 1 + src/audio/google/CMakeLists.txt | 20 + src/audio/google/Kconfig | 57 ++ .../google/google_ctc_audio_processing.c | 543 ++++++++++++++++++ .../google/google_ctc_audio_processing.toml | 17 + .../google/google_ctc_audio_processing_mock.c | 81 +++ src/include/sof/audio/component.h | 1 + .../include/google_ctc_audio_processing.h | 44 ++ ..._ctc_audio_processing_sof_message_reader.h | 30 + tools/rimage/config/mtl.toml.h | 4 + zephyr/CMakeLists.txt | 19 + 12 files changed, 821 insertions(+) create mode 100644 app/overlays/mtl/ctc_overlay.conf create mode 100644 src/audio/google/google_ctc_audio_processing.c create mode 100644 src/audio/google/google_ctc_audio_processing.toml create mode 100644 src/audio/google/google_ctc_audio_processing_mock.c create mode 100644 third_party/include/google_ctc_audio_processing.h create mode 100644 third_party/include/google_ctc_audio_processing_sof_message_reader.h diff --git a/app/overlays/mtl/ctc_overlay.conf b/app/overlays/mtl/ctc_overlay.conf new file mode 100644 index 000000000000..8aa78a1e374c --- /dev/null +++ b/app/overlays/mtl/ctc_overlay.conf @@ -0,0 +1,4 @@ +CONFIG_COMP_STUBS=n +CONFIG_COMP_MODULE_ADAPTER=y +CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=y +CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=n diff --git a/src/arch/host/configs/library_defconfig b/src/arch/host/configs/library_defconfig index deed943ab818..81226d252c82 100644 --- a/src/arch/host/configs/library_defconfig +++ b/src/arch/host/configs/library_defconfig @@ -4,6 +4,7 @@ CONFIG_COMP_DCBLOCK=y CONFIG_COMP_DRC=y CONFIG_COMP_FIR=y CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING=y +CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING=y CONFIG_COMP_IIR=y CONFIG_COMP_IGO_NR=y CONFIG_COMP_MFCC=y diff --git a/src/audio/google/CMakeLists.txt b/src/audio/google/CMakeLists.txt index 3936c8041b67..b6f8d3725cd8 100644 --- a/src/audio/google/CMakeLists.txt +++ b/src/audio/google/CMakeLists.txt @@ -29,6 +29,26 @@ if((NOT CONFIG_LIBRARY) OR CONFIG_LIBRARY_STATIC) target_link_libraries(sof PRIVATE c) endif() endif() + + if(CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING) + target_include_directories(sof PRIVATE ${CMAKE_SOURCE_DIR}/third_party/include) + add_local_sources(sof + google_ctc_audio_processing.c + ) + if(CONFIG_GOOGLE_CTC_AUDIO_PROCESSING_MOCK) + add_local_sources(sof + google_ctc_audio_processing_mock.c + ) + else() + message(INFO "Link with google_ctc_audio_processing") + target_link_directories(sof PRIVATE ${CMAKE_SOURCE_DIR}/third_party/lib) + target_link_libraries(sof PRIVATE google_ctc_audio_processing) + target_link_libraries(sof PRIVATE c++) + target_link_libraries(sof PRIVATE c++abi) + target_link_libraries(sof PRIVATE m) + target_link_libraries(sof PRIVATE c) + endif() + endif() return() endif() diff --git a/src/audio/google/Kconfig b/src/audio/google/Kconfig index 67d9a29171ac..6d984ea9780d 100644 --- a/src/audio/google/Kconfig +++ b/src/audio/google/Kconfig @@ -93,4 +93,61 @@ config GOOGLE_RTC_AUDIO_PROCESSING_MOCK Mock Google real-time communication audio processing. It allows for compilation check and basic audio flow checking. +config COMP_GOOGLE_CTC_AUDIO_PROCESSING + bool "Google Crosstalk Cancellation Audio processing" + select COMP_BLOB + select GOOGLE_CTC_AUDIO_PROCESSING_MOCK if COMP_STUBS + default n + help + Select for Google crosstalk cancellation audio processing. It + uses the Google real-time audio processing library to perform + crosstalk cancellation. + +config COMP_GOOGLE_CTC_AUDIO_PROCESSING_NUM_FRAMES + depends on COMP_GOOGLE_CTC_AUDIO_PROCESSING + int "Number of frames to process for Google Crosstalk Cancellation Audio processing" + default 64 + help + Sets the number of frames to process in the Google crosstalk + cancellation audio processing. + +config COMP_GOOGLE_CTC_AUDIO_PROCESSING_MAX_NUM_CHANNELS + depends on COMP_GOOGLE_CTC_AUDIO_PROCESSING + int "Max number of channels to process for Google Crosstalk Cancellation Audio processing" + default 2 + help + Sets the max number of channels to process in the Google crosstalk + cancellation audio processing. + +config COMP_GOOGLE_CTC_AUDIO_PROCESSING_PARTITION_SIZE + depends on COMP_GOOGLE_CTC_AUDIO_PROCESSING + int "Partition size to process for Google Crosstalk Cancellation Audio processing" + default 64 + help + Sets the partition size to process in the Google crosstalk + cancellation audio processing. + +config COMP_GOOGLE_CTC_AUDIO_PROCESSING_IMPULSE_SIZE + depends on COMP_GOOGLE_CTC_AUDIO_PROCESSING + int "Impulse size to process for Google Crosstalk Cancellation Audio processing" + default 256 + help + Sets the impulse size to process in the Google crosstalk + cancellation audio processing. + +config COMP_GOOGLE_CTC_AUDIO_PROCESSING_SAMPLE_RATE + depends on COMP_GOOGLE_CTC_AUDIO_PROCESSING + int "Sample rate to process for Google Crosstalk Cancellation Audio processing" + default 48000 + help + Sets the sample rate to process in the Google crosstalk + cancellation audio processing. + +config GOOGLE_CTC_AUDIO_PROCESSING_MOCK + bool "Google Crosstalk Cancellation Audio processing mock" + default n + depends on COMP_GOOGLE_CTC_AUDIO_PROCESSING + help + Mock Google crosstalk cancellation audio processing. + It allows for compilation check and basic audio flow checking. endmenu diff --git a/src/audio/google/google_ctc_audio_processing.c b/src/audio/google/google_ctc_audio_processing.c new file mode 100644 index 000000000000..efe269ccd729 --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Google LLC. +// +// Author: Eddy Hsu +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +LOG_MODULE_REGISTER(google_ctc_audio_processing, CONFIG_SOF_LOG_LEVEL); + +/* bf0e1bbc-dc6a-45fe-bc90-2554cb137ab4 */ +DECLARE_SOF_RT_UUID("google-ctc-audio-processing", google_ctc_audio_processing_uuid, + 0xbf0e1bbc, 0xdc6a, 0x45fe, 0xbc, 0x90, 0x25, 0x54, 0xcb, + 0x13, 0x7a, 0xb4); + +DECLARE_TR_CTX(google_ctc_audio_processing_tr, SOF_UUID(google_ctc_audio_processing_uuid), + LOG_LEVEL_INFO); + +struct google_ctc_audio_processing_comp_data; + +typedef void (*ctc_func)(struct google_ctc_audio_processing_comp_data *cd, + const struct audio_stream *source, + struct audio_stream *sink, + uint32_t frames); + +struct ctc_func_map { + enum sof_ipc_frame fmt; /**< source frame format */ + ctc_func func; /**< processing function */ +}; + +struct google_ctc_audio_processing_comp_data { + float *input; + float *output; + uint32_t num_frames; + uint32_t num_channels; + GoogleCtcAudioProcessingState *state; + struct comp_data_blob_handler *tuning_handler; + bool reconfigure; + ctc_func ctc_func; +}; + +static inline int16_t convert_float_to_int16(float data) +{ +#if XCHAL_HAVE_HIFI3 + const xtfloat ratio = 2 << 15; + xtfloat x0 = data; + xtfloat x1; + int16_t x; + + x1 = XT_MUL_S(x0, ratio); + x = XT_TRUNC_S(x1, 0); + + return x; +#else /* XCHAL_HAVE_HIFI3 */ + return Q_CONVERT_FLOAT(data, 15); +#endif /* XCHAL_HAVE_HIFI3 */ +} + +static inline float convert_int16_to_float(int16_t data) +{ +#if XCHAL_HAVE_HIFI3 + const xtfloat ratio = 2 << 15; + xtfloat x0 = data; + float x; + + x = XT_DIV_S(x0, ratio); + + return x; +#else /* XCHAL_HAVE_HIFI3 */ + return Q_CONVERT_QTOF(data, 15); +#endif /* XCHAL_HAVE_HIFI3 */ +} + +static inline int32_t convert_float_to_int32(float data) +{ +#if XCHAL_HAVE_HIFI3 + const xtfloat ratio = 2 << 15; + xtfloat x0 = data; + xtfloat x1; + int32_t x; + + x1 = XT_MUL_S(x0, ratio); + x = XT_TRUNC_S(x1, 0); + + return x; +#else /* XCHAL_HAVE_HIFI3 */ + return Q_CONVERT_FLOAT(data, 15); +#endif /* XCHAL_HAVE_HIFI3 */ +} + +static inline float convert_int32_to_float(int32_t data) +{ +#if XCHAL_HAVE_HIFI3 + const xtfloat ratio = 2 << 15; + xtfloat x0 = data; + float x; + + x = XT_DIV_S(x0, ratio); + + return x; +#else /* XCHAL_HAVE_HIFI3 */ + return Q_CONVERT_QTOF(data, 15); +#endif /* XCHAL_HAVE_HIFI3 */ +} + +static void ctc_s16_default(struct google_ctc_audio_processing_comp_data *cd, + const struct audio_stream *source, + struct audio_stream *sink, + uint32_t frames) +{ + int n_ch = audio_stream_get_channels(source); + + int samples = frames * n_ch; + int samples_to_process; + + int16_t *src = audio_stream_get_rptr(source); + int16_t *dest = audio_stream_get_wptr(sink); + + while (samples) { + samples_to_process = MIN(samples, + audio_stream_samples_without_wrap_s16(source, src)); + samples_to_process = MIN(samples_to_process, + audio_stream_samples_without_wrap_s16(sink, dest)); + for (int i = 0; i < samples_to_process; i ++) { + cd->input[i] = convert_int16_to_float(src[i]); + cd->output[i] = 0; + } + GoogleCtcAudioProcessingProcess(cd->state, cd->input, cd->output, + samples_to_process / n_ch, n_ch); + for (int i = 0; i < samples_to_process; i ++) { + dest[i] = convert_float_to_int16(cd->output[i]); + } + samples -= samples_to_process; + src = audio_stream_wrap(source, src + samples_to_process); + dest = audio_stream_wrap(sink, dest + samples_to_process); + } +} + +static void ctc_s24_default(struct google_ctc_audio_processing_comp_data *cd, + const struct audio_stream *source, + struct audio_stream *sink, + uint32_t frames) +{ + int n_ch = audio_stream_get_channels(source); + int samples = frames * n_ch; + int samples_to_process; + + int32_t *src = audio_stream_get_rptr(source); + int32_t *dest = audio_stream_get_wptr(sink); + + while (samples) { + // TODO(eddyhsu): fix s24 + samples_to_process = MIN(samples, + audio_stream_samples_without_wrap_s24(source, src)); + samples_to_process = MIN(samples_to_process, + audio_stream_samples_without_wrap_s24(sink, dest)); + for (int i = 0; i < samples_to_process; i ++) { + cd->input[i] = convert_int32_to_float(src[i]); + cd->output[i] = 0; + } + GoogleCtcAudioProcessingProcess(cd->state, cd->input, cd->output, + samples_to_process / n_ch, n_ch); + for (int i = 0; i < samples_to_process; i ++) { + dest[i] = convert_float_to_int32(cd->output[i]); + } + samples -= samples_to_process; + src = audio_stream_wrap(source, src + samples_to_process); + dest = audio_stream_wrap(sink, dest + samples_to_process); + } + +} + +static void ctc_s32_default(struct google_ctc_audio_processing_comp_data *cd, + const struct audio_stream *source, + struct audio_stream *sink, + uint32_t frames) +{ + int n_ch = audio_stream_get_channels(source); + int samples = frames * n_ch; + int samples_to_process; + + int32_t *src = audio_stream_get_rptr(source); + int32_t *dest = audio_stream_get_wptr(sink); + + while (samples) { + samples_to_process = MIN(samples, + audio_stream_samples_without_wrap_s32(source, src)); + samples_to_process = MIN(samples_to_process, + audio_stream_samples_without_wrap_s32(sink, dest)); + for (int i = 0; i < samples_to_process; i ++) { + cd->input[i] = convert_int32_to_float(src[i]); + cd->output[i] = 0; + } + GoogleCtcAudioProcessingProcess(cd->state, cd->input, cd->output, + samples_to_process / n_ch, n_ch); + for (int i = 0; i < samples_to_process; i ++) { + dest[i] = convert_float_to_int32(cd->output[i]); + } + samples -= samples_to_process; + src = audio_stream_wrap(source, src + samples_to_process); + dest = audio_stream_wrap(sink, dest + samples_to_process); + } +} + +/* Processing functions table */ +const struct ctc_func_map ctc_fnmap[] = { +#if CONFIG_FORMAT_S16LE + { SOF_IPC_FRAME_S16_LE, ctc_s16_default }, +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S24LE + { SOF_IPC_FRAME_S24_4LE, ctc_s24_default }, +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + { SOF_IPC_FRAME_S32_LE, ctc_s32_default }, +#endif /* CONFIG_FORMAT_S32LE */ +}; + +const size_t ctc_fncount = ARRAY_SIZE(ctc_fnmap); + +/** + * \brief Retrieves an CTC processing function matching + * the source buffer's frame format. + * \param fmt the frames' format of the source and sink buffers + */ +static ctc_func ctc_find_func(enum sof_ipc_frame fmt) +{ + int i; + + /* Find suitable processing function from map */ + for (i = 0; i < ctc_fncount; i++) { + if (fmt == ctc_fnmap[i].fmt) + return ctc_fnmap[i].func; + } + + return NULL; +} + +static int ctc_free(struct processing_module *mod) +{ + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + + if (cd) { + rfree(cd->input); + rfree(cd->output); + if (cd->state) { + GoogleCtcAudioProcessingFree(cd->state); + cd->state = NULL; + } + module_set_private_data(mod, NULL); + } + + return 0; +} + +static int ctc_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + struct comp_dev *dev = mod->dev; + struct google_ctc_audio_processing_comp_data *cd; + int ret; + int buf_size; + + comp_info(dev, "ctc_init()"); + + /* Create private component data */ + cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) { + ret = -ENOMEM; + goto fail; + } + + module_set_private_data(mod, cd); + + cd->num_frames = CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING_NUM_FRAMES; + cd->num_channels = CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING_MAX_NUM_CHANNELS; + + buf_size = cd->num_frames * sizeof(cd->input[0]) * cd->num_channels; + cd->input = rballoc(0, SOF_MEM_CAPS_RAM, buf_size); + if (!cd->input) { + ret = -ENOMEM; + goto fail; + } + + buf_size = cd->num_frames * sizeof(cd->output[0]) * cd->num_channels; + cd->output = rballoc(0, SOF_MEM_CAPS_RAM, buf_size); + if (!cd->output) { + ret = -ENOMEM; + goto fail; + } + + cd->state = GoogleCtcAudioProcessingCreateWithConfig( + cd->num_frames, + CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING_PARTITION_SIZE, + CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING_IMPULSE_SIZE, + CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING_SAMPLE_RATE, + /*is_symmetric=*/0, /*config=*/NULL, /*config_size=*/0); + + cd->tuning_handler = comp_data_blob_handler_new(dev); + if (!cd->tuning_handler) { + ret = -ENOMEM; + goto fail; + } + + comp_dbg(dev, "ctc_init(): Ready"); + + return 0; +fail: + comp_err(dev, "ctc_init(): Failed"); + ctc_free(mod); + return ret; +} + +static int google_ctc_audio_processing_reconfigure(struct processing_module *mod) +{ + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + uint8_t *config; + size_t size; + int ret; + + comp_dbg(dev, "google_ctc_audio_processing_reconfigure()"); + + config = comp_get_data_blob(cd->tuning_handler, &size, NULL); + if (size == 0) { + /* No data to be handled */ + return 0; + } + + if (!config) { + comp_err(dev, "google_ctc_audio_processing_reconfigure(): Tuning config not set"); + return -EINVAL; + } + + comp_info(dev, "google_ctc_audio_processing_reconfigure(): New tuning config %p (%zu bytes)", + config, size); + + cd->reconfigure = false; + + uint8_t *processing_config; + size_t processing_config_size; + bool processing_config_present; + + GoogleCtcAudioProcessingParseSofConfigMessage(config, size, + &processing_config, + &processing_config_size, + &processing_config_present); + + if (processing_config_present) { + comp_info(dev, + "google_ctc_audio_processing_reconfigure(): Applying config of size %zu bytes", + processing_config_size); + + ret = GoogleCtcAudioProcessingReconfigure(cd->state, + processing_config, + processing_config_size); + if (ret) { + comp_err(dev, "GoogleCtcAudioProcessingReconfigure failed: %d", + ret); + return ret; + } + } + + return 0; +} + +static int ctc_prepare(struct processing_module *mod, + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) +{ + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + struct comp_dev *dev = mod->dev; + struct comp_buffer *source; + int ret; + + comp_info(mod->dev, "ctc_prepare()"); + + source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); + cd->ctc_func = ctc_find_func(audio_stream_get_frm_fmt(&source->stream)); + if (!cd->ctc_func) { + comp_err(mod->dev, "ctc_prepare(): No suitable processing function found."); + ret = -EINVAL; + goto err; + } + + return 0; +err: + return ret; +} + +static int ctc_reset(struct processing_module *mod) +{ + comp_dbg(mod->dev, "ctc_reset()"); + + return 0; +} + +static int ctc_process(struct processing_module *mod, + struct input_stream_buffer *input_buffers, + int num_input_buffers, + struct output_stream_buffer *output_buffers, + int num_output_buffers) +{ + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + struct audio_stream *source = input_buffers[0].data; + struct audio_stream *sink = output_buffers[0].data; + uint32_t frames = input_buffers[0].size; + + int ret; + + comp_dbg(mod->dev, "ctc_process()"); + + if (cd->reconfigure) { + ret = google_ctc_audio_processing_reconfigure(mod); + if (ret) + return ret; + } + + cd->ctc_func(cd, source, sink, frames); + + module_update_buffer_position(&input_buffers[0], &output_buffers[0], frames); + return 0; +} + +#if CONFIG_IPC_MAJOR_3 +static int ctc_cmd_set_data(struct processing_module *mod, + struct sof_ipc_ctrl_data *cdata) +{ + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + int ret; + + switch (cdata->cmd) { + case SOF_CTRL_CMD_BINARY: + ret = comp_data_blob_set_cmd(cd->tuning_handler, cdata); + if (ret) + return ret; + if (comp_is_new_data_blob_available(cd->tuning_handler)) { + comp_get_data_blob(cd->tuning_handler, NULL, NULL); + cd->reconfigure = true; + } + return 0; + default: + comp_err(mod->dev, + "google_ctc_audio_processing_ctrl_set_data(): Only binary controls supported %d", + cdata->cmd); + return -EINVAL; + } +} + +static int ctc_cmd_get_data(struct processing_module *mod, + struct sof_ipc_ctrl_data *cdata, + size_t max_data_size) +{ + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + + comp_info(mod->dev, "google_ctc_audio_processing_ctrl_get_data(): %u", cdata->cmd); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_BINARY: + return comp_data_blob_get_cmd(cd->tuning_handler, cdata, max_data_size); + default: + comp_err(mod->dev, + "google_ctc_audio_processing_ctrl_get_data(): Only binary controls supported %d", + cdata->cmd); + return -EINVAL; + } +} +#endif + +static int ctc_set_config(struct processing_module *mod, uint32_t param_id, + enum module_cfg_fragment_position pos, + uint32_t data_offset_size, + const uint8_t *fragment, + size_t fragment_size, uint8_t *response, + size_t response_size) +{ +#if CONFIG_IPC_MAJOR_4 + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + int ret; + + switch (param_id) { + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + comp_err(mod->dev, "google_ctc_audio_processing_set_data(): Only binary controls supported"); + return -EINVAL; + } + + ret = comp_data_blob_set(cd->tuning_handler, pos, data_offset_size, + fragment, fragment_size); + if (ret) + return ret; + + if (comp_is_new_data_blob_available(cd->tuning_handler)) { + comp_get_data_blob(cd->tuning_handler, NULL, NULL); + cd->reconfigure = true; + } + + return 0; +#elif CONFIG_IPC_MAJOR_3 + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + + return ctc_cmd_set_data(mod, cdata); +#endif +} + +static int ctc_get_config(struct processing_module *mod, + uint32_t param_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ +#if CONFIG_IPC_MAJOR_4 + comp_err(mod->dev, "ctc_get_config(): Not supported"); + return -EINVAL; +#elif CONFIG_IPC_MAJOR_3 + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + + return ctc_cmd_get_data(mod, cdata, fragment_size); +#endif +} + +static struct module_interface google_ctc_audio_processing_interface = { + .init = ctc_init, + .free = ctc_free, + .process_audio_stream = ctc_process, + .prepare = ctc_prepare, + .set_configuration = ctc_set_config, + .get_configuration = ctc_get_config, + .reset = ctc_reset, +}; + +DECLARE_MODULE_ADAPTER(google_ctc_audio_processing_interface, + google_ctc_audio_processing_uuid, google_ctc_audio_processing_tr); +SOF_MODULE_INIT(google_ctc_audio_processing, + sys_comp_module_google_ctc_audio_processing_interface_init); diff --git a/src/audio/google/google_ctc_audio_processing.toml b/src/audio/google/google_ctc_audio_processing.toml new file mode 100644 index 000000000000..0466dfb3dba7 --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing.toml @@ -0,0 +1,17 @@ + # CTC module config + [[module.entry]] + name = "CTC" + uuid = "BF0E1BBC-DC6A-45FE-BC90-2554CB137AB4" + affinity_mask = "0x1" + instance_count = "40" + domain_types = "0" + load_type = "0" + module_type = "9" + auto_start = "0" + sched_caps = [1, 0x00008000] + # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] + mod_cfg = [0, 0, 0, 0, 4096, 1000000, 128, 128, 0, 0, 0] + + index = __COUNTER__ diff --git a/src/audio/google/google_ctc_audio_processing_mock.c b/src/audio/google/google_ctc_audio_processing_mock.c new file mode 100644 index 000000000000..49868fead984 --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing_mock.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Google LLC. +// +// Author: Eddy Hsu +#include "google_ctc_audio_processing.h" + +#include +#include +#include +#include + +#include "ipc/topology.h" + +struct GoogleCtcAudioProcessingState { + int num_frames; + int partition_size; + int impulse_size; + int sample_rate; + int is_symmetric; +}; + +GoogleCtcAudioProcessingState *GoogleCtcAudioProcessingCreate(void) +{ + struct GoogleCtcAudioProcessingState *s = + rballoc(0, SOF_MEM_CAPS_RAM, sizeof(GoogleCtcAudioProcessingState)); + if (!s) + return NULL; + + s->num_frames = CONFIG_COMP_GOOGLE_CTC_AUDIO_PROCESSING_NUM_FRAMES; + s->partition_size = 64; + s->impulse_size = 256; + s->sample_rate = 48000; + s->is_symmetric = 0; + return s; +} + +GoogleCtcAudioProcessingState *GoogleCtcAudioProcessingCreateWithConfig( + int num_frames, int partition_size, int impulse_size, int sample_rate, + int is_symmetric, const uint8_t *config, int config_size) +{ + struct GoogleCtcAudioProcessingState *s = + rballoc(0, SOF_MEM_CAPS_RAM, sizeof(GoogleCtcAudioProcessingState)); + if (!s) + return NULL; + + s->num_frames = num_frames; + s->partition_size = partition_size; + s->impulse_size = impulse_size; + s->sample_rate = sample_rate; + s->is_symmetric = is_symmetric; + return s; +} + +void GoogleCtcAudioProcessingFree(GoogleCtcAudioProcessingState *state) +{ + rfree(state); +} + +void GoogleCtcAudioProcessingProcess(GoogleCtcAudioProcessingState *state, + const float *src, float *dest, + int num_frames, int num_channels) +{ + memcpy_s(dest, sizeof(float) * num_frames * num_channels, + src, sizeof(float) * num_frames * num_channels); +} + +void GoogleCtcAudioProcessingParseSofConfigMessage( + uint8_t *message, size_t message_size, + uint8_t **config, size_t *config_size, bool *config_present) +{ + *config = NULL; + *config_size = 0; + *config_present = false; +} + +int GoogleCtcAudioProcessingReconfigure(GoogleCtcAudioProcessingState *state, + const uint8_t *config, int config_size) +{ + return 0; +} diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index 9f427cccb6ed..937f98ee60f3 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -707,6 +707,7 @@ void sys_comp_module_dts_interface_init(void); void sys_comp_module_eq_fir_interface_init(void); void sys_comp_module_eq_iir_interface_init(void); void sys_comp_module_google_rtc_audio_processing_interface_init(void); +void sys_comp_module_google_ctc_audio_processing_interface_init(void); void sys_comp_module_igo_nr_interface_init(void); void sys_comp_module_mfcc_interface_init(void); void sys_comp_module_mixer_interface_init(void); diff --git a/third_party/include/google_ctc_audio_processing.h b/third_party/include/google_ctc_audio_processing.h new file mode 100644 index 000000000000..957f19dc904e --- /dev/null +++ b/third_party/include/google_ctc_audio_processing.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 Google LLC. + * + * Author: Eddy Hsu + */ +#ifndef GOOGLE_CTC_AUDIO_PROCESSING_H +#define GOOGLE_CTC_AUDIO_PROCESSING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GoogleCtcAudioProcessingState GoogleCtcAudioProcessingState; + +// Creates an instance of GoogleCtcAudioProcessing with the tuning embedded in +// the library. If creation fails, NULL is returned. +GoogleCtcAudioProcessingState *GoogleCtcAudioProcessingCreate(void); + +GoogleCtcAudioProcessingState *GoogleCtcAudioProcessingCreateWithConfig( + int num_frames, int partition_size, int impulse_size, int sample_rate, + int is_symmetric, const uint8_t *config, int config_size); + +// Frees all allocated resources in `state`. +void GoogleCtcAudioProcessingFree(GoogleCtcAudioProcessingState *state); + +// Apply CTC on `src` and produce result in `dest`. +void GoogleCtcAudioProcessingProcess(GoogleCtcAudioProcessingState *state, + const float *src, float *dest, + int num_frames, int num_channels); + + +// Reconfigure the audio processing. +// Returns 0 if success and non zero if failure. +int GoogleCtcAudioProcessingReconfigure(GoogleCtcAudioProcessingState *state, + const uint8_t *config, int config_size); + +#ifdef __cplusplus +} +#endif + +#endif // GOOGLE_CTC_AUDIO_PROCESSING_H diff --git a/third_party/include/google_ctc_audio_processing_sof_message_reader.h b/third_party/include/google_ctc_audio_processing_sof_message_reader.h new file mode 100644 index 000000000000..febff51d12a4 --- /dev/null +++ b/third_party/include/google_ctc_audio_processing_sof_message_reader.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * Copyright(c) 2024 Google LLC. + * + * Author: Eddy Hsu + */ +#ifndef GOOGLE_CTC_AUDIO_PROCESSING_SOF_MESSAGE_READER_H_ +#define GOOGLE_CTC_AUDIO_PROCESSING_SOF_MESSAGE_READER_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Parses the fields from a SOF config message `message` of size `message_size` +// intended for the GoogleCtcAudioProcessing component and the corresponding +// outputs parameters based on the content. Any previous content in the output +// parameters is overwritten regardless of the content in `message`. +void GoogleCtcAudioProcessingParseSofConfigMessage( + uint8_t *message, size_t message_size, + uint8_t **config, size_t *config_size, bool *config_present); + +#ifdef __cplusplus +} +#endif + +#endif // GOOGLE_CTC_AUDIO_PROCESSING_SOF_MESSAGE_READER_H_ diff --git a/tools/rimage/config/mtl.toml.h b/tools/rimage/config/mtl.toml.h index a1c23dbcba2c..7b867981706f 100644 --- a/tools/rimage/config/mtl.toml.h +++ b/tools/rimage/config/mtl.toml.h @@ -106,6 +106,10 @@ #include