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.
79 lines
4.4 KiB
79 lines
4.4 KiB
#ifndef VOICE_JITTER_H |
|
#define VOICE_JITTER_H |
|
|
|
// voice_jitter.h — адаптивный джиттер-буфер голоса с time-stretch (SoundTouch), C API. |
|
// |
|
// Хранит КОДИРОВАННЫЕ (Opus) кадры: uasync-поток кладёт кодированные кадры, |
|
// аудио-поток на pull декодирует их (через коллбэк decode) и пропускает через |
|
// SoundTouch с плавно меняющимся темпом. Излишек голоса держится до декодирования — |
|
// декодируется только то, что готово к воспроизведению (экономия памяти ~48x и |
|
// разгрузка uasync-потока). |
|
// |
|
// Потоки: |
|
// - vj_push — uasync-поток (producer); |
|
// - vj_pull — аудио-поток (consumer; единственный владелец decode/SoundTouch); |
|
// - vj_get_stats — любой поток. |
|
// Кольцо кодированных кадров защищено мьютексом (SPSC, дёшево: ~50 кадров/с). |
|
|
|
#include <stdint.h> |
|
|
|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
|
|
struct vj; |
|
|
|
/* decode: закодированный кадр → PCM. Возвращает число декодированных сэмплов. */ |
|
typedef int (*vj_decode_fn)(void* arg, const uint8_t* enc, int len, int16_t* pcm, int max_samples); |
|
|
|
/* Полная конфигурация адаптивного джиттер-буфера. */ |
|
struct vj_cfg { |
|
int sample_rate; |
|
int channels; |
|
int frame_samples; /* сэмплов в кадре (960 @20мс/48k) */ |
|
int frame_ms; /* длительность кадра в мс */ |
|
int max_frames; /* ёмкость кодированных кадров (50 = 1000мс) */ |
|
double target_ms; /* целевая глубина буфера */ |
|
double min_tempo; /* темп при пустом буфере (<1.0 = замедление, накопление) */ |
|
double max_tempo; /* темп при глубоком буфере (>1.0 = догон live) */ |
|
int pre_roll; /* 1 = не отдавать звук, пока глубина < target_ms */ |
|
vj_decode_fn decode; |
|
void* decode_arg; |
|
}; |
|
|
|
/* Создать буфер с полной конфигурацией (pre-roll, симметричный темп). */ |
|
struct vj* vj_create_cfg(const struct vj_cfg* cfg); |
|
|
|
/* Создать буфер с конфигурацией по умолчанию (совместимо со звонком: без pre-roll, |
|
* темп 1.0..1.6, target 60мс). frame_samples — сэмплов в кадре (960 @20мс/48k). */ |
|
struct vj* vj_create(int sample_rate, int channels, int frame_samples, int frame_ms, |
|
int max_frames, vj_decode_fn decode, void* decode_arg); |
|
|
|
void vj_destroy(struct vj* j); |
|
|
|
/* producer: положить кодированный кадр (копируется). При переполнении дропает старейший. */ |
|
void vj_push(struct vj* j, const uint8_t* enc, int len); |
|
|
|
/* consumer: выдать до max_samples декодированного+растянутого PCM. Может вернуть |
|
* < max_samples при нехватке данных (андерфлоу). */ |
|
int vj_pull(struct vj* j, int16_t* out, int max_samples); |
|
|
|
/* audio-поток: вход закончен (FIN) — принудительно снять pre-roll, чтобы дренировать |
|
* накопленный остаток до конца. Безопасно вызывать многократно. */ |
|
void vj_end(struct vj* j); |
|
|
|
/* Диагностика: глубина буфера (мс), темп (×100, 100 = 1.0x), дропнуто кадров |
|
* при переполнении, число underrun-ов (pull вернул меньше запрошенного). */ |
|
void vj_get_stats(struct vj* j, int* depth_ms, int* tempo_x100, uint32_t* dropped, uint32_t* underruns); |
|
|
|
/* Число дропнутых кадров при переполнении (для диагностики/тестов). */ |
|
uint32_t vj_dropped(struct vj* j); |
|
|
|
/* Число хард-ресинков к live (после сталла аудио-девайса) — диагностика. */ |
|
uint32_t vj_resyncs(struct vj* j); |
|
|
|
#ifdef __cplusplus |
|
} |
|
#endif |
|
|
|
#endif /* VOICE_JITTER_H */
|
|
|