SpeechSynthesis API onend 回调不起作用

Posted

技术标签:

【中文标题】SpeechSynthesis API onend 回调不起作用【英文标题】:SpeechSynthesis API onend callback not working 【发布时间】:2014-06-22 10:25:57 【问题描述】:

我在 Google Chrome v34.0.1847.131 上使用 Speech Synthesis API。该 API 从 v33 开始在 Chrome 中实现。

文本转语音在大多数情况下都有效,除非将回调分配给onend。比如下面的代码:

var message = window.SpeechSynthesisUtterance("Hello world!");
message.onend = function(event) 
    console.log('Finished in ' + event.elapsedTime + ' seconds.');
;
window.speechSynthesis.speak(message);

有时会调用onend,有时不会调用它。时机似乎完全关闭了。当它被调用时,打印出来的elapsedTime 总是像1399237888 这样的纪元时间。

【问题讨论】:

仅仅因为规范是在 w3 中编写的......并不意味着它们在所有浏览器中都可以正常工作或工作,特别是如果它们是新的和实验性的,如语音合成......并不是说这种能力是某种形式技术突破,但它是第一次被带到浏览器。 感谢您的检查。看到其他人遇到这个问题是令人鼓舞的。我想这可能只是一个半生不熟的实现,所以这个问题可能没有答案。 检查一下...出于某种奇怪的原因,如果您注销话语对象message,那么它可以正常工作。 :D jsfiddle.net/QYw6b 事实上我认为问题是在声明消息对象后立即调用 speak 函数是问题..如果你这样做` setTimeout(function()speechSynthesis.speak(u);, 100);` 它可以工作......或者攻击说​​话功能来点击事件它也可以正常工作。 我仍然在适用于 Windows 的 chrome v46 上看到这个。我不记得它发生在 Chrome for android 上。 【参考方案1】:

根据this comment Kevin Hakanson 在the answer 中提到的错误,这可能是垃圾收集的问题。在调用 speak seems to do the trick 之前将话语存储在变量中:

window.utterances = [];
var utterance = new SpeechSynthesisUtterance( 'hello' );
utterances.push( utterance );
speechSynthesis.speak( utterance );

【讨论】:

谢谢!一旦我改变了我的话语变量的范围,我就不再有问题了。我同意可能存在与浏览器内部 GC 相关的错误。 成功了!为了让像我这样的初学者清楚,使SpeechSynthesisUtterance 变量的范围更广,例如全局,就行了。 推送是干什么的?什么是话语? utterances 是在第一行创建的数组。 push 在数组末尾添加一项:developer.mozilla.org/en-US/docs/Web/javascript/Reference/… 好人!仅将当前话语存储在全局 window 上,并在所有讲话完成后将其删除 — 非常适合我!【参考方案2】:

虽然这是我发现它的工作方式,但我不确定这是否是正确的行为......

先不要马上调用speak函数,使用回调。

第二,要获得时间,请使用timeStamp 而不是elapsedTime。您也可以使用performance.now()

var btn = document.getElementById('btn');
speechSynthesis.cancel()
var u = new SpeechSynthesisUtterance();
u.text = "This text was changed from the original demo.";

var t;
u.onstart = function (event) 
    t = event.timeStamp;
    console.log(t);
;

u.onend = function (event) 
    t = event.timeStamp - t;
    console.log(event.timeStamp);
    console.log((t / 1000) + " seconds");
;

btn.onclick = function () speechSynthesis.speak(u);;

演示:http://jsfiddle.net/QYw6b/2/

时间过去了,这两个事件肯定会触发。

【讨论】:

虽然在这个例子中它确实有效,但只要你使用非英语语音,它就会停止触发 onend 事件。【参考方案3】:

您可以像我为 Speakerbot (http://www.speakerbot.de/) 那样使用 EventListener 来开始和结束。

说话时我的脸会变。

newUtt = new SpeechSynthesisUtterance();

newUtt.addEventListener('start', function () 
     console.log('started');
)

newUtt.addEventListener('end', function () 
     console.log('stopped');
)

【讨论】:

【参考方案4】:

我发现这里建议的两种解决方案都不适用于an app I just wrote。我能想出的唯一解决方案是(有点)忙于等待:

function speak( text, onend ) 
  window.speechSynthesis.cancel();
  var ssu = new SpeechSynthesisUtterance( text );
  window.speechSynthesis.speak( ssu );
  function _wait() 
    if ( ! window.speechSynthesis.speaking ) 
      onend();
      return;
    
    window.setTimeout( _wait, 200 );
  
  _wait();

你可以在this codepen找到一个完整的例子

【讨论】:

我喜欢你通过调用cancel() 来启动函数的方式,这解决了我的问题。虽然对我来说speechSynthesis.speaking 确实比它应该的要长得多,所以忙碌的等待对我没有用。【参考方案5】:

这看起来类似于 2015 年 7 月 12 日报告的 Chromium 错误。

问题509488:Web Speech API:SpeechSynthesisUtterance 对象的“结束”事件有时未调度

【讨论】:

【参考方案6】:

在说话似乎有效之前打印话语...... 如果我删除控制台,就会出现这个问题,不知道为什么

console.log("utterance", utterThis);
synth.speak(utterThis);

【讨论】:

【参考方案7】:

我还发现使这项工作可靠的唯一方法是使用 .cance。我使用 17 秒超时。我所有的录音都不到 20 秒,所以这对我有用。

utterance.onstart = function (event) 
setTimeout(function()window.speechSynthesis.cancel();,17000);
;

在我尝试每 8-10 条消息时遇到此问题之前。一旦我添加了 .cancel ,它似乎总是有效的。调用时我也会调用 set timeout。

setTimeout(function()window.speechSynthesis.speak(utterance);,100);

【讨论】:

【参考方案8】:

唯一对我有用的是避免localServicetrue 的声音。这些声音从未触发过onend,而其他声音(localService 为假)确实触发了onend

【讨论】:

【参考方案9】:

此外,在 Chrome(但不是 Safari)上,如果您尝试说出空字符串,则永远不会调用回调。

【讨论】:

以上是关于SpeechSynthesis API onend 回调不起作用的主要内容,如果未能解决你的问题,请参考以下文章

SpeechSynthesis.speak 在 chrome 中不起作用

[答疑]onEnded

如果我嵌入标签,onEnded 事件将不起作用

onEnded 事件未在 dojo 对话框中触发

调用 Howler onend() 方法的正确方法

播放多个音视频文件