You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

74 lines
4.1 KiB

/*
* speex_aec.h — акустическое эхоподавление (AEC), C-обёртка над SpeexDSP mdf.c.
*
* Подавляет эхо дальнего конца (то, что играем в динамик) в сигнале микрофона
* перед кодированием. Работает на int16 PCM, один канал, частота 48000 (можно
* 8000/16000/32000/48000), кадр 20 мс (960 сэмплов @48 кГц).
*
* Модель использования (duplex-контур звонка):
* - рендер (far-end, то что пошло в динамик) → speex_aec_feed_playback();
* - захват (near-end, микрофон) → speex_aec_process_capture().
*
* Обёртка держит собственную линию задержки рендера на `delay_frames` кадров и
* зовёт синхронный speex_echo_cancellation(rec, play_delayed, out). Это делает
* выравнивание рендер↔захват предсказуемым и настраиваемым (встроенный буфер
* SpeexDSP фиксирован в 2 кадра и для Android-задержки не годится).
*
* Дрейф двух независимых потоков (capture/play на Android) компенсируется
* ограниченной глубиной линии: переполнение → отбрасываем старый рендер-кадр,
* недозаполнение → passthrough без канселлера (с подробным логом категории "aec").
*
* Зависимости: SpeexDSP (mdf.c/fftwrap.c/kiss_fft*) из lib/speexdsp, флаги
* FLOATING_POINT + USE_KISS_FFT. Собирается всегда (без внешних зависимостей).
*
* Лицензия SpeexDSP: 3-clause BSD (Xiph) — см. lib/speexdsp/COPYING.
*/
#ifndef SPEEX_AEC_H
#define SPEEX_AEC_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct speex_aec speex_aec_t;
/**
* Создать эхоканселлер.
* sample_rate — 48000 (также 8000/16000/32000);
* frame_samples — сэмплов в кадре (960 = 20 мс @48 кГц);
* filter_samples— длина эхо-хвоста в сэмплах (14400 = 300 мс, кратно кадру);
* delay_frames — задержка рендер→захват в кадрах (>=0; 0 = без линии задержки).
* Возвращает NULL при ошибке (лог категории "aec").
*/
speex_aec_t* speex_aec_create(int sample_rate, int frame_samples, int filter_samples, int delay_frames);
/* Освободить канселлер. NULL безопасен. */
void speex_aec_destroy(speex_aec_t* aec);
/* Сбросить адаптивный фильтр и линию задержки (смена устройства/роута). */
void speex_aec_reset(speex_aec_t* aec);
/**
* Подать рендер (дальний конец). Накопление до кадра внутри; полный кадр
* кладётся в линию задержки. count может быть любым (обычно 480 или 960).
*/
void speex_aec_feed_playback(speex_aec_t* aec, const int16_t* pcm, int count);
/**
* Обработать захват (микрофон). Накопление до кадра внутри. Когда кадр собран —
* подавляет эхо (с учётом линии задержки) и пишет результат в out.
* Возвращает число сэмплов, записанных в out (frame_samples, если кадр готов;
* 0 — кадр ещё накапливается). out не должен алиаситься с pcm.
*/
int speex_aec_process_capture(speex_aec_t* aec, const int16_t* pcm, int count, int16_t* out);
/* Актуальная глубина линии задержки (кадров) — для диагностики дрейфа. */
int speex_aec_delay_fill(const speex_aec_t* aec);
#ifdef __cplusplus
}
#endif
#endif /* SPEEX_AEC_H */