skip to Main Content

I’m having some trouble loading an audio file in WAV format returned from the backend as a Blob in Angular.

I have in my services the following:

getFileBlob(uniformName: string, path: string) {
    const currentPath = path.replace(/\/g, '/');
    return this.http.get(`${environment.api_url}/content/v1.4/${currentPath}/${uniformName}/_blob`, { responseType: 'blob' });
  }

Where in my Angular component, I have the following:

this.dService.getFileBlob().subscribe((response: Blob) => {
        const url = URL.createObjectURL(response);
        this.type.set(response.type);
        this.src.set(url);
      });

I have the correct mapping in my audio source tag:
[screenshot from the inspect1

In my template, I have:

<audio #media [vgMedia]="$any(media)" id="myAudio" preload="{{ preload }}" crossorigin>
      <source src="{{ src() }}" type="{{ type() }}">
      <track
      src="assets/data/Downloaded_transcriptVVV.vtt"
      kind="metadata"
      label="Cue Points"
      default
      #metadataTrack
    />
  </audio>

When I paste the blob in the browser, I get the file downloaded – (blob:http://localhost:4200/7071f3e7-9738-4ad7-b08f-67ddb5852c53)
The problem is that the native HTML audio does not play at all.
One important note is that I’m using Angular in a zoneless mode.
If, however, I put a direct relative URL in the place of the src, it works:

`this.src.set(‘/assets/audio/E_2024-10-07_H_100748_060.wav’)

I would highly appreciate anyone’s advice on what I’m doing wrong.

2

Answers


  1. The issue is that the audio player is loaded without a source. The player doesn’t listen for new or changed sources and is therefore unaware of the added audio. The fix is to use audio.load(), which forces the browser to recheck the sources and notice the now added audio.

    The example below demonstrates that the browser doesn’t play the audio if the src is set dynamically.

    const source = document.querySelector('source');
    const audio = document.querySelector('audio');
    
    fetch('https://upload.wikimedia.org/wikipedia/commons/3/3d/Alcal%C3%A1_de_Henares_%28RPS_13-04-2024%29_canto_de_ruise%C3%B1or_%28Luscinia_megarhynchos%29_en_el_Soto_del_Henares.wav')
      .then(res => res.blob())
      .then(blob => {
        const url = URL.createObjectURL(blob);
    
        source.type = blob.type;
        source.src = url;
      })
    <audio id="myAudio" preload="auto" crossorigin controls>
        <source />
    </audio>

    The fix is to use audio.load() to reset the player and force it to recheck the sources.

    const source = document.querySelector('source');
    const audio = document.querySelector('audio');
    
    fetch('https://upload.wikimedia.org/wikipedia/commons/3/3d/Alcal%C3%A1_de_Henares_%28RPS_13-04-2024%29_canto_de_ruise%C3%B1or_%28Luscinia_megarhynchos%29_en_el_Soto_del_Henares.wav')
      .then(res => res.blob())
      .then(blob => {
        const url = URL.createObjectURL(blob);
    
        source.type = blob.type;
        source.src = url;
    
        // add this line
        audio.load();
      })
    <audio id="myAudio" preload="auto" crossorigin controls>
        <source />
    </audio>
    Login or Signup to reply.
  2. Wrap src() in an if clause

    When reading the answer from @lusc I realized that this would probably also work and might be even more correct since it won’t render the audio link without a valid src:

    @if (src() as src) { 
      <audio #media [vgMedia]="$any(media)" id="myAudio" [preload]="preload" crossorigin>
        <source [src]="src" [type]="type()">
        <track src="assets/data/Downloaded_transcriptVVV.vtt" kind="metadata" label="Cue Points" default #metadataTrack/> 
      </audio>
    }
    

    this will render the audio element only when you have a src hence there will be no need to call load() afterwards…

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search