Skip to content

Commit

Permalink
[WIP] CTC
Browse files Browse the repository at this point in the history
  • Loading branch information
Eddy Hsu committed Dec 12, 2023
1 parent 51159d8 commit d525d84
Show file tree
Hide file tree
Showing 5 changed files with 387 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/audio/google/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,26 @@ if(NOT CONFIG_LIBRARY)
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()

257 changes: 257 additions & 0 deletions src/audio/google/google_ctc_audio_processing.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
#include <google_ctc_audio_processing.h>
#include <sof/audio/buffer.h>
#include <sof/audio/component.h>
#include <sof/audio/format.h>
#include <sof/audio/pipeline.h>

struct comp_driver comp_ctc_audio_processing;

/* bf0e1bbc-dc6a-45fe-bc90-2554cb137ab4 */
DECLARE_SOF_RT_UUID("ctc_audio_processing", ctc_audio_processing_uuid,
0xbf0e1bbc, 0xdc6a, 0x45fe, 0xbc, 0x90, 0x25, 0x54, 0xcb,
0x13, 0x7a, 0xb4);

DECLARE_TR_CTX(ctc_audio_processing_tr, SOF_UUID(ctc_audio_processing_uuid),
LOG_LEVEL_INFO);

struct ctc_audio_processing_comp_data {
struct comp_data_blob_handler *model_handler;
struct comp_buffer *input;
struct comp_buffer *output;
uint32_t num_frames;
GoogleCtcAudioProcessingState *state;
struct comp_data_blob_handler *tuning_handler;
bool reconfigure;
};

struct comp_driver comp_ctc_audio_processing = {
.uid = SOF_RT_UUID(ctc_audio_processing_uuid),
.tctx = &ctc_audio_processing_tr,
.ops =
{
.create = ctc_audio_processing_create,
.free = ctc_audio_processing_free,
.params = NULL,
.cmd = ctc_audio_processing_cmd,
.trigger = ctc_audio_processing_trigger,
.prepare = ctc_audio_processing_prepare,
.reset = ctc_audio_processing_reset,
.copy = ctc_audio_processing_copy,
},
};

static SHARED_DATA struct comp_driver_info comp_ctc_audio_processing_info = {
.drv = &comp_ctc_audio_processing,
};

static void sys_comp_ctc_audio_processing_init(void) {
comp_register(platform_shared_get(&comp_ctc_audio_processing_info,
sizeof(comp_ctc_audio_processing_info)));
}

static struct comp_dev *ctc_audio_processing_create(
const struct comp_driver *drv, struct comp_ipc_config *config, void *spec) {
struct comp_dev *dev;
struct ctc_audio_processing_comp_data *cd;
struct ipc_config_process *ipc_ctc = spec;

comp_cl_info(&comp_ctc_audio_processing, "ctc_audio_processing_create()");

dev = comp_alloc(drv, sizeof(*dev));
if (!dev) return NULL;
dev->ipc_config = *config;

cd = rzalloc(SOF_MEM_ZONE_RUNTIME, 0, SOF_MEM_CAPS_RAM, sizeof(*cd));
if (!cd) {
rfree(dev);
return NULL;
}

cd->num_frames = 64; // TODO(eddyhsu): figure out correct num_frames

cd->input =
rballoc(0, SOF_MEM_CAPS_RAM, cd->num_frames * sizeof(cd->input[0]));
if (!cd->input) goto fail;
bzero(cd->input, cd->num_frames * sizeof(cd->input[0]));

cd->output =
rballoc(0, SOF_MEM_CAPS_RAM, cd->num_frames * sizeof(cd->output[0]));
if (!cd->output) goto fail;
bzero(cd->output, cd->num_frames * sizeof(cd->output[0]));

cd->state = GoogleCtcAudioProcessingCreate();

comp_set_drvdata(dev, cd);

dev->state = COMP_STATE_READY;

comp_dbg(dev, "crosstalk cancellation created");

return dev;
fail:
comp_err(dev, "google_ctc_audio_processing_create(): Failed");
if (cd) {
rfree(cd->input);
rfree(cd->output);
if (cd->state) {
GoogleCtcAudioProcessingFree(cd->state);
}
rfree(cd);
}
rfree(dev);
return NULL;
}

static void ctc_audio_processing_free(struct comp_dev *dev) {
struct comp_data *cd = comp_get_drvdata(dev);

GoogleCtcAudioProcessingFree(cd->state);
cd->state = NULL;
rfree(cd->input);
rfree(cd->output);
rfree(cd);
rfree(dev);
}

static int ctc_audio_processing_trigger(struct comp_dev *dev, int cmd) {
comp_dbg(dev, "crosstalk cancellation got trigger cmd %d", cmd);
return comp_set_state(dev, cmd);
}

static int ctc_audio_processing_prepare(struct comp_dev *dev) {
int ret;

comp_info(dev, "google_ctc_audio_processing_prepare()");

ret = comp_set_state(dev, COMP_TRIGGER_PREPARE);
if (ret < 0) return ret;

if (ret == COMP_STATUS_STATE_ALREADY_SET) return PPL_STATUS_PATH_STOP;

comp_dbg(dev, "crosstalk cancellation prepared");
return 0;
}

static int ctc_audio_processing_reset(struct comp_dev *dev) {
return comp_set_state(dev, COMP_TRIGGER_RESET);
}

static int ctc_audio_processing_copy(struct comp_dev *dev) {
struct comp_copy_limits cl;
struct comp_buffer *source;
struct comp_buffer *sink;
struct ctc_audio_processing_comp_data *cd = comp_get_drvdata(dev);
int frame;
int channel;
uint32_t buff_frag = 0;
int16_t *src;
int16_t *dst;

comp_dbg(dev, "ctc_audio_processing_copy()");

source = list_first_item(&dev->bsource_list, struct comp_buffer, sink_list);
sink = list_first_item(&dev->bsink_list, struct comp_buffer, source_list);

comp_get_copy_limits_with_lock(source, sink, &cl);

buffer_invalidate(source, cl.source_bytes);

for (frame = 0; frame < cl.frames; frame++) {
for (channel = 0; channel < sink->stream.channels; channel++) {
src = audio_stream_read_frag_s16(&source->stream, buff_frag);
dst = audio_stream_write_frag_s16(&sink->stream, buff_frag);

GoogleCtcAudioProcessingProcess(cd->state, src, dst);

++buff_frag;
}
}

buffer_writeback(sink, cl.sink_bytes);

comp_update_buffer_produce(sink, cl.sink_bytes);
comp_update_buffer_consume(source, cl.source_bytes);

return 0;
}

static int ctc_audio_processing_cmd_set_data(struct comp_dev *dev,
struct sof_ipc_ctrl_data *cdata) {
struct ctc_audio_processing_comp_data *cd = comp_get_drvdata(dev);

if (cdata->cmd != SOF_CTRL_CMD_BINARY) {
comp_err(dev, "ctc_audio_processing_cmd_set_data(): invalid cmd %d",
cdata->cmd);
return -EINVAL;
}

ret = comp_data_blob_set_cmd(cd->tuning_handler, cdata);
if (ret) return ret;

/* Accept the new blob immediately so that userspace can write
* the control in quick succession without error.
* This ensures the last successful control write from userspace
* before prepare/copy is applied.
* The config blob is not referenced after reconfigure() returns
* so it is safe to call comp_get_data_blob here which frees the
* old blob. This assumes cmd() and prepare()/copy() cannot run
* concurrently which is the case when there is no preemption.
*/
if (comp_is_new_data_blob_available(cd->tuning_handler)) {
comp_get_data_blob(cd->tuning_handler, NULL, NULL);
cd->reconfigure = true;
}

comp_dbg(dev, "crosstalk cancellation new settings");
return 0;
}

static int ctc_audio_processing_cmd_get_data(struct comp_dev *dev,
struct sof_ipc_ctrl_data *cdata,
int max_data_size) {
struct ctc_audio_processing_comp_data *cd = comp_get_drvdata(dev);

if (cdata->cmd != SOF_CTRL_CMD_BINARY) {
comp_err(dev, "ctc_audio_processing_cmd_get_data(): invalid cmd %d",
cdata->cmd);
return -EINVAL;
}

return comp_data_blob_get_cmd(cd->tuning_handler, cdata, max_data_size);
}

static int ctc_audio_processing_cmd(struct comp_dev *dev, int cmd, void *data,
int max_data_size) {
struct sof_ipc_ctrl_data *cdata = data;
int ret = 0;

switch (cmd) {
case COMP_CMD_SET_VALUE:
case COMP_CMD_GET_VALUE:
return 0;
case COMP_CMD_SET_DATA:
ret = ctc_audio_processing_cmd_set_data(dev, cdata);
break;
case COMP_CMD_GET_DATA:
ret = ctc_audio_processing_cmd_get_data(dev, cdata, max_data_size);
break;
default:
comp_err(dev, "ctc_audio_processing_cmd(): unhandled command %d", cmd);
ret = -EINVAL;
break;
}
return ret;
}

static SHARED_DATA struct comp_driver_info google_ctc_audio_processing_info = {
.drv = &google_ctc_audio_processing,
};

UT_STATIC void sys_comp_google_ctc_audio_processing_init(void) {
comp_register(platform_shared_get(&google_ctc_audio_processing_info,
sizeof(google_ctc_audio_processing_info)));
}

DECLARE_MODULE(sys_comp_google_ctc_audio_processing_init);
SOF_MODULE_INIT(google_ctc_audio_processing,
sys_comp_google_ctc_audio_processing_init);
43 changes: 43 additions & 0 deletions src/audio/google/google_ctc_audio_processing_mock.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include <rtos/alloc.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "google_ctc_audio_processing.h"
#include "ipc/topology.h"

struct GoogleCtcAudioProcessingState {
int num_frames;
int partition_size;
int impulse_size;
int chunk_frames;
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 = 64;
s->partition_size = 64;
s->impulse_size = 256;
s->chunk_frames = 480;
s->sample_rate = 48000;
s->is_symmetric = 0;
return s;
}

void GoogleCtcAudioProcessingFree(GoogleCtcAudioProcessingState *state) {
if (state != NULL) {
rfree(state);
}
}

int GoogleCtcAudioProcessingProcess(GoogleCtcAudioProcessingState *const state,
const int16_t *const src,
int16_t *const dest) {
memcpy(dest, src, sizeof(int16_t) * state->num_frames);
return 0;
}
26 changes: 26 additions & 0 deletions third_party/include/google_ctc_audio_processing.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef GOOGLE_RTC_AUDIO_PROCESSING_H
#define GOOGLE_RTC_AUDIO_PROCESSING_H

#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);

// Frees all allocated resources in `state`.
void GoogleCtcAudioProcessingFree(GoogleCtcAudioProcessingState *state);

// Apply CTC on `src` and produce result in `dest`.
int GoogleCtcAudioProcessingProcess(GoogleCtcAudioProcessingState *const state,
const int16_t *const src,
int16_t *const dest);

#ifdef __cplusplus
}
#endif

#endif // GOOGLE_RTC_AUDIO_PROCESSING_H
41 changes: 41 additions & 0 deletions tools/topology/topology2/platform/intel/google-ctc-reference.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Object.Pipeline.google-ctc-capture [
{
index 18 # TODO: update index
core_id $GOOGLE_CTC_CORE_ID

Object.Widget.pipeline.1 {
stream_name "DMIC0 CTC"
core $GOOGLE_CTC_CORE_ID
priority $GOOGLE_CTC_PIPELINE_PRIORITY
}

Object.Widget.google-ctc.1 {
Object.Base.input_pin_binding.1 {
input_pin_binding_name "module-copier.18.1"
}

Object.Base.input_pin_binding.2 {
input_pin_binding_name "dai-copier.SSP.$SPEAKER_CODEC_NAME.capture"
}
}
}
]

Object.Base.route [
{
source $DMIC0_DAI_PIPELINE_SRC
sink module-copier.18.1
}
{
source "dai-copier.SSP.$SPEAKER_CODEC_NAME.capture"
sink "google-rtc-aec.18.1"
}
{
source "module-copier.18.2"
sink "host-copier.27.capture"
}
{
source "gain.20.1"
sink "host-copier.28.capture"
}
]

0 comments on commit d525d84

Please sign in to comment.