スピーチシンセシスAPIを使用しようとしています。デスクトップブラウザーとモバイルChromeで機能しますが、モバイルSafariでは機能しません。
const msg = new SpeechSynthesisUtterance("Hello World");
window.speechSynthesis.speak(msg);
少しテストを追加しましたが、APIがSafariでサポートされているようですが、機能していないのは権限の問題でしょうか?
if ("speechSynthesis" in window) {
alert("yay");
} else {
alert("no");
}
私の側では、この問題はモバイルSafariでの適切なloading音声合成に分解されました。
順番に確認することがいくつかあります。
次の例は、これらのチェックをまとめたもので、MacOSデスクトップブラウザーとiOS Safariで機能します。
_let _speechSynth
let _voices
const _cache = {}
/**
* retries until there have been voices loaded. No stopper flag included in this example.
* Note that this function assumes, that there are voices installed on the Host system.
*/
function loadVoicesWhenAvailable (onComplete = () => {}) {
_speechSynth = window.speechSynthesis
const voices = _speechSynth.getVoices()
if (voices.length !== 0) {
_voices = voices
onComplete()
} else {
return setTimeout(function () { loadVoicesWhenAvailable(onComplete) }, 100)
}
}
/**
* Returns the first found voice for a given language code.
*/
function getVoices (locale) {
if (!_speechSynth) {
throw new Error('Browser does not support speech synthesis')
}
if (_cache[locale]) return _cache[locale]
_cache[locale] = _voices.filter(voice => voice.lang === locale)
return _cache[locale]
}
/**
* Speak a certain text
* @param locale the locale this voice requires
* @param text the text to speak
* @param onEnd callback if tts is finished
*/
function playByText (locale, text, onEnd) {
const voices = getVoices(locale)
// TODO load preference here, e.g. male / female etc.
// TODO but for now we just use the first occurrence
const utterance = new window.SpeechSynthesisUtterance()
utterance.voice = voices[0]
utterance.pitch = 1
utterance.rate = 1
utterance.voiceURI = 'native'
utterance.volume = 1
utterance.rate = 1
utterance.pitch = 0.8
utterance.text = text
utterance.lang = locale
if (onEnd) {
utterance.onend = onEnd
}
_speechSynth.cancel() // cancel current speak, if any is running
_speechSynth.speak(utterance)
}
// on document ready
loadVoicesWhenAvailable(function () {
console.log("loaded")
})
function speak () {
setTimeout(() => playByText("en-US", "Hello, world"), 300)
}
_
<button onclick="speak()">speak</button>
コードの詳細はスニペット内のコメントとして追加されます。
音声を取得するタイミングの問題である可能性があるため、ページをロードするときに音声を要求すると、ユーザーが[発声]ボタンをクリックする前に準備が整います。
例を簡単にするために、タイムアウトは設定していません。
if ( 'speechSynthesis' in window ) {
speechSynthesis.cancel(); // removes anything 'stuck'
speechSynthesis.getVoices();
// Safari loads voices synchronously so now safe to enable
speakBtn.disabled = false;
}
const speak = () => {
const utter = new SpeechSynthesisUtterance();
utter.text = textToSpeak.value || textToSpeak.placeholder;
speechSynthesis.speak(utter);
};
speakBtn.addEventListener('click', speak);
<input type="text" id="textToSpeak" placeholder="1, 2, 3">
<button type="button" id="speakBtn" disabled>Speak</button>
これは非常に基本的な例であり、使用する音声や言語を選択するものではありません。
これが機能しない場合は、別の問題があります。サウンドがデバイスで機能することをテストしましたか? " soft mute "はオンになっていますか?