Загрузка данных
#include "gst_imx_ai_aecnr_core.h"
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/flowcontrol.h"
typedef struct ImxAiAecState {
struct imx_ai_aecnr_core *aec_core;
MSBufferizer delayed_ref;
MSFlowControlledBufferizer ref;
MSBufferizer echo;
int samplerate;
int framesize;
int delay_ms;
int nominal_ref_samples;
bool_t echostarted;
bool_t bypass_mode;
bool_t using_zeroes;
} ImxAiAecState;
static void imx_ai_aec_init(MSFilter *f) {
ImxAiAecState *s = ms_new0(ImxAiAecState, 1);
s->samplerate = AI_AECNR_SAMPLE_RATE; // 16000
s->framesize = AI_AECNR_IO_SAMPLES; // 256
ms_bufferizer_init(&s->delayed_ref);
ms_bufferizer_init(&s->echo);
ms_flow_controlled_bufferizer_init(&s->ref, f, s->samplerate, 1);
s->delay_ms = 0;
s->echostarted = FALSE;
s->bypass_mode = FALSE;
s->using_zeroes = FALSE;
f->data = s;
}
static void imx_ai_aec_preprocess(MSFilter *f) {
ImxAiAecState *s = (ImxAiAecState *)f->data;
imx_ai_aecnr_config config;
int delay_samples;
mblk_t *m;
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, bypass mode");
s->bypass_mode = TRUE;
return;
}
s->echostarted = FALSE;
delay_samples = s->delay_ms * s->samplerate / 1000;
s->nominal_ref_samples = delay_samples;
ms_message("IMX AI AECNR initialized: %s, framesize=%i, delay=%i ms",
config.version, s->framesize, s->delay_ms);
// Настройка flow control для синхронизации потоков
ms_flow_controlled_bufferizer_set_samplerate(&s->ref, s->samplerate);
ms_flow_controlled_bufferizer_set_max_size_ms(&s->ref, s->delay_ms);
/* Заполнение начальной задержки нулями */
m = allocb(delay_samples * 2, 0);
memset(m->b_wptr, 0, delay_samples * 2);
m->b_wptr += delay_samples * 2;
ms_bufferizer_put(&s->delayed_ref, m);
}
static void imx_ai_aec_process(MSFilter *f) {
ImxAiAecState *s = (ImxAiAecState *)f->data;
int nbytes = s->framesize * sizeof(int16_t);
mblk_t *refm;
int16_t *ref_tmp = (int16_t *)alloca(nbytes);
int16_t *echo_tmp = (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] != NULL) {
if (s->echostarted) {
while ((refm = ms_queue_get(f->inputs[0])) != NULL) {
ms_bufferizer_put(&s->delayed_ref, dupmsg(refm));
ms_flow_controlled_bufferizer_put(&s->ref, refm);
}
} else {
ms_queue_flush(f->inputs[0]);
}
}
// 2. Получаем сигнал с микрофона
ms_bufferizer_put_from_queue(&s->echo, f->inputs[1]);
// 3. Основной цикл обработки
while (ms_bufferizer_get_avail(&s->echo) >= (size_t)nbytes) {
mblk_t *out_clean = allocb(nbytes, 0);
int avail;
if (!s->echostarted) s->echostarted = TRUE;
// Проверка наличия данных в буфере задержки
avail = (int)ms_bufferizer_get_avail(&s->delayed_ref);
if (avail < ((s->nominal_ref_samples * 2) + nbytes)) {
// Инъекция тишины, если референс отстал
refm = allocb(nbytes, 0);
memset(refm->b_wptr, 0, nbytes);
refm->b_wptr += nbytes;
ms_bufferizer_put(&s->delayed_ref, refm);
// В отличие от Speex, тут мы не пушим тишину в output[0],
// чтобы не плодить лишнюю задержку в звуковой карте
if (!s->using_zeroes) {
ms_warning("IMX AEC: Not enough ref samples, using zeroes");
s->using_zeroes = TRUE;
}
} else {
s->using_zeroes = FALSE;
refm = allocb(nbytes, 0);
ms_flow_controlled_bufferizer_read(&s->ref, refm->b_wptr, nbytes);
refm->b_wptr += nbytes;
ms_queue_put(f->outputs[0], refm);
}
// Читаем выровненные данные
ms_bufferizer_read(&s->echo, (uint8_t *)echo_tmp, nbytes);
ms_bufferizer_read(&s->delayed_ref, (uint8_t *)ref_tmp, nbytes);
// AI Обработка (AEC + NR)
if (imx_ai_aecnr_core_process(s->aec_core, ref_tmp, echo_tmp, (int16_t *)out_clean->b_wptr) != 0) {
ms_error("imx_ai_aecnr_core_process failed");
memcpy(out_clean->b_wptr, echo_tmp, nbytes); // Fallback
}
out_clean->b_wptr += nbytes;
ms_queue_put(f->outputs[1], out_clean);
}
}
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_flush(&s->delayed_ref);
ms_bufferizer_flush(&s->echo);
}
static void imx_ai_aec_uninit(MSFilter *f) {
ImxAiAecState *s = (ImxAiAecState *)f->data;
ms_bufferizer_uninit(&s->delayed_ref);
ms_bufferizer_uninit(&s->echo);
ms_free(s);
}