自 M71 起不再允许在没有用户激活的情况下使用 JavaScript voiceSynthesis.speak()

问题描述 投票:0回答:8

我是这样使用speechSynthesis API的:

speechSynthesis.speak(new SpeechSynthesisUtterance("hello world"));

但是现在我在更新 Google Chrome 后收到错误:

[弃用]没有用户激活的speechSynthesis.speak()是不行的 自 M71 以来允许的时间更长,大约在 2018 年 12 月。参见 https://www.chromestatus.com/feature/5687444770914304了解更多详情 语音合成消息@ 应用程序-2c16c437c2795ae01c0a8852e5f8da58dad99d6e17814a31f1eea19922c5ebd2.js:147

如何解决此问题并请求许可?

javascript google-chrome speech-synthesis
8个回答
24
投票

这是 Chrome 关于从网页发出声音的新政策的一部分。
您只需要您的用户在父文档的生命周期内提供一个用户手势(您可以在here找到该手势的列表)(即,只要用户与页面进行过交互,该事件就可能长期消失) 。

请注意,这些事件甚至可以遍历框架,因此例如在 StackOverflow 中,您必须单击“运行”按钮这一简单事实将使内部框架允许执行此代码:

const ut = new SpeechSynthesisUtterance('No warning should arise');
speechSynthesis.speak(ut);

在您的代码中,您只需提供某种 UI,以确保您的用户在调用此方法之前已与页面进行交互(例如按钮/切换按钮就可以完美执行)。


11
投票

如果您在 chrome://settings/content/sound 中将站点地址设置为“受信任”,即使没有用户交互,似乎也可以启用声音和语音合成。

我在电视中使用 Chrome 作为系统监视器,使用信息亭模式,无需任何用户交互。它甚至没有键盘和鼠标。 不过,我能够在某些版本的 Chrome/Chromium 中启用,但在其他版本中则不能。


5
投票

此错误意味着整个文档(网站)没有用户交互,Google Chrome 更新了有关在没有用户交互的情况下从网站发出声音的政策。

用户交互意味着:

click, dblclick, mouseup, pointerup, reset, submit etc.

解决方案:

因此,如果您想在没有真正用户交互的情况下运行

speechSynthesis.speak();
,那么您只需使用
.click()
等方法创建临时用户交互即可。


2
投票

虽然我还没有找到任何方式来请求许可,但是用户可以在Google Chrome中启用权限:

  1. 点击地址栏左侧的图标,打开站点设置

  2. 声音设置从“自动(默认)”更改为“允许

完成此操作后,该网站将能够在没有任何用户交互(包括语音)的情况下发出声音。

不幸的是,我还没有在代码中找到一种方法来知道这是否有效。 (也许我们可以尝试其他音频 API 之一,看看它是否响应错误消息。)


0
投票

我求助于

swal("Click OK to speak").then(() => speakButton.click());
(与https://sweetalert.js.org)--https://patarapolw.github.io/tts-api/?q=你好&lang=zh-CN&rate=0.8

请注意,

if (confirm("Click OK to speak")) speakButton.click()
不起作用。


0
投票

使用模拟 btn 开始演讲对我来说很有效。

请小心检查页面是否静音,这花了我几个小时才找到错误。(当页面静音时,speak()方法将返回错误“不允许”)

speak(message: string): Observable<string> {

return new Observable(observer => {

  const callback = () => {
    const utterance = new SpeechSynthesisUtterance(message);

    utterance.voice = speechSynthesis.getVoices().find((voice) => voice.lang === 'zh-CN' && voice.localService === true);
    utterance.onend = () => {
      console.log('TTS_SPEAK', message);
      observer.next(message);
      observer.complete();
    };
    utterance.onerror = (err) => {
      if(err.error === 'not-allowed') {
        this.msg.warning('The page is muted');
      }
      observer.error(err)
    };
    window.speechSynthesis?.speak(utterance);
  }

  if (!window.navigator.userAgent.includes('Edg') && window.navigator.userAgent.includes('Chrome')) {
    // https://stackoverflow.com/questions/41539680/speechsynthesis-speak-not-working-in-chrome
    // https://chromestatus.com/feature/5687444770914304
    const btn = document.createElement('button');
    btn.style.display = 'none';

    btn.id = 'TTS_btn';
    btn.addEventListener('click', () => {
      callback();
    });

    document.body.appendChild(btn);


    let event = new MouseEvent('click', {
      view: window,
      bubbles: true,
      cancelable: true
    })
    btn.dispatchEvent(event);

    document.body.removeChild(btn);

  } else {
    callback();
  }



});

}


-1
投票

我遇到了同样的问题,可以使用 window.onload 对其进行排序:

window.onload = function(){ 
var u = new SpeechSynthesisUtterance('All is Ok');
 u.text = 'Hello World';    
 u.lang = 'en-US';
 u.rate = 1;
 u.pitch = .4;     
 speechSynthesis.speak(u);
}

当然,这只会在页面加载后触发一次,但这对我来说是一个很好的解决方案。


-3
投票

一个简单的黑客,不需要真正的用户活动,就是像这样在隐藏按钮上执行单击事件。

document.querySelector('button').click();
var msg = new SpeechSynthesisUtterance('Test');
© www.soinside.com 2019 - 2024. All rights reserved.