brightlyopposite
brightlyopposite

Reputation: 75

Google Chrome Uncaught (in promise) DOMException while playing AUDIO

Chrome blocks auto-playing audio/video. I've found solutions for auto-playing video, but my use case requires auto-playing audio. Here is my code:

let audio = new Audio('music/test.mp3'); audio.play(); audio.loop = true;

This results in an "Uncaught (in promise) DOMException" on Chromium browsers because of new policies.

Upvotes: 7

Views: 19504

Answers (4)

Octo Poulos
Octo Poulos

Reputation: 775

I've had to deal with this issue as well, it's quite annoying when you want to trigger all exceptions in the browser, and it triggers the audio one.

So, the best solution that I found in pure javascript:

let has_clicked;
window.addEventListener('click', () => {has_clicked = true;});
window.addEventListener('touchstart', () => {has_clicked = true;});

function playSound() {
    if (!has_clicked)
        return;

    // insert the play code, for ex yours:
    let audio = new Audio('music/test.mp3'); audio.play(); audio.loop = true;
}

Upvotes: 0

Kardi Teknomo
Kardi Teknomo

Reputation: 1450

The browser requires the user to explicitly start media playback by clicking a "play" button. Code below solves your problem.

<!DOCTYPE html>
<html>
<head>
<title>Play MP3 music on web</title>
<script>
function playMusic(){
    var promise = document.querySelector('audio').play();
    if (promise !== undefined) {
        promise.then(_ => {
            // Autoplay started!
        }).catch(error => {
            // Autoplay was prevented. Show a "Play" button so that user can start playback.
        });
    }
}
</script> 
</head>  
<body>
    <p>Play MP3</p>
    <input type="button" value="play music" onClick="playMusic();">
    <audio loop id="sound">
        <source src="audio/audio.mp3" type="audio/mpeg">
        <p>Browser doesn't support html5</p>
    </audio>
</body>
</html>

Upvotes: 1

Daweb
Daweb

Reputation: 84

This code may help. It will fire the autoplay (and loop) with a first user's interaction with the DOM.

<!doctype html>

<html lang="fr">
<head>
    <meta charset="utf-8">
</head>

<style>html,body{height:100%}</style>

<body>


    <!-- SOUND -->
    <audio loop id="sound">
        <source src="sound.mp3" type="audio/mpeg">
        <p>Browser doesn't support html5</p>
    </audio>


    <!-- CONTENT -->
    <button onClick="audio_manager.play()">Play sound</button>
    <button onClick="document.querySelector('body').style.backgroundColor = '#'+(0x1000000+(Math.random())*0xffffff).toString(16).substr(1,6);">Do something else</button>
    <ol id="text"><li>Autoplay will be start on user first interaction with body (click anywhere to test)</li></ol>


    <!-- JS SCRIPT -->
    <script>
        var audio_manager = {

            // Variables
            user_has_interacted: false,
            detection_is_active: false,


            /**
             * Init function
             * 
             * Detect first user's interaction
             */ 

            init: function(){

                // If already detecting => return
                if( audio_manager.detection_is_active){
                    return false;
                }

                // Detection active
                audio_manager.detection_is_active = true;

                // Set up eventListener for user's first interaction
                document.querySelector('body').addEventListener('click', audio_manager.detect_first_interaction, true);

            },


            detect_first_interaction: function(e) {

                // Set user_has_interacted to true
                audio_manager.user_has_interacted = true;

                // Remove listener
                document.querySelector('body').removeEventListener(e.type, audio_manager.detect_first_interaction, true);

                // Play media (= Autoplay)
                audio_manager.play();

                // Log first detection
                document.getElementById('text').innerHTML += "<li>Autoplay, first interaction detected on " + e.type + " on " + e.target.nodeName + "</li>";
            },


            /**
             * Play function
             * 
             * Play "sound" or init first user's detection
             */ 

            play: function(){

                // If user interaction, play media
                if(audio_manager.user_has_interacted){
                    document.getElementById('sound').play();                    
                    return true;
                }

                // Init detection
                audio_manager.init();
            }

        };

        // Load autoplay
        audio_manager.play();

        // Uncomment next line to test autoplay on load without workaround => throw error "Uncaught (in promise) DOMException" or "NotAllowedError: The play method is not allowed by the user agent or the platform in the current context, possibly because the user denied permission."
        //document.getElementById('sound').play();  
    </script>

    </body>
</html>

Not a perfect workaround, but useful in some case.

Upvotes: 0

Norman Breau
Norman Breau

Reputation: 2417

You're receiving an uncaught exception because you aren't handling an error.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play

Audio is an HTMLMediaElement object, and the play() method returns a promise. Therefore I recommend handling the error.

var promise = audio.play();
if (promise) {
    //Older browsers may not return a promise, according to the MDN website
    promise.catch(function(error) { console.error(error); });
}

One of two errors are possible:

NotSupportedError

This means that the audio source is not supported by the browser (probably due to audio format)

NotAllowedError

This is the one I suspect you are triggering. This means the user needs to explicitly trigger the audio.play(), so the method is only usable if it is in response to a user generated event such as a click event.

Docs:

The user agent (browser) or operating system doesn't allow playback of media in the current context or situation. This may happen, for example, if the browser requires the user to explicitly start media playback by clicking a "play" button.

Upvotes: 13

Related Questions