fix(ios): avoid installTap sample-rate assertion crash when starting stream recording - #623
Open
striver2006 wants to merge 1 commit into
Open
Conversation
…stream recording
AVFAudio aborts the process with an uncatchable NSException
('required condition is false: format.sampleRate == hwFormat.sampleRate')
when installTap is called with a stale input format while an asynchronous
hardware sample-rate switch (session reconfiguration, Bluetooth HFP/A2DP
negotiation, route change) is still in progress.
Two changes in RecorderStreamDelegate.start():
- Configure the audio session before creating the AVAudioEngine, so the
engine cannot observe a pre-switch input format.
- Wait (bounded, 10 x 25ms on the plugin's background serial queue) for
the input format to settle before installing the tap, re-creating the
engine per retry since the input node caches the first observed format.
If no valid format shows up, throw a RecorderError instead of tripping
the AVFAudio assertion.
Edit by CZB
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Addresses #622 (full root-cause analysis there).
RecorderStreamDelegate.start()can abort the whole app with an uncatchable NSException (required condition is false: format.sampleRate == hwFormat.sampleRate) wheninstallTapruns while an asynchronous hardware sample-rate switch (session reconfiguration, Bluetooth HFP/A2DP negotiation, route change) is still in progress andinputFormat(forBus:)returned a stale format.Changes (pure Swift, no API change)
initAVAudioSession; since session configuration (category/activation/preferred sample rate) is what triggers the async hardware switch, creating the engine afterwards removes the structural half of the race.installTap. Poll until the format is non-zero and (unless voice processing is enabled, where the input node format may legitimately differ) matchesAVAudioSession.sampleRate. The engine is re-created per retry because the input node caches the first format it observed. Bounded at 10×25 ms on the plugin's background serial queue — in normal operation it takes 0 rounds, so the happy path is unchanged. If no valid format shows up, aRecorderErroris thrown instead of tripping the AVFAudio assertion.Testing
Note: a third, defense-in-depth layer (ObjC
@try/@catcharoundinstallTap/prepare/startso any residual race becomes a catchablePlatformExceptioninstead of SIGABRT) is deliberately not included — it needs an ObjC file and a single SPM target can't mix languages. See #622 for discussion.🤖 Generated with Claude Code