Skip to content

Conversation

@richiemcilroy
Copy link
Member

@richiemcilroy richiemcilroy commented Dec 31, 2025

Adds drift correction for audio and video timestamps to prevent sync issues during long recordings, resolution downscaling for hardware encoder limits, and retry logic for Windows file operations. Also filters incomplete recordings by cutoff date in recovery and removes verbose camera trace logs.

Greptile Summary

  • Implements comprehensive drift correction for audio/video timestamps to prevent sync issues during long recordings by tracking wall clock vs stream time divergence
  • Adds resolution downscaling for hardware encoder compatibility to prevent recording failures when capture resolution exceeds H.264 limits (4096px max dimension)
  • Introduces Windows-specific retry logic for file operations and filters old incomplete recordings from recovery to improve stability and performance

Important Files Changed

Filename Overview
crates/recording/src/output_pipeline/core.rs Added AudioDriftTracker and VideoDriftTracker with extensive testing; implements baseline offset capture and drift ratio corrections for A/V sync
crates/recording/src/studio_recording.rs Refactored audio muxer from segmented to fragmented approach; added GPU-compatible resolution calculation and changed audio output to single files
crates/recording/src/sources/audio_mixer.rs Added drift correction tracking per audio source with wall clock vs audio duration comparison to maintain sync during extended recordings

Confidence score: 4/5

  • This PR introduces complex timing and synchronization logic that requires careful testing to ensure it works correctly across different hardware configurations and recording durations
  • Score reflects the comprehensive nature of the changes affecting core recording infrastructure, though the implementation appears well-structured with good test coverage and safety bounds
  • Pay close attention to the drift correction algorithms in core.rs and audio_mixer.rs as these directly impact A/V synchronization quality

Sequence Diagram

sequenceDiagram
    participant User
    participant RecordingModule as "recording.rs"
    participant SegmentedVideoEncoder as "SegmentedVideoEncoder"
    participant H264Encoder
    participant AudioMixer
    participant DriftTracker as "Audio/VideoDriftTracker"
    participant RecoveryManager
    
    User->>RecordingModule: "start_recording(inputs)"
    
    RecordingModule->>RecordingModule: "validate state & create project dir"
    RecordingModule->>RecordingModule: "write initial RecordingMeta"
    RecordingModule->>SegmentedVideoEncoder: "init(path, video_config, config)"
    SegmentedVideoEncoder->>H264Encoder: "build(&mut output)"
    H264Encoder-->>SegmentedVideoEncoder: "encoder instance"
    SegmentedVideoEncoder-->>RecordingModule: "encoder ready"
    
    RecordingModule->>AudioMixer: "setup(audio_sources)"
    AudioMixer-->>RecordingModule: "mixer ready"
    
    RecordingModule->>RecordingModule: "emit RecordingEvent::Started"
    
    loop "Recording Loop"
        RecordingModule->>SegmentedVideoEncoder: "queue_frame(frame, timestamp)"
        SegmentedVideoEncoder->>DriftTracker: "calculate_timestamp(raw_duration, wall_clock)"
        DriftTracker-->>SegmentedVideoEncoder: "corrected_timestamp"
        SegmentedVideoEncoder->>H264Encoder: "queue_frame(frame, corrected_timestamp)"
        H264Encoder-->>SegmentedVideoEncoder: "frame encoded"
        
        RecordingModule->>AudioMixer: "send audio frames"
        AudioMixer->>DriftTracker: "calculate_timestamp(samples, sample_rate, wall_clock)"
        DriftTracker-->>AudioMixer: "corrected_timestamp"
        AudioMixer-->>RecordingModule: "mixed audio frame"
        
        alt "Segment Complete"
            SegmentedVideoEncoder->>SegmentedVideoEncoder: "on_segment_completed()"
            SegmentedVideoEncoder->>SegmentedVideoEncoder: "write_manifest()"
        end
    end
    
    User->>RecordingModule: "stop_recording()"
    RecordingModule->>SegmentedVideoEncoder: "finish(timestamp)"
    SegmentedVideoEncoder->>H264Encoder: "flush()"
    SegmentedVideoEncoder->>SegmentedVideoEncoder: "finalize_manifest()"
    SegmentedVideoEncoder-->>RecordingModule: "recording finished"
    
    alt "Fragmented Recording (if interrupted)"
        RecordingModule->>RecoveryManager: "find_incomplete(recordings_dir)"
        RecoveryManager-->>RecordingModule: "incomplete recordings list"
        User->>RecordingModule: "recover_recording(project_path)"
        RecordingModule->>RecoveryManager: "recover(recording)"
        RecoveryManager-->>RecordingModule: "recovered recording"
    end
    
    RecordingModule->>RecordingModule: "handle_recording_finish()"
    RecordingModule->>RecordingModule: "emit RecordingEvent::Stopped"
Loading

Context used:

  • Context from dashboard - CLAUDE.md (source)
  • Context from dashboard - AGENTS.md (source)

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

10 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +224 to +231
let adjusted_timestamp = if let Some(pause) = &self.pause {
match pause.adjust(timestamp)? {
Some(ts) => ts,
None => return Ok(()),
}
} else {
timestamp
};
Copy link

Choose a reason for hiding this comment

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

style: Frame skipping logic returns Ok(()) when pause.adjust() returns None - ensure this doesn't cause audio gaps or sync drift when resuming. Should there be logging when audio frames are skipped during pause to help debug sync issues?

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!

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/recording/src/output_pipeline/ffmpeg.rs
Line: 224:231

Comment:
**style:** Frame skipping logic returns Ok(()) when pause.adjust() returns None - ensure this doesn't cause audio gaps or sync drift when resuming. Should there be logging when audio frames are skipped during pause to help debug sync issues?

<sub>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!</sub>

How can I resolve this? If you propose a fix, please make it concise.


use crate::create_screenshot;

const RECOVERY_CUTOFF_DATE: (i32, u32, u32) = (2025, 12, 31);
Copy link

Choose a reason for hiding this comment

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

logic: The cutoff date is in the future (2025-12-31 vs current date 2025-12-31). This means the filter will currently exclude all recordings since no recordings can be created after today's date. Should the cutoff date be in the past to filter out old recordings, or is this intentionally filtering all current recordings?

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/recovery.rs
Line: 12:12

Comment:
**logic:** The cutoff date is in the future (2025-12-31 vs current date 2025-12-31). This means the filter will currently exclude all recordings since no recordings can be created after today's date. Should the cutoff date be in the past to filter out old recordings, or is this intentionally filtering all current recordings?

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +14 to +18
fn parse_recording_date(pretty_name: &str) -> Option<NaiveDate> {
let date_part = pretty_name.strip_prefix("Cap ")?;
let date_str = date_part.split(" at ").next()?;
NaiveDate::parse_from_str(date_str, "%Y-%m-%d").ok()
}
Copy link

Choose a reason for hiding this comment

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

style: Parsing relies on exact string format "Cap YYYY-MM-DD at ..." which creates fragile coupling to the recording naming convention

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!

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/recovery.rs
Line: 14:18

Comment:
**style:** Parsing relies on exact string format "Cap YYYY-MM-DD at ..." which creates fragile coupling to the recording naming convention

<sub>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!</sub>

How can I resolve this? If you propose a fix, please make it concise.

RECOVERY_CUTOFF_DATE.1,
RECOVERY_CUTOFF_DATE.2,
)
.expect("Invalid cutoff date");
Copy link

Choose a reason for hiding this comment

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

style: The .expect() will panic if the hardcoded date constants are invalid, but this could be validated at compile time or replaced with a safer approach

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!

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/src/recovery.rs
Line: 29:29

Comment:
**style:** The `.expect()` will panic if the hardcoded date constants are invalid, but this could be validated at compile time or replaced with a safer approach

<sub>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!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +607 to +608
const MAX_RETRIES: u32 = 10;
const RETRY_DELAY_MS: u64 = 50;
Copy link

Choose a reason for hiding this comment

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

style: Consider making MAX_RETRIES and RETRY_DELAY_MS configurable parameters rather than constants. Are these retry values based on empirical testing, or would making them configurable be beneficial for different environments?

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!

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/enc-ffmpeg/src/mux/segmented_stream.rs
Line: 607:608

Comment:
**style:** Consider making MAX_RETRIES and RETRY_DELAY_MS configurable parameters rather than constants. Are these retry values based on empirical testing, or would making them configurable be beneficial for different environments?

<sub>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!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@richiemcilroy richiemcilroy merged commit 6d6c67d into main Dec 31, 2025
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants