Skip to content

fix(recording): prevent double-count of VideoStartGate trim in mic_start_time#1966

Merged
richiemcilroy merged 1 commit into
CapSoftware:mainfrom
ManthanNimodiya:fix/mic-av-sync-double-count
Jul 2, 2026
Merged

fix(recording): prevent double-count of VideoStartGate trim in mic_start_time#1966
richiemcilroy merged 1 commit into
CapSoftware:mainfrom
ManthanNimodiya:fix/mic-av-sync-double-count

Conversation

@ManthanNimodiya

@ManthanNimodiya ManthanNimodiya commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Root Cause

When VideoStartGate trims leading samples from the first audio frame to align it with the first video frame, the returned AudioFrame kept the original buffer capture timestamp instead of the adjusted timestamp of the first committed sample.

This flowed into first_timestamp → mic_start_time in project metadata.
In the editor, mic_offset = display_start − mic_start = trim_duration, so the renderer skipped trim_duration into the audio file, but those samples were already removed by the gate.
Same gap counted twice: audio arrives late by up to one buffer period (~35 ms at 48 kHz / 1680-sample buffers).

Fix

Advance the frame timestamp by trim_samples / sample_rate before returning UseFrame, so mic_start_time reflects the first committed sample (≈ video start) and mic_offset collapses to ~0.

No change to the Passthrough path or the stale-startup audio_timing_repair_offset mechanism.
Added a timestamp assertion to the existing apply_gate_audio_leads_trims_front unit test; all 190 unit tests pass.

Greptile Summary

This PR fixes a double-counting bug where VideoStartGate trimmed leading audio samples to align with the first video frame but kept the original buffer-capture timestamp on the returned AudioFrame, causing the editor to also skip ahead by trim_duration because mic_offset = display_start − mic_start equalled the already-removed gap. The fix advances frame.timestamp by trim_samples * 1e9 / sample_rate nanoseconds before constructing the trimmed AudioFrame, collapsing mic_offset to near-zero.

  • Core fix (apply_video_start_gate): computes trim_duration from the integer trim-sample count and adds it to frame.timestamp using the existing Timestamp + Duration trait impl, which handles every platform variant (Instant, SystemTime, PerformanceCounter, MachAbsoluteTime) correctly.
  • Test update (apply_gate_audio_leads_trims_front): adds an assertion that the returned frame's timestamp equals start + trim_duration, comparing via signed_duration_since_secs to avoid direct Timestamp equality. The formula mirrors the production code's integer round-trip, which is exact for the 20 ms / 48 kHz values in the test.

Confidence Score: 5/5

Safe to merge — the change is a narrow, self-contained timestamp correction with no impact on the Passthrough or DropFrame paths.

The arithmetic is correct, division by zero is guarded by the existing zero-sample early return, integer overflow is not a concern given the 500 ms alignment limit, and the Timestamp + Duration trait handles all platform variants. The new unit-test assertion validates the same computation end-to-end.

No files require special attention.

Important Files Changed

Filename Overview
crates/recording/src/output_pipeline/core.rs Advances the AudioFrame timestamp by trim_samples / sample_rate after the VideoStartGate front-trim so that mic_start_time in metadata reflects the first committed sample; adds a matching assertion to the existing unit test.

Reviews (1): Last reviewed commit: "fix(recording): advance gate frame times..." | Re-trigger Greptile

// Without this, the editor's mic_offset = display_start - mic_start equals
// trim_duration and causes it to skip that same duration a second time.
let trim_duration = Duration::from_nanos(
trim_samples as u64 * 1_000_000_000 / sample_rate as u64,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix. Minor tweak: consider reusing the existing samples_to_nanos() helper here to avoid a potential divide-by-zero and to keep overflow/rounding behavior consistent.

Suggested change
trim_samples as u64 * 1_000_000_000 / sample_rate as u64,
let trim_duration =
Duration::from_nanos(samples_to_nanos(trim_samples as u64, sample_rate));

// metadata reflects the first committed sample, preventing the editor
// from double-counting the same gap as a skip offset.
let trim_duration = Duration::from_nanos(
expected_trim as u64 * 1_000_000_000 / info.sample_rate as u64,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thought in the test: using samples_to_nanos() keeps the conversion logic centralized and avoids info.sample_rate == 0 panicking in the future.

Suggested change
expected_trim as u64 * 1_000_000_000 / info.sample_rate as u64,
let trim_duration = Duration::from_nanos(
samples_to_nanos(expected_trim as u64, info.sample_rate),
);

@richiemcilroy richiemcilroy merged commit cb90632 into CapSoftware:main Jul 2, 2026
14 of 17 checks passed
@richiemcilroy

Copy link
Copy Markdown
Member

/tip $150

@ManthanNimodiya

Copy link
Copy Markdown
Contributor Author

@algora-pbc

@richiemcilroy

richiemcilroy commented Jul 2, 2026

Copy link
Copy Markdown
Member

@algora-pbc /tip $150

@ManthanNimodiya

Copy link
Copy Markdown
Contributor Author

hey @zcesur, I think there might be an issue with @algora-pbc on this PR, the tip command was posted but the bot didn't respond. could you have a look when you get a chance?
Thank you

@algora-pbc

algora-pbc Bot commented Jul 2, 2026

Copy link
Copy Markdown

Please visit Algora to complete your tip via Stripe.

@richiemcilroy

Copy link
Copy Markdown
Member

/tip $220

@algora-pbc

algora-pbc Bot commented Jul 2, 2026

Copy link
Copy Markdown

Please visit Algora to complete your tip via Stripe.

@algora-pbc

algora-pbc Bot commented Jul 2, 2026

Copy link
Copy Markdown

🎉🎈 @ManthanNimodiya has been awarded $220 by Cap! 🎈🎊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants