react-native-track-player
Version:
A fully fledged audio module created for music apps
177 lines (150 loc) • 5.59 kB
text/typescript
import { DeviceEventEmitter } from 'react-native';
import { Event, PlaybackState, State } from '../src';
import type { Track, UpdateOptions } from '../src';
import { PlaylistPlayer, RepeatMode } from './TrackPlayer';
import { SetupNotCalledError } from './TrackPlayer/SetupNotCalledError';
export class TrackPlayerModule extends PlaylistPlayer {
protected emitter = DeviceEventEmitter;
protected progressUpdateEventInterval: any;
// Capabilities
public readonly CAPABILITY_PLAY = 'CAPABILITY_PLAY';
public readonly CAPABILITY_PLAY_FROM_ID = 'CAPABILITY_PLAY_FROM_ID';
public readonly CAPABILITY_PLAY_FROM_SEARCH = 'CAPABILITY_PLAY_FROM_SEARCH';
public readonly CAPABILITY_PAUSE = 'CAPABILITY_PAUSE';
public readonly CAPABILITY_STOP = 'CAPABILITY_STOP';
public readonly CAPABILITY_SEEK_TO = 'CAPABILITY_SEEK_TO';
public readonly CAPABILITY_SKIP = 'CAPABILITY_SKIP';
public readonly CAPABILITY_SKIP_TO_NEXT = 'CAPABILITY_SKIP_TO_NEXT';
public readonly CAPABILITY_SKIP_TO_PREVIOUS = 'CAPABILITY_SKIP_TO_PREVIOUS';
public readonly CAPABILITY_JUMP_FORWARD = 'CAPABILITY_JUMP_FORWARD';
public readonly CAPABILITY_JUMP_BACKWARD = 'CAPABILITY_JUMP_BACKWARD';
public readonly CAPABILITY_SET_RATING = 'CAPABILITY_SET_RATING';
public readonly CAPABILITY_LIKE = 'CAPABILITY_LIKE';
public readonly CAPABILITY_DISLIKE = 'CAPABILITY_DISLIKE';
public readonly CAPABILITY_BOOKMARK = 'CAPABILITY_BOOKMARK';
// States
public readonly STATE_NONE = 'STATE_NONE';
public readonly STATE_READY = 'STATE_READY';
public readonly STATE_PLAYING = 'STATE_PLAYING';
public readonly STATE_PAUSED = 'STATE_PAUSED';
public readonly STATE_STOPPED = 'STATE_STOPPED';
public readonly STATE_BUFFERING = 'STATE_BUFFERING';
public readonly STATE_CONNECTING = 'STATE_CONNECTING';
// Rating Types
public readonly RATING_HEART = 'RATING_HEART';
public readonly RATING_THUMBS_UP_DOWN = 'RATING_THUMBS_UP_DOWN';
public readonly RATING_3_STARS = 'RATING_3_STARS';
public readonly RATING_4_STARS = 'RATING_4_STARS';
public readonly RATING_5_STARS = 'RATING_5_STARS';
public readonly RATING_PERCENTAGE = 'RATING_PERCENTAGE';
// Repeat Modes
public readonly REPEAT_OFF = RepeatMode.Off;
public readonly REPEAT_TRACK = RepeatMode.Track;
public readonly REPEAT_QUEUE = RepeatMode.Playlist;
// Pitch Algorithms
public readonly PITCH_ALGORITHM_LINEAR = 'PITCH_ALGORITHM_LINEAR';
public readonly PITCH_ALGORITHM_MUSIC = 'PITCH_ALGORITHM_MUSIC';
public readonly PITCH_ALGORITHM_VOICE = 'PITCH_ALGORITHM_VOICE';
// observe and emit state changes
public get state(): PlaybackState {
return super.state;
}
public set state(newState: PlaybackState) {
super.state = newState;
this.emitter.emit(Event.PlaybackState, newState);
}
public async updateOptions(options: UpdateOptions) {
this.setupProgressUpdates(options.progressUpdateEventInterval);
}
protected setupProgressUpdates(interval?: number) {
// clear and reset interval
this.clearUpdateEventInterval();
if (interval) {
this.clearUpdateEventInterval()
this.progressUpdateEventInterval = setInterval(
async () => {
if (this.state.state === State.Playing) {
const progress = await this.getProgress()
this.emitter.emit(Event.PlaybackProgressUpdated, {
...progress,
track: this.currentIndex,
});
}
},
interval * 1000,
)
}
}
protected clearUpdateEventInterval() {
if (this.progressUpdateEventInterval) {
clearInterval(this.progressUpdateEventInterval);
}
}
protected async onTrackEnded() {
const position = this.element!.currentTime;
await super.onTrackEnded();
this.emitter.emit(Event.PlaybackTrackChanged, {
track: this.lastIndex,
position,
nextTrack: this.currentIndex,
});
}
protected async onPlaylistEnded() {
await super.onPlaylistEnded();
this.emitter.emit(Event.PlaybackQueueEnded, {
track: this.currentIndex,
position: this.element!.currentTime,
});
}
public get playWhenReady(): boolean {
return super.playWhenReady;
}
public set playWhenReady(pwr: boolean) {
const didChange = pwr !== this._playWhenReady;
super.playWhenReady = pwr;
if (didChange) {
this.emitter.emit(Event.PlaybackPlayWhenReadyChanged, { playWhenReady: this._playWhenReady });
}
}
public getPlayWhenReady(): boolean {
return this.playWhenReady;
}
public setPlayWhenReady(pwr: boolean): boolean {
this.playWhenReady = pwr;
return this.playWhenReady;
}
public async load(track: Track) {
if (!this.element) throw new SetupNotCalledError();
const lastTrack = this.current;
const lastPosition = this.element.currentTime;
await super.load(track);
this.emitter.emit(Event.PlaybackActiveTrackChanged, {
lastTrack,
lastPosition,
lastIndex: this.lastIndex,
index: this.currentIndex,
track,
});
}
public getQueue(): Track[] {
return this.playlist;
}
public getActiveTrack(): Track | undefined {
return this.current;
}
public getActiveTrackIndex(): number | undefined {
// per the existing spec, this should throw if setup hasn't been called
if (!this.element || !this.player) throw new SetupNotCalledError();
return this.currentIndex;
}
/**
* @deprecated
* @returns State
*/
public getState(): State {
return this.state.state;
}
public getPlaybackState(): PlaybackState {
return this.state;
}
};