Kaibear
Kaibear

Reputation: 95

SpeechSynthesis.speaking never true

I try to realize a small web page with a javascript, that allows to playback a spechsynthesis part from text in between two mp3.

As for whatever reason the onend statement of the spoken part does not work, I wanted to create a recursive function, that helps me. For that, I use the "speaking" methode of the SpeechSynthesis. But for whatever reason, speaking is never true.

I debugged and also tried several statements (see code), but it never ever turns out to be true. Is there something with the code? Otherwise, how to report a bug of this library?

        function doSpeech() {
            var synth = window.speechSynthesis;

            var utterance1 = new SpeechSynthesisUtterance('How about we say this now? This is quite a long sentence to say.');
            var utterance2 = new SpeechSynthesisUtterance('We should say another sentence too, just to be on the safe side.');
            synth.speak(utterance1);
            if(synth.speaking){
                doNothing();
            }else{
                playEnd();
            }

playEnd() just plays an mp3 if synth is speaking. Please note, when I put playEnd() in the if statement, it won't play. I can put whatever code in there, it is never reached, as synth.speaking will never be true. This example is close to the example of Mozilla foundations documentation on this (https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis/speaking). I wanted to test it, as the recursion never worked.

EDIT: Recursion still won't do it in my specific coding. Am I missing something here?

  function doSpeech() {
            var synth = window.speechSynthesis;
            var speech = new SpeechSynthesisUtterance();
            speech.text = getText();
            speech.lang = "en-US";
            speech.voice = speechSynthesis.getVoices().filter(function(voice) { return voice.name == 'Google UK English Male'; })[0];

            speech.addEventListener('start', function(){
                speechEndLoop(synth);
            });


            synth.speak(speech);
    }

   function speechEndLoop(x) {
          if (x.speaking) {
               speechEndLoop(x);  
            } else {
               playEnd(); 
            }
        }

Upvotes: 1

Views: 2159

Answers (1)

Carlos Delgado
Carlos Delgado

Reputation: 3065

It works perfectly, the problem is that according to your code you are verifying immediately for the status. This may be a problem because it depends on how the API is converting the text to audio (using the local text to speech of the operative system or using the google servers):

function doSpeech() {
    var synth = window.speechSynthesis;

    var utterance1 = new SpeechSynthesisUtterance('How about we say this now? This is quite a long sentence to say. Make it longer !');
    var utterance2 = new SpeechSynthesisUtterance('We should say another sentence too, just to be on the safe side. even longer !');

    synth.speak(utterance1);

    // If you check immediately (js code executed in less than ms) the
    // status won't be true
    if (synth.speaking) {
        console.log("This is usually printed, if the utterance uses the default voice of the browser (native)");
    }

    // Wait 500ms to check for the status of the utterance
    setTimeout(function(){
        if (synth.speaking) {
            console.log("This will be printed if starts after 500ms :)");
        }
    }, 500);
}

doSpeech();

In my case, both of the console.log statements are being printed. But if in your case it isn't being printed, execute your code only after the start event of the utterance:

function doSpeech() {
    var synth = window.speechSynthesis;
    var msg = new SpeechSynthesisUtterance();
    msg.text = "We should say another sentence too, just to be on the safe side. even longer !";

    msg.addEventListener('start', function () {
        if(synth.speaking){
            console.log("This will be printed !");
        }
    });

    synth.speak(msg);
} 

doSpeech();

Is pretty nice to work with the plain API by yourself, but if you want something more robust to solve the text to speech problem, i recommend you to use the JS Library Artyom.js, it offers a pretty nice wrapper for the Speech Synthesis API. Even with this library you will see the same behaviour:

function doSpeech() {
    let assistant = new Artyom();

    assistant.say('How about we say this now? This is quite a long sentence to say. Make it longer !', {
        onStart: function() {
            if(assistant.isSpeaking()){
                console.log("This will be shown");
            }
        }
    });

    if(assistant.isSpeaking()){
        console.log("This won't appear !");
    }
} 

doSpeech();

Upvotes: 1

Related Questions