Browse Source

Cover immediate buffer probe failures and document tuning

master
evgeny 4 days ago
parent
commit
91030de5ea
  1. 31
      doc/chat_call_arch.md
  2. 26
      tools/chatgui-android/app/src/test/java/com/utun/chat/data/CallPlaybackBufferTest.kt

31
doc/chat_call_arch.md

@ -141,8 +141,8 @@ ACTIVE запрашивается до создания аудиоустройс
INFO-логи Android показывают длительности настройки режима, регистрации callback, BT-профиля, выбора маршрута, INFO-логи Android показывают длительности настройки режима, регистрации callback, BT-профиля, выбора маршрута,
создания/старта устройств, первого чтения микрофона и первой записи в AudioTrack, а также готовность другого направления. создания/старта устройств, первого чтения микрофона и первой записи в AudioTrack, а также готовность другого направления.
Общий `call_audio` логирует время ожидания первого PCM; запись в AudioTrack может содержать начальную тишину. Общий `call_audio` логирует время ожидания первого PCM; запись в AudioTrack может содержать начальную тишину.
Эффективный рабочий буфер AudioTrack на всех поддерживаемых API запрашивается размером Эффективный рабочий буфер AudioTrack на всех поддерживаемых API при старте запрашивается размером
два блока PCM (40мс); на API 31+ отдельно задаётся такой же стартовый порог. два блока PCM (40мс); на API 31+ стартовый порог следует фактически принятому размеру.
Ёмкость выделенной памяти может быть больше. Ограничение повторяется по callback фактической Ёмкость выделенной памяти может быть больше. Ограничение повторяется по callback фактической
смены выхода на main, под trackLock; callback старого AudioTrack игнорируется и снимается при stop. смены выхода на main, под trackLock; callback старого AudioTrack игнорируется и снимается при stop.
Подачу PCM задаёт свободное место в AudioTrack, без дополнительного таймера 20мс. Подачу PCM задаёт свободное место в AudioTrack, без дополнительного таймера 20мс.
@ -155,7 +155,9 @@ INFO-логи Android показывают длительности настро
written-played оставался 120–160мс; одного стартового порога недостаточно. written-played оставался 120–160мс; одного стартового порога недостаточно.
Замер Samsung подтвердил постоянную очередь 40мс. При прежнем параллельном управлении маршрутом Замер Samsung подтвердил постоянную очередь 40мс. При прежнем параллельном управлении маршрутом
AudioTrack пересоздавался, очередь временно достигала 160мс, а ожидание свободного места — 328–336мс. AudioTrack пересоздавался, очередь временно достигала 160мс, а ожидание свободного места — 328–336мс.
При старте AudioTrack.play занимал 1080мс. Новое владение маршрутом нужно проверить тем же сценарием. При старте AudioTrack.play занимал 1080мс. После перехода к единственному владельцу Telecom
в проверенном звонке старт занял 62мс, очередь оставалась не более 40мс и при смене выхода.
Переключение всё ещё останавливало потребление на 293–328мс; этот всплеск принимает сетевой JB.
На desktop `AudioDiag: capture clock` при call=debug выводит секундную сводку исходных backend-блоков: На desktop `AudioDiag: capture clock` при call=debug выводит секундную сводку исходных backend-блоков:
число блоков/сэмплов, накопленную последовательность, диапазон ошибки относительно конца предыдущего блока, число блоков/сэмплов, накопленную последовательность, диапазон ошибки относительно конца предыдущего блока,
@ -172,12 +174,23 @@ Backend публикует только числовой снимок в огр
Счётчик sequence описывает полученные backend-сэмплы; отсутствие потерь очереди само по себе Счётчик sequence описывает полученные backend-сэмплы; отсутствие потерь очереди само по себе
не доказывает непрерывность физического захвата. Проверять вместе с hole/overflow и route-событиями. не доказывает непрерывность физического захвата. Проверять вместе с hole/overflow и route-событиями.
Дальнейший подбор минимальной очереди аудиоустройства (ещё не реализован) отделён от JB/SoundTouch: На Android `CallPlaybackBuffer` подбирает рабочую очередь отдельно от JB/SoundTouch:
старт с проверенного размера, редкие попытки уменьшения после стабильного участка, увеличение при после 30с наблюдаемого продвижения playback head без underrun пробует уменьшить её на один
подтверждённом backend underrun, пауза обучения при смене маршрута/запуске. Размер запрашивается блок PCM (960 сэмплов, 20мс), до одного блока или фактического минимума устройства.
аппаратными шагами; сохраняется фактически принятый размер, а не только запрос. При росте AudioTrack.underrunCount добавляет один блок в пределах выделенной ёмкости.
Ожидание полного буфера и недостача сети не являются поводом увеличить очередь устройства. Интервал следующей пробы удваивается (60/120/240/300с), чтобы не повторять частые неудачные уменьшения.
На Android регулируется AudioTrack без flush/recreate; на desktop выход принадлежит SoundManager, После старта, запроса/подтверждения маршрута и увеличения даются 2с на стабилизацию;
после уменьшения первый underrun учитывается немедленно. Отсутствие продвижения head или
пропуск наблюдений >1с обнуляет стабильный участок. Сброс системного счётчика учитывается отдельно.
Фактическая смена выхода начинает подбор с 40мс заново. Непринятая меньшая заявка фиксирует
нижнюю границу до следующего выхода; ошибки API выключают подбор с WARN/ERROR, сохраняя воспроизведение.
Reporter управляет размером под trackLock независимо от фильтра debug; playback не берёт этот lock.
Нет flush/recreate, частичная запись PCM сохраняется. После смены размера/выхода через секунду
повторно измеряется задержка для AEC. Ожидание полного буфера и недостача сети не увеличивают его размер.
Лог настройки содержит reason, previous/requested/actualFrames и прирост underruns;
достижение ёмкости предупреждает не чаще раза в 10с. Принятие и стабильность 20мс ещё требуют
проверки на Samsung; буферы HAL и Bluetooth могут добавлять собственную задержку.
На desktop адаптация устройства ещё не реализована: выход принадлежит SoundManager,
изменение backend-буфера должно выполняться его владельцем, а не отдельным звонком. изменение backend-буфера должно выполняться его владельцем, а не отдельным звонком.
Диагностика Android при `call=debug`: playback сохраняет один числовой снимок на блок (20мс) Диагностика Android при `call=debug`: playback сохраняет один числовой снимок на блок (20мс)

26
tools/chatgui-android/app/src/test/java/com/utun/chat/data/CallPlaybackBufferTest.kt

@ -63,7 +63,7 @@ class CallPlaybackBufferTest {
assertEquals("stable-probe", d.tick()?.reason) assertEquals("stable-probe", d.tick()?.reason)
} }
@Test fun AcceptedHardwareMinimumIsNotProbedForever() { @Test fun acceptedHardwareMinimumIsNotProbedForever() {
val d = Device(minimum = 1440) val d = Device(minimum = 1440)
d.run(32_000) d.run(32_000)
assertEquals(1440, d.frames) assertEquals(1440, d.frames)
@ -113,4 +113,28 @@ class CallPlaybackBufferTest {
d.run(32_000) d.run(32_000)
assertEquals(960, d.frames) assertEquals(960, d.frames)
} }
@Test fun firstUnderrunImmediatelyAfterShrinkRejectsProbe() {
val d = Device()
d.run(32_000)
assertEquals(960, d.frames)
d.underruns++
assertEquals("underrun", d.tick()?.reason)
assertEquals(1920, d.frames)
}
@Test fun repeatedFailuresBackOffToFiveMinutesButStillAllowRecovery() {
val d = Device()
d.run(32_000)
val delays = listOf(60_000L, 120_000L, 240_000L, 300_000L, 300_000L)
for (delay in delays) {
d.underruns++
assertEquals("underrun", d.tick()?.reason)
assertEquals(1920, d.frames)
d.run(delay + 1_800)
assertEquals(1920, d.frames)
assertEquals("stable-probe", d.tick()?.reason)
assertEquals(960, d.frames)
}
}
} }

Loading…
Cancel
Save