Skip to content

Conversation

@Brendonovich
Copy link
Contributor

@Brendonovich Brendonovich commented Oct 28, 2025

Summary by CodeRabbit

  • Refactor

    • Widespread internal cleanup and formatting standardization; improved logging/error message consistency and slimmer macOS shareable-content handling.
  • Tests

    • Adjusted and relocated tests to reflect internal refactors.
  • Chores

    • Removed obsolete example(s) and deprecated playback-related internals for cleaner maintenance.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 28, 2025

Warning

Rate limit exceeded

@Brendonovich has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 30 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between efa6a3a and 66b6f3e.

📒 Files selected for processing (1)
  • crates/recording/src/output_pipeline/core.rs (8 hunks)

Walkthrough

Systematic refactor: consistent string/interpolation style, import narrowing, small API removals/field renames, Option-pattern modernizations, minor control-flow and path-type adjustments, example removal, and several test updates across multiple crates and desktop app code.

Changes

Cohort / File(s) Summary
Error & Logging formatting
apps/desktop/src-tauri/src/{lib.rs,logging.rs,main.rs,target_select_overlay.rs,upload.rs}
Normalized error message formatting to named placeholders ({e}, {err}, {path:?}), consolidated header/truncation formatting, and adjusted a few error constructions; small call-site arg passing change for upload_multipart_initiate (pass app by value).
macOS shareable content & thumbnails
apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs, apps/desktop/src-tauri/src/thumbnails/mac.rs, crates/scap-ffmpeg/examples/cli.rs
Removed timing instrumentation and trimmed cache state in shareable content; renamed an enum variant (Full_Full) and replaced slicing/indexing with iterator patterns in thumbnail conversion; updated macOS example usage to new ShareableContent patterns.
Recording surface & sources
apps/desktop/src-tauri/src/{recording.rs,recording_settings.rs,target_select_overlay.rs}, crates/recording/src/{sources/microphone.rs,sources/screen_capture/macos.rs,sources/screen_capture/mod.rs,studio_recording.rs}
Removed several public re-exports; renamed/removed methods and enum variants; changed Microphone from tuple struct to named fields; shifted various Actor/ActorHandle fields (added/removed); simplified some error branches and Option handling.
Audio subsystem refactor / removals
crates/audio/src/{lib.rs,playback.rs}, crates/recording/src/{audio_buffer.rs, sources/audio_mixer.rs}
Removed playback module re-export; deleted audio_buffer.rs file and public AudioBuffer type; in audio mixer, renamed fields, removed AudioMixerHandle, adapted tests to named field access.
Muxer & output pipeline path/type changes
crates/recording/src/output_pipeline/core.rs
Switched many path params from PathBuf to &Path, converted some clones to to_path_buf(), simplified async setup signature to return a Future (non-async fn returning impl Future), and adjusted muxer typing.
Option/cond-expression modernizations
crates/{enc-ffmpeg,rendering,rendering/src/decoder,enc-avfoundation,media-info,enc-ffmpeg/src/audio}
Replaced map_or/manual None checks with is_some_and/is_none_or, merged nested if-let patterns, used clamp and other concise constructs; stylistic simplifications (trailing expressions, +=).
Examples & tests
crates/recording/examples/screen_capture.rs (removed), crates/recording/examples/camera.rs, crates/rendering-skia/src/layers/background.rs, crates/rendering/src/layers/cursor.rs
Removed screen_capture.rs example; adjusted import paths in camera example; tests updated/relocated and explicitly set some fields (e.g., border: None).
Small behavioral/type edits across crates
crates/recording/src/{instant_recording.rs,lib.rs}, crates/recording/src/sources/screen_capture/*, crates/enc-ffmpeg/src/{video,h264.rs,audio/buffered_resampler.rs}, crates/audio/src/latency.rs, crates/project/src/configuration.rs, Cargo.toml
Parity checks switched to is_multiple_of, minor signature/field visibility changes, removed instrumentation, simplified bounds with clamp, small Path/borrow tweaks, and added workspace Clippy denies in Cargo.toml.

Sequence Diagram(s)

(omitted — changes are refactors and do not introduce a new or modified high-level control-flow needing a sequence diagram)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas needing closer attention:
    • crates/recording/src/output_pipeline/core.rs — Muxer::setup signature change and Path/PathBuf adjustments.
    • apps/desktop/src-tauri/src/upload.rsupload_multipart_initiate call-site signature change and error parsing tweaks.
    • Deletions: crates/recording/src/audio_buffer.rs removal and propagation effects across recording/audio code.
    • Public API/field changes in crates/recording/src/studio_recording.rs and crates/recording/src/sources/microphone.rs (struct layout/visibility).

Possibly related PRs

Poem

🐰 I hopped through lines of code today,
Trimmed some strings and chased bugs away,
Options pruned and imports neat,
Fields renamed on tiny feet,
A carrot-coded patch — swift, not fey! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.17% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive The PR title "run clippy" is vague and generic, making it ambiguous what specific changes were applied. While the changeset does contain Clippy-driven refactorings (such as replacing .max().min() with .clamp(), using is_some_and instead of map_or patterns, and simplifying conditional logic), the phrase "run clippy" could refer to multiple actions without clarifying intent. Additionally, the PR includes significant structural changes beyond typical Clippy fixes, including file deletions, public API removals, method signature changes, and type modifications that a colleague scanning the commit history would struggle to discern from the current title alone. Consider revising the title to be more descriptive of the actual changes, such as "Apply Clippy lints and refactor APIs" or "Address Clippy warnings and remove unused code." This would better communicate the scope of the changes to developers reviewing the git history and make the PR's intent immediately clear without requiring inspection of the full changeset.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
crates/enc-ffmpeg/src/audio/buffered_resampler.rs (1)

78-93: Avoid extra flush when delay is zero

Using delay().is_some() will still iterate when delay == Some(0), causing a redundant flush before breaking on samples == 0. Prefer checking for a positive delay.

-        while self.resampler.delay().is_some() {
+        while matches!(self.resampler.delay(), Some(d) if d > 0) {
apps/desktop/src-tauri/src/logging.rs (1)

41-63: Tail large logs without blocking and tolerate non‑UTF8

Current path reads the whole file into a String twice and assumes UTF‑8. For ~1MB this is OK, but we can improve UX and reliability:

  • Use std::fs::File + seek to last MAX_SIZE to avoid loading entire file.
  • Read bytes and convert with from_utf8_lossy to avoid failures on invalid UTF‑8.
  • Consider spawn_blocking for the heavy I/O in this async fn.
-        let content =
-            fs::read_to_string(&log_file).map_err(|e| format!("Failed to read log file: {e}"))?;
+        use std::io::{Read, Seek, SeekFrom};
+        let mut f = fs::File::open(&log_file)
+            .map_err(|e| format!("Failed to read log file: {e}"))?;
+        let to_read = MAX_SIZE.saturating_sub(1);
+        let pos = file_size.saturating_sub(to_read);
+        f.seek(SeekFrom::Start(pos)).ok();
+        let mut buf = Vec::with_capacity(to_read as usize);
+        f.read_to_end(&mut buf)
+            .map_err(|e| format!("Failed to read log file: {e}"))?;
+        let content = String::from_utf8_lossy(&buf).into_owned();
...
-                format!("{header}{truncated}")
+                format!("{header}{truncated}")
...
-        fs::read_to_string(&log_file).map_err(|e| format!("Failed to read log file: {e}"))?
+        String::from_utf8_lossy(&fs::read(&log_file)
+            .map_err(|e| format!("Failed to read log file: {e}"))?).into_owned()
crates/scap-ffmpeg/examples/cli.rs (3)

50-60: Avoid panics in example path

These unwraps can panic on misconfigured systems. Consider propagating or logging errors to keep the example robust.

-    let config = StreamCfgBuilder::default()
+    let size = display.physical_size().ok_or("failed to get display size")?;
+    let config = StreamCfgBuilder::default()
         .with_fps(60.0)
-        .with_width(display.physical_size().unwrap().width() as usize)
-        .with_height(display.physical_size().unwrap().height() as usize)
+        .with_width(size.width() as usize)
+        .with_height(size.height() as usize)
         .build();

-    let capturer = Capturer::builder(
-        display
-            .raw_handle()
-            .as_content_filter(sc::ShareableContent::current().await.unwrap())
-            .await
-            .unwrap(),
+    let shareable = sc::ShareableContent::current().await
+        .map_err(|_| "failed to get shareable content")?;
+    let capturer = Capturer::builder(
+        display.raw_handle().as_content_filter(shareable).await
+            .map_err(|_| "failed to build content filter")?,

63-74: No-op method calls in output callback

Calling width()/height()/format() and discarding results has no effect. Either log these or remove to keep the example minimal.

-        .with_output_sample_buf_cb(|frame| {
+        .with_output_sample_buf_cb(|frame| {
             use scap_ffmpeg::AsFFmpeg;
             let Frame::Screen(video_frame) = frame else { return; };
             let ff = video_frame.as_ffmpeg().unwrap();
-            ff_frame.width();
-            ff_frame.height();
-            ff_frame.format();
+            println!("frame: {}x{} {:?}", ff.width(), ff.height(), ff.format());
         })

75-77: Use underscore args instead of producing an unused tuple

This reads cleaner and avoids constructing a value just to silence warnings.

-        .with_stop_with_err_cb(|stream, error| {
-            (stream, error);
-        })
+        .with_stop_with_err_cb(|_stream, _error| {})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9bfcdbd and 8399fa5.

📒 Files selected for processing (20)
  • apps/desktop/src-tauri/src/lib.rs (4 hunks)
  • apps/desktop/src-tauri/src/logging.rs (3 hunks)
  • apps/desktop/src-tauri/src/main.rs (1 hunks)
  • apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs (1 hunks)
  • apps/desktop/src-tauri/src/recording.rs (3 hunks)
  • apps/desktop/src-tauri/src/target_select_overlay.rs (3 hunks)
  • apps/desktop/src-tauri/src/thumbnails/mac.rs (2 hunks)
  • apps/desktop/src-tauri/src/upload.rs (6 hunks)
  • crates/enc-ffmpeg/src/audio/buffered_resampler.rs (3 hunks)
  • crates/enc-ffmpeg/src/video/h264.rs (1 hunks)
  • crates/project/src/configuration.rs (1 hunks)
  • crates/recording/examples/camera.rs (1 hunks)
  • crates/recording/examples/screen_capture.rs (0 hunks)
  • crates/recording/src/sources/audio_mixer.rs (1 hunks)
  • crates/rendering-skia/src/layers/background.rs (2 hunks)
  • crates/rendering/src/decoder/avassetreader.rs (2 hunks)
  • crates/rendering/src/decoder/frame_converter.rs (2 hunks)
  • crates/rendering/src/layers/cursor.rs (1 hunks)
  • crates/rendering/src/lib.rs (2 hunks)
  • crates/scap-ffmpeg/examples/cli.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • crates/recording/examples/screen_capture.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using rustfmt and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.

Files:

  • crates/rendering/src/layers/cursor.rs
  • apps/desktop/src-tauri/src/thumbnails/mac.rs
  • crates/recording/examples/camera.rs
  • crates/rendering-skia/src/layers/background.rs
  • crates/rendering/src/decoder/avassetreader.rs
  • apps/desktop/src-tauri/src/logging.rs
  • crates/rendering/src/decoder/frame_converter.rs
  • crates/project/src/configuration.rs
  • apps/desktop/src-tauri/src/target_select_overlay.rs
  • crates/scap-ffmpeg/examples/cli.rs
  • apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs
  • crates/rendering/src/lib.rs
  • crates/enc-ffmpeg/src/audio/buffered_resampler.rs
  • crates/enc-ffmpeg/src/video/h264.rs
  • apps/desktop/src-tauri/src/recording.rs
  • crates/recording/src/sources/audio_mixer.rs
  • apps/desktop/src-tauri/src/main.rs
  • apps/desktop/src-tauri/src/upload.rs
  • apps/desktop/src-tauri/src/lib.rs
crates/*/src/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Rust crates should place tests within the src/ and/or a sibling tests/ directory for each crate inside crates/*.

Files:

  • crates/rendering/src/layers/cursor.rs
  • crates/rendering-skia/src/layers/background.rs
  • crates/rendering/src/decoder/avassetreader.rs
  • crates/rendering/src/decoder/frame_converter.rs
  • crates/project/src/configuration.rs
  • crates/rendering/src/lib.rs
  • crates/enc-ffmpeg/src/audio/buffered_resampler.rs
  • crates/enc-ffmpeg/src/video/h264.rs
  • crates/recording/src/sources/audio_mixer.rs
🧬 Code graph analysis (12)
crates/recording/examples/camera.rs (1)
apps/desktop/src/utils/tauri.ts (1)
  • DeviceOrModelID (388-388)
crates/rendering/src/decoder/avassetreader.rs (1)
crates/rendering/src/decoder/mod.rs (2)
  • width (24-26)
  • height (28-30)
crates/rendering/src/decoder/frame_converter.rs (2)
crates/scap-direct3d/src/lib.rs (1)
  • stride (518-520)
crates/rendering/src/decoder/mod.rs (2)
  • width (24-26)
  • height (28-30)
crates/project/src/configuration.rs (1)
apps/desktop/src-tauri/src/recording.rs (1)
  • project_path (173-178)
apps/desktop/src-tauri/src/target_select_overlay.rs (3)
crates/scap-targets/src/platform/macos.rs (5)
  • get_containing_cursor (78-92)
  • id (49-49)
  • id (302-304)
  • from_id (48-51)
  • get_topmost_at_cursor (285-300)
crates/scap-targets/src/platform/win.rs (5)
  • get_containing_cursor (152-165)
  • id (131-131)
  • id (424-426)
  • from_id (130-133)
  • get_topmost_at_cursor (319-362)
crates/scap-targets/src/lib.rs (6)
  • get_containing_cursor (36-38)
  • id (28-30)
  • id (118-120)
  • from_id (32-34)
  • from_id (122-124)
  • get_topmost_at_cursor (114-116)
crates/scap-ffmpeg/examples/cli.rs (3)
crates/scap-targets/src/platform/macos.rs (2)
  • display (519-539)
  • primary (28-30)
crates/scap-targets/src/lib.rs (2)
  • display (146-148)
  • primary (20-22)
crates/scap-screencapturekit/src/capture.rs (1)
  • builder (78-87)
crates/rendering/src/lib.rs (1)
crates/rendering/src/cursor_interpolation.rs (1)
  • interpolate_cursor (16-75)
crates/enc-ffmpeg/src/video/h264.rs (2)
crates/camera-windows/src/lib.rs (2)
  • formats (145-162)
  • formats (150-152)
crates/camera-mediafoundation/src/lib.rs (1)
  • formats (170-195)
apps/desktop/src-tauri/src/recording.rs (1)
apps/desktop/src/utils/tauri.ts (2)
  • RecordingMode (447-447)
  • InstantRecordingMeta (416-416)
crates/recording/src/sources/audio_mixer.rs (2)
crates/timestamp/src/lib.rs (1)
  • duration_since (24-33)
crates/media-info/src/lib.rs (1)
  • rate (125-127)
apps/desktop/src-tauri/src/upload.rs (1)
apps/desktop/src-tauri/src/api.rs (2)
  • upload_multipart_initiate (12-47)
  • upload_multipart_complete (119-170)
apps/desktop/src-tauri/src/lib.rs (2)
apps/desktop/src/utils/tauri.ts (1)
  • GeneralSettingsStore (399-399)
apps/desktop/src-tauri/src/general_settings.rs (1)
  • update (222-231)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Clippy
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (37)
crates/project/src/configuration.rs (1)

648-651: LGTM!

The change from borrowing to an owned value for the destination path is correct. Both forms work due to AsRef<Path>, but the owned version is more idiomatic per clippy's recommendations.

apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs (1)

10-10: LGTM!

Correctly removes unused imports (debug, info) while keeping trace. The usage of tracing::warn! with a full path qualifier at line 213 is appropriate.

apps/desktop/src-tauri/src/main.rs (1)

69-71: LGTM!

The change from format!("{}", e) to direct string interpolation is more idiomatic and aligns with Rust 2021 edition best practices.

crates/rendering/src/layers/cursor.rs (1)

620-685: LGTM!

Well-structured unit tests covering cursor idle opacity behavior. The use of approximate equality checks at line 676 appropriately handles floating-point comparisons.

crates/recording/examples/camera.rs (1)

3-3: LGTM!

The import refactor removes the redundant CameraFeed import and uses a more specific path for DeviceOrModelID.

crates/rendering-skia/src/layers/background.rs (2)

357-363: LGTM!

Explicitly setting border: None makes the test initialization clearer and more maintainable.


381-387: LGTM!

Consistent with the previous test case, explicitly setting border: None improves test clarity.

apps/desktop/src-tauri/src/thumbnails/mac.rs (2)

25-25: LGTM!

Removes the unused std::slice import since std::slice::from_raw_parts is used with its full path at line 125.


190-195: LGTM!

Replacing manual ceiling division (height + 1) / 2 with height.div_ceil(2) is more idiomatic and makes the intent explicit. Both are mathematically equivalent.

apps/desktop/src-tauri/src/target_select_overlay.rs (3)

68-75: LGTM!

Removing unnecessary closure wrappers and passing function pointers directly is more efficient and idiomatic. The function signatures correctly match the expected closure types.


129-132: LGTM!

Using direct string interpolation is more concise and aligns with modern Rust conventions.


143-146: LGTM!

Consistent with the previous change, using direct string interpolation improves readability.

crates/enc-ffmpeg/src/audio/buffered_resampler.rs (1)

51-51: LGTM — clearer trailing expression

Returning remaining_samples as a trailing expression improves readability and satisfies clippy.

crates/enc-ffmpeg/src/video/h264.rs (2)

98-106: is_some_and simplifies the formats check — OK

Semantics match previous logic and read clearer. No issues.


265-269: Minor cleanup in finish() — OK

Dropping the explicit return is fine; function already returns ().

apps/desktop/src-tauri/src/logging.rs (2)

39-47: LGTM — constants and formatting tightened

Value unchanged; formatting consistent with repo style.


75-76: Consistent error interpolation — OK

{e} interpolation matches the PR’s formatting goals.

apps/desktop/src-tauri/src/lib.rs (4)

898-899: Error message now includes path — OK

Using {path:?} gives better context. No behavior change.


1195-1196: Return stringified error — OK

Err(e.to_string()) keeps types simple; consistent with nearby code.


2254-2256: Settings store update call — OK

Closure mutates only server_url as intended; aligns with update(&mut Self).


2583-2584: Directory read error mapping — OK

Consistent error propagation; no blocking issues added beyond existing sync I/O.

apps/desktop/src-tauri/src/upload.rs (5)

74-74: LGTM: Correct parameter passing.

The change from &app to app is correct since app is already &AppHandle at the call site, so passing it directly provides the reference the function expects.


228-228: LGTM: Improved string interpolation.

The inline variable interpolation {fps} is more idiomatic than the previous format string.


248-252: LGTM: Simplified error handling.

The changes improve readability:

  • Direct parsing without dereferencing (body instead of &*body)
  • Streamlined conditional flow with && chaining
  • Direct error return without nested blocks

496-496: LGTM: Using newer io::Error::other API.

This is the idiomatic way to construct "other" category errors, replacing the more verbose io::Error::new(io::ErrorKind::Other, ...).


682-682: LGTM: More specific error context.

Including {expected_part_number:?} provides clearer debugging information than a generic part reference.

apps/desktop/src-tauri/src/recording.rs (4)

12-12: LGTM: Narrowed import scope.

Importing only the specific type needed (RecordingMode) improves clarity and reduces the API surface.


472-472: LGTM: Simplified string construction.

Using .to_string() on a static string is clearer than format!() when no interpolation is needed.


831-831: LGTM: Field initialization shorthand.

Using { error } instead of { error: error } is the idiomatic Rust field shorthand.


982-984: LGTM: Improved cleanup resilience.

The change to log the error instead of returning early ensures that upload completion proceeds even if local file cleanup fails. This is appropriate behavior—the upload succeeded, and file cleanup is a "nice to have" rather than critical.

crates/rendering/src/decoder/avassetreader.rs (2)

82-84: LGTM: Using is_none_or for clearer Option handling.

The is_none_or method (stabilized in Rust 1.82) is more expressive than the map_or(false, ...) pattern for checking if an Option is None or matches a condition.


101-102: LGTM: Removed unnecessary type casts.

The width() and height() methods already return the correct types (usize), so the casts are unnecessary.

crates/rendering/src/decoder/frame_converter.rs (3)

27-29: LGTM: Removed unnecessary cast.

The stride() method returns usize directly, matching the function parameter type.


51-51: LGTM: Consistent stride handling.

Matches the improvement at line 27—no cast needed.


58-60: LGTM: Modern Option handling with is_none_or.

This is clearer than the previous map_or pattern for checking if the scaler needs recreation.

crates/rendering/src/lib.rs (2)

1286-1290: LGTM: Clearer buffer size check with is_none_or.

The is_none_or method provides a more straightforward way to check if a new buffer is needed.


1441-1518: LGTM: Test module repositioned.

The test module has been moved to the end of the file with no changes to its content. This is purely organizational.

Comment on lines +712 to 714
assert_eq!(item.timestamp.duration_since(start), ONE_SECOND / 2);
assert_eq!(item.inner.samples(), SOURCE_INFO.rate() as usize / 2);

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Good move to named fields; update remaining tuple-style usages to avoid breakage

These assertions now target item.timestamp/item.inner, consistent with AudioFrame { inner, timestamp }. Other tests in this file still use .0/.1 on AudioFrame and will fail after this refactor. Please update them for consistency.

Run to find remaining tuple-style usages of AudioFrame:

Example fixes in this file:

-            assert_eq!(
-                source.buffer[1].1.duration_since(mixer.timestamps),
-                ONE_SECOND / 2
-            );
-            assert_eq!(
-                source.buffer[1].0.samples(),
-                SOURCE_INFO.rate() as usize / 2
-            );
+            assert_eq!(
+                source.buffer[1].timestamp.duration_since(mixer.timestamps),
+                ONE_SECOND / 2
+            );
+            assert_eq!(
+                source.buffer[1].inner.samples(),
+                SOURCE_INFO.rate() as usize / 2
+            );

Also applies to: 716-718


🏁 Script executed:

#!/bin/bash
# Find tuple-field access on AudioFrame in this crate
rg -nP '(buffer\[[^\]]+\])\.(0|1)\b|AudioFrame\([^)]' -g 'crates/recording/src/**' -C2

Length of output: 1302


🏁 Script executed:

#!/bin/bash
# Check the actual content at lines 712-718 and the AudioFrame struct definition
cat crates/recording/src/sources/audio_mixer.rs | sed -n '712,718p'
echo "---"
# Find the AudioFrame struct definition
rg -nP 'struct\s+AudioFrame|pub\s+struct\s+AudioFrame' crates/recording/src/sources/audio_mixer.rs -A5

Length of output: 366


🏁 Script executed:

#!/bin/bash
# Search for AudioFrame struct definition in the crate (may be in different file)
rg -nP 'struct\s+AudioFrame\s*\{' crates/recording/src/ -A10

echo "---"
# Also check if it's defined in a separate types or frames module
fd -e rs . crates/recording/src/ | xargs grep -l 'struct AudioFrame'

Length of output: 822


Fix remaining tuple-style usages at lines 637, 641, 670, 672 to complete the refactor

The changes at lines 712-718 are correct. However, four other locations in the same file still use tuple-style access on AudioFrame and will fail to compile:

  • Line 637: source.buffer[1].1source.buffer[1].timestamp
  • Line 641: source.buffer[1].0source.buffer[1].inner
  • Line 670: source.buffer[0].1source.buffer[0].timestamp
  • Line 672: source.buffer[0].0source.buffer[0].inner
🤖 Prompt for AI Agents
In crates/recording/src/sources/audio_mixer.rs around lines 637, 641, 670, and
672, remaining tuple-style accesses on AudioFrame must be replaced with struct
field names following the refactor: change source.buffer[1].1 to
source.buffer[1].timestamp, source.buffer[1].0 to source.buffer[1].inner,
source.buffer[0].1 to source.buffer[0].timestamp, and source.buffer[0].0 to
source.buffer[0].inner; update those four sites accordingly so compilation
succeeds.

@Brendonovich Brendonovich merged commit a133751 into main Oct 28, 2025
13 of 14 checks passed
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/recording/src/sources/microphone.rs (1)

31-36: Fix misleading error text ("camera" vs "microphone").

The error reads “Failed to add camera sender” in the microphone source.

-                .map_err(|e| anyhow!("Failed to add camera sender: {e}"))?;
+                .map_err(|e| anyhow!("Failed to add microphone sender: {e}"))?;
crates/recording/src/studio_recording.rs (1)

750-759: Context string copy-paste: “microphone pipeline setup” for system audio.

The second context should say “system audio pipeline setup”.

-    .context("microphone pipeline setup")?;
+    .context("system audio pipeline setup")?;
🧹 Nitpick comments (7)
apps/desktop/src-tauri/src/window_exclusion.rs (1)

24-30: Good refactoring to let-chains.

The refactoring from nested conditionals to a let-chain pattern is clean and addresses clippy warnings effectively.

Optionally, the comparison logic can be simplified further for improved readability:

 if let Some(identifier) = self.bundle_identifier.as_deref()
-    && bundle_identifier
-        .map(|candidate| candidate == identifier)
-        .unwrap_or(false)
+    && bundle_identifier == Some(identifier)
 {
     return true;
 }

This is more idiomatic since both sides are Option<&str> types.

apps/desktop/src-tauri/src/thumbnails/mac.rs (1)

231-231: Remove redundant .take(width).

The .take(width) is unnecessary since y_row is already sliced to exactly width length at line 217.

Apply this diff:

-        for (x, y_val) in y_row.iter().enumerate().take(width) {
+        for (x, y_val) in y_row.iter().enumerate() {
crates/recording/src/feeds/microphone.rs (1)

99-102: API rename default → default_device: consider a deprecation shim.

This is a breaking rename for callers. If feasible, add a deprecated default() wrapper to smooth upgrades and keep clippy happy.

Apply:

 impl MicrophoneFeed {
+    #[deprecated(note = "Use default_device()", since = "0.?.?")]
+    pub fn default() -> Option<(String, Device, SupportedStreamConfig)> {
+        Self::default_device()
+    }
crates/recording/src/studio_recording.rs (3)

293-301: Watcher deduplication guard: OK, but note race window.

Gating on completion_tx.borrow().is_none() prevents duplicate sends in practice. There’s a tiny race if multiple errors hit simultaneously; acceptable given watch semantics. Add a short comment to capture intent.

-                if let Err(err) = res
-                    && completion_tx.borrow().is_none()
+                // Avoid duplicate completion notifications; only send first error.
+                if let Err(err) = res
+                    && completion_tx.borrow().is_none()
                 {

673-686: Path ergonomics: good shift to &Path.

Accepting &Path reduces clones. Consider propagating this change to ensure_dir for consistency.

Apply:

-async fn create_segment_pipeline(
-    segments_dir: &Path,
+async fn create_segment_pipeline(
+    segments_dir: &Path,
     cursors_dir: &Path,

And update ensure_dir below (see next comment).


796-800: Prefer &Path for ensure_dir and avoid cloning.

Modernize to accept &Path and return PathBuf via to_path_buf().

-fn ensure_dir(path: &PathBuf) -> Result<PathBuf, MediaError> {
-    std::fs::create_dir_all(path)?;
-    Ok(path.clone())
+fn ensure_dir(path: &Path) -> Result<PathBuf, MediaError> {
+    std::fs::create_dir_all(path)?;
+    Ok(path.to_path_buf())
 }

Call sites (e.g., lines 424-428, 711) will continue to work with coercions from &PathBuf.

crates/recording/src/output_pipeline/core.rs (1)

577-581: Minor ergonomics: consider returning &Path.

OutputPipeline::path(&self) -> &PathBuf could return &Path to reduce PathBuf exposure.

-    pub fn path(&self) -> &PathBuf {
-        &self.path
+    pub fn path(&self) -> &Path {
+        &self.path
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8399fa5 and efa6a3a.

📒 Files selected for processing (24)
  • Cargo.toml (1 hunks)
  • apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs (2 hunks)
  • apps/desktop/src-tauri/src/recording.rs (4 hunks)
  • apps/desktop/src-tauri/src/recording_settings.rs (1 hunks)
  • apps/desktop/src-tauri/src/thumbnails/mac.rs (7 hunks)
  • apps/desktop/src-tauri/src/upload.rs (9 hunks)
  • apps/desktop/src-tauri/src/window_exclusion.rs (1 hunks)
  • crates/audio/src/latency.rs (4 hunks)
  • crates/audio/src/lib.rs (0 hunks)
  • crates/audio/src/playback.rs (0 hunks)
  • crates/editor/src/playback.rs (2 hunks)
  • crates/enc-avfoundation/src/mp4.rs (3 hunks)
  • crates/enc-ffmpeg/src/audio/buffered_resampler.rs (3 hunks)
  • crates/media-info/src/lib.rs (1 hunks)
  • crates/recording/src/audio_buffer.rs (0 hunks)
  • crates/recording/src/feeds/microphone.rs (2 hunks)
  • crates/recording/src/instant_recording.rs (4 hunks)
  • crates/recording/src/lib.rs (0 hunks)
  • crates/recording/src/output_pipeline/core.rs (8 hunks)
  • crates/recording/src/sources/audio_mixer.rs (4 hunks)
  • crates/recording/src/sources/microphone.rs (2 hunks)
  • crates/recording/src/sources/screen_capture/macos.rs (1 hunks)
  • crates/recording/src/sources/screen_capture/mod.rs (0 hunks)
  • crates/recording/src/studio_recording.rs (2 hunks)
💤 Files with no reviewable changes (5)
  • crates/recording/src/lib.rs
  • crates/audio/src/playback.rs
  • crates/audio/src/lib.rs
  • crates/recording/src/audio_buffer.rs
  • crates/recording/src/sources/screen_capture/mod.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/desktop/src-tauri/src/recording.rs
  • apps/desktop/src-tauri/src/upload.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format Rust code using rustfmt and ensure all Rust code passes workspace-level clippy lints.
Rust modules should be named with snake_case, and crate directories should be in kebab-case.

Files:

  • apps/desktop/src-tauri/src/window_exclusion.rs
  • crates/enc-ffmpeg/src/audio/buffered_resampler.rs
  • crates/recording/src/feeds/microphone.rs
  • crates/media-info/src/lib.rs
  • crates/recording/src/sources/screen_capture/macos.rs
  • crates/editor/src/playback.rs
  • apps/desktop/src-tauri/src/thumbnails/mac.rs
  • apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs
  • crates/audio/src/latency.rs
  • crates/recording/src/instant_recording.rs
  • crates/recording/src/output_pipeline/core.rs
  • crates/enc-avfoundation/src/mp4.rs
  • crates/recording/src/studio_recording.rs
  • crates/recording/src/sources/audio_mixer.rs
  • apps/desktop/src-tauri/src/recording_settings.rs
  • crates/recording/src/sources/microphone.rs
crates/*/src/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Rust crates should place tests within the src/ and/or a sibling tests/ directory for each crate inside crates/*.

Files:

  • crates/enc-ffmpeg/src/audio/buffered_resampler.rs
  • crates/recording/src/feeds/microphone.rs
  • crates/media-info/src/lib.rs
  • crates/recording/src/sources/screen_capture/macos.rs
  • crates/editor/src/playback.rs
  • crates/audio/src/latency.rs
  • crates/recording/src/instant_recording.rs
  • crates/recording/src/output_pipeline/core.rs
  • crates/enc-avfoundation/src/mp4.rs
  • crates/recording/src/studio_recording.rs
  • crates/recording/src/sources/audio_mixer.rs
  • crates/recording/src/sources/microphone.rs
🧠 Learnings (2)
📚 Learning: 2025-09-22T14:19:56.010Z
Learnt from: CR
PR: CapSoftware/Cap#0
File: AGENTS.md:0-0
Timestamp: 2025-09-22T14:19:56.010Z
Learning: Applies to **/*.rs : Format Rust code using `rustfmt` and ensure all Rust code passes workspace-level clippy lints.

Applied to files:

  • Cargo.toml
📚 Learning: 2025-10-17T05:58:22.586Z
Learnt from: Brendonovich
PR: CapSoftware/Cap#1219
File: crates/enc-avfoundation/src/mp4.rs:350-373
Timestamp: 2025-10-17T05:58:22.586Z
Learning: In crates/enc-avfoundation/src/mp4.rs, the `finish()` method intentionally skips video extension when `is_paused` is true. This is correct behavior because if recording is paused, the video should not be extended beyond the pause point—the pause is user-initiated, unlike the case where ScreenCaptureKit stops providing frames during static content.

Applied to files:

  • crates/enc-avfoundation/src/mp4.rs
🧬 Code graph analysis (4)
apps/desktop/src-tauri/src/window_exclusion.rs (1)
crates/scap-targets/src/platform/macos.rs (1)
  • bundle_identifier (350-378)
crates/recording/src/output_pipeline/core.rs (3)
crates/recording/src/output_pipeline/win.rs (2)
  • oneshot (67-67)
  • setup (41-269)
crates/recording/src/output_pipeline/ffmpeg.rs (2)
  • setup (36-66)
  • setup (114-132)
crates/recording/src/output_pipeline/macos.rs (1)
  • setup (27-50)
crates/recording/src/sources/audio_mixer.rs (3)
crates/timestamp/src/win.rs (2)
  • now (49-53)
  • duration_since (30-47)
crates/timestamp/src/lib.rs (2)
  • now (103-112)
  • duration_since (24-33)
crates/media-info/src/lib.rs (1)
  • rate (125-127)
crates/recording/src/sources/microphone.rs (2)
crates/recording/src/feeds/microphone.rs (1)
  • audio_info (243-245)
crates/recording/src/output_pipeline/core.rs (2)
  • audio_info (682-684)
  • audio_info (760-760)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (37)
crates/media-info/src/lib.rs (1)

76-76: LGTM! Idiomatic clamp usage.

The refactor from min().max() to clamp() is more idiomatic and maintains identical behavior, ensuring the channel count stays within [1, 8].

crates/editor/src/playback.rs (2)

328-338: LGTM! Cleaner guard clause for buffer adjustment logging.

The combined if let with && clamped != desired is more idiomatic and reduces log noise by only emitting when actual clamping occurs within a known range.


406-423: LGTM! Streamlined latency hint logging.

The combined guard if let Some(hint) && hint.latency_secs > 0.0 followed by a match statement is clearer than nested conditionals. The transport-specific messaging (AirPlay vs wireless vs default) improves observability.

crates/recording/src/sources/screen_capture/macos.rs (2)

46-52: Good dead code removal.

Removing the unused CreateActor and DidStopWithError enum variants simplifies the error type. The remaining variants (NoDisplay and AsContentFilter) cover all the error cases actually used in this module.


110-110: LGTM: Correct clippy optimization.

Replacing ok_or_else with ok_or is appropriate here since SourceError::AsContentFilter is a simple enum variant with no construction cost. This eliminates unnecessary closure overhead.

crates/enc-ffmpeg/src/audio/buffered_resampler.rs (4)

51-51: LGTM! Idiomatic trailing expression.

Removing the explicit return keyword in favor of a trailing expression is the idiomatic Rust style and resolves the clippy lint.


59-63: LGTM! Modern let-chains pattern.

The chained let-pattern is more concise and equally readable compared to nested if-let statements. This is a good use of modern Rust syntax.


78-78: LGTM! More direct condition check.

Using .is_some() is clearer than while let Some(_) when the matched value isn't used, and resolves the clippy lint.


92-92: LGTM! Compound assignment operator.

Using += is more concise and idiomatic than the expanded form, and resolves the clippy lint.

apps/desktop/src-tauri/src/thumbnails/mac.rs (6)

25-25: LGTM: Import narrowing improves clarity.

The import is now more specific and makes the dependency explicit.


190-190: LGTM: Using div_ceil is more idiomatic.

The div_ceil method is clearer and safer than manual ceiling division with (height + 1) / 2.

Also applies to: 195-195


244-244: LGTM: Consistent with iterator change.

The dereference is correct and avoids indexing, which is safer.


263-263: LGTM: Consistent with enum variant rename.

The reference is correctly updated to match the renamed variant.


274-274: LGTM: Using clamp is more idiomatic.

The clamp method is clearer and more concise than chaining max and min.


163-166: The _Full variant is actively used and should not be removed.

The grep search confirms the variant is used in a pattern match at line 263 (Nv12Range::_Full => (y, 1.0_f32),). The underscore prefix is a valid Rust convention for variants or bindings whose values aren't referenced in the match arm body—not an indicator of dead code. Removing it would break the match expression.

Likely an incorrect or invalid review comment.

apps/desktop/src-tauri/src/platform/macos/sc_shareable_content.rs (2)

2-4: LGTM: Clean import consolidation and narrowing.

The import changes consolidate std::sync imports and narrow the tracing import to only trace, which are both standard clippy-recommended improvements that enhance code clarity.


112-114: LGTM: Simplified struct initialization.

The constructor simplification to Self { content } is cleaner and more idiomatic, consistent with the removal of unused cache fields mentioned in the summary.

crates/audio/src/latency.rs (4)

260-261: Excellent use of clamp() for bounds checking.

Replacing max().min() with clamp() is more idiomatic and clearly expresses the intent to constrain a value within bounds.


294-295: Consistent bounds checking with clamp().

Good application of the same pattern as in with_bias().


370-377: Nice refactor using let-chains to reduce nesting.

The combined conditional if let Some(prev_raw) = self.last_raw_latency_secs && self.update_count < ... && clamped > ... effectively flattens the warmup spike detection logic while preserving the same behavior.


587-592: Cleaner conditional flow in stream latency calculation.

Combining the output stream check with the latency retrieval in a single conditional reduces nesting and improves readability.

crates/enc-avfoundation/src/mp4.rs (4)

235-240: Improved pause handling with let-chains.

The combined conditional elegantly handles the case where both pause_timestamp exists and the gap can be computed, reducing nesting while maintaining the same logic.


246-265: Well-structured monotonic PTS correction.

Consolidating the PTS correction logic into a single conditional block with let-chains makes the monotonic guarantee more explicit and easier to follow. The sequence of compute → log → adjust is now clearly contained within the correction path.


295-300: Consistent pause handling for audio frames.

Good application of the same let-chain pattern used for video frames, maintaining consistency across the codebase.


344-365: Consistent monotonic PTS correction for audio.

The audio PTS correction mirrors the video implementation structure, ensuring both media types handle timing consistency in the same way. The unified conditional block clearly expresses the correction logic.

crates/recording/src/sources/audio_mixer.rs (2)

161-161: LGTM: Underscore prefix follows Rust conventions.

The rename to _resamplers aligns with clippy's unused field lint and signals that the field is retained for its Drop implementation.


345-385: LGTM: Let-chains improve readability.

The refactored control flow using let-chains is more idiomatic and easier to follow than nested if-let statements.

crates/recording/src/feeds/microphone.rs (1)

154-163: Nice: removed unnecessary clone in config selection.

with_sample_rate on &SupportedStreamConfigRange already returns an owned SupportedStreamConfig; avoiding clone() is correct.

crates/recording/src/sources/microphone.rs (4)

10-13: Struct encapsulation improvement LGTM.

Moving from tuple to named fields clarifies intent; _lock keeps the guard alive without exposing it.


18-23: Manual async fn allow: acceptable here.

Given the trait requires returning impl Future, the lint suppression is appropriate.

Ensure other sources follow the same pattern for consistency across the crate.


47-50: Constructor update LGTM.

Named struct construction is clear and matches the new layout.


54-56: audio_info accessor remains correct.

Returning the stored AudioInfo is unchanged semantically.

crates/recording/src/output_pipeline/core.rs (5)

301-305: Error mapping cleanup LGTM.

map_err(anyhow::Error::from) simplifies type conversion before wrapping in PipelineDoneError.


315-320: finish_build signature simplification LGTM.

Bounding to impl AudioMuxer is sufficient (inherits Muxer), and switching to &Path is ergonomic.


469-471: Early return for no audio sources: good guard.

Prevents spinning up the mixer when unused. Nice.


497-500: Awaiting mixer readiness directly: OK.

Direct await with proper error mapping keeps the flow simple.


383-401: All Muxer implementations correctly satisfy the trait signature.

All four Muxer implementers (WindowsMuxer, AVFoundationMp4Muxer, Mp4Muxer, OggMuxer) have been verified to adopt the correct setup method signature. Each implementation includes all required parameters (config, output_path, video_config, audio_config, pause_flag, tasks) and uses async fn, which is the syntactic sugar equivalent of fn(...) -> impl Future<Output = Result<Self>> + Send and fully satisfies the trait requirement.

Comment on lines 41 to +60
// i don't trust anyone to not overwrite the whole store lols
pub fn update(app: &AppHandle, update: impl FnOnce(&mut Self)) -> Result<(), String> {
let Ok(store) = app.store("store") else {
return Err("Store not found".to_string());
};

let mut settings = Self::get(app)?.unwrap_or_default();
update(&mut settings);
store.set(Self::KEY, json!(settings));
store.save().map_err(|e| e.to_string())
}

fn save(&self, app: &AppHandle) -> Result<(), String> {
let Ok(store) = app.store("store") else {
return Err("Store not found".to_string());
};

store.set(Self::KEY, json!(self));
store.save().map_err(|e| e.to_string())
}
// pub fn update(app: &AppHandle, update: impl FnOnce(&mut Self)) -> Result<(), String> {
// let Ok(store) = app.store("store") else {
// return Err("Store not found".to_string());
// };

// let mut settings = Self::get(app)?.unwrap_or_default();
// update(&mut settings);
// store.set(Self::KEY, json!(settings));
// store.save().map_err(|e| e.to_string())
// }

// fn save(&self, app: &AppHandle) -> Result<(), String> {
// let Ok(store) = app.store("store") else {
// return Err("Store not found".to_string());
// };

// store.set(Self::KEY, json!(self));
// store.save().map_err(|e| e.to_string())
// }
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Remove commented-out code entirely.

Commented-out code should be deleted rather than left in the codebase. Version control preserves the history if these methods need to be recovered later. The informal comment on line 41 doesn't clearly explain why these methods were removed or whether this is temporary.

Apply this diff to remove the commented-out code:

-    // i don't trust anyone to not overwrite the whole store lols
-    // pub fn update(app: &AppHandle, update: impl FnOnce(&mut Self)) -> Result<(), String> {
-    //     let Ok(store) = app.store("store") else {
-    //         return Err("Store not found".to_string());
-    //     };
-
-    //     let mut settings = Self::get(app)?.unwrap_or_default();
-    //     update(&mut settings);
-    //     store.set(Self::KEY, json!(settings));
-    //     store.save().map_err(|e| e.to_string())
-    // }
-
-    // fn save(&self, app: &AppHandle) -> Result<(), String> {
-    //     let Ok(store) = app.store("store") else {
-    //         return Err("Store not found".to_string());
-    //     };
-
-    //     store.set(Self::KEY, json!(self));
-    //     store.save().map_err(|e| e.to_string())
-    // }

Since update was a public method, verify that it's not called elsewhere in the codebase:


🏁 Script executed:

#!/bin/bash
# Description: Search for calls to RecordingSettingsStore::update

# Search for usage of the update method
rg -n 'RecordingSettingsStore::update' --type rust

# Also check for potential method calls on instances
rg -n '\.update\s*\(' apps/desktop/src-tauri/src/recording_settings.rs -A 2 -B 2 --type rust

Length of output: 0




🏁 Script executed:

#!/bin/bash
# Check the current state of the recording_settings.rs file around lines 41-60
cat apps/desktop/src-tauri/src/recording_settings.rs | head -70 | tail -35

Length of output: 1313


🏁 Script executed:

#!/bin/bash
# Broader search for 'update' calls in the codebase (all types of files)
# Focus on RecordingSettings context
rg -n 'update' apps/desktop/src-tauri/src/recording_settings.rs -B 2 -A 2 --type rust

Length of output: 507


🏁 Script executed:

#!/bin/bash
# Check if 'update' is called in JavaScript/TypeScript frontend files
# (Tauri apps often have JS frontend calling Rust backend)
rg -n "RecordingSettings.*update\|recording.*update" apps/desktop/src --type ts --type js -C 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for invocations to this struct/methods
rg -n 'recording_settings\|RecordingSettings' apps/desktop/src-tauri/src/ --type rust -C 1

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if the method might be used via module::method pattern
rg -n '\.update\(' apps/desktop/src-tauri/src/ --type rust --glob '!recording_settings.rs'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for any trait implementations that might reference this
rg -n 'impl.*RecordingSettings' apps/desktop/src-tauri/src/ --type rust

Length of output: 81


🏁 Script executed:

#!/bin/bash
# Verify if the file compiles by checking it directly for syntax issues
cat apps/desktop/src-tauri/src/recording_settings.rs | sed -n '35,65p'

Length of output: 870


🏁 Script executed:

#!/bin/bash
# Try to find all methods defined in this file and check what's actually there
ast-grep --pattern $'impl RecordingSettingsStore {
  $$$
}'

Length of output: 3319


🏁 Script executed:

#!/bin/bash
# Check for pub fn update pattern more broadly
rg -n 'pub fn update' apps/desktop/src-tauri/src/recording_settings.rs --type rust

Length of output: 96


🏁 Script executed:

#!/bin/bash
# Search for commented fn update pattern
rg -n '// pub fn update\|// fn update' apps/desktop/src-tauri/src/recording_settings.rs --type rust

Length of output: 0


🏁 Script executed:

#!/bin/bash
# List all function definitions in recording_settings to understand the scope
rg -n 'fn ' apps/desktop/src-tauri/src/recording_settings.rs --type rust

Length of output: 236


🏁 Script executed:

#!/bin/bash
# Check Tauri invoke commands if any reference this
rg -n 'invoke.*update\|update.*settings' apps/desktop/src --type ts --type js --type json -C 1

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Simple: just show the exact lines requested in the review
sed -n '41,60p' apps/desktop/src-tauri/src/recording_settings.rs

Length of output: 792


Remove commented-out code entirely at lines 41-60.

Verification confirms the update method is not called anywhere in the codebase, making its removal safe. Commented-out code should be deleted rather than preserved; git history preserves it if needed later.

Apply this diff:

-    // i don't trust anyone to not overwrite the whole store lols
-    // pub fn update(app: &AppHandle, update: impl FnOnce(&mut Self)) -> Result<(), String> {
-    //     let Ok(store) = app.store("store") else {
-    //         return Err("Store not found".to_string());
-    //     };
-
-    //     let mut settings = Self::get(app)?.unwrap_or_default();
-    //     update(&mut settings);
-    //     store.set(Self::KEY, json!(settings));
-    //     store.save().map_err(|e| e.to_string())
-    // }
-
-    // fn save(&self, app: &AppHandle) -> Result<(), String> {
-    //     let Ok(store) = app.store("store") else {
-    //         return Err("Store not found".to_string());
-    //     };
-
-    //     store.set(Self::KEY, json!(self));
-    //     store.save().map_err(|e| e.to_string())
-    // }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// i don't trust anyone to not overwrite the whole store lols
pub fn update(app: &AppHandle, update: impl FnOnce(&mut Self)) -> Result<(), String> {
let Ok(store) = app.store("store") else {
return Err("Store not found".to_string());
};
let mut settings = Self::get(app)?.unwrap_or_default();
update(&mut settings);
store.set(Self::KEY, json!(settings));
store.save().map_err(|e| e.to_string())
}
fn save(&self, app: &AppHandle) -> Result<(), String> {
let Ok(store) = app.store("store") else {
return Err("Store not found".to_string());
};
store.set(Self::KEY, json!(self));
store.save().map_err(|e| e.to_string())
}
// pub fn update(app: &AppHandle, update: impl FnOnce(&mut Self)) -> Result<(), String> {
// let Ok(store) = app.store("store") else {
// return Err("Store not found".to_string());
// };
// let mut settings = Self::get(app)?.unwrap_or_default();
// update(&mut settings);
// store.set(Self::KEY, json!(settings));
// store.save().map_err(|e| e.to_string())
// }
// fn save(&self, app: &AppHandle) -> Result<(), String> {
// let Ok(store) = app.store("store") else {
// return Err("Store not found".to_string());
// };
// store.set(Self::KEY, json!(self));
// store.save().map_err(|e| e.to_string())
// }
🤖 Prompt for AI Agents
In apps/desktop/src-tauri/src/recording_settings.rs around lines 41 to 60,
remove the entire commented-out block containing the unused update and save
methods (all commented lines shown) so the file no longer contains that
dead/commented code; commit the deletion (rely on git history to recover if
needed) and run a quick build or formatting check to ensure no unrelated
formatting issues were introduced.

Comment on lines +72 to +81
collapsible_if = "deny"
manual_is_multiple_of = "deny"
clone_on_copy = "deny"
redundant_closure = "deny"
ptr_arg = "deny"
len_zero = "deny"
let_unit_value = "deny"
unnecessary_lazy_evaluations = "deny"
needless_range_loop = "deny"
manual_clamp = "deny"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Clippy lint configuration looks good; verify full workspace compliance.

The added lints are well-established best practices that promote code quality across readability, idiomaticity, optimization, and API design. However, since these are set to "deny", the entire workspace must pass these checks for builds to succeed.

Please verify that all workspace members pass these new lints by running:


🏁 Script executed:

#!/bin/bash
# Description: Verify entire workspace passes the newly added Clippy lints.

# Build and check the entire workspace with the new lints
cargo build --workspace 2>&1 | tee clippy-check.log

# Additionally, run clippy explicitly to catch all warnings
cargo clippy --workspace --all-targets 2>&1 | tee clippy-verbose.log

# Search for any deny-level clippy violations in the output
echo "=== Checking for deny-level violations ==="
grep -E "(error\[E|error:.*clippy)" clippy-check.log || echo "No errors found"

Length of output: 192



🏁 Script executed:

#!/bin/bash
# Static analysis to detect potential Clippy lint violations without running cargo
# This searches for common patterns that would trigger the newly added deny lints

echo "=== Searching for Clone-on-Copy violations ==="
# Look for .clone() calls that might be on Copy types
rg '\.clone\(\)' --type=rs -C2 | head -30

echo ""
echo "=== Searching for len_zero violations (checking .len() == 0) ==="
# Look for .len() == 0 patterns
rg -nP '\.len\(\)\s*==\s*0' --type=rs | head -20

echo ""
echo "=== Searching for ptr_arg violations (checking &Vec or &String parameters) ==="
# Look for function parameters with &Vec or &String
rg -nP 'fn\s+\w+\([^)]*&(Vec|String)<' --type=rs | head -20

echo ""
echo "=== Checking for existing clippy config in source ==="
# Check if clippy attributes are in use
rg -nP '#\[allow|#\[deny|#\[warn' --type=rs | head -20

echo ""
echo "=== Searching for let _ patterns (let_unit_value) ==="
rg -nP 'let\s+_\s*=' --type=rs | head -20

Length of output: 437



🏁 Script executed:

#!/bin/bash
# Static analysis using glob patterns to find Rust files

echo "=== Searching for Clone-on-Copy violations ==="
rg '\.clone\(\)' -g '*.rs' -C2 | head -40

echo ""
echo "=== Searching for len_zero violations ==="
rg '\.len\(\)\s*==\s*0' -g '*.rs' | head -20

echo ""
echo "=== Searching for ptr_arg violations ==="
rg -P 'fn\s+\w+\([^)]*&(Vec|String)<' -g '*.rs' | head -20

echo ""
echo "=== Summary: List all Rust files in workspace ==="
fd -e rs | head -20

Length of output: 4095



🏁 Script executed:

#!/bin/bash
# Comprehensive search for len_zero violations

echo "=== All len_zero violations (comprehensive) ==="
rg '\.len\(\)\s*==\s*0|\.len\(\)\s*!=\s*[1-9]' -g '*.rs' -n

echo ""
echo "=== All let_unit_value violations ==="
rg 'let\s+_\s*=' -g '*.rs' -n | head -30

echo ""
echo "=== Check Cargo.toml for new lints ==="
grep -A 20 'lints.rust.unsafe_code' Cargo.toml | head -30

Length of output: 3228


Workspace does not pass new deny lints—multiple violations must be fixed before merge.

The added lints are well-established best practices, but verification found violations that will cause build failures:

len_zero violations (2):

  • crates/camera-mediafoundation/examples/cli.rs:24: Replace .len() == 0 with .is_empty()
  • crates/camera-ffmpeg/src/windows.rs:27: Replace .len() == 0 with .is_empty()

let_unit_value violations (29+):

  • crates/scap-targets/src/platform/win.rs: 24 instances (Windows FFI cleanup calls)
  • crates/video-decode/src/bin/print_frames.rs:20
  • crates/scap-ffmpeg/src/screencapturekit.rs:119
  • crates/scap-direct3d/src/lib.rs:389

The let_unit_value pattern is common for intentionally ignoring return values in FFI and cleanup code. Consider using let _ = ...; with #[allow(let_unit_value)] attributes on affected functions instead of removing them entirely.

🤖 Prompt for AI Agents
In Cargo.toml around lines 72–81 you added deny lints that cause build failures;
fix the reported violations by (1) replacing `.len() == 0` with `.is_empty()` in
crates/camera-mediafoundation/examples/cli.rs (line ~24) and
crates/camera-ffmpeg/src/windows.rs (line ~27), and (2) handle the many
let_unit_value violations (≈29+) in FFI/cleanup code by changing bare `let
expr;` return-ignores to `let _ = expr;` where appropriate and adding
`#[allow(let_unit_value)]` to the containing functions (or smallest enclosing
scope) for the Windows FFI cleanup functions in
crates/scap-targets/src/platform/win.rs (24 occurrences), and the other files
listed (crates/video-decode/src/bin/print_frames.rs,
crates/scap-ffmpeg/src/screencapturekit.rs, crates/scap-direct3d/src/lib.rs);
then re-run cargo clippy to confirm no remaining deny failures before merging.

Comment on lines +407 to 409
if width.is_multiple_of(2) {
width -= 1;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Inverted parity logic makes dimensions odd instead of even.

The conditions are checking if value.is_multiple_of(2) (i.e., "if even") and then decrementing, which converts even dimensions to odd. Video codecs require even dimensions, so this logic must be inverted.

Apply this diff to fix the inverted logic:

-        if width.is_multiple_of(2) {
+        if !width.is_multiple_of(2) {
             width -= 1;
         }
-        if height.is_multiple_of(2) {
+        if !height.is_multiple_of(2) {
             height -= 1;
         }

Apply the same negation (!) to all eight occurrences of is_multiple_of(2) checks in this function (lines 407, 413, 422, 428, 437, 443, 453, 459).

Also applies to: 413-415, 422-424, 428-430, 437-439, 443-445, 453-455, 459-461

🤖 Prompt for AI Agents
In crates/recording/src/instant_recording.rs around lines 407-461, the parity
checks currently use if value.is_multiple_of(2) and then decrement the
dimension, which turns even values odd; change each check to if
!value.is_multiple_of(2) so we only decrement when the value is odd. Apply this
negation to all eight occurrences at the specified lines (407, 413, 422, 428,
437, 443, 453, 459 and the corresponding +1 lines listed in the comment) so each
dimension is adjusted only when odd to ensure dimensions remain even for video
codecs.

Comment on lines +666 to +671
assert_eq!(item.timestamp.duration_since(start), ONE_SECOND / 2);
assert_eq!(item.inner.samples(), SOURCE_INFO.rate() as usize / 2);

let item = &source.buffer[1];
assert_eq!(item.1.duration_since(start), ONE_SECOND);
assert_eq!(item.0.samples(), SOURCE_INFO.rate() as usize / 2);
assert_eq!(item.timestamp.duration_since(start), ONE_SECOND);
assert_eq!(item.inner.samples(), SOURCE_INFO.rate() as usize / 2);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Incomplete AudioFrame refactor: Lines 591, 595, 624, 626 still use tuple-style access.

While these test assertions correctly use named fields (.timestamp, .inner), the frame_gap test at lines 591, 595 and the start_gap test at lines 624, 626 still use the old tuple-style access (.1, .0). This will cause compilation errors.

Apply this diff to fix the frame_gap test:

             assert_eq!(
-                source.buffer[1].1.duration_since(mixer.timestamps),
+                source.buffer[1].timestamp.duration_since(mixer.timestamps),
                 ONE_SECOND / 2
             );
             assert_eq!(
-                source.buffer[1].0.samples(),
+                source.buffer[1].inner.samples(),
                 SOURCE_INFO.rate() as usize / 2
             );

Apply this diff to fix the start_gap test:

-            assert_eq!(source.buffer[0].1.duration_since(start), ONE_SECOND / 2);
+            assert_eq!(source.buffer[0].timestamp.duration_since(start), ONE_SECOND / 2);
             assert_eq!(
-                source.buffer[0].0.samples(),
+                source.buffer[0].inner.samples(),
                 SOURCE_INFO.rate() as usize / 2
             );

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In crates/recording/src/sources/audio_mixer.rs around lines 591-595 and 624-626,
the tests still use tuple-style field access (.1 and .0) from the old AudioFrame
shape; update those occurrences to use the named fields used elsewhere: replace
.1 with .inner and .0 with .timestamp so the assertions read e.g.
item.inner.samples() and item.timestamp.duration_since(start).

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