Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS Speech Synthesis Issue on iOS

I recently implemented a basic web app which relied on Google's TTS URL to generate clear MP3 files for playback on the front end.

This has since been subject to an additional security check, meaning I have had to update the code base to use alternative methods.

One such alternative is javascript's speech synthesis API, i.e. SpeechSynthesisUtterance() and window.speechSynthesis.speak('...'). This works really well on my desktop and laptop but as soon as I use it on my iOS devices, the rate of the audio is accelerated significantly.

Can anyone suggest what I can do to resolve this?

See below for example code:

var msg = new SpeechSynthesisUtterance(); 
    msg.text = item.title;
    msg.voice = "Google UK English Male";
    msg.rate = 0.7;
    msg.onend = function(){
        console.log('message has ended');
        $('.word-img').removeClass('img-isplaying');
    };
    msg.onerror = function(){
        console.log('ERROR WITH SPEECH API');
        $('.word-img').removeClass('img-isplaying');
    };
window.speechSynthesis.speak(msg);
like image 306
Bob-ob Avatar asked Aug 25 '15 00:08

Bob-ob


2 Answers

IOS doesn't allow to use the new SpeechSynthesis-Api programmatically. The user must trigger the action explicit. I can understand this decision. But I don't understand, why the Api is not working in webapps, like playing audio files. This is not working in IOS's default safari, but its working in webapps.

Here is a little trick:

<a id="trigger_me" onclick="speech_text()"></a>
<script>
    function speech_text() {
        var msg = new SpeechSynthesisUtterance();
        /* ... */
    }
    /* and now you must trigger the event for #trigger_me */
    $('#trigger_me').trigger('click');
</script>

This is working only with native dom elements. If you add a new tag programmatically into the dom like...

$('body').append('<a id="trigger_me" onclick="speech_text()"></a>');

... the function will not triggered. It seems that IOS-Safari registers events for special internal functions only once after domload.

like image 119
AppGeer Avatar answered Nov 20 '22 11:11

AppGeer


OK. I solved this problem today. The problem is that the iOS would not let the speech API run programmatically unless we have triggered one time under the user's interaction.

So we can listen to the user interaction and trigger one silent speech which can let us speak programmatically later.

Here is my code.

let hasEnabledVoice = false;

document.addEventListener('click', () => {
  if (hasEnabledVoice) {
    return;
  }
  const lecture = new SpeechSynthesisUtterance('hello');
  lecture.volume = 0;
  speechSynthesis.speak(lecture);
  hasEnabledVoice = true;
});
like image 29
To-xic Avatar answered Nov 20 '22 09:11

To-xic