AudioBufferSourceNode.setBuffer() deep-copies the entire audio buffer, doubling memory usage
Description
AudioBufferSourceNode::setBuffer() creates a full deep copy of the AudioBuffer's underlying AudioBus data. This effectively doubles the memory cost of decoded audio, and for apps that play multiple tracks simultaneously this can become an issue.
Usage context
My app is a music practice tool that plays multiple audio tracks simultaneously (usually 5: tenor, alto, bass, soprano, instrumental). Each track is decoded via decodeAudioData() at 22,050 Hz, then assigned to its own AudioBufferSourceNode (with pitchCorrection: true) connected through a GainNode to audioContext.destination. This allows independent volume control per track. All buffers are decoded and assigned upfront before playback starts, so that every source node can be started simultaneously and the tracks stay in sync.
Code path
AudioBufferSourceNode::setBuffer() deep-copies the entire audio buffer into alignedBus_, in both the pitch-correction branch (lines 97-100) and the non-pitch-correction branch (line 102).
Impact
For a real-world scenario — 5 simultaneous tracks of a 4:45 song decoded at 22,050 Hz:
| Allocation |
Size |
Decoded audio buffers (decodeAudioData) |
144 MB |
Deep copies created by setBuffer() |
144 MB |
| Metadata / alignment overhead |
~20 MB |
| Total native heap cost |
~308 MB |
The measured overhead is 2.14x the raw PCM size. On mobile devices this is significant — it can push a multi-track music app past 500 MB native heap during playback.
Questions
- Is this deep copy intentional / expected? I imagine there's a good reason for it but wanted to check.
- Are there any planned improvements in this area for upcoming releases?
- Is there anything I can do on my side to reduce the memory cost of audio buffer handling? (e.g. different usage patterns, options I might be missing, etc.)
Environment
react-native-audio-api: 0.11.7
- React Native: 0.81.5
- Platform: Android (not tested on iOS, but the code is in
common/cpp/ so both platforms are affected)
AudioBufferSourceNode.setBuffer()deep-copies the entire audio buffer, doubling memory usageDescription
AudioBufferSourceNode::setBuffer()creates a full deep copy of theAudioBuffer's underlyingAudioBusdata. This effectively doubles the memory cost of decoded audio, and for apps that play multiple tracks simultaneously this can become an issue.Usage context
My app is a music practice tool that plays multiple audio tracks simultaneously (usually 5: tenor, alto, bass, soprano, instrumental). Each track is decoded via
decodeAudioData()at 22,050 Hz, then assigned to its ownAudioBufferSourceNode(withpitchCorrection: true) connected through aGainNodetoaudioContext.destination. This allows independent volume control per track. All buffers are decoded and assigned upfront before playback starts, so that every source node can be started simultaneously and the tracks stay in sync.Code path
AudioBufferSourceNode::setBuffer()deep-copies the entire audio buffer intoalignedBus_, in both the pitch-correction branch (lines 97-100) and the non-pitch-correction branch (line 102).Impact
For a real-world scenario — 5 simultaneous tracks of a 4:45 song decoded at 22,050 Hz:
decodeAudioData)setBuffer()The measured overhead is 2.14x the raw PCM size. On mobile devices this is significant — it can push a multi-track music app past 500 MB native heap during playback.
Questions
Environment
react-native-audio-api: 0.11.7common/cpp/so both platforms are affected)