Audio API 1.0.0 is the first stable release. It moves the library closer to the Web Audio API specification, takes optional features out of the default build, and cleans up the APIs that grew organically through 0.x. Spatial audio arrives with PannerNode and AudioListener, worklets now live in their own package, and FFmpeg is opt-in, so local playback no longer pays for a decoder most apps do not need.
Upgrading from 0.13.x needs code changes, and the migration guide covers all of them. If you use TypeScript, start by running tsc, which surfaces most items. The renamed event handlers are the exception in plain JavaScript, where assigning an old name silently creates an unused property.
Breaking changes
- FFmpeg is off by default. Local files, assets and
ArrayBuffers,m4a,aacandmp4included, now decode through the platform decoders. You still need FFmpeg for remote URL streaming, HLS sources andgetAudioDurationon remote URLs. The build options moved out of the Podfile andgradle.propertiesinto your app'spackage.json, and the Expo plugin optiondisableFFmpegbecameenableFFmpeg(#1177, #1336) - Worklets moved to
react-native-audio-worklets.WorkletNode,WorkletProcessingNodeandWorkletSourceNodeare classes imported from the new package instead of factory methods on the context, and it requiresreact-native-worklets0.10.0 or newer plus the New Architecture (#1152, #1159, #1169) - Event handler properties use the spec's lowercase names.
onEndedbecameonended,onPositionChangedbecameonpositionchanged, and the rest followed, with no aliases left behind. Reassigning a handler now replaces the previous one, where in 0.x the old callback kept firing.<Audio>props,AudioRecordercallbacks and system events keep their names (#1286, #1289) setAudioSessionOptionsis nowsetSystemOptions, with iOS options nested under anioskey and theiosprefix dropped from each one. A new optionalandroidsection configures the communication session.- The recorder connects to the graph directly.
recorder.connect(ctx, ctx.destination)replaces the explicit adapter node, which is created internally now.pause(),resume()anddisableFileOutput()return promises and are serialized withstart()andstop();start()no longer takes options, since the file name moved toenableFileOutput; andenableFileOutputthrowsNotSupportedErrorrather than returning an errorResult. AudioBufferQueueSourceNodehas a real playback state machine. Callresume()afterpause()instead of callingstart()again, which now throwsInvalidStateErrorthe second time. The defaultoffsetofstart(when, offset)changed from-1to0, so a barestart()works (#1189)StreamerNodewas removed in favour of<Audio>(#1155)- Deep imports no longer resolve. The package declares an
exportsmap, so import everything from the package root (#1194) - Android recordings can outlive the app UI. With
androidFSStopWithTask: falsethe foreground service follows the C++ recorder, so a recording can keep going after the screen unmounts or the app is swiped away from recents (#1234) - In
useAudioInput,onSelectInputbecameselectInput, and it accepts'default'to hand input selection back to the system. - Recording to
Cafon Android throws, and theSessionOptions,AudioRecorderStartOptionsandBaseAudioBufferSourceOptionstypes were removed.
Spec conformance
We run the Web Platform Tests webaudio subtree, the same suite browser vendors hold their implementations to, against the library through a Node harness. Across the interfaces the library implements, the assertion pass rate went from 1758/2503 (70.2%) in 0.13.6 to 2643/3109 (85.0%) in 1.0.0. Six interfaces now pass their whole suite: AudioBuffer, ChannelMergerNode, ChannelSplitterNode, GainNode, OscillatorNode and PeriodicWave. AudioNode climbed from 59.2% to 98.9%, DelayNode from 66.7% to 96.2%, AnalyserNode from 84.9% to 99.3%, and AudioParam from 63.5% to 78.8%. The coverage page carries the full per-interface table (#1148)
Features
Audio graph
PannerNodewith equal-power spatialization, distance models and cone gain, plus theAudioListenerit positions sound against (#1227, #1153)ChannelMergerNodeandChannelSplitterNode, both at full WPT conformance (#1174)baseLatencyandoutputLatencyonAudioContext, so you can line visuals up against what the speaker is actually playing (#1129)addEventListener('ended', ...)andremoveEventListeneron scheduled sources, withtypeandtargeton the event (#1286)- A rewritten audio graph, with link-aware topological ordering and per-context event queues (#991, #1302)
Worklets
react-native-audio-workletsships as its own package withWorkletAudioContext, a'frequency-domain'mode onWorkletNode, and channel counts passed to processing callbacks (#1159, #1169)
Recording and encoding
- An encoder layer for recordings, with an Opus encoder and ADTS AAC output for compressed recordings that survive a crash mid-file (#1183, #1366, #1333)
- An
androidInputPresetoption onAudioRecorderto pick the capture preset (#1210)
Android
setInputDeviceis implemented, where it used to be a no-op, including the Bluetooth SCO link a headset mic needs (#1255)- A communication session for voice chat, owning the mode preference, voice-communication focus and route-change handling (#1324)
- An output profile option, and
AudioContextOptions.latencyHintis respected when the Oboe output stream opens (#1323, #1232) - Faster decoding through asynchronous
MediaCodecand a raw WAV path (#1376)
Playback, system and build
- Swift Package Manager support for both packages, alongside CocoaPods (#1354, #1355)
- A buffering state on
AudioFileSourceNodeand<Audio>, exposed asonWaitingandonPlaying(#1243) isLiveStreaminPlaybackNotificationInfo, configurable fast-forward and rewind intervals, and sharper artwork in notifications (#1240, #1165, #1291)AudioManager.getSystemVolume()for a synchronous volume read (#1211)- React Native 0.88 support (#1352)
Performance
- Convolvers were redesigned: several of them now share four worker threads instead of four each, and the audio thread no longer waits on them (#1331, #1357)
- Buffers are reused across render quanta instead of reallocated, and the recorder and context share a single promise lane, which cut seven threads per context down to two (#1283, #1338)
- External memory pressure is reported per buffer rather than per node, which was pushing large graphs into Hermes out-of-memory errors (#1383)
- The audio engine initializes lazily, and unprocessed nodes advance without rendering so stopped sources are released (#1251, #1341)
Fixes
- iOS: an engine and worker deadlock, a use-after-free in the audio player, a voice-processing driver loop, and recording that failed to resume after an interruption (#1290, #1334, #1317, #1257)
- Android: an active recording is finalized when the system destroys the foreground service, and the Kotlin plugin is skipped when AGP already registers the extension (#1321, #1271)
exponentialRampToValueAtTimeaccepts anendTimeof 0,ConvolverNode.bufferenforces the spec limits and allows 32-channel buffers, and starting a buffer source resumes the context (#1274, #1258, #1272)- A memory leak in
AudioScheduledSourceNode, teardown races inRuntimeObserver, and the channel count negotiation algorithm (#1197, #1386, #1145) detectHttpByteRangesretries with a range GET after an inconclusive HEAD, andIOSFileWriter::closeFilereturns a frame-count duration (#1245, #1320)