Загрузка данных


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