JS Speech Synthesis Issue on iOS
Asked Answered
G

2

10

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);
Gounod answered 25/8, 2015 at 0:21 Comment(0)
P
9

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.

Picrite answered 17/11, 2015 at 3:7 Comment(1)
Additional info: After you triggered one tts call manually, you can trigger as many as you like with javascript.Sheared
T
9

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;
});
Teddie answered 26/6, 2020 at 3:0 Comment(7)
Build a package for this npmjs.com/package/enable-auto-ttsTeddie
Awesome, this works on safari browser but not with IOS. It works only with Mac OS safari browser. are you able to make it work on IOS Mobile device.Bartel
I test on the iOS web view and it works but I have not checked the Safari. Let me check.Teddie
I test on my iOS safari browser and it works. You can use this URL for the test. codepen.io/toxic-johann/pen/JjGrPzgTeddie
Some devices work, some don't. Not consistent on iOS.Chatty
This trick works on iOS 14.6 (11. July 2021). Tested on iPhone and iPad.Ruble
This works for my iPhone Xs ios17 but not for my samsung S7 edge Internet browserTymothy

© 2022 - 2024 — McMap. All rights reserved.