diff --git a/tools/chatgui/tests/test_call_delay.cpp b/tools/chatgui/tests/test_call_delay.cpp index 3457798d..9e8c404c 100644 --- a/tools/chatgui/tests/test_call_delay.cpp +++ b/tools/chatgui/tests/test_call_delay.cpp @@ -143,9 +143,27 @@ static void phase_after_silence() { DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS delay phase: 20 arbitrary initial silence/block combinations converge using cuts only"); } +static void changing_blocks() { + Trial t; + const unsigned blocks[] = {1, 191, 192, 193, 575, 576, 577, 768, 960, 1920, 8192}; + uint64_t next = 0, time = 0; + t.available = 48000; + for (unsigned tick = 0; tick < 3000; ++tick) { + unsigned block = blocks[tick % (sizeof(blocks) / sizeof(blocks[0]))]; + while (next <= time) { t.available += 960; next += 960; } + // Пауза устройства на каждый новый цикл создаёт избыток, затем резерв заставляет выйти из DSP. + if (!(tick % 50)) t.available += 48000; + unsigned reserve = tick % 50 < 25 ? 960 : (unsigned)(t.available + t.delay.stats().pending + 960); + t.pull(block, reserve); + time += block; + } + CHECK(t.boundaries >= 120); + DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS delay changing blocks 1..8192 samples, boundaries=%llu", (unsigned long long)t.boundaries); +} + int main() { debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); for (unsigned block : {240, 480, 777, 960}) for (unsigned phase : {0, 239, 479, 719, 959}) steady(block, phase); - switching(); tail_and_reset(); phase_after_silence(); + switching(); tail_and_reset(); phase_after_silence(); changing_blocks(); return 0; } diff --git a/tools/chatgui/tests/test_call_jitter.cpp b/tools/chatgui/tests/test_call_jitter.cpp index f551a98c..f2859941 100644 --- a/tools/chatgui/tests/test_call_jitter.cpp +++ b/tools/chatgui/tests/test_call_jitter.cpp @@ -29,6 +29,34 @@ static void push(call_jitter* j, int id, int64_t received_ms = -1) { call_jitter_push(j, (const uint8_t*)&id, sizeof(id), (uint32_t)(id * 20), received_ms < 0 ? id * 20 : received_ms, nullptr); } +static void test_network_recovery() { + for (int block : {240, 480, 777, 960}) { + decoder d; + auto* j = call_jitter_create(decode, &d, 1000); + std::vector output(block); + int next = 0, largest_reserve = 0; + uint32_t stable_underruns = 0; + call_jitter_diagnostics state{}; + for (int64_t time = 0; time < 30 * 48000; time += block) { + // Один перебой 80мс, затем приходит накопленная пачка и продолжается ровная доставка. + bool stalled = time >= 48000 && time < 48000 + 3840; + while (!stalled && next * 960ll <= time) push(j, next++, time / 48); + int n = call_jitter_pull(j, output.data(), block); + if (n < block) call_jitter_silence(j, block - n); + call_jitter_get_diagnostics(j, &state, 0); + largest_reserve = std::max(largest_reserve, state.reserve_ms); + if (time < 3 * 48000) stable_underruns = state.underruns; + else CHECK(state.underruns == stable_underruns); + } + CHECK(largest_reserve >= 60 && state.reserve_ms == 20); + CHECK(state.delay_mode == 0 && state.phase_samples == 0 && state.tempo_ppm == 1000000); + CHECK(state.underruns > 0 && state.underruns <= 2); + DEBUG_INFO(DEBUG_CATEGORY_CALL, "recovery block=%d max_reserve=%dms final=%dms phase=%u underruns=%u", + block, largest_reserve, state.reserve_ms, state.phase_samples, state.underruns); + call_jitter_destroy(j); + } +} + static void test_audio_clock() { const uint64_t id = 987; CHECK(call_audio_start(id) == 0); @@ -116,6 +144,7 @@ int main() { debug_set_level(DEBUG_LEVEL_WARN); debug_enable_console(1); test_audio_clock(); + test_network_recovery(); int16_t pcm[480]; int depth, tempo; uint32_t dropped, under;