One.Audio plays a local file:// URI or an https:// audio URL through
AVPlayer. It handles one playback or recording operation at a time. Starting
playback replaces the previous player; stop a paused player before recording.
An ended or failed player is cleared when recording starts. Calls reject with
a coded error when the requested operation cannot run.
import { One } from 'one'
await One.Audio.play('https://example.com/episode.m4a')const status = await One.Audio.getPlaybackStatus()if (status.state === 'playing') { await One.Audio.pause() await One.Audio.seek(30_000) await One.Audio.resume()}await One.Audio.stop()getPlaybackStatus() returns state, positionMs, and a durationMs when the
media has a finite duration. States are idle, loading, playing, paused,
ended, and failed. A remote source may initially be loading; read its
status again when your app needs current progress. A failed source reports its
error in the status. seek() needs a ready item and rejects with
E_AUDIO_STATE while a source is loading or failed. resume() restarts an
ended item from the beginning.
Recording writes AAC in an .m4a file under the app cache. Set
native.app.audio.microphone to the purpose shown in the iOS microphone
prompt and rerun prebuild. For Expo-prebuilt apps, pass the same
audio: { microphone: '...' } option to the vxrn config plugin. Playback
alone needs no microphone permission or purpose string.
For playback while another app is in front, set native.app.audio.background: true
and rerun prebuild. Expo-prebuilt apps use the same audio: { background: true }
option in the vxrn config plugin. This adds audio to UIBackgroundModes; the
Expo plugin preserves other background modes. Audio.play() activates the iOS
playback category before your app enters the background. Apple
requires that category and background mode
for continued playback. Picture in Picture also declares the same mode. Request
microphone access separately if you record. The iOS 27 simulator continued
playing without the mode in our control run, so confirm background behavior on a
device before relying on it in production.
const permission = await One.Audio.requestRecordingPermission()if (permission === 'granted') { const started = await One.Audio.startRecording() await One.Audio.pauseRecording() await One.Audio.resumeRecording() const recorded = await One.Audio.stopRecording() console.log(started.uri, recorded.uri, recorded.durationMs, recorded.size) await One.Audio.play(recorded.uri)}getRecordingPermissionStatus() reads undetermined, granted, or denied
without prompting. getRecordingStatus() reports idle, recording, or
paused, its file URI, and elapsed time. An interrupted recorder reports
paused; call resumeRecording() after the interruption ends. Keep a file you want to
retain by moving it from cache with One.FileSystem.move.
Use watchInterruptions() to react when another audio session interrupts playback
or recording. The callback receives type (began or ended) and shouldResume.
On began, One pauses its current player or recorder. Resume
only after ended, according to your app’s playback policy; shouldResume is
the system’s recommendation, not an automatic action. Call the returned function
when the listener is no longer needed.
If iOS suspends the app, it may deliver a delayed began after the app returns
without a matching ended. Use app foreground state when deciding whether to
offer playback again in that case.
const stopWatching = One.Audio.watchInterruptions((event) => { if (event.type === 'ended' && event.shouldResume) { void One.Audio.resume() }})// call stopWatching() when this screen unmountsAfter play(), call setNowPlayingInfo() to register the current player for
Lock Screen and Control Center media controls. The handlers play, pause, and
seek the current track, and watchRemoteCommands() reports those actions
so your screen can update its state. Set the info again when the title or artwork
changes. Artwork must be an existing local file:// image; download remote
artwork to cache first. stop() or a new play() clears the current info and
remote handlers. clearNowPlayingInfo() removes the metadata and handlers while
the player remains active. Enable the background audio mode described above if
playback must continue while another app is in front.
await One.Audio.play(trackUri)await One.Audio.setNowPlayingInfo({ title: 'Chapter One', artist: 'Example Author', artworkUri: coverFileUri,})const stopWatchingRemote = One.Audio.watchRemoteCommands((event) => { // event.type is play, pause, or seek; seek includes positionMs. void One.Audio.getPlaybackStatus().then((status) => { console.log(event.type, status.state, status.positionMs) })})// call stopWatchingRemote() when this screen unmountsThe iOS 27 simulator verified that metadata setup and cleanup completed through the native bridge. Control Center and Lock Screen stayed empty; the cause is unconfirmed. Confirm the visible controls, tile removal, and remote callbacks on a device before relying on them in production.
Errors expose error.code: E_AUDIO_URI, E_AUDIO_FILE,
E_AUDIO_MANIFEST, E_AUDIO_PERMISSION, E_AUDIO_BUSY, E_AUDIO_STATE,
E_AUDIO_POSITION, E_AUDIO_METADATA, E_AUDIO_ARTWORK, or E_AUDIO_FAILED.
This API is iOS only. Playback and
recording use the app’s shared audio session. Playback switches its category
to playback and can replace another feature’s audio session configuration,
including picture in picture. Stop this audio before starting speech recognition
or another audio feature. Background recording is not configured by this API.
Audio is implemented on iOS and Android. On Android, playback runs over MediaPlayer, recording over MediaRecorder as AAC .m4a under cache, interruptions from audio focus, and now-playing metadata with play/pause/seek commands over MediaSession. Recording needs native.app.audio.microphone; background playback needs native.app.audio.background, which stamps a media-playback foreground service. SSR reports denied recording permission and idle status. Stop and metadata effects do nothing; listeners return a remover that does nothing. Starting playback or recording and requesting a recording file reject with Audio.<verb> needs an iOS or Android build where unimplemented.
On web, HTMLAudioElement provides playback, pause, resume, millisecond seek,
status, and stop. URI inputs use browser HTTP, HTTPS, data, or blob URLs.
Autoplay policy can reject playback without a user gesture. MediaRecorder and
getUserMedia provide microphone permission, recording, pause, resume, and stop.
Playback and recording cannot run together. Recording duration excludes pauses,
and a stopped recording returns its encoded byte length and a blob URL; the
browser chooses the audio codec. Release returned URLs with
URL.revokeObjectURL when finished. Media Session supplies metadata and remote
commands when present. Metadata needs an existing player and decodable artwork.
Remote play, pause, and seek update the player before notifying listeners;
clearing metadata or stopping the player removes its controls. Removing a
listener leaves controls active until the metadata is cleared. Operating-system audio interruptions have no equivalent
browser event, so watchInterruptions retains its inert remover. Missing media
capabilities and invalid operations reject rather than report success.
Edit this page on GitHub.