Audio API 1.0.0

v1.​0.​0Major Release

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, aac and mp4 included, now decode through the platform decoders. You still need FFmpeg for remote URL streaming, HLS sources and getAudioDuration on remote URLs. The build options moved out of the Podfile and gradle.properties into your app's package.json, and the Expo plugin option disableFFmpeg became enableFFmpeg (#1177, #1336)
  • Worklets moved to react-native-audio-worklets. WorkletNode, WorkletProcessingNode and WorkletSourceNode are classes imported from the new package instead of factory methods on the context, and it requires react-native-worklets 0.10.0 or newer plus the New Architecture (#1152, #1159, #1169)
  • Event handler properties use the spec's lowercase names. onEnded became onended, onPositionChanged became onpositionchanged, 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, AudioRecorder callbacks and system events keep their names (#1286, #1289)
  • setAudioSessionOptions is now setSystemOptions, with iOS options nested under an ios key and the ios prefix dropped from each one. A new optional android section 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() and disableFileOutput() return promises and are serialized with start() and stop(); start() no longer takes options, since the file name moved to enableFileOutput; and enableFileOutput throws NotSupportedError rather than returning an error Result.
  • AudioBufferQueueSourceNode has a real playback state machine. Call resume() after pause() instead of calling start() again, which now throws InvalidStateError the second time. The default offset of start(when, offset) changed from -1 to 0, so a bare start() works (#1189)
  • StreamerNode was removed in favour of <Audio> (#1155)
  • Deep imports no longer resolve. The package declares an exports map, so import everything from the package root (#1194)
  • Android recordings can outlive the app UI. With androidFSStopWithTask: false the 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, onSelectInput became selectInput, and it accepts 'default' to hand input selection back to the system.
  • Recording to Caf on Android throws, and the SessionOptions, AudioRecorderStartOptions and BaseAudioBufferSourceOptions types 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

  • PannerNode with equal-power spatialization, distance models and cone gain, plus the AudioListener it positions sound against (#1227, #1153)
  • ChannelMergerNode and ChannelSplitterNode, both at full WPT conformance (#1174)
  • baseLatency and outputLatency on AudioContext, so you can line visuals up against what the speaker is actually playing (#1129)
  • addEventListener('ended', ...) and removeEventListener on scheduled sources, with type and target on the event (#1286)
  • A rewritten audio graph, with link-aware topological ordering and per-context event queues (#991, #1302)

Worklets

  • react-native-audio-worklets ships as its own package with WorkletAudioContext, a 'frequency-domain' mode on WorkletNode, 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 androidInputPreset option on AudioRecorder to pick the capture preset (#1210)

Android

  • setInputDevice is 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.latencyHint is respected when the Oboe output stream opens (#1323, #1232)
  • Faster decoding through asynchronous MediaCodec and a raw WAV path (#1376)

Playback, system and build

  • Swift Package Manager support for both packages, alongside CocoaPods (#1354, #1355)
  • A buffering state on AudioFileSourceNode and <Audio>, exposed as onWaiting and onPlaying (#1243)
  • isLiveStream in PlaybackNotificationInfo, 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)
  • exponentialRampToValueAtTime accepts an endTime of 0, ConvolverNode.buffer enforces 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 in RuntimeObserver, and the channel count negotiation algorithm (#1197, #1386, #1145)
  • detectHttpByteRanges retries with a range GET after an inconclusive HEAD, and IOSFileWriter::closeFile returns a frame-count duration (#1245, #1320)

Docs

  • A full-duplex voice AI assistant guide and a matching demo app (#1344, #1365)
  • Versioned docs, so latest and next are both browsable, each with its own WPT report (#1241, #1237)
  • Engine-internal documentation for anyone reading or extending the C++ side (#1275)

Full changelog

Release card
Audio API 1.0.0 release card