Rocket.Chat.ReactNative/app/lib/methods/audioPlayer.ts

120 lines
2.8 KiB
TypeScript

import { AVPlaybackStatus, Audio, InterruptionModeAndroid, InterruptionModeIOS } from 'expo-av';
import { Sound } from 'expo-av/build/Audio/Sound';
const AUDIO_MODE = {
allowsRecordingIOS: false,
playsInSilentModeIOS: true,
staysActiveInBackground: true,
shouldDuckAndroid: true,
playThroughEarpieceAndroid: false,
interruptionModeIOS: InterruptionModeIOS.DoNotMix,
interruptionModeAndroid: InterruptionModeAndroid.DoNotMix
};
class AudioPlayer {
private audioQueue: { [uri: string]: Sound };
private audioPlaying: string;
constructor() {
this.audioQueue = {};
this.audioPlaying = '';
}
async loadAudio(uri: string): Promise<Sound> {
if (this.audioQueue[uri]) {
return this.audioQueue[uri];
}
const { sound } = await Audio.Sound.createAsync({ uri }, { androidImplementation: 'MediaPlayer' });
this.audioQueue[uri] = sound;
return sound;
}
onPlaybackStatusUpdate(uri: string, status: AVPlaybackStatus, callback: (status: AVPlaybackStatus) => void) {
if (status) {
callback(status);
this.onEnd(uri, status);
}
}
async onEnd(uri: string, status: AVPlaybackStatus) {
if (status.isLoaded) {
if (status.didJustFinish) {
try {
await this.audioQueue[uri]?.stopAsync();
this.audioPlaying = '';
} catch {
// do nothing
}
}
}
}
setOnPlaybackStatusUpdate(uri: string, callback: (status: AVPlaybackStatus) => void): void {
return this.audioQueue[uri]?.setOnPlaybackStatusUpdate(status => this.onPlaybackStatusUpdate(uri, status, callback));
}
async playAudio(uri: string) {
if (this.audioPlaying) {
await this.pauseAudio(this.audioPlaying);
}
await Audio.setAudioModeAsync(AUDIO_MODE);
await this.audioQueue[uri]?.playAsync();
this.audioPlaying = uri;
}
async pauseAudio(uri: string) {
await this.audioQueue[uri]?.pauseAsync();
this.audioPlaying = '';
}
async pauseCurrentAudio() {
if (this.audioPlaying) {
await this.pauseAudio(this.audioPlaying);
}
}
async setPositionAsync(uri: string, time: number) {
try {
await this.audioQueue[uri]?.setPositionAsync(time);
} catch {
// Do nothing
}
}
async setRateAsync(uri: string, value = 1.0) {
await this.audioQueue[uri].setRateAsync(value, true);
}
async unloadAudio(uri: string) {
await this.audioQueue[uri]?.stopAsync();
await this.audioQueue[uri]?.unloadAsync();
delete this.audioQueue[uri];
this.audioPlaying = '';
}
async unloadCurrentAudio() {
if (this.audioPlaying) {
await this.unloadAudio(this.audioPlaying);
}
}
async unloadAllAudios() {
const audiosLoaded = Object.values(this.audioQueue);
try {
await Promise.all(
audiosLoaded.map(async audio => {
await audio?.stopAsync();
await audio?.unloadAsync();
})
);
} catch {
// Do nothing
}
this.audioPlaying = '';
this.audioQueue = {};
}
}
const audioPlayer = new AudioPlayer();
export default audioPlayer;