5
votes

I am using a simple code to use Text-To-Speech:

package ch.yourclick.kitt.fragments;

import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import java.util.Locale;
import ch.yourclick.kitt.R;

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link GeneralFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class GeneralFragment extends Fragment {
    private TextToSpeech tts;

    public GeneralFragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @return A new instance of fragment General.
     */
    // TODO: Rename and change types and number of parameters
    public static GeneralFragment newInstance() {
        GeneralFragment fragment = new GeneralFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_general, container, false);
        Button hello = view.findViewById(R.id.hello);

        // Text to speech
        tts = new TextToSpeech(getActivity(), new TextToSpeech.OnInitListener() {
            @Override
            public void onInit(int status) {
                if (status == TextToSpeech.SUCCESS) { // <-- I never get into that if statement
                    int result = tts.setLanguage(Locale.getDefault());
                    // Language is not supported
                    if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                        Log.e("TTS", "Language not supported");
                    }
                }
                else {
                    Log.e("TTS", "" + status); // Returns -1
                    Log.e("TTS", "" + TextToSpeech.SUCCESS); // Returns 0
                }
            }
        });

        hello.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                speak();
            }
        });
        return view;
    }

    /**
     * Speak
     */
    private void speak() {
        String text = "Hello";
        tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
    }

    /**
     * Turn off
     */
    @Override
    public void onDestroy() {
        if (tts != null) {
            tts.stop();
            tts.shutdown();
        }
        super.onDestroy();
    }
}

I get the message:

W/TextToSpeech: speak failed: not bound to TTS engine

My problem is that Text To Speech cannot be initialized:

status returns -1 and TextToSpeech.SUCCESS returns 0.

I am using Android Studio and my virtual device is Pixel 2 API 30. So Google Text-to-speech Engine seems to be installed on it:

enter image description here

Settings -> Accessibility -> Text-to-speech output

If I click on Play, I hear a voice and so I know that it should not be a device issue. But why is it not working on my application? I do not get any errors on it.

I have no idea what I am doing wrong. If you know the answer or have any advice on what it could be, please let me know!

3
it would probably be better to simply edit the original question rather than posting subsequent questions. (I'm also interested in the answer). - Nerdy Bunz
@NerdyBunz I have deleted my other question. - xRay
I tested your code in original device and it's working. Maybe the problem is only with the emulator. - cgb_pandey
before executing speak() function try to check if tts != null && tts != speaking and rather move your tts initialization code on onActivityCreated block and intstead of passing getActivity() in 1st tts constructor parameter pass requireActivity(). - Amanth Rai

3 Answers

3
votes

Google says "Apps targeting Android 11 that use text-to-speech should declare TextToSpeech.Engine#INTENT_ACTION_TTS_SERVICE in the queries elements of their manifest:"

So add this to your AndroidManifest.xml:

<queries>
    <intent>
        <action android:name="android.intent.action.TTS_SERVICE" />
    </intent>
</queries>

Adding this before <application tag worked for me. (Android Studio says Element queries is not allowed here though).

0
votes

As said by the log "not bound to TTS engine". On my side it was just deactivate and that was the reason that it couldn't bound to TTS engine. See my answer in another thread, there

0
votes

speak failed: not bound to TTS engine
This maybe not an error, just print an ordinary log.

But if this log appears, the voice announcement maybe cannot be performed

After searching for information, I found that the way to solve this reason is: Over-write voice play function in the onInit method that implements the OnInitListener interface:

@Override
public void onInit(int status) {
            textToSpeech.setSpeechRate(speechRate);
            textToSpeech.setPitch(pitch);
            textToSpeech.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}

By this way you can avoid the error of speak failed: not bound to TTS engine