annotate src/app/services/audio-player/audio-player.service.ts @ 57:6ece58c96868

Guard against playing when the HTMLMediaElement is not ready.
author Lucas Thompson <dev@lucas.im>
date Thu, 08 Dec 2016 16:23:22 +0000
parents ec38b85be3ac
children 1bd1a44f5dd3
rev   line source
dev@37 1 import {Injectable, Inject} from '@angular/core';
dev@52 2 import {Subject} from "rxjs/Subject";
dev@52 3 import {Observable} from "rxjs";
dev@37 4
dev@37 5 @Injectable()
dev@37 6 export class AudioPlayerService {
dev@37 7
dev@52 8 private currentObjectUrl: string;
dev@52 9 private playingStateChange: Subject<boolean>;
dev@52 10 playingStateChange$: Observable<boolean>;
dev@52 11 private seeked: Subject<number>;
dev@52 12 seeked$: Observable<number>;
dev@52 13
dev@37 14 constructor(@Inject(HTMLAudioElement) private audioElement: HTMLAudioElement /* TODO probably shouldn't play audio this way */,
dev@37 15 @Inject('AudioContext') private audioContext: AudioContext) {
dev@52 16 this.currentObjectUrl = '';
dev@52 17 this.playingStateChange = new Subject<boolean>();
dev@52 18 this.playingStateChange$ = this.playingStateChange.asObservable();
dev@52 19 this.seeked = new Subject<number>();
dev@52 20 this.seeked$ = this.seeked.asObservable();
dev@52 21 this.audioElement.addEventListener('ended', () => {
dev@52 22 this.playingStateChange.next(this.isPlaying());
dev@52 23 });
dev@52 24 this.audioElement.addEventListener('seeked', () => {
dev@52 25 this.seeked.next(this.audioElement.currentTime);
dev@52 26 });
dev@37 27 }
dev@37 28
dev@37 29 getCurrentTime(): number {
dev@37 30 return this.audioElement.currentTime;
dev@37 31 }
dev@37 32
dev@37 33 isPlaying(): boolean {
dev@37 34 return !this.audioElement.paused;
dev@37 35 }
dev@37 36
dev@37 37 decodeAudioData(buffer: ArrayBuffer): Promise<AudioBuffer> {
dev@37 38 return new Promise((res, rej) => this.audioContext.decodeAudioData(buffer, res, rej));
dev@37 39 }
dev@37 40
dev@37 41 loadAudioFromUrl(url: string): void {
dev@52 42 if (this.currentObjectUrl)
dev@52 43 URL.revokeObjectURL(this.currentObjectUrl);
dev@52 44 this.currentObjectUrl = url;
dev@37 45 this.audioElement.pause();
dev@37 46 this.audioElement.src = url;
dev@37 47 }
dev@37 48
dev@37 49 togglePlaying(): void {
dev@57 50 if (this.audioElement.readyState >= 2) {
dev@57 51 this.isPlaying() ? this.audioElement.pause() : this.audioElement.play();
dev@57 52 this.playingStateChange.next(this.isPlaying());
dev@57 53 }
dev@37 54 }
dev@37 55
dev@37 56 setVolume(value: number): void {
dev@37 57 this.audioElement.volume = value; // TODO check bounds?
dev@37 58 }
dev@37 59
dev@37 60 seekBy(seconds: number): void {
dev@37 61 // TODO some kind of error handling?
dev@37 62 this.audioElement.currentTime += seconds;
dev@37 63 }
dev@37 64
dev@37 65 seekToStart(): void {
dev@37 66 this.audioElement.currentTime = 0;
dev@37 67 }
dev@37 68
dev@37 69 seekToEnd(): void {
dev@37 70 this.audioElement.currentTime = this.getDuration();
dev@37 71 }
dev@37 72
dev@37 73 getDuration(): number {
dev@37 74 return this.audioElement.duration;
dev@37 75 }
dev@37 76 }