Joe
Joe

Reputation: 4514

How to force the HTML5 Audio tag to reload a (changing) file

I have a bit of code in javascript that generates a wav file and then attaches it to a button so it can be played:

function makeWav(){        
            $.get(("../testsound/getsound.pl?text="+document.myform.outputtext.value));
setTimeout(callback, 500);
            return false;
        }
function callback() {
var audio = new Audio('http://www.joereddington.com/testsound/hope.wav');
audio.load();
audio.play();
           //     $("#player").html("<embed src=http://www.joereddington.com/testsound/hope.wav autostart=true  >");
        }

Obviously the hope.wav file changes very regularly. But my problem is that only the first .wav to be generated is played unless I completely reload the site each time. How do I make the (presumably) callback function go and get a new version of the .wav rather than the cache?

EDIT: Works fine on the iPad - I'm having this problem in firefox.

Upvotes: 17

Views: 25344

Answers (4)

Herr_Hansen
Herr_Hansen

Reputation: 2421

In Vue 3 it helped me to use preload="none" and to change the fileURL with an ?[Date.now()] suffix, every time there is an update in the audio file (change shown with loading prop).

It seems the ?[date12233333] suffix tricks browsers cache, and makes it load the audio file again.

// VUE 3 example
<template>
  <div v-if="!src || loading">
    ... loading
  </div>
  <audio v-else controls preload="none" :src="src" type="audio/mpeg" />
</template>
<script>
import {ref, watch} from "vue";

export default {
  name: "Audio",
  props: {
    loading: {
      type: Boolean,
      required: true,
    },
    src: {
      type: String,
      required: true,
    },
    setup(props) {
      const srcUpdated = ref(null)
      watch(() => props.loading, () => {
        srcUpdated.value = props.src + "?" + Date.now();
      })
      return {
        srcUpdated
      }
    }
  }
}
</script>

Upvotes: 0

Spankied
Spankied

Reputation: 1895

For those trying to change the src attribute of a source element, I found this spec note .

Dynamically modifying a source element and its attribute when the element is already inserted in a video or audio element will have no effect. To change what is playing, just use the src attribute on the media element directly

So lets say you have:

<audio>
    <source src='./first-src'/>
</audio>

To modify the src:

<audio src='./second-src'/>
    <source src='./first-src'/>
</audio>

Upvotes: 10

Rama Al-Maliki
Rama Al-Maliki

Reputation: 1

function Speech()
{
     var fileName = new Date().getTime();

     $.ajax({
         url: Host + "api/speech",
         data: {
             'text': $("input[id='searchBox']").val(),
             'language': $("input[id='languageChoice']:checked").val(),
             'fileName': fileName
         },
         dataType: "json",
         type: "Get",
         contentType: "application/json; charset=utf-8",
         success: function () {
             var audioUrl = Host + '/Assets/Audio/' + fileName + '.mp3';
             var audio = new Audio(audioUrl);
             audio.load();
             audio.play();
         }
     });
}

Upvotes: 0

Alex P
Alex P

Reputation: 6072

You can't directly control the caching from within your JavaScript. Retrieving files is the responsibility of the browser, which is why you're getting different results on different browsers.

When a web server sends a file to the browser, it also sends some headers with extra details about that file. One of them is the Cache-Control header, which tells the browser if the file is cacheable. Sending a Cache-Control: no-cache header should stop browsers caching the file, and make subsequent requests retrieve the file from your server.

On Apache, you can use an .htaccess file or a <Directory> rule in your server configuration to change the caching for files in the /testsound directory. Put the following in /testsound/.htaccess:

<ifModule mod_headers.c>
    Header set Cache-Control no-cache
</ifModule>

Another technique is to include a "cache-busting" parameter in your request. Your web server is serving a static file - but your web browser doesn't know that. For all it knows, a request for /testsound/hope.wav?cb=foo could return a completely different file to a request for /testsound/hope.wav?cb=bar. Thus, if you include an always-changing parameter in your web request, the browser won't find it in its cache and it will retrieve the new file. A timestamp is a good choice:

function callback() {
  var url = "http://www.joereddington.com/testsound/hope.wav?cb=" + new Date().getTime();
  var audio = new Audio(url);
  audio.load();
  audio.play();        
}

Upvotes: 35

Related Questions