如何处理“未捕获(承诺中)DOMException:play() 失败,因为用户没有首先与文档交互。”在使用 Chrome 66 的桌面上?

发布于 2025-01-16 08:12:43 字数 724 浏览 4 评论 0 原文

我收到错误消息..

未捕获(承诺中)DOMException:play() 失败,因为用户没有先与文档交互。

..当尝试使用 Chrome 版本 66 在桌面上播放视频时。

我确实发现一个广告在网站上自动开始播放,但是使用以下 HTML:

<video
    title="Advertisement"
    webkit-playsinline="true"
    playsinline="true"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://ds.serving-sys.com/BurstingRes/Site-2500/Type-16/1ff26f6a-aa27-4b30-a264-df2173c79623.mp4"
    autoplay=""></video>

绕过 Chrome v66 的自动播放拦截器真的很简单,只需添加 的 >webkit-playsinline="true"、playsinline="true"autoplay="" 属性代码> 元素?这样做有什么负面影响吗?

I'm getting the error message..

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

..when trying to play video on desktop using Chrome version 66.

I did find an ad that began playback automatically on a website however using the following HTML:

<video
    title="Advertisement"
    webkit-playsinline="true"
    playsinline="true"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://ds.serving-sys.com/BurstingRes/Site-2500/Type-16/1ff26f6a-aa27-4b30-a264-df2173c79623.mp4"
    autoplay=""></video>

So is by-passing Chrome v66's autoplay blocker really as easy as just adding the webkit-playsinline="true", playsinline="true", and autoplay="" attributes to the <video> element? Are there any negative consequences to this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(19

水染的天色ゝ 2025-01-23 08:12:43

要在 chrome 66 更新后使 html 5 元素自动播放,您只需将 muted 属性添加到 video 元素即可。

所以你当前的视频 HTML

<video
    title="Advertisement"
    webkit-playsinline="true"
    playsinline="true"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    autoplay=""></video>

只需要 muted="muted"

<video
    title="Advertisement"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    autoplay="true"
    muted="muted"></video>

我相信 chrome 66 更新正在尝试阻止选项卡在用户选项卡上产生随机噪音。这就是为什么静音属性使自动播放再次起作用的原因。

To make the autoplay on html 5 elements work after the chrome 66 update you just need to add the muted property to the video element.

So your current video HTML

<video
    title="Advertisement"
    webkit-playsinline="true"
    playsinline="true"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    autoplay=""></video>

Just needs muted="muted"

<video
    title="Advertisement"
    style="background-color: rgb(0, 0, 0); position: absolute; width: 640px; height: 360px;"
    src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
    autoplay="true"
    muted="muted"></video>

I believe the chrome 66 update is trying to stop tabs creating random noise on the users tabs. That's why the muted property make the autoplay work again.

静赏你的温柔 2025-01-23 08:12:43

对我来说(在 Angular 项目中)这段代码有帮助:

在 HTML 中,你应该添加 autoplay muted

在 JS/TS 中

playVideo() {
    const media = this.videoplayer.nativeElement;
    media.muted = true; // without this line it's not working although I have "muted" in HTML
    media.play();
}

For me (in Angular project) this code helped:

In HTML you should add autoplay muted

In JS/TS

playVideo() {
    const media = this.videoplayer.nativeElement;
    media.muted = true; // without this line it's not working although I have "muted" in HTML
    media.play();
}
司马昭之心 2025-01-23 08:12:43

尝试使用 mousemove 事件监听器

var audio = document.createElement("AUDIO")
document.body.appendChild(audio);
audio.src = "./audio/rain.m4a"

document.body.addEventListener("mousemove", function () {
    audio.play()
})

Try to use mousemove event listener

var audio = document.createElement("AUDIO")
document.body.appendChild(audio);
audio.src = "./audio/rain.m4a"

document.body.addEventListener("mousemove", function () {
    audio.play()
})
北渚 2025-01-23 08:12:43

我收到这个错误

未捕获(承诺中)DOMException:play() 失败,因为用户没有先与文档交互。

这就是我在 Angular 项目中所做的

要点:永远不要假设视频会播放,也不要在视频未实际播放时显示暂停按钮。

您应该始终查看 play 函数返回的 Promise,看看它是否被拒绝:

ngOnInit(): void{
    this.ensureVideoPlays();
}

private ensureVideoPlays(): void{
    const video = document.querySelector("video");

    if(!video) return;
    
    const promise = video.play();
    if(promise !== undefined){
        promise.then(() => {
            // Autoplay started
        }).catch(error => {
            // Autoplay was prevented.
            video.muted = true;
            video.play();
        });
    }
}

来源:自动播放政策

I got this error

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

And here's what I did in my Angular Project

Key Point: Don't ever assume a video will play, and don't show a pause button when the video is not actually playing.

You should always look at the Promise returned by the play function to see if it was rejected:

ngOnInit(): void{
    this.ensureVideoPlays();
}

private ensureVideoPlays(): void{
    const video = document.querySelector("video");

    if(!video) return;
    
    const promise = video.play();
    if(promise !== undefined){
        promise.then(() => {
            // Autoplay started
        }).catch(error => {
            // Autoplay was prevented.
            video.muted = true;
            video.play();
        });
    }
}

Source: Autoplay policy

是伱的 2025-01-23 08:12:43

我发现的最佳解决方案是将视频

HTML静音

<video loop muted autoplay id="videomain">
  <source src="videoname.mp4" type="video/mp4">
</video>

The best solution i found out is to mute the video

HTML

<video loop muted autoplay id="videomain">
  <source src="videoname.mp4" type="video/mp4">
</video>
明月松间行 2025-01-23 08:12:43

扩展 DOM 元素,处理错误,优雅降级

下面我使用原型函数包装原生 DOM 播放函数,抓住它的承诺,然后在浏览器抛出异常时降级为播放按钮。该扩展解决了浏览器的缺点,并且可以在任何了解目标元素的页面中即插即用。

// JavaScript
// Wrap the native DOM audio element play function and handle any autoplay errors
Audio.prototype.play = (function(play) {
return function () {
  var audio = this,
      args = arguments,
      promise = play.apply(audio, args);
  if (promise !== undefined) {
    promise.catch(_ => {
      // Autoplay was prevented. This is optional, but add a button to start playing.
      var el = document.createElement("button");
      el.innerHTML = "Play";
      el.addEventListener("click", function(){play.apply(audio, args);});
      this.parentNode.insertBefore(el, this.nextSibling)
    });
  }
};
})(Audio.prototype.play);

// Try automatically playing our audio via script. This would normally trigger and error.
document.getElementById('MyAudioElement').play()

<!-- HTML -->
<audio id="MyAudioElement" autoplay>
  <source src="https://www.w3schools.com/html/horse.ogg" type="audio/ogg">
  <source src="https://www.w3schools.com/html/horse.mp3" type="audio/mpeg">
  Your browser does not support the audio element.
</audio>

Extend the DOM Element, Handle the Error, and Degrade Gracefully

Below I use the prototype function to wrap the native DOM play function, grab its promise, and then degrade to a play button if the browser throws an exception. This extension addresses the shortcoming of the browser and is plug-n-play in any page with knowledge of the target element(s).

// JavaScript
// Wrap the native DOM audio element play function and handle any autoplay errors
Audio.prototype.play = (function(play) {
return function () {
  var audio = this,
      args = arguments,
      promise = play.apply(audio, args);
  if (promise !== undefined) {
    promise.catch(_ => {
      // Autoplay was prevented. This is optional, but add a button to start playing.
      var el = document.createElement("button");
      el.innerHTML = "Play";
      el.addEventListener("click", function(){play.apply(audio, args);});
      this.parentNode.insertBefore(el, this.nextSibling)
    });
  }
};
})(Audio.prototype.play);

// Try automatically playing our audio via script. This would normally trigger and error.
document.getElementById('MyAudioElement').play()

<!-- HTML -->
<audio id="MyAudioElement" autoplay>
  <source src="https://www.w3schools.com/html/horse.ogg" type="audio/ogg">
  <source src="https://www.w3schools.com/html/horse.mp3" type="audio/mpeg">
  Your browser does not support the audio element.
</audio>
莫相离 2025-01-23 08:12:43

回答手头的问题...
不,仅仅拥有这些属性还不够,为了能够自动播放带有音频的媒体,您需要在文档上注册用户手势。

但是,这个限制非常弱:如果您确实在父文档上收到了这个用户手势,并且您的视频是从 iframe 加载的,那么您可以播放它......

所以以 this fiddle,这只是

<video src="myvidwithsound.webm" autoplay=""></video>

第一次加载,如果你不点击任何地方,它不会运行,因为我们没有任何事件尚未注册。
但是,一旦您单击“运行”按钮,父文档 (jsfiddle.net) 就会收到用户手势,现在视频就会播放,即使从技术上讲它是加载到另一个文档中的。

但以下代码片段将自动播放,因为它需要您实际单击运行代码片段按钮。

<video src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" autoplay=""></video>

这意味着您的广告可能能够播放,因为您确实向主页提供了用户手势。


现在,请注意,Safari 和 Mobile Chrome 的规则比这更严格,并且要求您以编程方式在 上实际触发至少一次 play() 方法。或来自用户事件处理程序本身的 元素。

btn.onclick = e => {
  // mark our MediaElement as user-approved
  vid.play().then(()=>vid.pause());
  // now we can do whatever we want at any time with this MediaElement
  setTimeout(()=> vid.play(), 3000);
};
<button id="btn">play in 3s</button>
<video
  src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" id="vid"></video>

如果您不需要音频,那么只需不要将其附加到您的媒体,只有视频轨道的视频也可以自动播放,并且会减少用户的带宽使用量。

Answering the question at hand...
No it's not enough to have these attributes, to be able to autoplay a media with audio you need to have an user-gesture registered on your document.

But, this limitation is very weak: if you did receive this user-gesture on the parent document, and your video got loaded from an iframe, then you could play it...

So take for instance this fiddle, which is only

<video src="myvidwithsound.webm" autoplay=""></video>

At first load, and if you don't click anywhere, it will not run, because we don't have any event registered yet.
But once you click the "Run" button, then the parent document (jsfiddle.net) did receive an user-gesture, and now the video plays, even though it is technically loaded in a different document.

But the following snippet, since it requires you to actually click the Run code snippet button, will autoplay.

<video src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" autoplay=""></video>

This means that your ad was probably able to play because you did provide an user-gesture to the main page.


Now, note that Safari and Mobile Chrome have stricter rules than that, and will require you to actually trigger at least once the play() method programmatically on the <video> or <audio> element from the user-event handler itself.

btn.onclick = e => {
  // mark our MediaElement as user-approved
  vid.play().then(()=>vid.pause());
  // now we can do whatever we want at any time with this MediaElement
  setTimeout(()=> vid.play(), 3000);
};
<button id="btn">play in 3s</button>
<video
  src="https://upload.wikimedia.org/wikipedia/commons/transcoded/2/22/Volcano_Lava_Sample.webm/Volcano_Lava_Sample.webm.360p.webm" id="vid"></video>

And if you don't need the audio, then simply don't attach it to your media, a video with only a video track is also allowed to autoplay, and will reduce your user's bandwidth usage.

不知所踪 2025-01-23 08:12:43

就我而言,我必须这样做

 // Initialization in the dom
 // Consider the muted attribute
 <audio id="notification" src="path/to/sound.mp3" muted></audio>


 // in the js code unmute the audio once the event happened
 document.getElementById('notification').muted = false;
 document.getElementById('notification').play();

In my case, I had to do this

 // Initialization in the dom
 // Consider the muted attribute
 <audio id="notification" src="path/to/sound.mp3" muted></audio>


 // in the js code unmute the audio once the event happened
 document.getElementById('notification').muted = false;
 document.getElementById('notification').play();
盗心人 2025-01-23 08:12:43

根据新的浏览器策略,用户在播放 Audio 元素之前必须先与 DOM 交互。

如果您想在页面加载时播放媒体,则只需将 autoplay 属性添加到 HTML 中的音频元素即可

或者,如果您不想自动播放,则可以使用 Javascript 来处理。由于 autoplay 属性设置为 true,因此将播放媒体,我们可以简单地将媒体静音。

document.getElementById('video').autoplay = true;
document.getElementById('video').muted = true; 

Imp:现在,每当您播放媒体时,请不要忘记将静音属性设置为 false。像这样

document.getElementById('video').muted = false; 
document.getElementById('video').play();

或者您也可以显示一个简单的弹出窗口,用户将在其中单击模式中的允许按钮。所以他先和DOM交互,然后你就不需要做任何事情了

According to the new browser policy, the user must interact with DOM first before playing the Audio element.

If you want to play the media on page load then you can simply add autoplay property to audio element in HTML like this

<video id="video" src="./music.mp4" autoplay>

or if you don't want to do autoplay then you can handle this using Javascript. Since the autoplay property is set to true, media will be played, we can simply mute the media.

document.getElementById('video').autoplay = true;
document.getElementById('video').muted = true; 

Imp: Now Whenever you play the media don't forget to turn the muted property to false. Like this

document.getElementById('video').muted = false; 
document.getElementById('video').play();

Or you can also show a simple popup where the user will click the allow button in the modal. So he interacts with DOM first, then you don't need anything to do

零時差 2025-01-23 08:12:43

就我而言,它只是在开始时自动调用的点击声(我不介意它是否静音)。所以我使用:

const clickSound = new Audio('click.wav');
clickSound.play().catch(function (error) {
    console.log("Chrome cannot play sound without user interaction first")});

来消除错误。

In my case it's just a click sound which is automatically invoked at the start (which I don't mind if it's silenced). So I use:

const clickSound = new Audio('click.wav');
clickSound.play().catch(function (error) {
    console.log("Chrome cannot play sound without user interaction first")});

to get rid of the error.

尴尬癌患者 2025-01-23 08:12:43

我遇到了类似的问题,我需要播放视频而不将其静音。我这样做的方式是,等待一秒钟,然后通过按钮触发事件。这是我的代码

if (playVideo == '1') {
    setTimeout(function() {
        $("#watch_video_btn").trigger('click');
    }, 1000);
}

I had a similar problem, I need to play the video without muting it. The way i did this, wait for a second then triggered the event by button. Here is my code

if (playVideo == '1') {
    setTimeout(function() {
        $("#watch_video_btn").trigger('click');
    }, 1000);
}
空城旧梦 2025-01-23 08:12:43

我更改了 UI,让用户按下按钮来加载网站(当用户单击按钮后加载网站时,音频就会播放),

因为他们与 DOM 交互,所以音频就会播放!

I changed my UI to have the user press a button to load the website (and when the website loads after they click the button, the audio plays)

Since they interact with the DOM, then the audio plays!!!

来世叙缘 2025-01-23 08:12:43

Chrome 需要用户交互才能自动播放或通过 js 播放视频 (video.play())。
但互动可以是任何类型、任何时刻。
如果您只是在页面上随机单击,视频就会自动播放。
然后我决定添加一个按钮(仅在 Chrome 浏览器上),上面写着“启用视频自动播放”。该按钮不执行任何操作,只需单击它即可观看任何其他视频所需的用户交互。

Chrome needs a user interaction for the video to be autoplayed or played via js (video.play()).
But the interaction can be of any kind, in any moment.
If you just click random on the page, the video will autoplay.
I resolved then, adding a button (only on chrome browsers) that says "enable video autoplay". The button does nothing, but just clicking it, is the required user interaction for any further video.

清风疏影 2025-01-23 08:12:43

我在 Android 手机上玩时遇到一些问题。
经过几次尝试,我发现当数据保护程序打开时,没有自动播放:

如果 数据保护程序模式已启用。如果启用数据保护模式,则会在媒体设置中禁用自动播放。

来源

I had some issues playing on Android Phone.
After few tries I found out that when Data Saver is on there is no auto play:

There is no autoplay if Data Saver mode is enabled. If Data Saver mode is enabled, autoplay is disabled in Media settings.

Source

梦里兽 2025-01-23 08:12:43

我在尝试播放音频文件时遇到了类似的错误。起初,它可以工作,然后当我开始在同一函数中使用 ChangeDetector 的 markForCheck 方法来在承诺解决时触发重新渲染时(我遇到了视图渲染问题),它就停止工作了。

当我将 markForCheck 更改为 detectChanges 时,它再次开始工作。我真的无法解释发生了什么,我只是想把它放在这里,也许会对某人有所帮助。

I encountered a similar error with while attempting to play an audio file. At first, it was working, then it stopped working when I started using ChangeDetector's markForCheck method in the same function to trigger a re-render when a promise resolves (I had an issue with view rendering).

When I changed the markForCheck to detectChanges it started working again. I really can't explain what happened, I just thought of dropping this here, perhaps it would help someone.

月寒剑心 2025-01-23 08:12:43

您应该在 videoElement 中添加 muted 属性,以便代码按预期工作。请看下面..

<video id="IPcamerastream" muted="muted" autoplay src="videoplayback%20(1).mp4" width="960" height="540"></video>

不要忘记添加有效的视频链接作为来源

You should have added muted attribute inside your videoElement for your code work as expected. Look bellow ..

<video id="IPcamerastream" muted="muted" autoplay src="videoplayback%20(1).mp4" width="960" height="540"></video>

Don' t forget to add a valid video link as source

拿命拼未来 2025-01-23 08:12:43

有一些针对该问题的编程解决方案可以绕过该功能。

一些示例是使用 Java 的 Robot 或 Autohotkey,作为 Chrome 层之上的另一个解决方案。但在我看来,这不是很聪明。因此,我最喜欢的解决该问题的方法(尽管有点棘手)是使用 Chrome 扩展 API 中的 chrome.debugger 的 Input.dispatchMouseEvent API。

var __target = 1857385916; // -- replace here with the tab id you desire

var x = 360 // -- replace here with your desired position to emulate click
var y = 360 // -- here as well
var button = "right"
var clickCount = 1

chrome.debugger.sendCommand({ tabId: __target }, 'Input.dispatchMouseEvent', {
    type: 'mousePressed',
    x: x,
    y: y,
    button: button,
    clickCount: clickCount,
}, () => {
  chrome.debugger.sendCommand({ tabId: __target }, 'Input.dispatchMouseEvent', {
    type: 'mouseReleased',
    x: x,
    y: y,
    button: button,
    clickCount: clickCount,
  })
});

初学者注意事项

创建一个 Chrome 扩展程序,其中使用上述脚本创建的 background.js 以及当然启用了 debugger 权限的创建的 manifest.json。

Chrome 的菜单 -> “管理扩展”-> “开发者模式”已启用 ->像往常一样,“加载解压”以加载扩展。

您可能想知道想要模拟鼠标事件的选项卡的选项卡 ID。我制作的以下脚本可能有助于快速识别每个选项卡的 ID。

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (changeInfo.status === "complete" && tab.active && tab.url) {
        var obj = {
            tabId: tabId,
            title: tab.title,
            url: tab.url,
        }
        console.log("[(background) tab id logger]", obj, );
    }
});

在manifest.json中添加“tabs”权限,重新加载扩展,点击“后台页面”打开后台脚本检查窗口,将上述JavaScript脚本粘贴到控制台即可运行脚本。如果您没有看到任何错误,请重新加载任何选项卡,您将很快在控制台上看到记录的选项卡的选项卡 ID。

There are some programmatic solutions for the issue to bypass the feature.

Some examples would be using Java's Robot or Autohotkey, as an another solution on top of the Chrome layer. But IMO it's not very smart. So my favorite workaround for the issue (although a little tricky) is using chrome.debugger's Input.dispatchMouseEvent API from Chrome Extension API.

var __target = 1857385916; // -- replace here with the tab id you desire

var x = 360 // -- replace here with your desired position to emulate click
var y = 360 // -- here as well
var button = "right"
var clickCount = 1

chrome.debugger.sendCommand({ tabId: __target }, 'Input.dispatchMouseEvent', {
    type: 'mousePressed',
    x: x,
    y: y,
    button: button,
    clickCount: clickCount,
}, () => {
  chrome.debugger.sendCommand({ tabId: __target }, 'Input.dispatchMouseEvent', {
    type: 'mouseReleased',
    x: x,
    y: y,
    button: button,
    clickCount: clickCount,
  })
});

Notes for beginners:

Create a Chrome extension with background.js created as the above script, and manifest.json created with debugger permission enabled of course.

Chrome's menu -> "Manage Extensions" -> "Developer mode" enabled -> "load unpacked" to load the extension, as usual.

You may want to know the tab id for your desired tab to emulate a mouse event on. The following script I made might be helpful for quickly identify id of each tab.

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
    if (changeInfo.status === "complete" && tab.active && tab.url) {
        var obj = {
            tabId: tabId,
            title: tab.title,
            url: tab.url,
        }
        console.log("[(background) tab id logger]", obj, );
    }
});

Add "tabs" permission to the manifest.json, reload the extension, click "background page" to open the background script inspection window, paste the above JavaScript script on the console to run the script. If you don't see any error, reload any tab, you would quickly see the tab id for the tab on the console logged.

策马西风 2025-01-23 08:12:43
  1. 打开 chrome://settings/content/sound
  2. 设置无需用户手势
  3. 重新启动 Chrome
  1. Open chrome://settings/content/sound
  2. Setting No user gesture is required
  3. Relaunch Chrome
蓬勃野心 2025-01-23 08:12:43

在地址栏中输入 Chrome://flags

搜索:自动播放

自动播放政策

决定是否允许音频或视频时使用的策略
自动播放。

-Mac、Windows、Linux、Chrome 操作系统、Android

将其设置为“无需用户手势

重新启动 Chrome,您无需更改任何代码

Type Chrome://flags in the address-bar

Search: Autoplay

Autoplay Policy

Policy used when deciding if audio or video is allowed
to autoplay.

– Mac, Windows, Linux, Chrome OS, Android

Set this to "No user gesture is required"

Relaunch Chrome and you don't have to change any code

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文