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
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 */
|
|
|