You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

31 lines
1.6 KiB

#pragma once
#include <algorithm>
#include <cmath>
#include <cstdint>
// Позиция PCM задаёт непрерывное время; backend уточняет привязку без скачков на каждом обновлении latency.
// Единственный владелец — capture worker. Настоящий разрыв sequence/route/time вызывает reset у владельца.
struct VoiceCaptureClock {
bool initialized = false;
uint64_t originSequence = 0, previousSequence = 0;
int64_t originUs = 0, errorUs = 0, adjustmentUs = 0;
double phaseUs = 0;
void reset() { *this = {}; }
int64_t map(uint64_t sequence, int64_t observedUs) {
if (!initialized) {
initialized = true; originSequence = previousSequence = sequence; originUs = observedUs;
return observedUs;
}
const double nominal = (sequence - originSequence) * (1000000.0 / 48000.0);
const double elapsed = (sequence - previousSequence) * (1000000.0 / 48000.0);
const double error = double(observedUs - originUs) - nominal - phaseUs;
// Постоянная времени 2с; предел 0.5% (не более 100мкс коррекции на 20мс PCM).
const double adjustment = std::clamp(error * (1.0 - std::exp(-elapsed / 2000000.0)), -elapsed / 200, elapsed / 200);
phaseUs += adjustment;
previousSequence = sequence;
errorUs = std::llround(error); adjustmentUs = std::llround(adjustment);
return originUs + std::llround(nominal + phaseUs);
}
};