33 lines
1.7 KiB
C++
33 lines
1.7 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
|
|
/* Только управляющий поток. Исходный запрос не меняется без повторных backend XRUN.
|
|
* Рост периода на 5мс, запрос полной ёмкости до 100мс; прогрев 1с, между изменениями 5с.
|
|
* Нужны два опроса с ошибками за 5с: пачка уведомлений одного сбоя не увеличивает буфер.
|
|
* Состояние живёт до смены устройства/сессии; begin() сохраняет подобранный размер при reopen. */
|
|
struct AudioBufferTuning {
|
|
enum Result { Unchanged, Increase, Limit };
|
|
unsigned requestedMs = 0, baseMs = 0, actualMs = 0, periods = 1;
|
|
int64_t settleUntil = 0, changeAfter = 0, firstFaultAt = -1;
|
|
unsigned faultPolls = 0;
|
|
|
|
void begin(int64_t now, unsigned actualPeriodMs, unsigned periodCount) {
|
|
actualMs = actualPeriodMs; periods = std::max(1u, periodCount);
|
|
settleUntil = now + 1000; firstFaultAt = -1; faultPolls = 0;
|
|
}
|
|
|
|
Result observe(int64_t now, unsigned glitches) {
|
|
if (!glitches || now < settleUntil) return Unchanged;
|
|
if (firstFaultAt < 0 || now - firstFaultAt > 5000) { firstFaultAt = now; faultPolls = 0; }
|
|
faultPolls = std::min(faultPolls + 1, 2u);
|
|
if (faultPolls < 2 || now < changeAfter) return Unchanged;
|
|
firstFaultAt = -1; faultPolls = 0; changeAfter = now + 5000;
|
|
unsigned current = std::max({actualMs, requestedMs, baseMs}), maximum = 100 / periods;
|
|
if (!current || current >= maximum) return Limit;
|
|
requestedMs = std::min(current + 5, maximum);
|
|
return Increase;
|
|
}
|
|
};
|