UNPKG

react-native-audio-api

Version:

react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification

114 lines (93 loc) 2.95 kB
import { AudioEventEmitter } from '../events'; import type { EventEmptyType } from '../events/types'; import type { IAudioFileSourceNode, IAudioScheduledSourceNode, } from '../jsi-interfaces'; import AudioScheduledSourceNode from '../core/AudioScheduledSourceNode'; type AttachFileSourceOptions = { loop: boolean; onEnded: () => void; }; const MAX_PLAYBACK_RATE = 4; export class AudioFileSourceNode extends AudioScheduledSourceNode { private readonly emitter = new AudioEventEmitter( globalThis.AudioEventEmitter ); attach(options: AttachFileSourceOptions): { duration: number } { this.resetNodeAndSubscriptions(); const sub = this.emitter.addAudioEventListener( 'ended', (_event: EventEmptyType) => { options.onEnded(); } ); (this.node as IAudioFileSourceNode).onEnded = sub.subscriptionId; return { duration: (this.node as IAudioFileSourceNode).duration, }; } dispose(): void { this.resetNodeAndSubscriptions(); } play(): void { (this.node as IAudioScheduledSourceNode).start(this.context.currentTime); } pause(): void { (this.node as IAudioFileSourceNode).pause(); } seekToTime(seconds: number): void { (this.node as IAudioFileSourceNode).seekToTime(seconds); } setVolume(value: number): void { (this.node as IAudioFileSourceNode).volume = value; } setLoop(value: boolean): void { (this.node as IAudioFileSourceNode).loop = value; } setPlaybackRate(value: number): void { if (!Number.isFinite(value) || value < 0 || value > MAX_PLAYBACK_RATE) { throw new Error( `AudioFileSourceNode: playbackRate must be a non-negative number, less than or equal to ${MAX_PLAYBACK_RATE}.` ); } (this.node as IAudioFileSourceNode).playbackRate = value; } setPreservesPitch(value: boolean): void { (this.node as IAudioFileSourceNode).preservesPitch = value; } getFileSourceNode(): IAudioFileSourceNode { return this.node as IAudioFileSourceNode; } getDuration(): number { return (this.node as IAudioFileSourceNode).duration; } getCurrentTime(): number { return (this.node as IAudioFileSourceNode).currentTime; } startPositionTracking(onTime: (seconds: number) => void): void { if (!this.node) { return; } this.stopPositionTracking(); const sub = this.emitter.addAudioEventListener( 'positionChanged', (event) => { onTime(event.value); } ); (this.node as IAudioFileSourceNode).onPositionChanged = sub.subscriptionId; } stopPositionTracking(): void { if (this.node) { (this.node as IAudioFileSourceNode).onPositionChanged = '0'; } } private resetNodeAndSubscriptions(): void { if (this.node) { (this.node as IAudioFileSourceNode).onPositionChanged = '0'; (this.node as IAudioFileSourceNode).onEnded = '0'; this.node.disconnect(undefined); } } }