Preload multiple audio files
var audioFiles = [
"http://www.teanglann.ie/CanC/nua.mp3",
"http://www.teanglann.ie/CanC/ag.mp3",
"http://www.teanglann.ie/CanC/dul.mp3",
"http://www.teanglann.ie/CanC/freisin.mp3"
];
function preloadAudio(url) {
var audio = new Audio();
// once this file loads, it will call loadedAudio()
// the file will be kept by the browser as cache
audio.addEventListener('canplaythrough', loadedAudio, false);
audio.src = url;
}
var loaded = 0;
function loadedAudio() {
// this will be called every time an audio file is loaded
// we keep track of the loaded files vs the requested files
loaded++;
if (loaded == audioFiles.length){
// all have loaded
init();
}
}
var player = document.getElementById('player');
function play(index) {
player.src = audioFiles[index];
player.play();
}
function init() {
// do your stuff here, audio has been loaded
// for example, play all files one after the other
var i = 0;
// once the player ends, play the next one
player.onended = function() {
i++;
if (i >= audioFiles.length) {
// end
return;
}
play(i);
};
// play the first file
play(i);
}
// we start preloading all the audio files
for (var i in audioFiles) {
preloadAudio(audioFiles[i]);
}
<audio id="player"></audio>
Can I preload audio files in javascript/html and play it also after network loss?
I think as long as you don't change audio.src
after the connection's lost you should be OK. So you'll need one audio element for each file you want to preload. Perhaps:
var audioPlayers = audioFiles.map( file => {
var audio = new Audio();
audio.src = file;
return audio;
})
Preload multiple (798) audio files in Chrome
This isn't really a code problem. It's a general architecture problem.
Depending not only on the number, but also the size of the samples, it's going to be unlikely you can get them all loaded at once. Even if you can, it'll run very poorly because of the high memory use and likely crash the tab after a certain amount of time.
Since it's offline, I would say you could even get away with not pre-loading them at all, since the read speed is going to be nearly instantaneous.
If you find that isn't suitable, or you may need like 5 at once and it might be too slow, I'd say you'll need to architect your game in a way that you can determine which sounds you'll need for a certain game state, and just load those (and remove references to ones you don't need so they can be garbage collected).
This is exactly what all games do when they show you a loading screen, and for the same reasons.
If you want to avoid "loading screens", you can get clever by working out a way to know what is coming up and load it just ahead of time.
Most sensible way of preloading a batch of audio files
You can use fetch()
and Promise.all()
with .map()
or a for..of
loop and Promise
constructor to request the media resources as Blob
or ArrayBuffer
and render playback at a single <audio>
node using MediaSource
or simply setting src
of <audio>
node to next Blob
representation of file by passing Blob
to URL.createObjectURL()
to create a Blob URL
.
Use XMLHttpRequest to load multiple audio files and append them to play in Web Audio API
Well I figured out one solution myself. When I connected each buffer to the audioContext.destination, I can simply specify the time when the second audio play, which is the current time plus the duration of the first AudioBuffer.
Playing audio broken into multiple files in webpage
I'd take a look at this answer on another Stack Overflow question however I have made some modifications in order to match your question:
var audioFileURLs= [];
function preloadAudio(url) {
var audio = new Audio();
// once this file loads, it will call loadedAudio()
// the file will be kept by the browser as cache
audio.addEventListener('canplaythrough', loadedAudio, false);
audio.src = url;
}
var loaded = 0;
function loadedAudio() {
// this will be called every time an audio file is loaded
// we keep track of the loaded files vs the requested files
loaded++;
if (loaded == audioFileURLs.length){
// all have loaded
init();
}
}
var player = document.getElementById('player');
function play(index) {
player.src = audioFiles[index];
player.play();
}
function init() {
// do your stuff here, audio has been loaded
// for example, play all files one after the other
var i = 0;
// once the player ends, play the next one
player.onended = function() {
i++;
if (i >= audioFiles.length) {
// end
return;
}
play(i);
};
// play the first file
play(i);
}
// call node/express server to get a list of links we can hit to retrieve each audio file
fetch('/getAudioUrls/#BookNameOrIdHere#')
.then(r => r.json())
.then(arrayOfURLs => {
audioFileURLs = arrayOfURLs
arrayOfURLs.map(url => preloadAudio(URL))
})
And then just have an audio element on the screen with the id of "player" like <audio id="player"></audio>
With this answer though, the arrayOfURLs
array must contain URLs to an API on your server that will open the zip file and return the specified mp3 data. You may also just want to take this answer as a general reference, and not a complete solution because there is optimization to be done. You should probably only load the first audio file at first, and 5 minutes or so before the first file ends you may want to start pre-loading the next and then repeat this process for the entire thing... That all will be up to you but this should hopefully put you on your feet.
You may also run into an issue with the audio element though because it will only show the length of the current audio segment it is on, and not the full length of the audiobook. I would choose to believe this zip file has the book separated by chapter correct? If so you could create a chapter selector, that pretty much allows you to jump to a specific chapter aka getAudioUrls URL.
I hope this helps!
One other note for you... reading your comment on a potential answer down below, you could combine all the audio files into one using some sort of node module (audioconcat is one I found after a quick google search) and return that one file to the client. However, I would not personally take this route because the entire audiobook will be in the server's memory while it combines them, and until it returns it to the client. This could cause some memory issues down the road, so I would avoid it if I could. However, I will admit that this option could be potentially nice because the full length of the audiobook will display in the audio elements timeline.
The best option perhaps is to store the books full length and chapter lengths in a details.json file in the zip file and send that to the client in the first API call along with the URLs to each audio file. This would enable you to build a nice UI.
Related Topics
What Characters Must Be Escaped in an Http Query String
Drawing Multiple Edges Between Two Nodes with D3
Internet Explorer 11 Word Wrap Is Not Working
Add Outward Curving Border to Elements Like This: ◝◟_◞◜
How to Vertically Align Something Inside a Span Tag
CSS Show Div Background Image on Top of Other Contained Elements
How to Collapse/Expand a Div Within an Email? What Clients Support This
Add Padding to HTML Text Input Field
iOS Not Respecting Z-Index with -Webkit-Overflow-Scrolling
Animating with Variables Angular 4
Flexbox on Ie11: Image Stretched for No Reason
Style and Script Tags in HTML Body... Why Not
CSS Wrong Appearance of Border-Radius on a Nested Div
How to Calculate Required Hue-Rotate to Generate Specific Colour