-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Improve recording stability and A/V sync #1478
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this 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
| let adjusted_timestamp = if let Some(pause) = &self.pause { | ||
| match pause.adjust(timestamp)? { | ||
| Some(ts) => ts, | ||
| None => return Ok(()), | ||
| } | ||
| } else { | ||
| timestamp | ||
| }; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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.| 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() | ||
| } |
There was a problem hiding this comment.
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"); |
There was a problem hiding this comment.
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.| const MAX_RETRIES: u32 = 10; | ||
| const RETRY_DELAY_MS: u64 = 50; |
There was a problem hiding this comment.
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.
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
Important Files Changed
crates/recording/src/output_pipeline/core.rscrates/recording/src/studio_recording.rscrates/recording/src/sources/audio_mixer.rsConfidence score: 4/5
core.rsandaudio_mixer.rsas these directly impact A/V synchronization qualitySequence 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"Context used:
dashboard- CLAUDE.md (source)dashboard- AGENTS.md (source)