Skip to content

Conversation

@richiemcilroy
Copy link
Member

@richiemcilroy richiemcilroy commented Oct 22, 2025

Ensures that the audio frames output by AudioMixer have their rate set to AudioMixer::INFO.rate(), preventing downstream encoders from inheriting incorrect rates from upstream sources such as CoreAudio devices. This change also updates the elapsed time calculation to use the normalized output rate

Summary by CodeRabbit

  • Bug Fixes
    • Standardized audio timing to use the mixer's fixed output rate for buffering and downstream frames, improving timestamp alignment.
    • Reduces timing drift and increases stability when combining sources that report varying sample rates, improving compatibility with external encoders and players.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 22, 2025

Walkthrough

Buffer timestamping now uses each source's configured rate when buffering incoming frames; separately, the mixer enforces its fixed output rate on filtered frames and computes elapsed time using that mixer output rate for downstream timing.

Changes

Cohort / File(s) Summary
Audio mixer timing & buffering
crates/recording/src/sources/audio_mixer.rs
When buffering incoming frames, update per-source buffer_last using the source's configured rate (per-source rate) instead of the frame's reported rate; in the main tick loop, set the filtered/FFmpeg frame's rate to the mixer's fixed output rate (AudioMixer::INFO.rate()) and compute elapsed time using that fixed rate to align downstream timestamps.

Sequence Diagram

sequenceDiagram
    participant Source as Upstream Source
    participant Mixer as AudioMixer
    participant Buffer as Per-Source Buffer
    participant Timing as Downstream Timing

    rect rgb(240,250,255)
    Note over Source,Buffer: Incoming frame arrives (may report various rates)
    Source->>Buffer: push frame (frame.rate() = variable)
    end

    rect rgb(245,240,255)
    Note over Buffer,Mixer: Buffer timestamping uses source-configured rate
    Buffer->>Buffer: update buffer_last using source.rate (per-source)
    end

    rect rgb(245,255,240)
    Note over Mixer: Mixer normalizes output rate
    Mixer->>Mixer: set filtered_frame.rate = AudioMixer::INFO.rate()
    Mixer->>Timing: compute elapsed using AudioMixer::INFO.rate()
    end

    rect rgb(255,245,245)
    Note over Mixer: Downstream receives frames with consistent mixer rate
    Mixer->>Timing: emit frame with fixed output timestamps
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Audio fixes #1238: Modifies the same audio_mixer.rs buffering/timestamp logic (silence/gap detection and timestamp/rate computation), potentially overlapping with these timing fixes.

Poem

🐇 I hopped in with frames of every rate,

I nudged the buffers, set each timestamp straight,
The mixer hums true at one steady tune,
Downstream keeps time beneath the same moon,
A carrot-cheer for rhythm kept in state.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "Normalize audio frame rate in AudioMixer output" directly and accurately captures the main change described in the pull request. The modifications in audio_mixer.rs standardize frame rates by enforcing the mixer's output rate (AudioMixer::INFO.rate()) on all output frames, which is precisely what the title conveys. The title is concise at 7 words, avoids vague terminology or noise, and is specific enough that a team member reviewing commit history would clearly understand the primary objective: normalizing audio frame rates in the AudioMixer's output.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch normalize-audio

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cacab60 and ac61470.

📒 Files selected for processing (1)
  • crates/recording/src/sources/audio_mixer.rs (1 hunks)
🧰 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/recording/src/sources/audio_mixer.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/recording/src/sources/audio_mixer.rs
⏰ 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 (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)

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: 0

🧹 Nitpick comments (2)
crates/recording/src/sources/audio_mixer.rs (2)

134-141: Avoid long‑run/32‑bit overflow in sample counter.

samples_out: usize can overflow on 32‑bit or extremely long runs. Prefer u64 and cast at use sites.

Apply:

@@
-    samples_out: usize,
+    samples_out: u64,
@@
-            samples_out: 0,
+            samples_out: 0u64,
@@
-            let elapsed = Duration::from_secs_f64(self.samples_out as f64 / output_rate);
+            let elapsed = Duration::from_secs_f64(self.samples_out as f64 / output_rate);
@@
-            self.samples_out += filtered.samples();
+            self.samples_out += filtered.samples() as u64;

Also applies to: 206-220, 411-415


297-315: Use existing helpers for silence math (readability/consistency).

You already have samples_for_timeout and duration_from_samples. Using them here reduces duplication and keeps rounding consistent.

-                                let silence_samples_needed = (gap.as_secs_f64()) * rate as f64;
-                                let silence_samples_count = silence_samples_needed.ceil() as usize;
+                                let silence_samples_count = samples_for_timeout(rate, gap);
@@
-                                let silence_duration = Duration::from_secs_f64(
-                                    silence_samples_count as f64 / rate as f64,
-                                );
+                                let silence_duration = duration_from_samples(silence_samples_count, rate);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac61470 and 28eabb4.

📒 Files selected for processing (1)
  • crates/recording/src/sources/audio_mixer.rs (2 hunks)
🧰 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/recording/src/sources/audio_mixer.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/recording/src/sources/audio_mixer.rs
🧬 Code graph analysis (1)
crates/recording/src/sources/audio_mixer.rs (1)
crates/media-info/src/lib.rs (1)
  • rate (125-127)
⏰ 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 (aarch64-apple-darwin, macos-latest)
  • GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (2)
crates/recording/src/sources/audio_mixer.rs (2)

403-411: Output rate normalization + elapsed at mixer rate — correct and necessary.

Setting filtered to AudioMixer::INFO.rate() and computing elapsed from that fixed rate prevents downstream from inheriting bad upstream sample-rate metadata and keeps timestamps monotonic at 48 kHz. Nice.


323-326: Buffered-frame duration now uses source rate — fix verified and consistent.

The change at line 325 correctly switches to rate (per-source rate) for buffered-frame duration, keeping it aligned with silence generation at line 312 which already uses the same rate variable. Verified no other Duration calculations depend on frame.rate(). Output elapsed time at line 411 correctly uses output_rate (mixer rate) for downstream encoders. No additional fixes needed.

@richiemcilroy richiemcilroy merged commit 7468355 into main Oct 22, 2025
15 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.

1 participant