diff --git a/doc/stream.txt b/doc/stream.txt index 7d467d4c..9c8e43a2 100644 --- a/doc/stream.txt +++ b/doc/stream.txt @@ -864,7 +864,8 @@ Android: GAP создаёт новый input/origin, сохраняя общее устройство и часы остальных трансляций. Watchdog 2s проверяет отсутствие движения hardware head только при достаточном заполнении либо заблокированной записи; намеренная пауза и ожидание данных до порога запуска не считаются зависанием. Ошибка содержит состояние и счётчики устройства. - Защитный guard аудиоконтроллера — максимум 40ms и audio device lead + 20ms. + Защитный guard аудиоконтроллера — максимум 40ms и audio device lead + 20ms, плюс + внутренний lookahead SoundTouch (SETTING_INITIAL_LATENCY при текущем темпе). Наблюдённое опережение decoder остаётся диагностикой и не увеличивает задержку звука. Отсутствие output progress 10s при наличии работы даёт ERROR; сетевые паузы и ожидание PTS допустимы. Состояния ожидания KEY и decoder разделены; логи показывают inputs/decoded/shown, рабочие slots, inflight и decoderLeadUs. diff --git a/tools/chatgui-android/jni_bridge/android_stream_jni.c b/tools/chatgui-android/jni_bridge/android_stream_jni.c index aebbdbcd..0403769a 100644 --- a/tools/chatgui-android/jni_bridge/android_stream_jni.c +++ b/tools/chatgui-android/jni_bridge/android_stream_jni.c @@ -201,6 +201,7 @@ JNIEXPORT jlongArray JNICALL Java_com_utun_chat_data_NativeLib_nativeStreamPlayb if (proposed > p->position) p->position = proposed; } p->time_us = now; + if (p->audio) guard += stream_playback_audio_latency_us(p->audio); if (stream_playback_clock_update(&p->clock, now, p->position, ready, guard, pending, starved, &p->state) < 0) return NULL; jlong values[] = {p->position, p->state.reserve_us, p->state.minimum_us, p->state.tempo_milli, p->state.waiting, p->audio ? stream_playback_audio_needs_input(p->audio) : 0, diff --git a/tools/chatgui/src/streamplayer_window.cpp b/tools/chatgui/src/streamplayer_window.cpp index 880e0e9b..82631755 100644 --- a/tools/chatgui/src/streamplayer_window.cpp +++ b/tools/chatgui/src/streamplayer_window.cpp @@ -335,6 +335,7 @@ void StreamPlayerWindow::decode() { bool starved = p.underruns != observedGaps; observedGaps = p.underruns; if (!p.activeAudio && p.position + (now - p.clockAt) * p.adaptation.tempo_milli / 1000 > p.ready) starved = true; int64_t guardUs = p.activeAudio ? std::max(40000, p.deviceLead + 20000) : p.framePeriod; + if (p.sound) guardUs += stream_playback_audio_latency_us(p.sound); int64_t pending = p.sound ? stream_playback_audio_pending_gain(p.sound, played) : 0; if (stream_playback_clock_update(&p.adaptation, now, std::max(p.position, position), p.ready, guardUs, pending, !p.ended && starved, &p.timing) < 0) p.resync = true;