#ifndef CALL_JITTER_H #define CALL_JITTER_H #include #ifdef __cplusplus extern "C" { #endif /* Звонок: FIFO Opus, запас 60мс..max_reserve_ms по изменению задержки доставки за 10 секунд и догон после паузы устройства. * push — сетевой поток, pull/decode/SoundTouch — единственный аудиопоток. * destroy — после остановки обоих потребителей. get_stats — любой поток. */ #define CALL_JITTER_FRAME_MS 20 #define CALL_JITTER_MAX_FRAMES 750 /* 10с перебоя + 5с запаса на накопление и восстановление */ typedef int (*call_jitter_decode_fn)(void*, const uint8_t*, int, int16_t*, int); struct call_jitter_range { int min_ms, max_ms, reserve_ms; }; struct call_jitter; struct call_jitter_diagnostics { int depth_ms, reserve_ms, tempo_x100, error_result, error_len; uint32_t decode_errors, budget_hits; int resumed, catching_up, waiting; }; /* Снимок и сброс событий под mutex; логировать после выхода из mutex голосового стека. */ void call_jitter_take_diagnostics(struct call_jitter*, struct call_jitter_diagnostics*); struct call_jitter* call_jitter_create(call_jitter_decode_fn decode, void* arg, int max_reserve_ms); void call_jitter_destroy(struct call_jitter* j); /* sent_ms — timestamp кадра на проводе (uint32 с переполнением), received_ms — локальные монотонные часы. * Абсолютное смещение часов пиров не влияет на оценку джиттера. */ void call_jitter_push(struct call_jitter* j, const uint8_t* enc, int len, uint32_t sent_ms, int64_t received_ms); /* Только после остановки pull: убрать устаревший PCM, сохранить свежий сетевой запас. */ void call_jitter_reset(struct call_jitter* j); int call_jitter_pull(struct call_jitter* j, int16_t* out, int max_samples); void call_jitter_get_stats(struct call_jitter* j, int* depth_ms, int* tempo_x100, uint32_t* dropped, uint32_t* underruns, struct call_jitter_range* range); #ifdef __cplusplus } #endif #endif