Audio Playback

As of the version stream-chat-react-native@8.9.0 it is possible to build audio player components with the following combo of components:

  • AudioPlayerProvider React component
  • useAudioPlayerControl hook
  • useActiveAudioPlayer hook

The previous useAudioPlayer hook is deprecated and will be removed in the future as most of the functionality is now managed in the AudioPlayer class.

Until the version stream-chat-react-native@8.8.1, the audio was played using useAudioController hook. The audio player was handled directly in the player UI component. That was limiting in scenarios like audio playback in Virtualized FlatList/FlashList. During the scroll, the Message component with audio element was removed and thus the playback stopped. This is not the case of useAudioPlayerControl hook which reaches into a central pool of audio players.

All the audio playback is controlled using the combination of AudioPlayerProvider React component wrapper and useAudioPlayerControl hook. Component AudioPlayerProvider is necessary to initiate and maintain a pool of AudioPlayer instances (this holds the audio player reference). The pool is not publicly accessible. We access individual AudioPlayer instances using useAudioPlayerControl hook instead.

By default, the SDK renders AudioPlayerProvider component inside the Channel component. All the Channel component’s children can thus reach to one shared pool of AudioPlayer instances using useAudioPlayerControl hook.

Audio Playback mode

We can decide, whether we want to allow only a single or multiple audios to be played at a time.

Single-playback mode - only a single audio can be reproduced at a time (default in Channel component). Concurrent-playback mode - multiple audios can be reproduced at the same time

It is possible to change the default (false), by setting allowConcurrentPlayback param in the value prop of AudioPlayerProvider component.

Building Audio Components

If we wanted to build a React component separated from Channel and needed to play audio inside this component, we need to perform the following steps:

  1. Have a top-level component render AudioPlayerProvider
const TopLevelComponent = ({ children }) => {
  return (
    <AudioPlayerProvider value={{ allowConcurrentPlayback: false }}>
      {children}
    </AudioPlayerProvider>
  );
};
  1. Have a child component that renders the audio player
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

When operating in single-playback mode it can make sense to have a global audio player UI that displays the playback of active audio player. For example if a user starts the playback from a message’s audio widget and scrolls away, we may want to show the global audio player UI from which the playback could still be controlled without having to return to the original message

Note: This is relavant when you are playing only one audio at a time.

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

const activeAudioPlayer = useActiveAudioPlayer();

Audio Player API

These are the AudioPlayer methods needed to create a audio player UI widget:

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 the progress of the audio in percentage(0-1).
positionGet the current position of the audio in milliseconds.
currentPlaybackRateGet the current playback rate of the audio
playbackRatesGet the available playback rates of the audio
idGet the id of the audio player

Setters

MethodDescription
durationSet the duration of the audio in milliseconds.
positionSet the position of the audio in milliseconds and update the progress.
progressSet the progress of the audio in percentage(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: number);

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: number);

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" });
© Getstream.io, Inc. All Rights Reserved.