1

My actual project is more complex, but I’ve simplified my problem to the code below. How come when I press the button, JavaScript will only play the first sound? I’ve noticed that when I reduce the wait time to 500ms, both sounds play. But larger numbers like 1000ms don’t work. What’s happening and why isn’t the second sound playing?

const delay = millis => new Promise((resolve, reject) => {
    setTimeout(_ => resolve(), millis)
});

var firstAudio = new Audio('https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3');

var secondAudio = new Audio('https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3');


async function testAudio() {
    firstAudio.play();
    await delay(1000); 
    secondAudio.play();
}
<button onclick="testAudio()">
    <h1>Test the audio</h1>
</button>
Abin Thaha
  • 4,493
  • 3
  • 13
  • 41
  • I checked now, the delay is 1000ms and both sounds are being played. – Abin Thaha Aug 13 '21 at 05:14
  • it's working very well, just check the **Web Developer Tools** of your browser and see if you get any errors or warning. – Mohsen TOA Aug 13 '21 at 05:16
  • @MohsenNewtoa that’s strange. It could be because I am currently on mobile and don’t have access to my computer. I’m using the app Koder, and the built in browser may be a bad one (even though it’s worked fine until now). Thanks for checking my code on a computer. – Gabriele Scotto di Vettimo Aug 13 '21 at 05:19
  • @GabrieleScottodiVettimo I just checked it on mobile, it's working there as well – Mohsen TOA Aug 13 '21 at 05:23
  • Different browsers will have different rules, (even different users on the same browser version), but the stricter (iOS) require that you do handle the `play()` call from inside the user event. After 1s they consider you are not handling the event anymore. It works on desktop Chrome because there the default is to mark the full document as "approving media output" on the first user interaction. To workaround that, prepare all your Audio elements ahead of time, mark them all as allowed to be controlled by script in the event handler and pause them right after. Or have a look at the WebAudioAPI. – Kaiido Aug 13 '21 at 05:23
  • @Kaiido how would I “prepare” the elements ahead of time? I’ve tried using the html audio tags and then played them by getting there IDs in JavaScript and putting .play(); but this doesn’t work either. How do I prepare them? – Gabriele Scotto di Vettimo Aug 13 '21 at 15:03
  • You create them all (`new Audio(url)`) and store them in variables accessible later on, or even in an Array etc. In the click event, for each of this Audio objects you created you do `audio.play().then(() => audio.pause())`. (you may have to set their currentTime to 0) Now, they're all marked as being allowed for control through scripts, you can call their `play()` method at any time. Also, Safari has other bugs with short audio clips, if you are really using such short clips in your project, then switch to WebAudioAPI, see https://stackoverflow.com/questions/67629761/67630045#67630045 – Kaiido Aug 13 '21 at 15:20
  • @Kaiido sorry for all the questions, I’m still new to JavaScript. Would I create the audio variables globally (not inside a function)? And then I put the part with “.then(()” inside my on click function as the first two lines of code. And then after that I am able to use the audio whenever I want? – Gabriele Scotto di Vettimo Aug 14 '21 at 07:00
  • In testAudio should be fine. – Kaiido Aug 14 '21 at 07:05
  • @Kaiido thank you very much, you’ve solved my problem. However, your solution makes it so that the audio will play for a split second when the on click function is called. Code: var firstA = new Audio('https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3'); var secondA = new Audio('https://s3.amazonaws.com/freecodecamp/drums/Heater-1.mp3'); async function testAudio() { firstA.play().then(() => firstA.pause()); secondA.play().then(() => secondA.pause()); await delay(4000); firstA.play(); await delay(3000); secondA.play(); } – Gabriele Scotto di Vettimo Aug 14 '21 at 07:19
  • Han... This is https://stackoverflow.com/questions/67629761/67630045 They still didn't fix that bug... If you don't want to got the WebAudioAPI way, resetting the `src` (`audio.play(); audio.src=audio.src`) would be the only way, but this is a browser bug. – Kaiido Aug 14 '21 at 07:23

1 Answers1

0

The problem was that the browser considered the audio not in current use in my original code and couldn’t be called. I had to call it first, then immediately pause, and then call it when the right time came.