This document defines the contract between react-native-audio-pro's native media session behavior, playback lifecycle states, and the TypeScript-facing API/events.
| Method | Description | State Transitions | Emits |
|---|---|---|---|
configure() |
Set playback behavior (e.g., speech/music mode, debug) | None | None |
play(track, opts) |
Load & start track | → LOADING → PLAYING or → LOADING → PAUSED |
STATE_CHANGED: LOADING, then PLAYING or PAUSED |
pause() |
Pause playback | → PAUSED |
STATE_CHANGED: PAUSED |
resume() |
Resume playback | → PLAYING |
STATE_CHANGED: PLAYING |
stop() |
Stop playback, reset position | → STOPPED |
STATE_CHANGED: STOPPED |
clear() |
Full teardown | → IDLE |
STATE_CHANGED: IDLE |
onError() |
Critical error | → ERROR |
STATE_CHANGED: ERROR, PLAYBACK_ERROR |
seekTo() / seekForward() / seekBack() |
Seek to new position (via TypeScript) | No state change | SEEK_COMPLETE |
setPlaybackSpeed() |
Adjust speed | No state change | PLAYBACK_SPEED_CHANGED |
⚠️ All state transitions are emitted by native code only. The TypeScript layer must never infer or emit state. Native is the single source of truth for the current playback state.
| State | Emitted When | Represents |
|---|---|---|
IDLE |
After clear() |
No track loaded, session removed |
STOPPED |
After stop() or TRACK_ENDED |
Track loaded, session active, position reset to 0 (duration remains the track’s duration) |
LOADING |
After play() or mid-track buffer |
Track fetching/buffering |
PLAYING |
Playback is active | Audio playing, rate > 0 |
PAUSED |
After pause() or play({ autoPlay: false }) |
Audio paused, track retained |
ERROR |
After onError() |
Failure encountered, all cleared |
IDLEis never emitted on startup — it is assumed as the implicit default.clear()emitsSTATE_CHANGED: IDLE.onError()emitsSTATE_CHANGED: ERROR, and clears the player state just likeclear().STOPPEDassumes position is reset to 0 and rate is 0, but track and media session remain visible.
| Event | Triggered By | Causes State Change? | Notes |
|---|---|---|---|
STATE_CHANGED |
Any state transition | ✅ | Emits state, position, duration |
PROGRESS |
Every second during playback | ❌ | Includes updated position, duration |
TRACK_ENDED |
When track completes | ✅ → STOPPED |
Native must pause, seek to 0, then emit STATE_CHANGED: STOPPED. JS must not do this manually. |
SEEK_COMPLETE |
After a TypeScript-initiated seek completes | ❌ | Not emitted for native lock screen seeks |
PLAYBACK_SPEED_CHANGED |
On speed change | ❌ | Emits new rate |
REMOTE_NEXT / REMOTE_PREV |
Lock screen buttons | ❌ | Developer's app must handle and call play() |
PLAYBACK_ERROR |
On non-fatal error | ❌ | Separate from STATE_CHANGED: ERROR; may be emitted independently |
⚠️ Playback errors and playback state are separate.PLAYBACK_ERRORdoes not imply anERRORstate. Native must explicitly emitSTATE_CHANGED: ERRORif the player enters an unrecoverable failure.
If the player is buffering mid-playback (e.g. network stalls):
- Emit
STATE_CHANGED: LOADING - Do not emit
PAUSEDunless:- The user explicitly paused playback, or
- Buffering fails entirely and triggers
onError()
Native must distinguish between automatic buffering and user-intended pause.
| Control | Who Handles It | Emits Remote Event to JS? | Emits State Event? | Resulting State / Behavior |
|---|---|---|---|---|
| Native (automatic) | ❌ | ✅ STATE_CHANGED: PLAYING |
Resumes playback | |
| ⏸ Pause | Native (automatic) | ❌ | ✅ STATE_CHANGED: PAUSED |
Pauses playback |
| 📍 Seek Bar | Native (automatic) | ❌ | ✅ STATE_CHANGED: PLAYING/PAUSED in next PROGRESS |
Seek updates position; no SEEK_COMPLETE emitted |
| ⏭ Next Track | JS (developer's app) | ✅ REMOTE_NEXT |
❌ | App must call play(nextTrack) |
| ⏮ Previous Track | JS (developer's app) | ✅ REMOTE_PREV |
❌ | App must call play(prevTrack) |
⚠️ Native emits all state changes from lock screen interactions. TypeScript does not emit state — it only receivesSTATE_CHANGEDorREMOTE_*where applicable.
- Native (Swift/Kotlin) is the sole authority on current playback state.
- TypeScript receives state via
STATE_CHANGED— it does not determine state. PLAYBACK_ERRORis not linked toSTATE_CHANGED: ERROR. They may occur together or separately.- When a track ends, native is responsible for pausing, seeking to 0, and transitioning to
STOPPED. - Developers and agents working on this code must enforce strict alignment with this contract. Do not improvise or assume implicit behaviors — follow explicit transitions only.