Open
Conversation
…er mismatch iOS defaults to AVAudioSessionCategorySoloAmbient with a system-chosen buffer size (~4096 frames on device). Elementary's runtime is initialized with a fixed block size of 512, causing a mismatch that produces garbage audio (audible as a low-frequency square wave) immediately on app launch. Fix: set AVAudioSessionCategoryPlayback with MixWithOthers and AllowBluetoothA2DP, request a 512-frame preferred buffer duration, activate the session before creating AVAudioEngine, then derive the actual block size from session.IOBufferDuration so the runtime always matches what the engine delivers per callback.
There was a problem hiding this comment.
Pull request overview
This PR updates the iOS native audio startup path so AVAudioSession is configured before AVAudioEngine is created, with the goal of preventing the startup-time buffer-size mismatch that currently produces corrupted audio on launch.
Changes:
- Configure
AVAudioSessionduringElementaryinitialization, including playback category, options, preferred I/O buffer duration, and activation. - Extend init logging to include the granted
IOBufferDuration. - Derive the Elementary runtime block size from the active session’s actual buffer duration instead of hard-coding
512.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+25
to
+29
| NSError *sessionError; | ||
| AVAudioSession *session = [AVAudioSession sharedInstance]; | ||
| [session setCategory:AVAudioSessionCategoryPlayback | ||
| mode:AVAudioSessionModeDefault | ||
| options:AVAudioSessionCategoryOptionMixWithOthers | |
Comment on lines
+23
to
+42
| // Configure session before engine: iOS default (SoloAmbient, ~4096-frame buffers) | ||
| // mismatches Elementary's block size and produces garbage audio on launch. | ||
| NSError *sessionError; | ||
| AVAudioSession *session = [AVAudioSession sharedInstance]; | ||
| [session setCategory:AVAudioSessionCategoryPlayback | ||
| mode:AVAudioSessionModeDefault | ||
| options:AVAudioSessionCategoryOptionMixWithOthers | | ||
| AVAudioSessionCategoryOptionAllowBluetoothA2DP | ||
| error:&sessionError]; | ||
| if (sessionError) { | ||
| NSLog(@"[Elementary] Failed to set audio session category: %@", sessionError); | ||
| } | ||
| [session setPreferredIOBufferDuration:(512.0 / 48000.0) error:&sessionError]; | ||
| if (sessionError) { | ||
| NSLog(@"[Elementary] Failed to set preferred IO buffer duration: %@", sessionError); | ||
| } | ||
| [session setActive:YES error:&sessionError]; | ||
| if (sessionError) { | ||
| NSLog(@"[Elementary] Failed to activate audio session: %@", sessionError); | ||
| } |
Comment on lines
+107
to
111
| // Use granted IOBufferDuration — iOS may not honor the preferred value exactly. | ||
| int bufferSize = (int)round(outputFormat.sampleRate * session.IOBufferDuration); | ||
| if (bufferSize <= 0 || bufferSize > 4096) bufferSize = 512; // safety fallback | ||
| NSLog(@"[Elementary] Runtime block size: %d frames", bufferSize); | ||
| self.runtime = std::make_shared<elem::Runtime<float>>(outputFormat.sampleRate, bufferSize); |
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.
iOS defaults to AVAudioSessionCategorySoloAmbient with a system-chosen buffer size (~4096 frames on device). Elementary's runtime is initialised with a fixed block size of 512, causing a mismatch that produces garbage audio (audible as a low-frequency square wave) immediately on app launch.
Fix: set AVAudioSessionCategoryPlayback with MixWithOthers and AllowBluetoothA2DP, request a 512-frame preferred buffer duration, activate the session before creating AVAudioEngine, then derive the actual block size from session.IOBufferDuration so the runtime always matches what the engine delivers per callback.
I didn't notice this issue on Midicircuit because it still has its own AVAudioEngine setup and some custom native code to bridge between it and react-native-elementary-audio.