Click here to Skip to main content
15,867,330 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
i have been on this problem for a while, haven't figured a way around it, i was actually building this audio player website and everything seems working well except from the audio player itself, after fetching all the resources from my spring boot api, i cant initialize each resource with its specific information (e.g song-duration), when i click the play button on one resource, the slider moves for all resource, same with when i press the stop button.

What I have tried:

This is my component.html...
HTML
<div class="row car-filter">
    <div class="col-lg-3 col-md-4 col-sm-6 mix"
        *ngFor="let beat of appState.appData.data.beats['content']; let i=index">
        <div class="car__item card" style="background-color: black;">
            <div class="card-body" style="padding: 0;" >
                <div class="car__item__pic__slider">
                    <img [src]='clientApiUrl+"/"+beat?.artWork' alt="artwork"
                        style="max-width: 300px; border:0;position: relative; object-fit: cover;" height="169px">
                    <button class="btn shadow-md"
                        style="position:absolute;left:0; border-radius: 100%;top: 25%;width:100%;" (click)="playStream(clientApiUrl+'/'+beat?.uri)" [disabled]="state?.error">
                        
                        ^__i class="fa fa-3x shadow-md fa-pause-circle" *ngIf="(playing$ | async)" style="color: #5f7a61;">
                    </button>
                </div>
                <div style="margin: 0; padding: 4px 8px; color: white;">
                    <div class="song-slider">
                        <input type="range" min="0" [max]="state?.duration" step="0.01" [value]="state?.currentTime" (input)="onSliderChangeEnd($event)" [disabled]="state?.error" class="seek-bar">
                        <div class="d-flex justify-content-between align-items-center">

                            {{ state?.readableCurrentTime }}
                            {{ state?.readableDuration }}
                        </div>
                    </div>
                </div>
                <div class="card-details">
                    <p class="card-text">{{ beat?.name }}</p>
                    <small style="color: silver; font-size: 10px;">{{ beat?.genre.name}}</small>
                      | <small style="color: silver; font-size: 10px;">{{
                        beat?.mood.name}}</small>
                      | <small style="color: silver; font-size: 10px;">{{
                        beat?.beatKey.name}}</small>
                </div>
                <div id="cartbtns">
                    <div class="row">
                        <div class="col-md-6 mp3btn">
                            <button class="btn btn-block" (click)="addToCart(beat, 'MP3')"
                                style="background-color: #5cfe34;border-radius: 0%; position: relative;">
                                 
                                <span
                                    style="color: white; font-weight: 500; font-size: 12px;">${{beat?.priceMp3.toFixed(2)}}</span>
                                <sup style="position:absolute;right:0;top: 6px;">
                                    mp3
                                </sup>
                            </button>
                        </div>
                        <div class="col-md-6 wavbtn">
                            <button class="btn btn-block" (click)="addToCart(beat, 'WAV')"
                                style="background-color: #221F1F;border-radius: 0%;position: relative;">
                                ^__i class="fa fa-shopping-cart"
                                    style="font-size: 15px; color: gray;"> 
                                <span
                                    style="color: white; font-weight: 500; font-size: 12px;">${{beat?.priceWav.toFixed(2)}}</span>
                                <sup style="position:absolute;right:0;top: 6px;">
                                    wav
                                </sup>
                            </button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<div class="row align-items-center justify-content-center mt-2">
    <div class="align-self-baseline pt-2 col-md-12 text-center">
        <a class="btn btn-light btn-xl js-scroll-trigger text-uppercase" href="beats">Check Out
            More</a>
    </div>
</div>

My component.ts file
TypeScript
playing: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
  playing$ = this.playing.asObservable();
  files: Array<any> = [];
  state :StreamState;
  state$ = this.audioService.getState();
  currentTime: BehaviorSubject<string> = new BehaviorSubject<string>('00.00');
  currentTime$ = this.currentTime.asObservable();
constructor(private beatService: BeatServiceService,
    private cartService: CartServiceService,
    private toastrService: ToastrService,
    private router: Router, private audioService: AudioService) {
    this.cartItem = new CartItem();
    this.search = '';
    this.sortBy = "id";
    this.page = 0;
    this.audioService.getState().subscribe(state => {
      this.state = state;
    });
  }

  ngOnInit(): void {
  }

  playStream(url) {
    this.audioService.playStream(url).subscribe(events => {
      this.playing.next(true);
    });
  }
  pause() {
    this.audioService.pause();
  }
  play() {
    this.audioService.play();
  }
  stop() {
    this.audioService.stop();
  }

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

my audio-service.ts...
TypeScript
export class AudioService {

  private date: Date;
  private stop$ = new Subject();
  private audioObj = new Audio();
  beat: Beat;
  private readonly adminApiServerUrl = environment.apiBaseUrl.admin;
  clientApiServerUrl = environment.apiBaseUrl.client;
  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"
  ];
  
  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);
    });
  }

  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);
  }

}
Posted

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900