中文文本用 Web Speech 播放一次 API,但不会播放第二次

Chinese text plays once with Web Speech API, but not a second time

所以我正在使用修改后的脚本来尝试播放 Web 语音中的一些文本 API。

代码原在这里:

Chrome Speech Synthesis with longer texts

这是我修改后的变体:

function googleSpeech(text, rate) {
    if (!reading) {
        speechSynthesis.cancel();
        if (timer) {
            clearInterval(timer);
        }
        let msg = new SpeechSynthesisUtterance();
        let voices = window.speechSynthesis.getVoices();
        msg.voice = voices[63];
        msg.voiceURI = 'native';
        msg.volume = 1; // 0 to 1
        msg.rate = rate; // 0.1 to 10
        msg.pitch = 1; //0 to 2
        msg.text = text;
        msg.lang = 'zh-CN';

        msg.onerror = function (e) {
            speechSynthesis.cancel();
            reading = false;
            clearInterval(timer);
        };

        msg.onpause = function (e) {
        };

        msg.onboundary = function (event) {
        };

        msg.onend = function (e) {
            speechSynthesis.cancel();
            reading = false;
            clearInterval(timer);
        };

        speechSynthesis.onerror = function (e) {
            speechSynthesis.cancel();
            reading = false;
            clearInterval(timer);
        };

        console.log(msg);
        speechSynthesis.speak(msg);

        timer = setInterval(function () {
            if (speechSynthesis.paused) {
                speechSynthesis.resume();
            }

        }, 100);

        reading = true;
    }

}

我可以让它播放一次。每当我尝试让它再次播放时,它都不起作用 - 尽管 运行 speechSynthesis.cancel();。当我重新加载页面时,一切正常 - 播放一次。

有什么一致的方法可以再次播放文本吗?看起来这可能与 Web Speech API 中的许多错误有关。这是在 Chrome 68.

这是我正在播放的文本示例:

我是一个兵。来自老百姓。 打败了日本狗强盗。 消灭了蒋匪军。

let reading = false;
let timer;
// let VV="ja-JP";
let VV = 'en-US';


function handleSaying(msg, text, rate) {
  let voices = window.speechSynthesis.getVoices();


  // console.log(voices);
  msg.voice = voices.filter(v => v.lang === VV)[0];

  // console.log("voice: ", msg.voice);
  msg.voiceURI = 'native';
  msg.volume = 1; // 0 to 1
  msg.rate = rate; // 0.1 to 10
  msg.pitch = 1; //0 to 2
  msg.text = text;
  msg.lang = VV;

  msg.onerror = function(e) {
    speechSynthesis.cancel();
    reading = false;
    clearInterval(timer);
  };

  msg.onpause = function(e) {};

  msg.onboundary = function(event) {};

  msg.onend = function(e) {
    console.log("On end...");
    // speechSynthesis.cancel();
    reading = false;
    clearInterval(timer);
  };

  speechSynthesis.onerror = function(e) {
    speechSynthesis.cancel();
    reading = false;
    clearInterval(timer);
  };

  speechSynthesis.speak(msg);

  timer = setInterval(function() {
    if (speechSynthesis.paused) {
      speechSynthesis.resume();
    }

  }, 100);

  reading = true;
}


function googleSpeech(text, rate) {

  if (!reading) {
    speechSynthesis.cancel();
    if (timer) {
      clearInterval(timer);
    }
    let msg = new SpeechSynthesisUtterance();

    // Here is the problem -- if the voices are ALREADY loaded from an earlier attempt
    // onvoiceschanged does not fire a second time

    if (window.speechSynthesis.getVoices().length > 0) {
      handleSaying(msg, text, rate);
    }


    // wait on voices to be loaded before fetching list
    window.speechSynthesis.onvoiceschanged = function() {
      handleSaying(msg, text, rate);
    }

  };

}
<button type="button" onclick="googleSpeech('The quick brown fox jumped over the lazy dogs', 5)">English</button>

我已经修改了您的代码以播放两次声音,并且我在代码中评论了问题所在。我 运行 以前遇到过这个问题 -- 这是一个难题。

我也遇到过 onvoicechanged 多次触发的问题,因为它加载声音然后再加载一些声音。我没有输入代码来验证我们想要的声音是否存在。

我的系统无法播放您尝试使用的任何语言,因此我更改为英文文本和语音,但这很容易改回。

我还删除了对特定语音号码的硬编码引用,因为它们可能会发生变化。相反,我寻找与语言 ID 匹配的第一个语音。

您可能想参考这个答案。

Getting the list of voices in speechSynthesis of Chrome (Web Speech API)

你的代码按原样工作,除了我必须在函数之前定义 reading = falsetimer = false

我的观察是,当您传递速率值 而不是在 0.1 to 1o 之间时,您的函数仅被调用一次。您可能需要检查您的 rate 值。

此外,如果费率值不在指定范围内,您的 onend 活动将不会收到呼叫。

我的系统是Mac,chrome是Version 67.0.3396.99 (Official Build) (64-bit)

<script type="text/javascript">
    

reading = false;
timer = false;
function googleSpeech(text, rate) {
    if (!reading) {
        speechSynthesis.cancel();
        if (timer) {
            clearInterval(timer);
        }
        let msg = new SpeechSynthesisUtterance();
        let voices = window.speechSynthesis.getVoices();
        msg.voice = voices[63];
        msg.voiceURI = 'native';
        msg.volume = 1; // 0 to 1
        msg.rate = rate; // 0.1 to 10
        msg.pitch = 1; //0 to 2
        msg.text = text;
        msg.lang = 'zh-CN';

        msg.onerror = function (e) {
            speechSynthesis.cancel();
            reading = false;
            clearInterval(timer);
        };

        msg.onpause = function (e) {
        };

        msg.onboundary = function (event) {
        };

        msg.onend = function (e) {
            speechSynthesis.cancel();
            reading = false;
            clearInterval(timer);
        };

        speechSynthesis.onerror = function (e) {
            speechSynthesis.cancel();
            reading = false;
            clearInterval(timer);
        };

        console.log(msg);
        speechSynthesis.speak(msg);

        timer = setInterval(function () {
            if (speechSynthesis.paused) {
                speechSynthesis.resume();
            }

        }, 100);

        reading = true;
    }

}
</script>

<button  onclick="googleSpeech('我是一个兵。来自老百姓。 打败了日本狗强盗。 消灭了蒋匪军。',1)"> Play </button>

答案竟然与汇率的数值有关属性。

虽然 Web Speech API 的官方文档说它支持 0.1 到 10 的速率值,但似乎 Chrome(至少 Chrome 68,我的版本 运行) 不完全支持超出 .5 到 2 范围的速率。

超出此范围的任何内容都会在使用 API 一次后导致声音分散和中断,并且在页面刷新之前声音将不再有效。