Forty years ago I programmed my own 6502 Assembly language EEPROM for my Commodore PET, and now I’m having trouble to ‘just’ implement an abort method for a promise :-(
Made a program for the browser which has lots of text and many links (> 900) to soundclips. Clicking a link plays the sound. All very well till I had the idea that with so many sounds I could make a kind of jukebox which would play those sounds in a loop in random sequence. This now works fine using a promise, but sometimes I just want to skip the playing sound, so I need a way to abort the currently playing sound so that the program can pick the next sound. I found many examples here in Stackoverflow, mostly dealing with Fetch and Timeout, I studied and tried various methods, but still I’m unable to skip to the next sound.... It probably is some ‘simple’ error, but at the moment I don’t see which line is wrong or where I have to add some more coding, so any help is appreciated !
Have the following, which is working nicely: it plays random songs in an ‘infinite’ loop, but I just can’t find the correct way to implement the abort, so that I can skip a song.
const ac = new AbortController();
…
async function jukebox({ signal } = {}) {
var jbsong = ''; // holds the song’s filename
var maxSongs = 5; // set max nr of songs to play in a row
jbplays = true; // global that tells system that jukebox is playing
for (var j = 0; j < maxSongs; j++) { // loop over songs
jbsong = getRandomSong();
try {
const answer = await playSound(jbsong));
}
catch (playerror) {
console.log(j + ". NOT found: " + jbsong);
console.log("PlayError: " + playerror);
}
}
jbplays = false; // indication that jukebox is not running anymore
stopMedia(); // hide some info that was displayed
console.log("Jukebox Finished");
};
…
function playSound(soundfile) {
audio.src = (soundfile); // rest of audio was already defined
if (jbplays) { // if called from julebox
return new Promise(function(resolve, reject) { // return a promise
audio.onerror = reject; // an error
audio.onended = resolve; // done playing
})
}
else { // called as a normal one-song play
… playing of a single song (by click on a link) plays OK
}
};
For the time being I try to abort the promise using key S in my handleKeyboard as follows:
case 83: // S - Skip to next sound, so abort the promise
if (jbplays) { // jukebox is playing
console.log("Now trying to abort promise");
ac.abort(); // Doesn’t seem to do anything at the moment
}
break;
Summarizing:
Play by click on a link is OK.
Play in loop is OK.
Abort the promise, so as to go to next song in the loop is not OK.
The message "Now trying to abort promise" is displayed.
What am I missing ?
Thank you very much !
Follow-up:
The day after I implemented Townsheriff’s suggestion, I noticed that pausing the audio (my spacebar, that toggles pause-play) now (of course) also makes the program skip the audio, because using pause() triggers the audio.onpause event, which resolves, and thus plays the next audio in the loop.
After some digging I found the following solution to skip a soundclip:
audio.fastSeek(Math.round(audio.duration));This sets the audio ‘read’ position at the end of the audiofile, and it then thus automagically triggers the audio.onended = resolve event, which means that in the loop the next sound starts.
Ergo: when playing several soundclips in a row, there is no need for aborting promises, it can all be done by what audio has ‘in house’ itself.
Be aware though, that the fastSeek method at the moment is only supported by Firefox and Safari, but as I use Firefox anyway, this is OK with me ☺
Click here for more info on fastSeek