From b2521eaa7ba39b74d782b38dbd66413b234d8be2 Mon Sep 17 00:00:00 2001 From: Eddy Hsu Date: Mon, 15 Jul 2024 20:34:56 +0000 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 --- src/arch/host/configs/library_defconfig | 1 + src/audio/google/CMakeLists.txt | 25 + src/audio/google/Kconfig | 20 + .../google/google_ctc_audio_processing.c | 427 ++++++++++++++++++ .../google/google_ctc_audio_processing.h | 55 +++ .../google/google_ctc_audio_processing.toml | 17 + .../google/google_ctc_audio_processing_ipc3.c | 65 +++ .../google/google_ctc_audio_processing_ipc4.c | 60 +++ .../google/google_ctc_audio_processing_mock.c | 70 +++ src/include/sof/audio/component.h | 1 + .../include/google_ctc_audio_processing.h | 44 ++ ..._ctc_audio_processing_sof_message_reader.h | 32 ++ tools/rimage/config/mtl.toml.h | 4 + uuid-registry.txt | 1 + zephyr/CMakeLists.txt | 27 ++ 15 files changed, 849 insertions(+) create mode 100644 src/audio/google/google_ctc_audio_processing.c create mode 100644 src/audio/google/google_ctc_audio_processing.h create mode 100644 src/audio/google/google_ctc_audio_processing.toml create mode 100644 src/audio/google/google_ctc_audio_processing_ipc3.c create mode 100644 src/audio/google/google_ctc_audio_processing_ipc4.c 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/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..a53374e3a95a 100644 --- a/src/audio/google/CMakeLists.txt +++ b/src/audio/google/CMakeLists.txt @@ -29,6 +29,31 @@ 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_IPC_MAJOR_3) + add_local_sources(sof google_ctc_audio_processing_ipc3.c) + elseif(CONFIG_IPC_MAJOR_4) + add_local_sources(sof google_ctc_audio_processing_ipc4.c) + endif() + 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 f5bdfe033a1b..336817112301 100644 --- a/src/audio/google/Kconfig +++ b/src/audio/google/Kconfig @@ -88,4 +88,24 @@ config GOOGLE_RTC_AUDIO_PROCESSING_MOCK endif # COMP_GOOGLE_RTC_AUDIO_PROCESSING +config COMP_GOOGLE_CTC_AUDIO_PROCESSING + bool "Google Crosstalk Cancellation Audio processing" + select COMP_BLOB + select GOOGLE_CTC_AUDIO_PROCESSING_MOCK if COMP_STUBS + select STATIC_INIT_GNU if ZEPHYR_SOF_MODULE + default n + depends on ZEPHYR_SOF_MODULE + help + Select for Google crosstalk cancellation audio processing. It + uses the Google real-time audio processing library to perform + crosstalk cancellation. + +config GOOGLE_CTC_AUDIO_PROCESSING_MOCK + bool "Google Crosstalk Cancellation Audio processing mock" + default y if COMP_STUBS + 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..47205cdb3a99 --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing.c @@ -0,0 +1,427 @@ +// 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 + +#include "google_ctc_audio_processing.h" + +LOG_MODULE_REGISTER(google_ctc_audio_processing, CONFIG_SOF_LOG_LEVEL); + +SOF_DEFINE_REG_UUID(google_ctc_audio_processing); + +DECLARE_TR_CTX(google_ctc_audio_processing_tr, SOF_UUID(google_ctc_audio_processing_uuid), + LOG_LEVEL_INFO); + +// TODO(eddyhsu): Share these utils function with RTC. +static inline float clamp_rescale(float max_val, float x) +{ + float min = -1.0f; + float max = 1.0f - 1.0f / max_val; + + return max_val * (x < min ? min : (x > max ? max : x)); +} + +static inline int16_t convert_float_to_int16(float data) +{ + return (int16_t)clamp_rescale(-(float)SHRT_MIN, data); +} + +static inline float convert_int16_to_float(int16_t data) +{ + float scale = -(float)SHRT_MIN; + + return (1.0f / scale) * data; +} + +static inline int32_t convert_float_to_int32(float data) +{ + return (int32_t)clamp_rescale(-(float)INT_MIN, data); +} + +static inline float convert_int32_to_float(int32_t data) +{ + float scale = -(float)INT_MIN; + + return (1.0f / scale) * data; +} + +static const int kChunkFrames = 48; +static const int kMaxChannels = 2; + +#if CONFIG_FORMAT_S16LE +static void ctc_s16_default(struct google_ctc_audio_processing_comp_data *cd, + const struct audio_stream *source, + struct audio_stream *sink, + struct input_stream_buffer *input_buffers, + struct output_stream_buffer *output_buffers, + uint32_t frames) +{ + int n_ch = audio_stream_get_channels(source); + int samples = frames * n_ch; + + int16_t *src = audio_stream_get_rptr(source); + int16_t *dest = audio_stream_get_wptr(sink); + + int samples_to_process = MIN(samples, audio_stream_samples_without_wrap_s16(source, src)); + int samples_to_written = MIN(samples, audio_stream_samples_without_wrap_s16(sink, dest)); + int written_samples = 0; + + // writes previous processed samples to the output. + while (cd->next_avail_output_samples < cd->chunk_frames * n_ch && + written_samples < samples_to_written) { + dest[written_samples++] = + convert_float_to_int16(cd->output[cd->next_avail_output_samples]); + cd->next_avail_output_samples++; + } + for (int i = 0; i < samples_to_process; ++i) { + cd->input[cd->input_samples++] = convert_int16_to_float(src[i]); + if (cd->input_samples == cd->chunk_frames * n_ch) { + GoogleCtcAudioProcessingProcess(cd->state, cd->input, cd->output, + cd->chunk_frames, n_ch); + cd->input_samples = 0; + cd->next_avail_output_samples = 0; + // writes processed samples to the output. + while (cd->next_avail_output_samples < cd->chunk_frames * n_ch && + written_samples < samples_to_written) { + dest[written_samples++] = + convert_float_to_int16(cd->output[cd->next_avail_output_samples]); + cd->next_avail_output_samples++; + } + } + } + if (written_samples > 0) { + dest = audio_stream_wrap(sink, dest + written_samples); + output_buffers->size += audio_stream_frame_bytes(sink) * written_samples / n_ch; + } + src = audio_stream_wrap(source, src + samples_to_process); + input_buffers->consumed += audio_stream_frame_bytes(source) * samples_to_process / n_ch; +} +#endif + +#if CONFIG_FORMAT_S24LE +static void ctc_s24_default(struct google_ctc_audio_processing_comp_data *cd, + const struct audio_stream *source, + struct audio_stream *sink, + struct input_stream_buffer *input_buffers, + struct output_stream_buffer *output_buffers, + uint32_t frames) +{ + int n_ch = audio_stream_get_channels(source); + int samples = frames * n_ch; + + int32_t *src = audio_stream_get_rptr(source); + int32_t *dest = audio_stream_get_wptr(sink); + + int samples_to_process = MIN(samples, audio_stream_samples_without_wrap_s24(source, src)); + int samples_to_written = MIN(samples, audio_stream_samples_without_wrap_s24(sink, dest)); + int written_samples = 0; + + // writes previous processed samples to the output. + while (cd->next_avail_output_samples < cd->chunk_frames * n_ch && + written_samples < samples_to_written) { + dest[written_samples++] = + convert_float_to_int32(cd->output[cd->next_avail_output_samples]); + cd->next_avail_output_samples++; + } + for (int i = 0; i < samples_to_process; ++i) { + cd->input[cd->input_samples++] = convert_int32_to_float(src[i]); + if (cd->input_samples == cd->chunk_frames * n_ch) { + GoogleCtcAudioProcessingProcess(cd->state, cd->input, cd->output, + cd->chunk_frames, n_ch); + cd->input_samples = 0; + cd->next_avail_output_samples = 0; + // writes processed samples to the output. + while (cd->next_avail_output_samples < cd->chunk_frames * n_ch && + written_samples < samples_to_written) { + dest[written_samples++] = + convert_float_to_int32(cd->output[cd->next_avail_output_samples]); + cd->next_avail_output_samples++; + } + } + } + if (written_samples > 0) { + dest = audio_stream_wrap(sink, dest + written_samples); + output_buffers->size += audio_stream_frame_bytes(sink) * written_samples / n_ch; + } + src = audio_stream_wrap(source, src + samples_to_process); + input_buffers->consumed += audio_stream_frame_bytes(source) * samples_to_process / n_ch; +} +#endif + +#if CONFIG_FORMAT_S32LE +static void ctc_s32_default(struct google_ctc_audio_processing_comp_data *cd, + const struct audio_stream *source, + struct audio_stream *sink, + struct input_stream_buffer *input_buffers, + struct output_stream_buffer *output_buffers, + uint32_t frames) +{ + int n_ch = audio_stream_get_channels(source); + int samples = frames * n_ch; + + int32_t *src = audio_stream_get_rptr(source); + int32_t *dest = audio_stream_get_wptr(sink); + + int samples_to_process = MIN(samples, audio_stream_samples_without_wrap_s32(source, src)); + int samples_to_written = MIN(samples, audio_stream_samples_without_wrap_s32(sink, dest)); + int written_samples = 0; + + // writes previous processed samples to the output. + while (cd->next_avail_output_samples < cd->chunk_frames * n_ch && + written_samples < samples_to_written) { + dest[written_samples++] = + convert_float_to_int32(cd->output[cd->next_avail_output_samples]); + cd->next_avail_output_samples++; + } + for (int i = 0; i < samples_to_process; ++i) { + cd->input[cd->input_samples++] = convert_int32_to_float(src[i]); + if (cd->input_samples == cd->chunk_frames * n_ch) { + GoogleCtcAudioProcessingProcess(cd->state, cd->input, cd->output, + cd->chunk_frames, n_ch); + cd->input_samples = 0; + cd->next_avail_output_samples = 0; + // writes processed samples to the output. + while (cd->next_avail_output_samples < cd->chunk_frames * n_ch && + written_samples < samples_to_written) { + dest[written_samples++] = + convert_float_to_int32(cd->output[cd->next_avail_output_samples]); + cd->next_avail_output_samples++; + } + } + } + if (written_samples > 0) { + dest = audio_stream_wrap(sink, dest + written_samples); + output_buffers->size += audio_stream_frame_bytes(sink) * written_samples / n_ch; + } + src = audio_stream_wrap(source, src + samples_to_process); + input_buffers->consumed += audio_stream_frame_bytes(source) * samples_to_process / n_ch; +} +#endif + +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); + GoogleCtcAudioProcessingFree(cd->state); + rfree(cd); + module_set_private_data(mod, NULL); + } + + return 0; +} + +static int ctc_init(struct processing_module *mod) +{ + struct comp_dev *dev = mod->dev; + struct google_ctc_audio_processing_comp_data *cd; + 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) { + comp_err(dev, "ctc_init(): Failed to create component data"); + ctc_free(mod); + return -ENOMEM; + } + + module_set_private_data(mod, cd); + + cd->chunk_frames = kChunkFrames; + buf_size = cd->chunk_frames * sizeof(cd->input[0]) * kMaxChannels; + + cd->input = rballoc(0, SOF_MEM_CAPS_RAM, buf_size); + if (!cd->input) { + comp_err(dev, "ctc_init(): Failed to allocate input buffer"); + ctc_free(mod); + return -ENOMEM; + } + cd->output = rballoc(0, SOF_MEM_CAPS_RAM, buf_size); + if (!cd->output) { + comp_err(dev, "ctc_init(): Failed to allocate output buffer"); + ctc_free(mod); + return -ENOMEM; + } + + cd->tuning_handler = comp_data_blob_handler_new(dev); + if (!cd->tuning_handler) { + comp_err(dev, "ctc_init(): Failed to create tuning handler"); + ctc_free(mod); + return -ENOMEM; + } + + comp_dbg(dev, "ctc_init(): Ready"); + + return 0; +} + +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; + enum sof_ipc_frame fmt; + int num_channels; + + comp_info(mod->dev, "ctc_prepare()"); + + source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list); + switch (audio_stream_get_frm_fmt(&source->stream)) { +#if CONFIG_FORMAT_S16LE + case SOF_IPC_FRAME_S16_LE: + cd->ctc_func = ctc_s16_default; + break; +#endif +#if CONFIG_FORMAT_S24LE + case SOF_IPC_FRAME_S24_4LE: + cd->ctc_func = ctc_s24_default; + break; +#endif +#if CONFIG_FORMAT_S32LE + case SOF_IPC_FRAME_S32_LE: + cd->ctc_func = ctc_s32_default; + break; +#endif + default: + comp_err(mod->dev, "ctc_prepare(), invalid frame_fmt"); + return -EINVAL; + } + + num_channels = audio_stream_get_channels(&source->stream); + if (num_channels > kMaxChannels) { + comp_err(mod->dev, "ctc_prepare(), invalid number of channels"); + return -EINVAL; + } + cd->next_avail_output_samples = cd->chunk_frames * num_channels; + + cd->state = GoogleCtcAudioProcessingCreateWithConfig(cd->chunk_frames, + audio_stream_get_rate(&source->stream), + /*config=*/NULL, + /*config_size=*/0); + + return 0; +} + +static int ctc_reset(struct processing_module *mod) +{ + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + + comp_info(mod->dev, "ctc_reset()"); + + GoogleCtcAudioProcessingFree(cd->state); + cd->ctc_func = NULL; + 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, &input_buffers[0], &output_buffers[0], frames); + return 0; +} + +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.h b/src/audio/google/google_ctc_audio_processing.h new file mode 100644 index 000000000000..8fb00d9a5c7d --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2024 Google LLC. + * + * Author: Eddy Hsu + */ +#ifndef __SOF_AUDIO_GOOGLE_GOOGLE_CTC_AUDIO_PROCESSING_H__ +#define __SOF_AUDIO_GOOGLE_GOOGLE_CTC_AUDIO_PROCESSING_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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, + struct input_stream_buffer *input_buffers, + struct output_stream_buffer *output_buffers, + uint32_t frames); + +struct google_ctc_audio_processing_comp_data { + float *input; + float *output; + uint32_t input_samples; + uint32_t next_avail_output_samples; + uint32_t chunk_frames; + GoogleCtcAudioProcessingState *state; + struct comp_data_blob_handler *tuning_handler; + bool reconfigure; + ctc_func ctc_func; +}; + +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); + +int ctc_get_config(struct processing_module *mod, + uint32_t param_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size); + +#endif // __SOF_AUDIO_GOOGLE_GOOGLE_CTC_AUDIO_PROCESSING_H__ 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..849689dcc7fc --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing.toml @@ -0,0 +1,17 @@ + REM # 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] + REM # pin = [dir, type, sample rate, size, container, channel-cfg] + pin = [0, 0, 0xfeef, 0xf, 0xf, 0x45ff, 1, 0, 0xfeef, 0xf, 0xf, 0x1ff] + REM # 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_ipc3.c b/src/audio/google/google_ctc_audio_processing_ipc3.c new file mode 100644 index 000000000000..04e2bc563801 --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing_ipc3.c @@ -0,0 +1,65 @@ +// 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 "google_ctc_audio_processing.h" + +LOG_MODULE_DECLARE(google_ctc_audio_processing, CONFIG_SOF_LOG_LEVEL); + +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) +{ + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + 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; + } +} + +int ctc_get_config(struct processing_module *mod, + uint32_t param_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + struct sof_ipc_ctrl_data *cdata = (struct sof_ipc_ctrl_data *)fragment; + 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, fragment_size); + default: + return -EINVAL; + } +} diff --git a/src/audio/google/google_ctc_audio_processing_ipc4.c b/src/audio/google/google_ctc_audio_processing_ipc4.c new file mode 100644 index 000000000000..f02f749d3689 --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing_ipc4.c @@ -0,0 +1,60 @@ +// 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 "google_ctc_audio_processing.h" + +LOG_MODULE_DECLARE(google_ctc_audio_processing, CONFIG_SOF_LOG_LEVEL); + +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) +{ + struct google_ctc_audio_processing_comp_data *cd = module_get_private_data(mod); + int ret; + + switch (param_id) { + case 0: + break; + case SOF_IPC4_SWITCH_CONTROL_PARAM_ID: + case SOF_IPC4_ENUM_CONTROL_PARAM_ID: + default: + 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; +} + +int ctc_get_config(struct processing_module *mod, + uint32_t param_id, uint32_t *data_offset_size, + uint8_t *fragment, size_t fragment_size) +{ + comp_err(mod->dev, "ctc_get_config(): Not supported"); + return -EINVAL; +} 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..fe5c8fa79a5c --- /dev/null +++ b/src/audio/google/google_ctc_audio_processing_mock.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2024 Google LLC. +// +// Author: Eddy Hsu +#include "google_ctc_audio_processing.h" +#include "google_ctc_audio_processing_sof_message_reader.h" + +#include +#include +#include +#include + +#include "ipc/topology.h" + +struct GoogleCtcAudioProcessingState { +}; + +GoogleCtcAudioProcessingState *GoogleCtcAudioProcessingCreate(void) +{ + struct GoogleCtcAudioProcessingState *s = + rballoc(0, SOF_MEM_CAPS_RAM, sizeof(GoogleCtcAudioProcessingState)); + if (!s) + return NULL; + + return s; +} + +GoogleCtcAudioProcessingState *GoogleCtcAudioProcessingCreateWithConfig(int chunk_size, + int sample_rate, + const uint8_t *config, + int config_size) +{ + struct GoogleCtcAudioProcessingState *s = + rballoc(0, SOF_MEM_CAPS_RAM, sizeof(GoogleCtcAudioProcessingState)); + if (!s) + return NULL; + + 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 1bd3f50bce32..c10b3bf67858 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -752,6 +752,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..6c473425c3b8 --- /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 chunk_frames, + int sample_rate, + 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..0066c5ff5117 --- /dev/null +++ b/third_party/include/google_ctc_audio_processing_sof_message_reader.h @@ -0,0 +1,32 @@ +/* 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 62d14c5d88be..b4258c262607 100644 --- a/tools/rimage/config/mtl.toml.h +++ b/tools/rimage/config/mtl.toml.h @@ -108,6 +108,10 @@ #include