Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/afkcodes/react-native-audio-pro/llms.txt

Use this file to discover all available pages before exploring further.

React Native Audio Pro uses an event-driven architecture to communicate playback changes from the native layer to JavaScript. Rather than polling for state, your app subscribes to a stream of typed events and reacts as they arrive. Every meaningful change — a state transition, a progress tick, a track change, a remote button press — is delivered as a discrete event with a typed payload. This keeps your UI reactive and decoupled from the internal player implementation.

Adding an Event Listener

Use AudioPro.addEventListener(callback) to subscribe to all player events. It returns a subscription object with a .remove() method that you must call to clean up — typically in the cleanup function of a useEffect.
import { useEffect } from 'react';
import { AudioPro, AudioProEventType } from 'react-native-audio-pro';
import type { AudioProEvent } from 'react-native-audio-pro';

useEffect(() => {
  const subscription = AudioPro.addEventListener((event: AudioProEvent) => {
    switch (event.type) {
      case AudioProEventType.STATE_CHANGED:
        console.log('State:', event.payload?.state);
        break;
      case AudioProEventType.PROGRESS:
        console.log('Position:', event.payload?.position);
        break;
      case AudioProEventType.TRACK_ENDED:
        console.log('Track ended');
        break;
    }
  });

  return () => {
    subscription.remove();
  };
}, []);

Event Types

Every event object has the shape:
interface AudioProEvent {
  type: AudioProEventType;
  track: AudioProTrack | null; // null for REMOTE_NEXT and REMOTE_PREV
  payload?: { /* varies by event type — see below */ };
}

STATE_CHANGED

Emitted whenever the player transitions to a new AudioProState. This is the primary event to observe for updating play/pause buttons and showing loading indicators. Payload:
FieldTypeDescription
stateAudioProStateThe new playback state
positionnumberCurrent position in milliseconds
durationnumberTotal track duration in milliseconds
case AudioProEventType.STATE_CHANGED: {
  const { state, position, duration } = event.payload!;
  console.log(`State changed to ${state} at ${position}ms / ${duration}ms`);
  break;
}

PROGRESS

Emitted periodically during active playback at the progressIntervalMs interval (default 1000 ms). Use this to drive seek bars, elapsed-time labels, and buffering indicators. Payload:
FieldTypeDescription
positionnumberCurrent position in milliseconds
durationnumberTotal track duration in milliseconds
bufferedPositionnumberHow far ahead the buffer has loaded (ms)
case AudioProEventType.PROGRESS: {
  const { position, duration, bufferedPosition } = event.payload!;
  setProgress({ position, duration, bufferedPosition });
  break;
}

TRACK_ENDED

Emitted when the current track plays through to the end. After this event, native automatically pauses, seeks to position 0, and emits STATE_CHANGED: STOPPED. In a queue with multiple items, TRACK_CHANGED will follow as the next track loads. Payload:
FieldTypeDescription
positionnumberFinal position in milliseconds
durationnumberTrack duration in milliseconds

TRACK_CHANGED

Emitted when playback moves to a different track in the queue — either automatically (auto-advance) or by calling seekToMediaItem(), seekToNextMediaItem(), or seekToPreviousMediaItem(). Payload:
FieldTypeDescription
indexnumberZero-based index of the new track
positionnumberStarting position in milliseconds
durationnumberDuration of the new track in milliseconds
case AudioProEventType.TRACK_CHANGED: {
  const { index } = event.payload!;
  const newTrack = event.track;
  console.log(`Now playing track ${index}: ${newTrack?.title}`);
  break;
}

SEEK_COMPLETE

Emitted after a seek operation initiated from TypeScript (seekTo(), seekBy()) completes. Not emitted for seeks triggered by lock screen controls. Payload:
FieldTypeDescription
positionnumberResolved position after the seek
durationnumberTrack duration in milliseconds
triggeredByAudioProTriggerSource'USER' or 'SYSTEM'

PLAYBACK_SPEED_CHANGED

Emitted when the playback rate changes, either from calling AudioPro.setPlaybackSpeed() or from a system-level change. Payload:
FieldTypeDescription
speednumberNew playback rate (0.25 – 2.0)

REMOTE_NEXT

Emitted when the user taps the Next button on the lock screen or a media notification. The native layer does not handle this automatically — your app must respond by calling AudioPro.seekToNextMediaItem() or loading a new track. Payload: none. event.track will be null.
REMOTE_NEXT and REMOTE_PREV are informational only. Native does not advance the track automatically when these events fire. Your app is responsible for handling them by calling AudioPro.seekToNextMediaItem() or AudioPro.seekToPreviousMediaItem() (or your own queue navigation logic).
case AudioProEventType.REMOTE_NEXT:
  AudioPro.seekToNextMediaItem();
  break;

REMOTE_PREV

Emitted when the user taps the Previous button on the lock screen or media notification. Your app must respond by calling AudioPro.seekToPreviousMediaItem() or implementing your own back-navigation logic. Payload: none. event.track will be null.
case AudioProEventType.REMOTE_PREV:
  AudioPro.seekToPreviousMediaItem();
  break;

PLAYBACK_ERROR

Emitted when a playback error occurs. This event may be emitted independently of the ERROR state — a PLAYBACK_ERROR with recoverable: true means the player will retry and remains usable. Only a STATE_CHANGED: ERROR event means the player has entered a terminal failure state. Payload:
FieldTypeDescription
errorstringHuman-readable error message
errorCodeAudioProErrorCode | numberNumeric error code (see AudioProErrorCode enum)
recoverablebooleantrue if the player will retry automatically
causestringOptional underlying exception message
indexnumberQueue index of the track that failed

REPEAT_MODE_CHANGED

Emitted when the repeat mode changes — either from AudioPro.setRepeatMode() or from a user action on the media notification. Payload: none. Use event.track to identify which track was active when the mode changed.

SHUFFLE_MODE_CHANGED

Emitted when shuffle is toggled — either from AudioPro.setShuffleModeEnabled() or from a user action. Payload: none. Use event.track to identify which track was active when shuffle was toggled.

CUSTOM_ACTION

Emitted when the user taps a custom notification button such as Like, Save, Bookmark, Rewind 30, or Forward 30. Your app is responsible for handling the action. Payload:
FieldTypeDescription
actionstringOne of 'LIKE', 'SAVE', 'BOOKMARK', 'REWIND_30', 'FORWARD_30'
case AudioProEventType.CUSTOM_ACTION: {
  const action = event.payload?.action;
  if (action === 'LIKE') toggleLike(event.track?.id);
  if (action === 'FORWARD_30') AudioPro.seekBy(30000);
  if (action === 'REWIND_30') AudioPro.seekBy(-30000);
  break;
}

SLEEP_TIMER_COMPLETE

Emitted when a sleep timer started with AudioPro.startSleepTimer() expires. After this event, the player pauses automatically. Payload:
FieldTypeDescription
timerDurationnumberThe duration (in seconds) the timer was set to

QUEUE_CHANGED

Emitted whenever the queue is modified — items added, removed, moved, or cleared. Payload:
FieldTypeDescription
sizenumberTotal number of tracks in the queue
currentIndexnumberZero-based index of the active track

AUDIO_SESSION_CHANGED

Emitted when the native audio session ID changes. Useful when integrating with audio visualizers or equalizer effects that need the session ID. Payload:
FieldTypeDescription
audioSessionIdnumberThe new audio session ID

Complete Event Listener Example

import { useEffect } from 'react';
import {
  AudioPro,
  AudioProEventType,
  AudioProState,
} from 'react-native-audio-pro';
import type { AudioProEvent } from 'react-native-audio-pro';

function usePlayerEvents() {
  useEffect(() => {
    const subscription = AudioPro.addEventListener((event: AudioProEvent) => {
      switch (event.type) {
        case AudioProEventType.STATE_CHANGED:
          console.log('[Player] State:', event.payload?.state);
          break;

        case AudioProEventType.PROGRESS:
          // Update seek bar — fires at progressIntervalMs
          break;

        case AudioProEventType.TRACK_ENDED:
          console.log('[Player] Track ended');
          break;

        case AudioProEventType.TRACK_CHANGED:
          console.log('[Player] Track changed to index', event.payload?.index);
          break;

        case AudioProEventType.SEEK_COMPLETE:
          console.log('[Player] Seek complete at', event.payload?.position);
          break;

        case AudioProEventType.REMOTE_NEXT:
          // App must handle — native does not advance automatically
          AudioPro.seekToNextMediaItem();
          break;

        case AudioProEventType.REMOTE_PREV:
          AudioPro.seekToPreviousMediaItem();
          break;

        case AudioProEventType.PLAYBACK_ERROR: {
          const { error, errorCode, recoverable } = event.payload!;
          console.warn(`[Player] Error (code ${errorCode}): ${error}`, { recoverable });
          break;
        }

        case AudioProEventType.CUSTOM_ACTION: {
          const action = event.payload?.action;
          if (action === 'LIKE') console.log('[Player] Like pressed');
          if (action === 'FORWARD_30') AudioPro.seekBy(30000);
          if (action === 'REWIND_30') AudioPro.seekBy(-30000);
          break;
        }

        case AudioProEventType.QUEUE_CHANGED:
          console.log('[Player] Queue size:', event.payload?.size);
          break;

        case AudioProEventType.AUDIO_SESSION_CHANGED:
          console.log('[Player] Audio session ID:', event.payload?.audioSessionId);
          break;
      }
    });

    return () => {
      subscription.remove();
    };
  }, []);
}

Ambient Events

Ambient audio (played via AudioPro.ambientPlay()) uses a separate event channel. Subscribe with AudioPro.addAmbientListener():
import { useEffect } from 'react';
import { AudioPro, AudioProAmbientEventType } from 'react-native-audio-pro';
import type { AudioProAmbientEvent } from 'react-native-audio-pro';

useEffect(() => {
  const subscription = AudioPro.addAmbientListener((event: AudioProAmbientEvent) => {
    switch (event.type) {
      case AudioProAmbientEventType.AMBIENT_TRACK_ENDED:
        console.log('[Ambient] Track ended');
        break;

      case AudioProAmbientEventType.AMBIENT_ERROR:
        console.error('[Ambient] Error:', event.payload?.error);
        break;
    }
  });

  return () => {
    subscription.remove();
  };
}, []);
Ambient event types:
EventDescription
AMBIENT_TRACK_ENDEDThe ambient audio track finished playing (or loop ended)
AMBIENT_ERRORAn error occurred in the ambient audio player
Ambient events are completely separate from main player events. Adding a listener with addEventListener will not receive ambient events, and vice versa.

Build docs developers (and LLMs) love