35 lines
1.8 KiB
C++
35 lines
1.8 KiB
C++
#pragma once
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
|
|
/* Резерв готового PCM desktop: bufferMs = 20..80, кратно 20 (проверяет VoiceAudioIo::start).
|
|
* Размер callback и настроенный запас задают нижнюю границу; недостача добавляет
|
|
* один блок, 10 секунд стабильного вывода убирают один. Частично сыгранный блок — сверх резерва.
|
|
* Только RX worker; время монотонное. Четыре PCM-слота доступны в AudioEventQueue<Playback, 12>. */
|
|
class VoicePlaybackBuffer {
|
|
public:
|
|
explicit VoicePlaybackBuffer(unsigned bufferMs = 20) : minimumBlocks(bufferMs / 20) { reset(); }
|
|
unsigned blocks = 1;
|
|
unsigned callbackFrames = 960;
|
|
void reset() { blocks = minimumBlocks; callbackFrames = 960; stableSince = 0; lastGrowth = 0; lastSample = 0; probeUs = 10000000; }
|
|
void sample(int64_t nowUs, unsigned frames, bool missing) {
|
|
callbackFrames = frames;
|
|
unsigned minimum = std::max(minimumBlocks, std::clamp((frames + 959) / 960, 1u, 4u));
|
|
if (!stableSince || nowUs - lastSample > 1000000) stableSince = nowUs;
|
|
lastSample = nowUs;
|
|
if (minimum > blocks) { blocks = minimum; stableSince = nowUs; }
|
|
if (missing) {
|
|
stableSince = nowUs;
|
|
if (!lastGrowth || nowUs - lastGrowth >= 500000) {
|
|
blocks = std::min(blocks + 1, 4u); lastGrowth = nowUs;
|
|
probeUs = std::min(probeUs * 2, int64_t(300000000));
|
|
}
|
|
} else if (blocks > minimum && nowUs - stableSince >= probeUs) {
|
|
--blocks; stableSince = nowUs;
|
|
}
|
|
}
|
|
private:
|
|
unsigned minimumBlocks;
|
|
int64_t stableSince = 0, lastGrowth = 0, lastSample = 0, probeUs = 10000000;
|
|
};
|