最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Google Chrome Uncaught (in promise) DOMException while playing AUDIO - Stack Overflow

programmeradmin1浏览0评论

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.

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.

Share Improve this question edited Dec 16, 2020 at 16:15 brightlyopposite asked Feb 16, 2019 at 2:25 brightlyoppositebrightlyopposite 751 gold badge1 silver badge6 bronze badges 1
  • I believe in chrome audio.play() can only be used in an user triggered event, such as inside a click event. It's hard to say this is the case here without seeing more code though. – Norman Breau Commented Feb 16, 2019 at 2:40
Add a comment  | 

4 Answers 4

Reset to default 13

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.

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>

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.

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;
}
发布评论

评论列表(0)

  1. 暂无评论