Browse Source

Document adaptive buffer limits and preserve failed-open backoff

stream-multiview
evgeny 1 week ago
parent
commit
0c26daf3f5
  1. 14
      doc/service_lifecycle.md
  2. 2
      tools/chatgui/src/audio_device.cpp
  3. 3
      tools/chatgui/tests/test_audio_recovery.cpp

14
doc/service_lifecycle.md

@ -175,6 +175,20 @@ RX продолжает работать, рация снимает PTT, авт
Сброс контекста и уничтожение владельца дожидаются worker до освобождения miniaudio-контекста.
Штатное закрытие исправного устройства сохраняет синхронный порядок.
`AudioDevice` подстраивает буфер по подтверждённым backend XRUN: WASAPI DATA_DISCONTINUITY
на входе, ALSA EPIPE, PulseAudio capture hole/overflow и playback underflow. Notification
только увеличивает атомарный счётчик, решение и лог выполняются в GUI recovery timer.
Исходные параметры, включая Linux capture period=10мс, сохраняются до повторных сбоев.
Первая секунда после start исключена; нужны ошибки в двух опросах за 5с. Период увеличивается
на 5мс, не чаще раза в 5с, до общей запрошенной ёмкости 100мс с учётом числа периодов.
Фактический размер согласует backend; исходный или уже достигнутый больший размер не уменьшается.
При достижении предела повторные сбои логируются без новых перезапусков. Подобранный запрос
сохраняется при recovery, сбрасывается при смене устройства/сессии; стабильный звук не вызывает reopen.
Подстройка микрофона закрывает устройство асинхронно, останавливая TX worker и сохраняя RX.
Общая capture-сессия отсоединяет callbacks до close и заново подготавливает потребителей после init.
Новая подписка во время close откладывается, stop удаляет её без ожидания backend.
Первое переоткрытие после подстройки не использует backoff; при ошибке открытия действует обычный retry.
В desktop-видеозвонке Windows/Linux камера живёт в отдельном процессе того же
`vibechat --call-camera-worker`. Служебный вход выполняется до конфига, БД и
single-instance lock. Перечисление устройств, Qt/V4L2, преобразование и освобождение

2
tools/chatgui/src/audio_device.cpp

@ -215,7 +215,7 @@ bool AudioDevice::needsRecovery() {
bool AudioDevice::retryReady() const { return !m_device && !closing() && m_clock.elapsed() >= m_retryAt; }
void AudioDevice::retryLater() {
if (m_resizePending) { m_retryAt = m_clock.elapsed(); m_retryDelay = 250; return; }
if (m_resizePending) { m_resizePending = false; m_retryAt = m_clock.elapsed(); m_retryDelay = 250; return; }
m_retryAt = m_clock.elapsed() + m_retryDelay;
DEBUG_WARN(DEBUG_CATEGORY_CALL, "audio: %s retry in %dms", m_role, m_retryDelay);
m_retryDelay = std::min(m_retryDelay * 2, 2000);

3
tools/chatgui/tests/test_audio_recovery.cpp

@ -345,6 +345,9 @@ static void buffer_tuning_policy() {
tuning.begin(now + 100, 33, 3); now += 5000;
REQUIRE(tuning.observe(now, 1) == AudioBufferTuning::Unchanged);
REQUIRE(tuning.observe(now + 200, 1) == AudioBufferTuning::Limit && tuning.requestedMs == 33);
tuning = {}; tuning.baseMs = 20; tuning.begin(0, 10, 3); // Backend может округлить исходный запрос вниз.
REQUIRE(tuning.observe(1100, 1) == AudioBufferTuning::Unchanged);
REQUIRE(tuning.observe(1300, 1) == AudioBufferTuning::Increase && tuning.requestedMs == 25);
ma_context context{}; context.backend = ma_backend_pulseaudio;
auto config = ma_device_config_init(ma_device_type_capture); config.periodSizeInMilliseconds = 20;
AudioDevice::requestLowLatency(&context, config);

Loading…
Cancel
Save