3

Update: After some digging I managed to find some information in the Logcat. See bottom.

Edit 2: I have now created a new activity from scratch to reduce the problem. It does still not work correctly. Here is the code:

public class MainActivity extends AppCompatActivity {
    private TextToSpeech textToSpeech;
    private boolean isInitialized = false;
    private MainActivity mainActivity;
    int ctr = 0;
    private String words[] = {"ord", "kula", "fotboll"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        mainActivity = this;

        textToSpeech = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                if (status == TextToSpeech.SUCCESS){
                    textToSpeech.setOnUtteranceProgressListener(new UtteranceProgressListener() {
                        @Override
                        public void onStart(String utteranceId) {
                            System.out.println("---onStart");
                        }

                        @Override
                        public void onDone(String utteranceId) {
                           System.out.println("-----onDone");
                        }

                        @Override
                        public void onError(String utteranceId) {
                            System.out.println("-----onError");
                        }

                        @Override
                        public void onError(String utteranceId, int errorCode){
                            onError(utteranceId);
                            System.out.println("Error with code: " + errorCode);
                        }
                    });
                    isInitialized = true;
                    Locale locale = new Locale("swe");
                    textToSpeech.setLanguage(locale);
                }
            }
        });
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                if (isInitialized){
                    System.out.println(textToSpeech.getLanguage().getDisplayLanguage());
                    textToSpeech.speak(words[ctr], TextToSpeech.QUEUE_FLUSH, null, "SpeakTest");
                    ctr++;
                    ctr %= words.length;
                } else {
                    Snackbar.make(view, "Speaker not ready", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                }
            }
        });

    }
}

What is extremely surprising is that only the words "ord" and "fotboll" are spoken, but not "kula". If I change words to {"kula", "kula", "kula"} and try long enough, it suddenly starts to work. As I have understood the documentation one should use the tags here. I have tried se, swe, sv, all with same result. Further, the command System.out.println(textToSpeech.getLanguage().getDisplayLanguage()); gives svenska which is correct.

If I change to en it works all the time. Also I get System.out.println(textToSpeech.getLanguage().getDisplayLanguage()); = engelska again correct.

What on earth is going on?

EDIT:

I have added a UtteranceProgressListener, according to this, the method

onError(String id) is deprecated and should be replaced by onError(String id, int errorCode). However, I have extended my class with UtteranceProgressListener and it forces me to implement the old onError method. This is always called, so something is wrong but I do not know what.

This is because the other onError(String id, int code) is never called.

I have updated the code.


I have a function that is supposed to speak a word in a specific language when the function is called.

Until for a couple of days ago it worked fine in my Sony Compact XZ2, but now it is irregular. Sometimes the word is spoken and sometimes not. The command textToSpeech.getEngines() returns com.google.android.tts

For example for Swedish, in setLanguage, I have tried "sv" and "sv-SV" when I create the Locale object. That has not helped.

I just noticed that when I press the button that calls playWord(text) a bunch of times ( > 40) it works and sometimes it works directly. Seems to be some strange delay.

The function speakText is called from this function in my Fragment:

private void playWord(){
    if (text2Speech.isReady()) {
        text2Speech.checkSpeaking();
        text2Speech.setLanguage(getAcronym(mTraining.getCurrentSrc()));
        text2Speech.speakText(front);
    } else {
        Toast.makeText(getContext(),"Speaker not ready yet", Toast.LENGTH_SHORT).show();
    }
}

This is the class that handles the speaking. I have not obtained any error messages. It just seems random when the speaker works.

public class Text2Speech extends UtteranceProgressListener {
    private Context mContext;
    private TextToSpeech textToSpeech;
    private boolean isReady = false;
    public Text2Speech(Context context, final String src){
        mContext = context;
        System.out.println("text2Speech created");
        textToSpeech = new TextToSpeech(mContext, new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                if (status == TextToSpeech.SUCCESS) {
                    isReady = true;
                    Locale locale = new Locale(src);
                    int ttsLang = textToSpeech.setLanguage(locale);
                    if (ttsLang == TextToSpeech.LANG_MISSING_DATA
                            || ttsLang == TextToSpeech.LANG_NOT_SUPPORTED) {
                        Log.e("TTS", "The Language is not supported!");
                    } else {
                        Log.i("TTS", "Language Supported.");
                    }
                    Log.i("TTS", "Initialization success.");
                } else {
                    Toast.makeText(mContext, "TTS Initialization failed!", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    public boolean isReady(){
        return isReady;
    }
    public void checkSpeaking(){
        if (textToSpeech.isSpeaking()){
            textToSpeech.stop();
        }
    }

    public void showMessage(String msg){
        Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
    }
    public void speakText(String text){
        int speechStatus = textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null);
        switch (speechStatus){
            case TextToSpeech.ERROR_INVALID_REQUEST:
                showMessage("Invalid Request");
                break;
            case TextToSpeech.ERROR_NETWORK:
                showMessage("Network Error");
                break;
            case TextToSpeech.ERROR_NETWORK_TIMEOUT:
                showMessage("Network Timeout");
                break;
            case TextToSpeech.ERROR_NOT_INSTALLED_YET:
                showMessage("Error Not Yet Downloaded");
                break;
            case TextToSpeech.ERROR_OUTPUT:
                showMessage("Output Error");
                break;
            case TextToSpeech.ERROR_SERVICE:
                showMessage("Error of TTS service");
                break;
            case TextToSpeech.ERROR_SYNTHESIS:
                showMessage("Error synthesizing");
                break;
            case TextToSpeech.LANG_NOT_SUPPORTED:
                showMessage("Language nor supported");
                break;

        }
        if (speechStatus == TextToSpeech.ERROR) {
            Log.e("TTS", "Error in converting Text to Speech!");
        }
        System.out.println("speech status - text " + speechStatus + " - " + text);
    }

    public void setLanguage(String src){
        Locale locale = new Locale(src);
        int tts = textToSpeech.setLanguage(locale);
        System.out.println(tts + "  " + src);
        if (tts == TextToSpeech.LANG_MISSING_DATA
                || tts == TextToSpeech.LANG_NOT_SUPPORTED) {
            Toast.makeText(mContext, "Language not yet supported.", Toast.LENGTH_LONG).show();
        }
    }

    public void stop(){
        textToSpeech.stop();
        textToSpeech.shutdown();
    }

@Override
public void onStart(String utteranceId) {
    Log.e("START", "start speaking");
}

@Override
public void onDone(String utteranceId) {
    Log.e("DONE", "done speaking");
}

@Override
public void onError(String utteranceID){
    Log.e("Error", "Not infromative");
}

// This is not called!
@Override
public void onError(String utteranceId, int errorCode) {
    Log.e("Error", "Error speaking");
}
}

Here is the error message in the Logcat:

NetworkSynthesizer: ExecutionException during NetworkFetchTask
    java.util.concurrent.ExecutionException: clx: RESOURCE_EXHAUSTED: Quota exceeded for quota metric 's3-sessions' and limit 's3-session-limit' of service 'speechs3proto2-pa.googleapis.com' for consumer 'project_number:529030122437'.
        at java.util.concurrent.FutureTask.report(FutureTask.java:123)
        at java.util.concurrent.FutureTask.get(FutureTask.java:207)
        at avf.a(PG:37)
        at avf.a(PG:154)
        at com.google.android.tts.service.GoogleTTSService.onSynthesizeText(PG:250)
        at android.speech.tts.TextToSpeechService$SynthesisSpeechItem.playImpl(TextToSpeechService.java:1033)
        at android.speech.tts.TextToSpeechService$SpeechItem.play(TextToSpeechService.java:819)
        at android.speech.tts.TextToSpeechService$SynthHandler$1.run(TextToSpeechService.java:583)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:280)
        at android.os.HandlerThread.run(HandlerThread.java:65)
     Caused by: clx: RESOURCE_EXHAUSTED: Quota exceeded for quota metric 's3-sessions' and limit 's3-session-limit' of service 'speechs3proto2-pa.googleapis.com' for consumer 'project_number:529030122437'.
        at cze.a(PG:58)
        at cze.a(PG:29)
        at dao.a(PG:21)
        at ave.a(PG:36)
        at ave.call(PG:80)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)
2019-03-16 21:35:46.917 1356-5238/? E/ActivityManager: Sending non-protected broadcast com.sonymobile.intent.action.POWER_BACK_OFF_FACTOR_CHANGED from system 2179:com.android.phone/1001 pkg com.android.phone
    java.lang.Throwable
        at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:21814)
        at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:22423)
        at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:22565)
        at android.app.IActivityManager$Stub.onTransact$broadcastIntent$(IActivityManager.java:10171)
        at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:167)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3416)
        at android.os.Binder.execTransact(Binder.java:731)
2019-03-16 21:35:46.917 12061-13318/? E/TTS.GoogleTTSServiceImp: Synthesis failure with error status code: -4
2019-03-16 21:35:46.918 12061-13318/? W/PlaybackSynthesisRequest: done() was called before start() call
2019-03-16 21:35:46.919 6468-6489/com.erikbylow.tailoreddictfire D/SPEECH: Error

When I turn WiFi on, it works.

Speculation: Can it be that the languages were missing and not downloaded when I did not use WiFi? When I turned WiFi on, the languages were downloaded?

To me this error: clx: RESOURCE_EXHAUSTED: Quota exceeded for quota metric... looks like there was always a network request, but after turning WiFi on, I could use TextToSpeach in flight mode.

On the other hand, I tried it woth russian in flight mode, that did not work. I turned internet on without WiFi, then it worked. Turned WiFi on again and then Russian worked as well. At least this suggests something needed to be downloaded?

I would like to find out what causes the problem and how to solve it since it is an app on Google Play. (Although I currently have exactly 0 active users beside me...) :).

El_Loco
  • 1,716
  • 4
  • 20
  • 35
  • I think you could track the problem down with log statements. – Nerdy Bunz Mar 11 '19 at 22:31
  • That is what I am trying to do with the UtteranceProgressListener, but that does not return any error codes, on my physical device. – El_Loco Mar 12 '19 at 08:14
  • Yes, but *something* is different between the situations where it works and when it doesn't. You could also try building an extremely simple (as simple as humanly possible) project that speaks a word when you press a button. You will probably find that it works fine... so then you know the problem exists somewhere in between. – Nerdy Bunz Mar 12 '19 at 21:22
  • Also... I don't think it's necessary to check isSpeaking because QUEUE_FLUSH will automatically interrupt and restart the speech in progress... that could be the issue. – Nerdy Bunz Mar 12 '19 at 21:23
  • Yes, I have done that and that seems to work fine. It would help if the `OnUtteranceListener` returned an error code. – El_Loco Mar 12 '19 at 21:25
  • 1
    The reason it doesn't return an error code is because whatever speech engine is on that Sony device was coded prior to the Android API where that method was introduced... they can't use a method that didn't exist yet... or they just decided not to use it. – Nerdy Bunz Mar 12 '19 at 21:28
  • It did not work fine when I reduced the problem and started a new activity. – El_Loco Mar 13 '19 at 21:48
  • Well if that is the case, then it would seem the problem is out of your control / not your fault. You could post a new question with the reduced code, though. – Nerdy Bunz Mar 13 '19 at 22:36
  • I found some info in the logcat, when I turn WiFi on, it works perfectly. – El_Loco Mar 16 '19 at 20:58
  • Ah yes.. that's because the google tts engine does a lot of things in the background on the network, but tries to hide it. So does this new finding mean your question is resolved? If not, you may find these answers helpful: https://stackoverflow.com/questions/8573030/using-tts-on-android-punctuation-is-read-aloud, https://stackoverflow.com/questions/50962724/how-to-predict-failure-of-google-text-to-speech, https://stackoverflow.com/questions/51510129/android-text-to-speech-api-sounds-robotic – Nerdy Bunz Mar 16 '19 at 21:57
  • It works, but I have not changed anything. I have checked which TTS engine is loaded and that is always Google's. What does this "Quota exceeded for quota metric 's3-sessions' and limit 's3-session-limit" mean? Seems like a network request. I have tried in flight mode now and that also works. – El_Loco Mar 17 '19 at 08:29

1 Answers1

0

Just to give some closure: This was an Android Framework Bug that has been closed with Android 12 (API 31). See also my referenced Bug Ticket: https://issuetracker.google.com/issues/138321382?pli=1

Bernd Kampl
  • 4,837
  • 4
  • 21
  • 26