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

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