libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
ntv2clock.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_NTV2
13
14#include <promeki/atomic.h>
15#include <promeki/clock.h>
16#include <promeki/clockdomain.h>
17#include <promeki/framerate.h>
19#include <promeki/mutex.h>
20#include <promeki/namespace.h>
21#include <promeki/timestamp.h>
22
23PROMEKI_NAMESPACE_BEGIN
24
25class Ntv2Device;
26
118class Ntv2DeviceClock : public Clock {
119 public:
130 static const ClockDomain &domainFor(const Ntv2Device &device);
131
147 Ntv2DeviceClock(Ntv2Device *device, bool vbiFallback);
148
149 ~Ntv2DeviceClock() override;
150
172 static Ntv2DeviceClock *createForTest(const String &testDomainName, bool vbiFallback);
173
174 int64_t resolutionNs() const override;
175 ClockJitter jitter() const override;
176
202 double rateRatio() const override;
203
217 void noteVbi(const TimeStamp &now);
218
229 void setSampleRate(float sampleRateHz);
230
253 MediaTimeStamp mediaTimeStampFromSamples(uint64_t samples) const;
254
262 void setFrameRate(const FrameRate &frameRate);
263
264 // ---- Test seam ----
265
280 void setCounterSourceForTest(bool (*fn)(uint32_t *out, void *ctx), void *ctx);
281
296 void setWallTimeSourceForTest(int64_t (*fn)(void *ctx), void *ctx);
297
310 static constexpr int64_t kRateBaselineMinWindowNs = 5'000'000'000LL;
311
321 static constexpr int64_t kRateUpdateIntervalNs = 1'000'000'000LL;
322
333 static constexpr int _kRateLpfAlphaPer1000 = 100;
334
335 protected:
336 Result<int64_t> raw() const override;
337 Error sleepUntilNs(int64_t targetNs) const override;
338
339 private:
340 // Test-only constructor — takes the ClockDomain directly so
341 // we can build a clock without an Ntv2Device handle.
342 Ntv2DeviceClock(const ClockDomain &domain, bool vbiFallback);
343
344 int64_t sampleTicksToNs(uint64_t ticks) const;
345
346 Ntv2Device *_device = nullptr;
347 bool _vbiFallback = false;
348
349 // Sample rate in Hz; used to convert counter → ns.
350 // Mutated via setSampleRate which takes _mutex.
351 float _sampleRateHz = 48000.0f;
352
353 // 32 → 64 wrap shadow. _highBits and _lastLow are
354 // updated under _mutex on every raw() read.
355 mutable Mutex _mutex;
356 mutable uint32_t _lastLow = 0;
357 mutable uint64_t _highBits = 0;
358 mutable bool _hasShadow = false;
359
360 // VBI-fallback last-wake tick (host monotonic ns).
361 mutable Atomic<int64_t> _lastVbiNs{0};
362
363 // Jitter sizing in VBI mode.
364 FrameRate _frameRate;
365
366 // Optional test counter source (set via
367 // setCounterSourceForTest). Always nullptr in
368 // production — production reads CNTV2Card::GetRawAudioTimer.
369 bool (*_testCounterFn)(uint32_t *, void *) = nullptr;
370 void *_testCounterCtx = nullptr;
371
372 // Optional test wall-time source (set via
373 // setWallTimeSourceForTest). Production reads
374 // TimeStamp::now().nanoseconds() inside the drift
375 // estimator.
376 int64_t (*_testWallFn)(void *) = nullptr;
377 void *_testWallCtx = nullptr;
378
379 // Drift estimator state. All mutated from raw()
380 // under _mutex; rateRatio() reads _ratePpb lock-free
381 // via Atomic. PPB = parts per billion; 1e9 ≡ 1.0.
382 mutable Atomic<int64_t> _ratePpb{1'000'000'000};
383 mutable bool _rateBaselineValid = false;
384 mutable int64_t _rateBaselineWallNs = 0;
385 mutable int64_t _rateBaselineCounterNs = 0;
386 mutable int64_t _lastRateUpdateWallNs = 0;
387};
388
389PROMEKI_NAMESPACE_END
390
391#endif // PROMEKI_ENABLE_NTV2