fix: prevent panic in AudioInfo::channel_layout() for unsupported channel counts #1536
+95
−17
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Fixes crash and chipmunk audio on systems with professional audio interfaces that report high channel counts (e.g., RME Digiface with 34 outputs).
The Problem
When using Cap with a multi-channel audio interface, users experienced:
Option::unwrap()on aNonevalue" inchannel_layout()Root Cause
FFmpeg only supports channel layouts up to 8 channels (7.1 surround). When a device reported more channels (like 34), several things broke:
channel_layout()called.unwrap()onNonebecause there's no FFmpeg layout for 34 channelsThe Fix
for_ffmpeg_output()helper for consistent clamping across the codebasechannel_layout()gracefully handle any channel countFiles Changed
crates/media-info/src/lib.rs- Core AudioInfo fixes and helper methodcrates/editor/src/audio.rs- AudioResampler and buffer fixescrates/editor/src/playback.rs- Stream configuration fixesTesting
Tested on Mac with RME Digiface (34 output channels) + RØDE NT-USB Mini microphone:
Greptile Summary
This PR fixes crashes and chipmunk audio playback on systems with professional audio interfaces reporting more than 8 channels (e.g., RME Digiface with 34 outputs).
Key Changes:
AudioInfonow stores the actual device channel count for correct audio data parsing, while clamping to 8 channels when interfacing with FFmpeg (which only supports up to 7.1 surround)for_ffmpeg_output()helper method for consistent channel clamping across the codebasechannel_layout()to gracefully handle 0-channel and excessive channel counts instead of panickingwrap_frame_with_max_channels()to use actual channel count for input parsing while limiting output to FFmpeg-compatible layoutsImpact:
The fix properly separates the concern of parsing device audio data (which needs the real channel count) from FFmpeg encoding constraints (max 8 channels), eliminating both the panic and the playback speed issue.
Confidence Score: 5/5
Important Files Changed
for_ffmpeg_output()helper, prevents panics inchannel_layout(), handles 0-channel and 34+ channel edge cases correctly, includes comprehensive testsfor_ffmpeg_output()in AudioPlaybackBuffer, AudioResampler, and PrerenderedAudioBuffer constructors to ensure consistent FFmpeg compatibility across all audio processing pipelinescreate_stream()andcreate_stream_prerendered(), preventing channel count mismatches during playbackSequence Diagram
sequenceDiagram participant Device as Audio Device<br/>(34 channels) participant AudioInfo as AudioInfo participant Resampler as AudioResampler participant FFmpeg as FFmpeg<br/>(max 8 channels) participant Output as Audio Output Stream Note over Device,Output: Recording/Playback Initialization Device->>AudioInfo: from_stream_config(34 channels) activate AudioInfo Note over AudioInfo: Store actual channel count (34)<br/>for correct data parsing AudioInfo-->>Device: AudioInfo { channels: 34 } deactivate AudioInfo Note over Device,Output: Audio Processing Pipeline Device->>AudioInfo: wrap_frame_with_max_channels(data, 8) activate AudioInfo Note over AudioInfo: Use 34 channels to parse input<br/>Extract only first 8 channels<br/>Avoid div-by-zero with max(1) AudioInfo->>FFmpeg: Create frame with 8 channels activate FFmpeg FFmpeg-->>AudioInfo: Audio frame (8 channels) deactivate FFmpeg AudioInfo-->>Device: Properly formatted frame deactivate AudioInfo Device->>Resampler: new(output_info) activate Resampler Note over Resampler: Call for_ffmpeg_output()<br/>Clamp to 8 channels Resampler->>AudioInfo: for_ffmpeg_output() activate AudioInfo Note over AudioInfo: Return AudioInfo { channels: 8 } AudioInfo-->>Resampler: Clamped AudioInfo deactivate AudioInfo Resampler->>FFmpeg: Create resampler context (8 channels) FFmpeg-->>Resampler: Resampler ready deactivate Resampler Device->>Output: Configure stream activate Output Note over Output: Set config.channels = 8<br/>(matches clamped AudioInfo) Output-->>Device: Stream configured deactivate Output Note over Device,Output: Result: No panic, correct playback speed