Audio Playback

As of stream-chat-react-native@8.11.0, you can build audio players using:

  • AudioPlayerProvider React component
  • useAudioPlayerControl hook
  • useActiveAudioPlayer hook

Best Practices

  • Wrap audio UI in AudioPlayerProvider to keep playback stable in lists.
  • Use useStateStore selectors to avoid re-rendering on unrelated audio state.
  • Prefer single-playback mode unless your UX clearly needs concurrency.
  • Reuse the shared player pool instead of creating per-row players.
  • Test playback when items unmount to confirm continuity.

The old useAudioPlayer hook is deprecated; most functionality is now in AudioPlayer.

Before stream-chat-react-native@8.10.0, audio used useAudioController and lived inside the UI component, which broke playback in virtualized lists. useAudioPlayerControl uses a central pool, so playback continues even if the message component unmounts.

Audio playback is controlled via AudioPlayerProvider and useAudioPlayerControl. The provider maintains a pool of AudioPlayer instances; access them with useAudioPlayerControl.

By default, Channel renders AudioPlayerProvider, so its children share a single pool.

Audio Playback mode

Choose between single or concurrent playback:

Single-playback mode: only one audio at a time (default in Channel). Concurrent-playback mode: multiple audios can play at once.

Enable concurrent playback by setting allowConcurrentPlayback in AudioPlayerProvider’s value.

Building Audio Components

To build audio components outside Channel:

  1. Have a top-level component render AudioPlayerProvider
const TopLevelComponent = ({ children }) => {
  return (
    <AudioPlayerProvider value={{ allowConcurrentPlayback: false }}>
      {children}
    </AudioPlayerProvider>
  );
};
  1. Render the audio player in a child component
import {
  AudioPlayerState,
  useAudioPlayerControl,
  useStateStore,
} from "stream-chat-react-native";

const audioPlayerSelector = (state: AudioPlayerState) => ({
  currentPlaybackRate: state.currentPlaybackRate,
  duration: state.duration,
  isPlaying: state.isPlaying,
  position: state.position,
  progress: state.progress,
});

const AudioPlayerComponent = () => {
  const audioPlayer = useAudioPlayerControl({
    duration: item.duration ?? 0,
    mimeType: item.mime_type ?? "",
    requester: "audio-player-component",
    type: isVoiceRecording ? "voiceRecording" : "audio",
    uri: item.asset_url ?? "",
  });
  // You can use the following state to build your own audio player UI
  const { duration, isPlaying, position, progress, currentPlaybackRate } =
    useStateStore(audioPlayer.state, audioPlayerSelector);
};
  1. Get the active audio player

In single-playback mode, a global player UI can show the active audio even if the user scrolls away.

Note: This is relevant only for single-playback mode.

import { useActiveAudioPlayer } from "stream-chat-react-native";

const activeAudioPlayer = useActiveAudioPlayer();

Audio Player API

Use the following AudioPlayer methods to build a UI:

Getters

MethodDescription
isPlayingGet the current playing state of the audio, whether it is playing or not.
durationGet the duration of the audio in milliseconds.
progressGet progress as a percentage (0-1).
positionGet the current position of the audio in milliseconds.
currentPlaybackRateGet the current playback rate.
playbackRatesGet available playback rates.
idGet the audio player ID.

Setters

MethodDescription
durationSet the duration of the audio in milliseconds.
positionSet the position of the audio in milliseconds and update the progress.
progressSet progress (0-1) and update the position.
isPlayingSet the playing state of the audio.

Methods

play - plays the audio.

TypeDescription
() => voidPlays the audio.
audioPlayer.play();

pause - pauses the audio.

TypeDescription
() => voidPauses the audio.
audioPlayer.pause();

toggle - toggles the playing state of the audio.

TypeDescription
() => voidToggles the playing state of the audio.
audioPlayer.toggle();

seek - seeks to a specific position in the audio.

TypeDescription
(positionInSeconds: number) => Promise<void>Seeks to a specific position in the audio.
await audioPlayer.seek(positionInSeconds);

stop - stops the audio.

TypeDescription
() => Promise<void>Stops the audio.
await audioPlayer.stop();

changePlaybackRate - changes the playback rate of the audio.

TypeDescription
() => Promise<void>Changes the playback rate of the audio.
await audioPlayer.changePlaybackRate(playbackRate);

initPlayer - initializes the audio player using the provided URL or provided player reference.

TypeDescription
({url?: string, playerRef?: React.RefObject<AudioPlayer>}) => Promise<void>Initializes the audio player using the provided URL or provided player reference. For Expo, we pass the URL while for audio playing using react-native-video, we pass the player reference.
await audioPlayer.initPlayer({ url: "https://example.com/audio.mp3" });