'How do i set audio states for a custom multi-player in my web app

am having some issues developing a custom streaming multi audio player web app with angular... First of all, when the page gets loaded, i cant set the audio information like the current time and the audio duration (both for the time in text and the slider), the first screenshot explains this... Secondly, as it is a multi audio player, there is a list of audios on the page, when the click the play button on one audio, it shows the pause button for all the audio players, the slider moves for all audio players and it reads the current time for the audio i am playing in all the audio... Below is the snapshot of the first and second sceneraios i have written, and this is the code for my component file and service file... I will appreciate any assistance i can get... Thanks enter image description here

enter image description here

This is my component.html file

<div *ngFor="let beat of appState.appData.data.beats['content']">
     <div class="card">
        <div class="card-body">
            <div><img [src]='beat?.artWork'>
                <button class="btn" (click)="playStream(beat?.uri)">
                    <i class="fa fa-3x fa-play-circle" *ngIf="!(playing$ | async)"></i>
                    <i class="fa fa-3x fa-pause-circle" *ngIf="(playing$ | async)"></i>
                </button>
            </div>
            <div class="song-slider">
                <input type="range" min="0" [max]="state?.duration" step="0.01" [value]="state?.currentTime" (input)="onSliderChangeEnd($event)" [disabled]="state?.error">
                <div class="d-flex justify-content-between align-items-center">
                <span class="current-time">{{ state?.readableCurrentTime }}</span>
                <span class="song-duration">{{ state?.readableDuration }}</span>
                </div>
            </div>
    </div>
    </div>

My component.ts file...

state :StreamState;
appState$: Observable<AppState<CustomResponse>>;
constructor(private audioService: AudioService) {
    this.audioService.getState().subscribe(state => {
      this.state = state;
    });
  }
playStream(url) {
    this.audioService.playStream(url).subscribe(events => {
      this.playing.next(true);
    });
  }
  play() {
    this.audioService.play();
  }

  onSliderChangeEnd(change) {
    this.audioService.seekTo(change.value);
  }

My StreamState.ts file..

export class StreamState {
    playing: boolean;
    readableCurrentTime: string;
    readableDuration: string;
    duration: number | undefined;
    currentTime: number | undefined;
    canplay: boolean;
    error: boolean;
}

And lastly my Audio-Service.ts file...

private state: StreamState = {
    playing: false,
    readableCurrentTime: '',
    readableDuration: '',
    duration: undefined,
    currentTime: undefined,
    canplay: false,
    error: false,
  };

  stateChange: BehaviorSubject<StreamState> = new BehaviorSubject(this.state);

  private resetState() {
    this.state = {
      playing: false,
      readableCurrentTime: '',
      readableDuration: '',
      duration: undefined,
      currentTime: undefined,
      canplay: false,
      error: false
    };
  }

  getState(): Observable<StreamState> {
    return this.stateChange.asObservable();
  }

  private updateStateEvents(event: Event): void {
    switch (event.type) {
      case "canplay":
        this.state.duration = this.audioObj.duration;
        this.state.readableDuration = this.formatTime(this.state.duration);
        this.state.canplay = true;
        break;
      case "playing":
        this.state.playing = true;
        break;
      case "pause":
        this.state.playing = false;
        break;
      case "timeupdate":
        this.state.currentTime = this.audioObj.currentTime;
        this.state.readableCurrentTime = this.formatTime(
          this.state.currentTime
        );
        break;
      case "error":
        this.resetState();
        this.state.error = true;
        break;
    }
    this.stateChange.next(this.state);
  }

  constructor() { }

  audioEvents = [
    "ended",
    "error",
    "play",
    "playing",
    "pause",
    "timeupdate",
    "canplay",
    "loadedmetadata",
    "loadstart"
  ];
playStream(url) {
    return this.streamObservable(url).pipe(takeUntil(this.stop$));
  }

  play() {
    this.audioObj.play();
  }

  pause() {
    this.audioObj.pause();
  }

  stop() {
    this.stop$.next();
  }

  seekTo(seconds) {
    this.audioObj.currentTime = seconds;
  }

  formatTime(time: number, format: string = "HH:mm:ss") {
    const momentTime = time * 1000;
    return moment.utc(momentTime).format(format);
  }
private streamObservable(url: string) {
    return new Observable(observer => {
      // Play audio
      this.audioObj.src = url;
      this.audioObj.load();
      this.audioObj.play();

      const handler = (event: Event) => {
        this.updateStateEvents(event);
        observer.next(event);
      };

      this.addEvents(this.audioObj, this.audioEvents, handler);
      return () => {
        // Stop Playing
        this.audioObj.pause();
        this.audioObj.currentTime = 0;
        // remove event listeners
        this.removeEvents(this.audioObj, this.audioEvents, handler);
        // reset state
        this.resetState();
      };
    });
  }

  private addEvents(obj, events, handler) {
    events.forEach(event => {
      obj.addEventListener(event, handler);
    });
  }

  private removeEvents(obj, events, handler) {
    events.forEach(event => {
      obj.removeEventListener(event, handler);
    });
  }


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source