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

javascript - `.play()` failed because the user didn't interact with the document first issue - Stack Overflow

programmeradmin6浏览0评论

I want to play sound, after my page has loaded.

Here is my JavaScript code:

var playAudio = $("#sound")[0];
playAudio.play();

Here is my HTML code:

<audio id="sound">
  <source src="../music/hide.ogg" type="audio/ogg">
  <source src="../music/hide.mp3" type="audio/mp3">
</audio>

Console output:

Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.

I want to play sound, after my page has loaded.

Here is my JavaScript code:

var playAudio = $("#sound")[0];
playAudio.play();

Here is my HTML code:

<audio id="sound">
  <source src="../music/hide.ogg" type="audio/ogg">
  <source src="../music/hide.mp3" type="audio/mp3">
</audio>

Console output:

Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.

Share Improve this question edited Oct 29, 2023 at 10:37 Agi Hammerthief 2,1341 gold badge22 silver badges40 bronze badges asked Nov 20, 2020 at 12:47 user14643128user14643128
Add a ment  | 

3 Answers 3

Reset to default 6

Most browsers block any audio that is played by a web page and is not related to user interaction (see https://developer.mozilla/en-US/docs/Web/Media/Autoplay_guide). With user interaction I mean things like pressing a button. You can't do anything against that.

But you could add a start button that displays the page and starts the music, like this:

const startbtn = document.getElementById("startbtn");
const content = document.getElementById("content");
const loader = document.getElementById("loader");
const music = document.getElementById("music");

//Add an event listner to the start button
startbtn.addEventListener("click", () => {
  //Show the loader and hide the button
  loader.style.display = "";
  startbtn.style.display = "none";
  //Wait for the music to start
  music.play().then(() => {
    //Hide the loader and show the content
    content.style.display = "";
    loader.style.display = "none";
  });
});
<!-- The start button --->
<button id="startbtn">Start</button>

<!-- The actual content, hidden by default -->
<div id="content" style="display: none;">
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
  <p>Bla</p>
</div>

<!-- This is displayed when the user has pressed the start button, but the music is still loading -->
<div id="loader" style="display: none;">
  <p>Loading ...</p>
</div>

<!-- The music. It is started by the Javascript -->
<audio id="music" src="https://opengameart/sites/default/files/audio_preview/swing_0.mp3.ogg" style="display: none;" loop></audio>

When this happens on Google Chrome, the error is currently showing a link to this page: https://developer.chrome./blog/autoplay/.

As the post explains, Google Chrome keeps track of an individual's propensity to consume media on a site, using a metric called MEI (Media Engagement Index).

Based on that metric, an attempt to play sound on page load may or may not work. You can see a list of the scores of which Chrome keeps track by going to chrome://media-engagement/ on your browser.

To handle cases in which the play on page load doesn't work, the post suggests the following code snippet:

var promise = document.querySelector('video').play();

if (promise !== undefined) {
  promise.then(_ => {
    // Autoplay started!
  }).catch(error => {
    // Autoplay was prevented.
    // Show a "Play" button so that user can start playback.
  });
}

In your case it could be:

const playAudio = $("#sound")[0];
const promise = playAudio.play();

let playedOnLoad;

if (promise !== undefined) {
  promise.then(_ => {
    // Autoplay started!
    playedOnLoad = true;
  }).catch(error => {
    // Autoplay was prevented.
    playedOnLoad = true;
  });
}

At this point you can use the playedOnLoad value to show a button or add a listener to some other types of user interaction.

Another option (the one I'm adopting) is to always show a toggle for the sound, and to change it's state (play/stop or enable/disable) based on the result of the promise.

Please remember that the MEI score is also saved for your local development environment, so, based on your personal interaction with the page, the sound may or may not start on page load even in your local environment.

This is my code and works fine. I added two params to Notification class object

silent: false, requireInteraction: false

import silenceSound from '../assets/sounds/light.mp3';

export const playSound = async (soundPathOrBase64Data) => {
  var sound;
  if (soundPathOrBase64Data && soundPathOrBase64Data.toString().length) {
    sound = new Audio(soundPathOrBase64Data);
  } else {
    sound = new Audio(silenceSound);
  }
  sound.load();
  var promise = sound.play();
  if (promise) {
    //Older browsers may not return a promise, according to the MDN website
    promise.catch(function (error) {
      console.error(error);
    });
  }
};

function sendNotification(messageObj) {
  if (document.hidden) {
    const notification = new Notification('New message from Chat', {
      icon: 'https://cdn-icons-png.flaticon./512/733/733585.png',
      body: `@${messageObj?.userName || messageObj?.userEmail}: ${messageObj?.message || ''}`,
      silent: false,
      requireInteraction: false
    });

    playSound();

    notification.onclick = () =>
      function () {
        window.open('http://localhost:5500');
      };
  }
}

export default function checkPageStatus(message) {
  const localUser = localStorage.getItem('chat-app-user');
  const parsedUser = localUser ? JSON.parse(localUser) : undefined;

  if (message?.sender !== parsedUser?._id) {
    if (!('Notification' in window)) {
      alert('This browser does not support system notifications!');
    } else if (Notification.permission === 'granted' || Notification.permission === 'default') {
      sendNotification(message);
    } else if (Notification.permission !== 'denied') {
      Notification.requestPermission((permission) => {
        if (permission === 'granted') {
          sendNotification(message);
        }
      });
    }
  }
}
发布评论

评论列表(0)

  1. 暂无评论