Expose SoundTouch starvation with a 20 ms jitter reserve
This commit is contained in:
1 parent
f1aec9bb2d
commit
ff16adda17
2 files changed
+42
-16
No files matched your search
@@ -86,8 +86,8 @@ int main() {
|
||||
w.observe(0, 100); w.observe(500, 400);
|
||||
CHECK(w.low == 100 && w.high == 400 && w.reserve == 300);
|
||||
w.observe(1000, 2000); CHECK(w.reserve == 1000);
|
||||
w.observe(10000, 2000); CHECK(w.low == 2000 && w.reserve == 60);
|
||||
w.observe(30000, 80); CHECK(w.low == 80 && w.high == 80 && w.reserve == 60);
|
||||
w.observe(10000, 2000); CHECK(w.low == 2000 && w.reserve == 20);
|
||||
w.observe(30000, 80); CHECK(w.low == 80 && w.high == 80 && w.reserve == 20);
|
||||
for (int cap : {500, 2000}) {
|
||||
call_jitter_window limited;
|
||||
limited.max_reserve = cap;
|
||||
@@ -100,13 +100,18 @@ int main() {
|
||||
// Разные часы и переполнение uint32 не создают джиттер при ровной доставке.
|
||||
uint32_t sent = UINT32_MAX - 39;
|
||||
for (int i = 0; i < 100; i++) arrival.observe_arrival(900000 + i * 20, sent + (uint32_t)(i * 20));
|
||||
CHECK(arrival.high == 0 && arrival.low == 0 && arrival.reserve == 60);
|
||||
CHECK(arrival.high == 0 && arrival.low == 0 && arrival.reserve == 20);
|
||||
arrival.observe_arrival(902200, sent + 2000); // задержка доставки +200мс
|
||||
CHECK(arrival.reserve == 200);
|
||||
arrival.observe_arrival(902220, sent + 2220); // очередь пришла пачкой
|
||||
CHECK(arrival.reserve == 200);
|
||||
arrival.observe_arrival(920000, sent + 20000); // старый burst ушёл из окна
|
||||
CHECK(arrival.reserve == 60);
|
||||
CHECK(arrival.reserve == 20);
|
||||
// Небольшой джиттер больше минимума тоже учитывается, без прежнего порога 60мс.
|
||||
arrival.observe_arrival(920055, sent + 20020);
|
||||
CHECK(arrival.reserve == 35);
|
||||
arrival.observe_arrival(931055, sent + 31020);
|
||||
CHECK(arrival.reserve == 20);
|
||||
}
|
||||
debug_set_level(DEBUG_LEVEL_WARN);
|
||||
debug_enable_console(1);
|
||||
@@ -118,13 +123,13 @@ int main() {
|
||||
decoder d;
|
||||
auto* j = call_jitter_create(decode, &d, 1000);
|
||||
CHECK(j);
|
||||
push(j, 0); push(j, 1);
|
||||
push(j, 0); // 20мс достаточно для допуска в decoder, но SoundTouch ещё накапливает PCM.
|
||||
CHECK(call_jitter_pull(j, pcm, 480) == 0);
|
||||
push(j, 2);
|
||||
push(j, 1);
|
||||
CHECK(call_jitter_pull(j, pcm, 480) > 0);
|
||||
call_jitter_diagnostics diagnostic{};
|
||||
call_jitter_get_diagnostics(j, &diagnostic, 0);
|
||||
CHECK(diagnostic.resumed == 1 && diagnostic.pcm_samples == 480 && diagnostic.reserve_ms == 60);
|
||||
CHECK(diagnostic.resumed == 1 && diagnostic.pcm_samples == 480 && diagnostic.reserve_ms == 20);
|
||||
CHECK(diagnostic.encoded_ms >= 0 && diagnostic.processing_ms >= 0 && diagnostic.arrival_spread_ms == 0);
|
||||
call_jitter_get_diagnostics(j, &diagnostic, 0);
|
||||
CHECK(diagnostic.resumed == 1); // Снимок playback не потребляет события для uasync.
|
||||
@@ -133,6 +138,7 @@ int main() {
|
||||
call_jitter_get_diagnostics(j, &diagnostic, 0);
|
||||
CHECK(diagnostic.resumed == 0);
|
||||
call_jitter_range range;
|
||||
push(j, 2);
|
||||
for (int i = 3; i < 503; i++) push(j, i, 10060); // 10с сетевой задержки, затем пачка
|
||||
call_jitter_get_stats(j, nullptr, nullptr, nullptr, nullptr, &range);
|
||||
CHECK(range.reserve_ms == 1000);
|
||||
@@ -144,7 +150,7 @@ int main() {
|
||||
if (tempo > highest) highest = tempo;
|
||||
}
|
||||
call_jitter_get_stats(j, nullptr, nullptr, nullptr, nullptr, &range);
|
||||
CHECK(range.reserve_ms == 60 && range.max_ms >= 10000);
|
||||
CHECK(range.reserve_ms == 20 && range.max_ms >= 10000);
|
||||
CHECK(range.min_ms <= range.max_ms);
|
||||
CHECK(highest >= 150);
|
||||
CHECK(depth < 200);
|
||||
@@ -153,16 +159,16 @@ int main() {
|
||||
for (size_t i = 0; i < d.seen.size(); i++) CHECK(d.seen[i] == (int)i);
|
||||
for (int i = 0; i < 100; i++) call_jitter_pull(j, pcm, 480);
|
||||
size_t before = d.seen.size();
|
||||
// Один кадр плюс остаток SoundTouch ниже 60мс; два кадра уже могут заполнить запас.
|
||||
// После опустошения один кадр дополняет остаток SoundTouch и возобновляет PCM при запасе 20мс.
|
||||
push(j, next++);
|
||||
int refill = call_jitter_pull(j, pcm, 480);
|
||||
if (refill) {
|
||||
if (refill != 480) {
|
||||
call_jitter_get_stats(j, &depth, nullptr, nullptr, nullptr, &range);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "refill check: pcm=%d remaining=%dms reserve=%dms decoded=%zu",
|
||||
refill, depth, range.reserve_ms, d.seen.size() - before);
|
||||
}
|
||||
CHECK(refill == 0);
|
||||
CHECK(d.seen.size() == before);
|
||||
CHECK(refill == 480);
|
||||
CHECK(d.seen.size() == before + 1);
|
||||
for (int i = 0; i < 50; i++) push(j, next++);
|
||||
CHECK(call_jitter_pull(j, pcm, 480) > 0);
|
||||
call_jitter_destroy(j);
|
||||
@@ -174,15 +180,24 @@ int main() {
|
||||
for (int i = 0; i < 60; i++) push(j, i);
|
||||
call_jitter_range range;
|
||||
call_jitter_get_stats(j, &depth, nullptr, nullptr, nullptr, &range);
|
||||
CHECK(depth == 1200 && range.reserve_ms == 60);
|
||||
CHECK(depth == 1200 && range.reserve_ms == 20);
|
||||
CHECK(call_jitter_pull(j, pcm, 480) == 480); // первый pull сразу воспроизводит речь
|
||||
int next = 60;
|
||||
int next = 60, short_pulls = 0;
|
||||
for (int tick = 0; tick < 6000; tick++) {
|
||||
if (tick % 2 == 0) push(j, next++);
|
||||
CHECK(call_jitter_pull(j, pcm, 480) == 480);
|
||||
int produced = call_jitter_pull(j, pcm, 480);
|
||||
if (produced != 480 && ++short_pulls <= 3) {
|
||||
call_jitter_diagnostics state{};
|
||||
call_jitter_get_diagnostics(j, &state, 0);
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL,
|
||||
"steady delivery short pull tick=%d pcm=%d depth_before=%d encoded=%d processing=%d reserve=%d tempo=%d spread=%lld",
|
||||
tick, produced, state.depth_ms, state.encoded_ms, state.processing_ms, state.reserve_ms,
|
||||
state.tempo_x100, (long long)state.arrival_spread_ms);
|
||||
}
|
||||
call_jitter_get_stats(j, &depth, &tempo, &dropped, &under, &range);
|
||||
CHECK(range.reserve_ms == 60); // догон не увеличивает сетевой резерв
|
||||
CHECK(range.reserve_ms == 20); // догон не увеличивает сетевой резерв
|
||||
}
|
||||
CHECK(short_pulls == 0);
|
||||
CHECK(depth < 150 && tempo <= 110 && dropped == 0 && under == 0);
|
||||
for (size_t i = 0; i < d.seen.size(); i++) CHECK(d.seen[i] == (int)i);
|
||||
call_jitter_destroy(j);
|
||||
|
||||
Reference in new issue
Block a user