From e53ea2e04a3ceb4c5aefa5cded1f5106c2efc191 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 15 Oct 2026 02:44:10 +0200 Subject: [PATCH] Expose non-destructive jitter buffer diagnostic snapshots --- src/call/call_audio.c | 11 +++++++---- src/call/call_jitter.cpp | 15 ++++++++++++--- src/call/call_jitter.h | 5 ++++- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/call/call_audio.c b/src/call/call_audio.c index 67a6def0..57f5cb55 100644 --- a/src/call/call_audio.c +++ b/src/call/call_audio.c @@ -571,7 +571,7 @@ int call_audio_get_stats(uint64_t call_id, int* buffer_ms, int* tempo_x100, pthread_mutex_lock(&g_mtx); if (g_active && call_id == g_call_id && g_vj) { call_jitter_get_stats(g_vj, buffer_ms, tempo_x100, dropped, underruns, range); - call_jitter_take_diagnostics(g_vj, &diagnostics); + call_jitter_get_diagnostics(g_vj, &diagnostics, 1); speex_aec_get_stats(g_aec, &aec_over, &aec_under); aec_changed = aec_over != g_aec_reported_over || aec_under != g_aec_reported_under; g_aec_reported_over = aec_over; g_aec_reported_under = aec_under; @@ -592,8 +592,11 @@ int call_audio_get_stats(uint64_t call_id, int* buffer_ms, int* tempo_x100, diagnostics.decode_errors, diagnostics.error_result, diagnostics.error_len, diagnostics.budget_hits, diagnostics.depth_ms); if (events) DEBUG_INFO(DEBUG_CATEGORY_CALL, "%s: PCM first=%d resumed=%d gap=%d tone_started=%d tone_stopped=%d", CALL_AUDIO_ID, !!(events & 1), !!(events & 2), !!(events & 4), !!(events & 16), !!(events & 8)); - if (ok) DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "call_jitter: depth=%dms reserve=%dms tempo=%d waiting=%d catching_up=%d resumed=%d", - diagnostics.depth_ms, diagnostics.reserve_ms, diagnostics.tempo_x100, diagnostics.waiting, - diagnostics.catching_up, diagnostics.resumed); + if (ok) DEBUG_DEBUG(DEBUG_CATEGORY_CALL, + "call_jitter: call=%llu depth=%dms reserve=%dms encoded=%dms processing=%dms spread=%lldms pcm=%d " + "tempo=%d waiting=%d catching_up=%d resumed=%d underruns=%u", + (unsigned long long)call_id, diagnostics.depth_ms, diagnostics.reserve_ms, diagnostics.encoded_ms, + diagnostics.processing_ms, (long long)diagnostics.arrival_spread_ms, diagnostics.pcm_samples, + diagnostics.tempo_x100, diagnostics.waiting, diagnostics.catching_up, diagnostics.resumed, diagnostics.underruns); return ok ? 0 : -1; } diff --git a/src/call/call_jitter.cpp b/src/call/call_jitter.cpp index 2e049eb5..aa2b2de1 100644 --- a/src/call/call_jitter.cpp +++ b/src/call/call_jitter.cpp @@ -133,6 +133,7 @@ int call_jitter_pull(struct call_jitter* j, int16_t* out, int max_samples) { std::lock_guard lock(j->mtx); j->diagnostics.depth_ms = (int)depth; j->diagnostics.reserve_ms = reserve; j->diagnostics.tempo_x100 = j->tempo_x100; j->diagnostics.waiting = 1; + j->diagnostics.pcm_samples = 0; return 0; } j->primed = true; @@ -198,6 +199,7 @@ int call_jitter_pull(struct call_jitter* j, int16_t* out, int max_samples) { j->diagnostics.resumed |= resumed; j->diagnostics.catching_up = catching; j->diagnostics.waiting = n < max_samples; + j->diagnostics.pcm_samples = n; } if (n < max_samples) { j->primed = false; @@ -205,11 +207,18 @@ int call_jitter_pull(struct call_jitter* j, int16_t* out, int max_samples) { return n; } -void call_jitter_take_diagnostics(struct call_jitter* j, struct call_jitter_diagnostics* out) { +void call_jitter_get_diagnostics(struct call_jitter* j, struct call_jitter_diagnostics* out, int reset_events) { std::lock_guard lock(j->mtx); *out = j->diagnostics; - j->diagnostics.decode_errors = j->diagnostics.budget_hits = 0; - j->diagnostics.resumed = 0; + out->encoded_ms = j->count * CALL_JITTER_FRAME_MS; + out->processing_ms = j->processing_ms; + out->reserve_ms = j->arrival_window.reserve; + out->arrival_spread_ms = j->arrival_window.high - j->arrival_window.low; + out->underruns = j->underruns; + if (reset_events) { + j->diagnostics.decode_errors = j->diagnostics.budget_hits = 0; + j->diagnostics.resumed = 0; + } } void call_jitter_silence(struct call_jitter* j, unsigned samples) { diff --git a/src/call/call_jitter.h b/src/call/call_jitter.h index 59cbfe1e..1cea4f96 100644 --- a/src/call/call_jitter.h +++ b/src/call/call_jitter.h @@ -20,9 +20,12 @@ 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; + int encoded_ms, processing_ms, pcm_samples; + int64_t arrival_spread_ms; + uint32_t underruns; }; /* Снимок и сброс событий под mutex; логировать после выхода из mutex голосового стека. */ -void call_jitter_take_diagnostics(struct call_jitter*, struct call_jitter_diagnostics*); +void call_jitter_get_diagnostics(struct call_jitter*, struct call_jitter_diagnostics*, int reset_events); 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 — локальные монотонные часы.