dev@37: import {Injectable, Inject} from '@angular/core'; dev@52: import {Subject} from "rxjs/Subject"; dev@52: import {Observable} from "rxjs"; dev@37: dev@37: @Injectable() dev@37: export class AudioPlayerService { dev@37: dev@52: private currentObjectUrl: string; dev@52: private playingStateChange: Subject; dev@52: playingStateChange$: Observable; dev@52: private seeked: Subject; dev@52: seeked$: Observable; dev@52: dev@37: constructor(@Inject(HTMLAudioElement) private audioElement: HTMLAudioElement /* TODO probably shouldn't play audio this way */, dev@37: @Inject('AudioContext') private audioContext: AudioContext) { dev@52: this.currentObjectUrl = ''; dev@52: this.playingStateChange = new Subject(); dev@52: this.playingStateChange$ = this.playingStateChange.asObservable(); dev@52: this.seeked = new Subject(); dev@52: this.seeked$ = this.seeked.asObservable(); dev@52: this.audioElement.addEventListener('ended', () => { dev@52: this.playingStateChange.next(this.isPlaying()); dev@52: }); dev@52: this.audioElement.addEventListener('seeked', () => { dev@52: this.seeked.next(this.audioElement.currentTime); dev@52: }); dev@37: } dev@37: dev@37: getCurrentTime(): number { dev@37: return this.audioElement.currentTime; dev@37: } dev@37: dev@37: isPlaying(): boolean { dev@37: return !this.audioElement.paused; dev@37: } dev@37: dev@37: decodeAudioData(buffer: ArrayBuffer): Promise { dev@37: return new Promise((res, rej) => this.audioContext.decodeAudioData(buffer, res, rej)); dev@37: } dev@37: dev@37: loadAudioFromUrl(url: string): void { dev@52: if (this.currentObjectUrl) dev@52: URL.revokeObjectURL(this.currentObjectUrl); dev@52: this.currentObjectUrl = url; dev@37: this.audioElement.pause(); dev@37: this.audioElement.src = url; dev@37: } dev@37: dev@37: togglePlaying(): void { dev@37: this.isPlaying() ? this.audioElement.pause() : this.audioElement.play(); dev@52: this.playingStateChange.next(this.isPlaying()); dev@37: } dev@37: dev@37: setVolume(value: number): void { dev@37: this.audioElement.volume = value; // TODO check bounds? dev@37: } dev@37: dev@37: seekBy(seconds: number): void { dev@37: // TODO some kind of error handling? dev@37: this.audioElement.currentTime += seconds; dev@37: } dev@37: dev@37: seekToStart(): void { dev@37: this.audioElement.currentTime = 0; dev@37: } dev@37: dev@37: seekToEnd(): void { dev@37: this.audioElement.currentTime = this.getDuration(); dev@37: } dev@37: dev@37: getDuration(): number { dev@37: return this.audioElement.duration; dev@37: } dev@37: }