Issues playing audio in website on iOS devices

I’ve build a basic webpage with a countdown timer that plays 3 short sounds at different points through the countdown, once the countdown is complete, a stopwatch timer appears and waits for the user to press stop.

The .play() function doesn’t seem to work on my iPhone for both Chrome and Safari. None of the three sounds are audible at all.

It plays fine for desktops and there are no issues at all.

Is there a fix for this? The whole idea of the training tool is that it is supposed to work on mobiles so competitors can train their reaction times at home.

<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
<style>
    #processed-content {
        background-image: url('https://www.slslnc.org.au/wp-content/uploads/timerbackground.jpg');
        background-position: center;
        background-size: cover;
        min-height: 96vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 16px;
        text-align: center;
    }

    #processed-content h1,
    #processed-content p {
        color: black;
        text-shadow: 0 0 15px white;
        font-size: 2rem;
        margin:50px 0;
    }
    
    p#timerDisplay.instructions {
    font-size: 18px !important;
}

    #processed-content button {
        color: black;
        font-size: 2rem;
        margin:20px 0;
    }
    .start-button {
        background-color:#ffd520;
        border:2px solid black;
    }
    .stop-button {
        background-color:#ed1c2e;
        border:2px solid black;
    }
    .reset-button {
        background-color:#00cc36;
        border:2px solid black;
    }
    .save-button {
        background-color:#0066db;
        border:2px solid black;
    }
    
    .hidden {
        display: none;
    }
    
    @media screen and (max-width:768px) {
    p#timerDisplay.instructions {
    font-size: 18px !important;
    }
}
</style>

<div id="processed-content">
    <h1 class="text-2xl font-bold mb-4">Beach Flags Reaction Time Trainer</h1>
    <button id="startButton" class="bg-gold hover:bg-gray-200 text-black font-bold py-4 px-10 rounded mb-4 start-button">START</button>
    <p id="timerDisplay" class="text-lg mb-4 instructions">When you press START, you will have up to 15 seconds to get into position and be ready for the audio prompts...</p>
    <button id="stopButton" class="hidden bg-white hover:bg-gray-200 text-black font-bold py-4 px-10 rounded mb-4 stop-button">STOP</button>
    <button id="resetButton" class="hidden bg-white hover:bg-gray-200 text-black font-bold py-2 px-4 rounded reset-button">RESET</button>
    <button id="screenshotButton" class="hidden bg-white hover:bg-gray-200 text-black font-bold py-2 px-4 rounded mt-4 save-button">SAVE SCREENSHOT</button>
</div>

<audio id="readyAudio" src="https://www.slslnc.org.au/wp-content/uploads/competitorsready.mp3"></audio>
<audio id="headsDownAudio" src="https://www.slslnc.org.au/wp-content/uploads/headsdown.mp3"></audio>
<audio id="whistleAudio" src="https://www.slslnc.org.au/wp-content/uploads/whistle.mp3"></audio>

<script>
    const startButton = document.getElementById("startButton");
    const stopButton = document.getElementById("stopButton");
    const resetButton = document.getElementById("resetButton");
    const screenshotButton = document.getElementById("screenshotButton");
    const timerDisplay = document.getElementById("timerDisplay");

    const readyAudio = document.getElementById("readyAudio");
    const headsDownAudio = document.getElementById("headsDownAudio");
    const whistleAudio = document.getElementById("whistleAudio");

    let countdownTimeout, headsDownTimeout, whistleTimeout, stopwatchInterval;
    let startTime;

    startButton.addEventListener("click", function() {
        startButton.classList.add("hidden");
        timerDisplay.textContent = "Get ready...";

        const randomCountdown = Math.floor(Math.random() * 6) + 10;

        countdownTimeout = setTimeout(() => {
            readyAudio.play();
            
            const randomReadyTime = Math.floor(Math.random() * 2) + 3;

            headsDownTimeout = setTimeout(() => {
                headsDownAudio.play();
                
                const randomWhistleTime = Math.floor(Math.random() * 3) + 2;

                whistleTimeout = setTimeout(() => {
                    whistleAudio.play();
                    startStopwatch();
                }, randomWhistleTime * 1000);
            }, randomReadyTime * 1000);
        }, randomCountdown * 1000);
    });

    function startStopwatch() {
        startTime = Date.now();
        stopButton.classList.remove("hidden");
        
        stopwatchInterval = setInterval(() => {
            const elapsedTime = ((Date.now() - startTime) / 1000).toFixed(2);
            timerDisplay.textContent = `Time: ${elapsedTime} s`;
        }, 10);
    }

    stopButton.addEventListener("click", function() {
        clearInterval(stopwatchInterval);
        stopButton.classList.add("hidden");
        resetButton.classList.remove("hidden");
        screenshotButton.classList.remove("hidden");
    });

    resetButton.addEventListener("click", function() {
        clearTimeout(countdownTimeout);
        clearTimeout(headsDownTimeout);
        clearTimeout(whistleTimeout);
        timerDisplay.textContent = "Get ready...";
        resetButton.classList.add("hidden");
        screenshotButton.classList.add("hidden");
        startButton.classList.remove("hidden");
    });

    screenshotButton.addEventListener("click", function() {
        html2canvas(document.querySelector("#processed-content")).then(canvas => {
            const link = document.createElement('a');
            link.href = canvas.toDataURL();
            link.download = 'reaction_time.png';
            link.click();
        });
    });

    function loadHtml2Canvas() {
        const script = document.createElement("script");
        script.src = "https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js";
        document.body.appendChild(script);
    }

    loadHtml2Canvas();
</script>