Repository navigation
Conversation
CapSoftware#2144) - Convert MachAbsoluteTimestamp and PerformanceCounterTimestamp tick/duration arithmetic to rounded 128-bit integer ratio math with cached timebase info - Add integer-exact signed_duration_since_nanos across MachAbsoluteTimestamp, PerformanceCounterTimestamp, and Timestamp - Route MasterClock::remap_raw_ns directly through signed_duration_since_nanos instead of roundtripping through f64 seconds on every video/audio frame - Add unit tests covering high-uptime tick counters (> 2^53), Apple Silicon 125/3 timebases, and multi-hour MasterClock nanosecond remapping
|
@cocvn157 is attempting to deploy a commit to the Cap Software Inc Team on Vercel. A member of the Team first needs to authorize it. |
| use serde::{Deserialize, Serialize}; | ||
| use specta::Type; |
There was a problem hiding this comment.
serde and specta are imported without being declared in crates/timestamp/Cargo.toml. Neither is available as a direct dependency, so cap-timestamp fails to compile on every platform. Add both dependencies or remove the new imports and derives.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/timestamp/src/lib.rs
Line: 11-12
Comment:
**New dependencies are missing**
`serde` and `specta` are imported without being declared in `crates/timestamp/Cargo.toml`. Neither is available as a direct dependency, so `cap-timestamp` fails to compile on every platform. Add both dependencies or remove the new imports and derives.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| impl MasterClock { | ||
| pub fn new() -> Self { | ||
| Self::from_timestamps(Timestamps::now()) |
There was a problem hiding this comment.
The replacement MasterClock removes APIs that the recording pipeline still uses. core.rs and audio_mixer.rs still import SourceClockState and SourceClockOutcome, call MasterClock::new(timestamps, rate), and use sample-count methods. These missing symbols and incompatible calls prevent the recording crate from compiling.
Keep the existing clock APIs and apply the integer conversion within them, or migrate all callers in this PR.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/timestamp/src/master_clock.rs
Line: 29-31
Comment:
**Recording clock calls break**
The replacement `MasterClock` removes APIs that the recording pipeline still uses. `core.rs` and `audio_mixer.rs` still import `SourceClockState` and `SourceClockOutcome`, call `MasterClock::new(timestamps, rate)`, and use sample-count methods. These missing symbols and incompatible calls prevent the recording crate from compiling.
Keep the existing clock APIs and apply the integer conversion within them, or migrate all callers in this PR.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| #[cfg(windows)] | ||
| Self::PerformanceCounter(counter) => { | ||
| counter.checked_duration_since(start.performance_counter) | ||
| pub fn duration_since(&self, start: Timestamps) -> Option<Duration> { |
There was a problem hiding this comment.
Timestamp::duration_since now returns Option<Duration>, but existing callers still use its result as a Duration. For example, AudioMixer::detect_laggard_source calls .checked_sub(...) on it. The rewrite also removes Timestamp::from_cpal, checked_duration_since, timestamp arithmetic, and PerformanceCounterTimestamp::from_100ns while capture code still calls them.
Preserve these APIs while adding nanosecond conversion, or update their callers together. Otherwise, the recording crate cannot compile.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/timestamp/src/lib.rs
Line: 90
Comment:
**Capture timestamp calls break**
`Timestamp::duration_since` now returns `Option<Duration>`, but existing callers still use its result as a `Duration`. For example, `AudioMixer::detect_laggard_source` calls `.checked_sub(...)` on it. The rewrite also removes `Timestamp::from_cpal`, `checked_duration_since`, timestamp arithmetic, and `PerformanceCounterTimestamp::from_100ns` while capture code still calls them.
Preserve these APIs while adding nanosecond conversion, or update their callers together. Otherwise, the recording crate cannot compile.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| /// Returns the signed elapsed duration in nanoseconds since `start`. | ||
| /// Negative if `self` is earlier than `start`. |
There was a problem hiding this comment.
The new documentation comments only restate the method name and return value. AGENTS.md requires comments to capture non-obvious context and explicitly bans comments that paraphrase parameter names or narrate the code. Remove these comments or explain a non-obvious timing constraint instead. The same pattern appears above signed_duration_since_secs and elsewhere in the rewrite. This repository requirement must be satisfied before merging.
Context Used: AGENTS.md (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/timestamp/src/lib.rs
Line: 105-106
Comment:
**Comments repeat the code**
The new documentation comments only restate the method name and return value. `AGENTS.md` requires comments to capture non-obvious context and explicitly bans comments that paraphrase parameter names or narrate the code. Remove these comments or explain a non-obvious timing constraint instead. The same pattern appears above `signed_duration_since_secs` and elsewhere in the rewrite. This repository requirement must be satisfied before merging.
**Context Used:** AGENTS.md ([source](https://github.com/capsoftware/cap/blob/main/AGENTS.md))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Fixes #2144
/claim #2144
Problem
During longer recordings (or on machines with high system uptime where raw hardware tick counters approach or exceed$2^{53}$ ), the cursor gradually drifts out of sync with the video track:
f64tick/nanosecond conversions in platform timestamps (macos.rs&win.rs):MachAbsoluteTimestamp(crates/timestamp/src/macos.rs) converted rawmach_absolute_time()ticks andDurationoffsets usingf64((diff as f64 * freq) as u64,(self.0 as f64 + ticks) as u64) and queriedmach_timebase_infoon every call. On Apple Silicon (numer = 125, denom = 3),numer / denomis a repeating fraction (41.666...) and casting raw tick counters throughf64loses low-order tick precision once uptime ticks exceed the 53-bitf64mantissa.PerformanceCounterTimestamp(crates/timestamp/src/win.rs) similarly usedrhs.as_secs_f64() * freq as f64inAdd<Duration>/Sub<Duration>and(self.0 - other.0) as f64 / (perf_freq() as f64)insigned_duration_since_secs, losing sub-tick and sub-microsecond precision on long recordings.Lossy
f64seconds roundtrip on every frame inMasterClock::remap_raw_ns(master_clock.rs&lib.rs):MasterClock::remap_raw_ns(source_ts)(crates/recording/src/output_pipeline/core.rs).MasterClock::remap_raw_nscalledsource_ts.signed_duration_since_secs(self.timestamps)(converting integer nanoseconds/ticks intof64seconds) and then multiplied back by1_000_000_000.0inf64(seconds_to_ns_saturating), whereas cursor events record elapsed time directly fromInstant::elapsed().Solution
crates/timestamp/src/macos.rs:mach_timebase_info(numer, denom)in aOnceLock<(u128, u128)>.f64tick/nanosecond conversions induration_since,checked_duration_since,duration_since_unix_epoch,Add<Duration>, andSub<Duration>with roundedu128ratio arithmetic (ticks_to_nanos_with_ratio/nanos_to_ticks_with_ratio) and integersaturating_add/saturating_sub.signed_duration_since_nanos(&self, other: Self) -> i128and derivesigned_duration_since_secsfrom it.crates/timestamp/src/win.rs:f64tick conversions with roundedi128/u128integer ratio math (counter_diff_to_nanos/duration_to_counter_ticks).signed_duration_since_nanos(&self, other: Self) -> i128and updatesigned_duration_since_secsto use exact integer nanosecond conversion rather than(self.0 - other.0) as f64 / (perf_freq() as f64).crates/timestamp/src/lib.rs&crates/timestamp/src/master_clock.rs:Timestamp::signed_duration_since_nanos(&self, start: Timestamps) -> i128across all platform variants (Instant,SystemTime,PerformanceCounter,MachAbsoluteTime).MasterClock::remap_raw_nsto usesource_ts.signed_duration_since_nanos(self.timestamps)directly and saturate toi64, eliminating theinteger -> f64 seconds -> f64 * 1e9 -> i64roundtrip on every frame.macos.rs,win.rs, andmaster_clock.rsverifying exactDuration::ZEROidentity at(1 << 53) + 1ticks, fractional frame intervals (16_666_667 ns), Apple Silicon125/3ratio rounding, and multi-hour nanosecond remapping inMasterClock::remap_raw_ns.Do not merge until the missing dependencies and broken recording APIs are fixed and the comments policy is satisfied.
Findings
Fix with agent prompt
Summary
Replaces floating-point timestamp conversions with integer arithmetic and adds exact nanosecond remapping.
Reviews (1) · Last reviewed commit: "fix(timestamp): eliminate f64 timebase a..." · Reviewed by Greptile