diff --git a/src/audio/CMakeLists.txt b/src/audio/CMakeLists.txt index 5b3fd261139b..9be7bcb50e26 100644 --- a/src/audio/CMakeLists.txt +++ b/src/audio/CMakeLists.txt @@ -70,6 +70,28 @@ if(NOT CONFIG_LIBRARY) target_link_libraries(sof PRIVATE c) target_link_libraries(sof PRIVATE m) endif() + + if(CONFIG_COMP_GOOGLE_RTC_AUDIO_PROCESSING) + target_include_directories(sof PRIVATE ${CMAKE_SOURCE_DIR}/third_party/include) + add_local_sources(sof + google_rtc_audio_processing.c + ) + if(CONFIG_GOOGLE_RTC_AUDIO_PROCESSING_MOCK) + add_local_sources(sof + google_rtc_audio_processing_mock.c + ) + else() + message(INFO "Link with google_rtc_audio_processing") + target_link_directories(sof PRIVATE ${CMAKE_SOURCE_DIR}/third_party/lib) + target_link_libraries(sof PRIVATE google_rtc_audio_processing) + target_link_libraries(sof PRIVATE google_rtc_audio_processing_tuning) + 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() + if(CONFIG_COMP_SEL) add_subdirectory(selector) endif() diff --git a/src/audio/Kconfig b/src/audio/Kconfig index c67c225e3035..55f4741aa723 100644 --- a/src/audio/Kconfig +++ b/src/audio/Kconfig @@ -145,6 +145,25 @@ config COMP_GOOGLE_HOTWORD_DETECT be set using the byte control 'Hotword Model' before running the detector. +config COMP_GOOGLE_RTC_AUDIO_PROCESSING + bool "Google Real Time Communication Audio processing" + default n + help + Select for Google real-time communication audio processing. It + uses the Google real-time audio processing library to perform + echo-cancelling and other processing. + This component takes raw microphones input and playback reference + and outputs an echo-free microphone signal. + +config GOOGLE_RTC_AUDIO_PROCESSING_MOCK + bool "Google Real Time Communication Audio processing mock" + default n + depends on COMP_GOOGLE_RTC_AUDIO_PROCESSING + help + Mock Google real-time communication audio processing. + It allows for compilation check and basic audio flow checking. + + config COMP_SEL bool "Channel selector component" default y diff --git a/src/audio/google_rtc_audio_processing.c b/src/audio/google_rtc_audio_processing.c new file mode 100644 index 000000000000..8ab910e04e77 --- /dev/null +++ b/src/audio/google_rtc_audio_processing.c @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2021 Google LLC. +// +// Author: Lionel Koenig +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define GOOGLE_RTC_AUDIO_PROCESSING_SAMPLERATE 48000 + +/* b780a0a6-269f-466f-b477-23dfa05af758 */ +DECLARE_SOF_RT_UUID("google-rtc-audio-processing", google_rtc_audio_processing_uuid, + 0xb780a0a6, 0x269f, 0x466f, 0xb4, 0x77, 0x23, 0xdf, 0xa0, + 0x5a, 0xf7, 0x58); +DECLARE_TR_CTX(google_rtc_audio_processing_tr, SOF_UUID(google_rtc_audio_processing_uuid), + LOG_LEVEL_INFO); + +struct google_rtc_audio_processing_comp_data { + struct comp_buffer *raw_microphone; + struct comp_buffer *aec_reference; + struct comp_buffer *output; + uint32_t num_frames; + GoogleRtcAudioProcessingState *state; + int16_t *aec_reference_buffer; + int16_t aec_reference_buffer_index; + int16_t *raw_mic_buffer; + int16_t raw_mic_buffer_index; + int16_t *output_buffer; + int16_t output_buffer_index; + struct comp_data_blob_handler *tuning_handler; +}; + +void *GoogleRtcMalloc(size_t size) +{ + return rballoc(0, SOF_MEM_CAPS_RAM, size); +} + +void GoogleRtcFree(void *ptr) +{ + return rfree(ptr); +} + +static int google_rtc_audio_processing_params( + struct comp_dev *dev, + struct sof_ipc_stream_params *params) +{ + int ret; + + ret = comp_verify_params(dev, 0, params); + if (ret < 0) { + comp_err(dev, + "google_rtc_audio_processing_params(): comp_verify_params failed."); + return -EINVAL; + } + + return 0; +} + +static int google_rtc_audio_processing_cmd_set_data( + struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata) +{ + struct google_rtc_audio_processing_comp_data *cd = comp_get_drvdata(dev); + + switch (cdata->cmd) { + case SOF_CTRL_CMD_BINARY: + return comp_data_blob_set_cmd(cd->tuning_handler, cdata); + default: + comp_err(dev, + "google_rtc_audio_processing_ctrl_set_data(): Only binary controls supported %d", + cdata->cmd); + return -EINVAL; + } +} + +static int google_rtc_audio_processing_cmd_get_data( + struct comp_dev *dev, + struct sof_ipc_ctrl_data *cdata, + int max_data_size) +{ + struct google_rtc_audio_processing_comp_data *cd = comp_get_drvdata(dev); + + comp_info(dev, "google_rtc_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(dev, + "google_rtc_audio_processing_ctrl_get_data(): Only binary controls supported %d", + cdata->cmd); + return -EINVAL; + } +} + +static int google_rtc_audio_processing_cmd(struct comp_dev *dev, int cmd, void *data, + int max_data_size) +{ + struct sof_ipc_ctrl_data *cdata = data; + + comp_dbg(dev, "google_rtc_audio_processing_cmd(): %d - data_cmd: %d", cmd, cdata->cmd); + + switch (cmd) { + case COMP_CMD_SET_DATA: + return google_rtc_audio_processing_cmd_set_data(dev, cdata); + case COMP_CMD_GET_DATA: + return google_rtc_audio_processing_cmd_get_data(dev, cdata, max_data_size); + default: + comp_err(dev, "google_rtc_audio_processing_cmd(): Unknown cmd %d", cmd); + return -EINVAL; + } +} + +static struct comp_dev *google_rtc_audio_processing_create( + const struct comp_driver *drv, + struct sof_ipc_comp *comp_template) +{ + struct comp_dev *dev; + struct google_rtc_audio_processing_comp_data *cd; + + comp_cl_info(drv, "google_rtc_audio_processing_create()"); + + /* Create component device with an effect processing component */ + dev = comp_alloc(drv, sizeof(*dev)); + if (!dev) + return NULL; + + /* Create private component data */ + cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd)); + if (!cd) + goto fail; + + cd->tuning_handler = comp_data_blob_handler_new(dev); + if (!cd->tuning_handler) + goto fail; + + cd->state = GoogleRtcAudioProcessingCreate(); + if (!cd->state) { + comp_err(dev, "Failed to initialized GoogleRtcAudioProcessing"); + goto fail; + } + + cd->num_frames = GOOGLE_RTC_AUDIO_PROCESSING_SAMPLERATE * + GoogleRtcAudioProcessingGetFramesizeInMs(cd->state) / 1000; + + cd->raw_mic_buffer = rballoc( + 0, SOF_MEM_CAPS_RAM, + cd->num_frames * sizeof(cd->raw_mic_buffer[0])); + if (!cd->raw_mic_buffer) + goto fail; + bzero(cd->raw_mic_buffer, cd->num_frames * sizeof(cd->raw_mic_buffer[0])); + cd->raw_mic_buffer_index = 0; + + cd->aec_reference_buffer = rballoc( + 0, SOF_MEM_CAPS_RAM, + cd->num_frames * sizeof(cd->aec_reference_buffer[0])); + if (!cd->aec_reference_buffer) + goto fail; + bzero(cd->aec_reference_buffer, cd->num_frames * sizeof(cd->aec_reference_buffer[0])); + cd->aec_reference_buffer_index = 0; + + cd->output_buffer = rballoc( + 0, SOF_MEM_CAPS_RAM, + cd->num_frames * sizeof(cd->output_buffer[0])); + if (!cd->output_buffer) + goto fail; + bzero(cd->output_buffer, cd->num_frames * sizeof(cd->output_buffer[0])); + cd->output_buffer_index = 0; + + comp_set_drvdata(dev, cd); + dev->state = COMP_STATE_READY; + comp_dbg(dev, "google_rtc_audio_processing_create(): Ready"); + return dev; +fail: + comp_err(dev, "google_rtc_audio_processing_create(): Failed"); + if (cd) { + rfree(cd->output_buffer); + rfree(cd->aec_reference_buffer); + rfree(cd->raw_mic_buffer); + comp_data_blob_handler_free(cd->tuning_handler); + rfree(cd); + } + rfree(dev); + return NULL; +} + +static void google_rtc_audio_processing_free(struct comp_dev *dev) +{ + struct google_rtc_audio_processing_comp_data *cd = comp_get_drvdata(dev); + + comp_dbg(dev, "google_rtc_audio_processing_free()"); + + GoogleRtcAudioProcessingFree(cd->state); + cd->state = NULL; + rfree(cd->output_buffer); + rfree(cd->aec_reference_buffer); + rfree(cd->raw_mic_buffer); + comp_data_blob_handler_free(cd->tuning_handler); + rfree(cd); + rfree(dev); +} + + +static int google_rtc_audio_processing_trigger(struct comp_dev *dev, int cmd) +{ + comp_dbg(dev, "google_rtc_audio_processing_trigger(): %d", cmd); + + return comp_set_state(dev, cmd); +} + +static int google_rtc_audio_processing_prepare(struct comp_dev *dev) +{ + struct google_rtc_audio_processing_comp_data *cd = comp_get_drvdata(dev); + struct comp_buffer *source_buffer; + struct list_item *source_buffer_list_item; + uint32_t flags; + + comp_dbg(dev, "google_rtc_audio_processing_prepare()"); + + /* searching for stream and feedback source buffers */ + list_for_item(source_buffer_list_item, &dev->bsource_list) { + source_buffer = container_of(source_buffer_list_item, struct comp_buffer, + sink_list); + buffer_lock(source_buffer, &flags); + if (source_buffer->source->comp.type == SOF_COMP_DEMUX) + cd->aec_reference = source_buffer; + else if (source_buffer->source->comp.type == SOF_COMP_DAI) + cd->raw_microphone = source_buffer; + buffer_unlock(source_buffer, flags); + } + + cd->output = list_first_item(&dev->bsink_list, struct comp_buffer, source_list); + + switch (cd->output->stream.frame_fmt) { +#if CONFIG_FORMAT_S16LE + case SOF_IPC_FRAME_S16_LE: + break; +#endif /* CONFIG_FORMAT_S16LE */ + default: + comp_err(dev, "unsupported data format: %d", cd->output->stream.frame_fmt); + return -EINVAL; + } + + if (cd->output->stream.rate != GOOGLE_RTC_AUDIO_PROCESSING_SAMPLERATE) { + comp_err(dev, "unsupported samplerate: %d", cd->output->stream.rate); + return -EINVAL; + } + + return comp_set_state(dev, COMP_TRIGGER_PREPARE); +} + +static int google_rtc_audio_processing_reset(struct comp_dev *dev) +{ + comp_dbg(dev, "google_rtc_audio_processing_reset()"); + + return comp_set_state(dev, COMP_TRIGGER_RESET); +} + +static int google_rtc_audio_processing_copy(struct comp_dev *dev) +{ + struct google_rtc_audio_processing_comp_data *cd = comp_get_drvdata(dev); + + struct comp_copy_limits cl; + int frame; + uint32_t aec_reference_buff_frag; + uint32_t raw_microphone_buff_frag; + uint32_t output_buff_frag; + int16_t *src; + int16_t *dst; + uint32_t num_aec_reference_frames; + uint32_t num_aec_reference_bytes; + uint32_t flags; + + buffer_lock(cd->aec_reference, &flags); + num_aec_reference_frames = audio_stream_get_avail_frames(&cd->aec_reference->stream); + num_aec_reference_bytes = audio_stream_get_avail_bytes(&cd->aec_reference->stream); + buffer_unlock(cd->aec_reference, flags); + + buffer_invalidate(cd->aec_reference, num_aec_reference_bytes); + + aec_reference_buff_frag = 0; + for (frame = 0; frame < num_aec_reference_frames; frame++) { + src = audio_stream_read_frag_s16(&cd->aec_reference->stream, + aec_reference_buff_frag); + cd->aec_reference_buffer[cd->aec_reference_buffer_index] = *src; + ++cd->aec_reference_buffer_index; + + if (cd->aec_reference_buffer_index == cd->num_frames) { + GoogleRtcAudioProcessingAnalyzeRender_int16(cd->state, + cd->aec_reference_buffer); + cd->aec_reference_buffer_index = 0; + } + aec_reference_buff_frag += cd->aec_reference->stream.channels; + } + comp_update_buffer_consume(cd->aec_reference, num_aec_reference_bytes); + + comp_get_copy_limits_with_lock(cd->raw_microphone, cd->output, &cl); + buffer_invalidate(cd->raw_microphone, cl.source_bytes); + + raw_microphone_buff_frag = 0; + output_buff_frag = 0; + for (frame = 0; frame < cl.frames; frame++) { + src = audio_stream_read_frag_s16(&cd->raw_microphone->stream, + raw_microphone_buff_frag); + cd->raw_mic_buffer[cd->raw_mic_buffer_index] = *src; + ++cd->raw_mic_buffer_index; + + dst = audio_stream_read_frag_s16(&cd->output->stream, output_buff_frag); + *dst = cd->output_buffer[cd->output_buffer_index]; + ++cd->output_buffer_index; + + if (cd->raw_mic_buffer_index == cd->num_frames) { + GoogleRtcAudioProcessingProcessCapture_int16( + cd->state, cd->raw_mic_buffer, + cd->output_buffer); + cd->output_buffer_index = 0; + cd->raw_mic_buffer_index = 0; + } + + raw_microphone_buff_frag += cd->raw_microphone->stream.channels; + output_buff_frag += cd->output->stream.channels; + } + + buffer_writeback(cd->output, cl.sink_bytes); + + comp_update_buffer_produce(cd->output, cl.sink_bytes); + comp_update_buffer_consume(cd->raw_microphone, cl.source_bytes); + return 0; +} + +static const struct comp_driver google_rtc_audio_processing = { + .uid = SOF_RT_UUID(google_rtc_audio_processing_uuid), + .tctx = &google_rtc_audio_processing_tr, + .ops = { + .create = google_rtc_audio_processing_create, + .free = google_rtc_audio_processing_free, + .params = google_rtc_audio_processing_params, + .cmd = google_rtc_audio_processing_cmd, + .trigger = google_rtc_audio_processing_trigger, + .copy = google_rtc_audio_processing_copy, + .prepare = google_rtc_audio_processing_prepare, + .reset = google_rtc_audio_processing_reset, + }, +}; + +static SHARED_DATA struct comp_driver_info google_rtc_audio_processing_info = { + .drv = &google_rtc_audio_processing, +}; + +UT_STATIC void sys_comp_google_rtc_audio_processing_init(void) +{ + comp_register( + platform_shared_get( + &google_rtc_audio_processing_info, + sizeof(google_rtc_audio_processing_info))); +} + +DECLARE_MODULE(sys_comp_google_rtc_audio_processing_init); diff --git a/src/audio/google_rtc_audio_processing_mock.c b/src/audio/google_rtc_audio_processing_mock.c new file mode 100644 index 000000000000..2876780bb459 --- /dev/null +++ b/src/audio/google_rtc_audio_processing_mock.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2021 Google LLC. +// +// Author: Lionel Koenig +#include "google_rtc_audio_processing.h" + +#include +#include +#include + +#include "sof/lib/alloc.h" +#include "ipc/topology.h" + +#define GOOGLE_RTC_AUDIO_PROCESSING_SAMPLE_RATE_HZ 48000 + +struct GoogleRtcAudioProcessingState { + int num_capture_channels; + int num_aec_reference_channels; + int num_output_channels; + int num_frames; + int16_t *aec_reference; +}; + +GoogleRtcAudioProcessingState *GoogleRtcAudioProcessingCreate() +{ + struct GoogleRtcAudioProcessingState *s = + rballoc(0, SOF_MEM_CAPS_RAM, sizeof(GoogleRtcAudioProcessingState)); + s->num_capture_channels = 1; + s->num_aec_reference_channels = 1; + s->num_output_channels = 1; + s->num_frames = GOOGLE_RTC_AUDIO_PROCESSING_SAMPLE_RATE_HZ * 10 / 1000; + s->aec_reference = rballoc(0, + SOF_MEM_CAPS_RAM, + sizeof(s->aec_reference[0]) * + s->num_frames * + s->num_aec_reference_channels + ); + return s; +} + +void GoogleRtcAudioProcessingFree(GoogleRtcAudioProcessingState *state) +{ + if (state != NULL) { + rfree(state->aec_reference); + rfree(state); + } +} + +int GoogleRtcAudioProcessingGetFramesizeInMs(GoogleRtcAudioProcessingState *state) +{ + return state->num_frames * 1000 / GOOGLE_RTC_AUDIO_PROCESSING_SAMPLE_RATE_HZ; +} + +int GoogleRtcAudioProcessingProcessCapture_int16( + GoogleRtcAudioProcessingState *const state, const int16_t *const src, + int16_t *const dest) +{ + int16_t *ref = state->aec_reference; + int16_t *mic = (int16_t *) src; + int16_t *out = dest; + int n; + + for (n = 0; n < state->num_frames; ++n) { + *out = *mic + *ref; + ref += state->num_aec_reference_channels; + out += state->num_output_channels; + mic += state->num_capture_channels; + } + return 0; +} + +int GoogleRtcAudioProcessingAnalyzeRender_int16( + GoogleRtcAudioProcessingState *const state, const int16_t *const data) +{ + const size_t buffer_size = + sizeof(state->aec_reference[0]) + * state->num_frames + * state->num_aec_reference_channels; + memcpy_s(state->aec_reference, buffer_size, + data, buffer_size); + return 0; +} diff --git a/third_party/include/google_rtc_audio_processing.h b/third_party/include/google_rtc_audio_processing.h new file mode 100644 index 000000000000..6832391311ec --- /dev/null +++ b/third_party/include/google_rtc_audio_processing.h @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2021 Google LLC. +// +// Author: Lionel Koenig +#ifndef GOOGLE_RTC_AUDIO_PROCESSING_H +#define GOOGLE_RTC_AUDIO_PROCESSING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// This define ensure that the linked library matches the header file. +#define GoogleRtcAudioProcessingCreate GoogleRtcAudioProcessingCreate_v1 + +typedef struct GoogleRtcAudioProcessingState GoogleRtcAudioProcessingState; + +// Creates an instance of GoogleRtcAudioProcessing with the tuning embedded in +// the library. +GoogleRtcAudioProcessingState *GoogleRtcAudioProcessingCreate(void); + +// Frees all allocated resources in `state`. +void GoogleRtcAudioProcessingFree(GoogleRtcAudioProcessingState *state); + +// Returns the framesize used for processing. +int GoogleRtcAudioProcessingGetFramesizeInMs( + GoogleRtcAudioProcessingState *state); + +// Processes the microphone stream. +// Accepts deinterleaved float audio with the range [-1, 1]. Each element of +// |src| points to an array of samples for the channel. At output, the channels +// will be in |dest|. +// Returns 0 if success and non zero if failure. +int GoogleRtcAudioProcessingProcessCapture_float32( + GoogleRtcAudioProcessingState *const state, const float *const *src, + float *const *dest); + +// Accepts and and produces a frame of interleaved 16 bit integer audio. `src` +// and `dest` may use the same memory, if desired. +// Returns 0 if success and non zero if failure. +int GoogleRtcAudioProcessingProcessCapture_int16( + GoogleRtcAudioProcessingState *const state, const int16_t *const src, + int16_t *const dest); + +// Analyzes the playback stream. +// Accepts deinterleaved float audio with the range [-1, 1]. Each element +// of |src| points to an array of samples for the channel. +// Returns 0 if success and non zero if failure. +int GoogleRtcAudioProcessingAnalyzeRender_float32( + GoogleRtcAudioProcessingState *const state, const float *const *src); + +// Accepts interleaved int16 audio. +// Returns 0 if success and non zero if failure. +int GoogleRtcAudioProcessingAnalyzeRender_int16( + GoogleRtcAudioProcessingState *const state, const int16_t *const src); + +#ifdef __cplusplus +} +#endif + +#endif // GOOGLE_RTC_AUDIO_PROCESSING_H diff --git a/third_party/include/google_rtc_audio_processing_platform.h b/third_party/include/google_rtc_audio_processing_platform.h new file mode 100644 index 000000000000..f0043d97c85d --- /dev/null +++ b/third_party/include/google_rtc_audio_processing_platform.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2021 Google LLC. +// +// Author: Lionel Koenig +#ifndef GOOGLE_RTC_AUDIO_PROCESSING_PLATFORM_H_ +#define GOOGLE_RTC_AUDIO_PROCESSING_PLATFORM_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Allocates memory of size `size` and returns a pointer to the allocated +// memory. If no memory is available, NULL is returned. +void *GoogleRtcMalloc(size_t size); + +// Frees the memory pointed to by `p`. +void GoogleRtcFree(void *p); + +#ifdef __cplusplus +} +#endif + +#endif // GOOGLE_RTC_AUDIO_PROCESSING_PLATFORM_H_ diff --git a/tools/topology/m4/google_rtc_audio_processing.m4 b/tools/topology/m4/google_rtc_audio_processing.m4 new file mode 100644 index 000000000000..1cea9dbbf0b5 --- /dev/null +++ b/tools/topology/m4/google_rtc_audio_processing.m4 @@ -0,0 +1,65 @@ +divert(-1) + +dnl Define macro for RTC Processing effect widget +DECLARE_SOF_RT_UUID("google-rtc-audio-processing", google_rtc_audio_processing_uuid, +0xb780a0a6, 0x269f, 0x466f, 0xb4, 0x77, 0x23, 0xdf, 0xa0, 0x5a, 0xf7, 0x58) + +dnl N_GOOGLE_RTC_AUDIO_PROCESSING(name) +define(`N_GOOGLE_RTC_AUDIO_PROCESSING', `GOOGLE_RTC_AUDIO_PROCESSING'PIPELINE_ID`.'$1) + +dnl W_GOOGLE_RTC_AUDIO_PROCESSING(name, format, periods_sink, periods_source, core, kcontrols_list) +define(`W_GOOGLE_RTC_AUDIO_PROCESSING', +`SectionVendorTuples."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_tuples_uuid" {' +` tokens "sof_comp_tokens"' +` tuples."uuid" {' +` SOF_TKN_COMP_UUID' STR(google_rtc_audio_processing_uuid) +` }' +`}' +`SectionData."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_data_uuid" {' +` tuples "'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_tuples_uuid"' +`}' +`SectionVendorTuples."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_tuples_w" {' +` tokens "sof_comp_tokens"' +` tuples."word" {' +` SOF_TKN_COMP_PERIOD_SINK_COUNT' STR($3) +` SOF_TKN_COMP_PERIOD_SOURCE_COUNT' STR($4) +` SOF_TKN_COMP_CORE_ID' STR($5) +` }' +`}' +`SectionData."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_data_w" {' +` tuples "'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_tuples_w"' +`}' +`SectionVendorTuples."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_tuples_str" {' +` tokens "sof_comp_tokens"' +` tuples."string" {' +` SOF_TKN_COMP_FORMAT' STR($2) +` }' +`}' +`SectionData."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_data_str" {' +` tuples "'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_tuples_str"' +`}' +`SectionVendorTuples."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_tuples_str_type" {' +` tokens "sof_process_tokens"' +` tuples."string" {' +` SOF_TKN_PROCESS_TYPE' "GRTCP" +` }' +`}' +`SectionData."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_data_str_type" {' +` tuples "'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_tuples_str_type"' +`}' +`SectionWidget."'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`" {' +` index "'PIPELINE_ID`"' +` type "effect"' +` no_pm "true"' +` data [' +` "'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_data_uuid"' +` "'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_data_w"' +` "'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_data_str"' +` "'N_GOOGLE_RTC_AUDIO_PROCESSING($1)`_data_str_type"' +` ]' +` bytes [' + $6 +` ]' +`}') + +divert(0)dnl