#include "gst_imx_ai_aecnr_core.h"
static void imx_ai_aec_preprocess(MSFilter *f) {
ImxAiAecState *s = (ImxAiAecState *)f->data;
imx_ai_aecnr_config config;
s->samplerate = AI_AECNR_SAMPLE_RATE; // Библиотека жестко задана на 16000
s->framesize = AI_AECNR_IO_SAMPLES;
s->bypass_mode = FALSE;
config.use_small_model = 0; // По умолчанию используем полную модель
s->aec_core = imx_ai_aecnr_core_open(&config);
if (s->aec_core == NULL) {
ms_error("imx_ai_aecnr_core_open() failed. Entering bypass mode.");
s->bypass_mode = TRUE;
return;
}
ms_message("IMX AI AECNR initialized: %s, framesize=%i", config.version, s->framesize);
ms_bufferizer_init(&s->echo);
ms_bufferizer_init(&s->ref);
}
static void imx_ai_aec_process(MSFilter *f) {
ImxAiAecState *s = (ImxAiAecState *)f->data;
int nsamples = AI_AECNR_IO_SAMPLES;
int nbytes = nsamples * sizeof(int16_t);
mblk_t *refm;
int16_t *ref_buf = (int16_t *)alloca(nbytes);
int16_t *echo_buf = (int16_t *)alloca(nbytes);
if (s->bypass_mode) {
while ((refm = ms_queue_get(f->inputs[0])) != NULL) ms_queue_put(f->outputs[0], refm);
while ((refm = ms_queue_get(f->inputs[1])) != NULL) ms_queue_put(f->outputs[1], refm);
return;
}
// 1. Собираем данные из входов
if (f->inputs[0]) ms_bufferizer_put_from_queue(&s->ref, f->inputs[0]);
if (f->inputs[1]) ms_bufferizer_put_from_queue(&s->echo, f->inputs[1]);
// 2. Обрабатываем, пока в обоих буферах достаточно данных
// Важно: AI AEC обычно требует синхронности ref и echo
while (ms_bufferizer_get_avail(&s->echo) >= nbytes &&
ms_bufferizer_get_avail(&s->ref) >= nbytes)
{
mblk_t *out_mic = allocb(nbytes, 0);
mblk_t *out_speaker = allocb(nbytes, 0);
// Читаем порцию данных
ms_bufferizer_read(&s->ref, (uint8_t *)ref_buf, nbytes);
ms_bufferizer_read(&s->echo, (uint8_t *)echo_buf, nbytes);
/*
Вызов основного API обработки.
Предполагается сигнатура (core, speaker_ref, mic_with_echo, output_clean)
*/
if (imx_ai_aecnr_core_process(s->aec_core, ref_buf, echo_buf, (int16_t *)out_mic->b_wptr) != 0) {
ms_error("imx_ai_aecnr_core_process() failed");
// В случае ошибки просто копируем вход на выход
memcpy(out_mic->b_wptr, echo_buf, nbytes);
}
// Копируем референсный сигнал на динамик (сквозной проход)
memcpy(out_speaker->b_wptr, ref_buf, nbytes);
out_mic->b_wptr += nbytes;
out_speaker->b_wptr += nbytes;
ms_queue_put(f->outputs[0], out_speaker); // На динамик
ms_queue_put(f->outputs[1], out_mic); // В сеть (очищенный голос)
}
}
static void imx_ai_aec_postprocess(MSFilter *f) {
ImxAiAecState *s = (ImxAiAecState *)f->data;
if (s->aec_core) {
imx_ai_aecnr_core_close(s->aec_core);
s->aec_core = NULL;
}
ms_bufferizer_uninit(&s->echo);
ms_bufferizer_uninit(&s->ref);
}