2012-08-02 9 views
18

Mi aplicación de Android tiene función de texto para hablar y más de una actividad usa esta característica. Así que creó una clase de ayuda estática para hacer esto fácil.Android "ha fallado: no está vinculado al motor de tts"

import java.util.Locale; 

import android.content.Context; 
import android.speech.tts.TextToSpeech; 
import android.speech.tts.TextToSpeech.OnInitListener; 
import android.util.Log; 

public class TextToSpeechController implements OnInitListener { 

    private static final String TAG = "TextToSpeechController"; 
    private TextToSpeech myTTS; 
    private String textToSpeak; 
    private Context context; 

    private static TextToSpeechController singleton; 

    public static TextToSpeechController getInstance(Context ctx) { 
     if (singleton == null) 
      singleton = new TextToSpeechController(ctx); 
     return singleton; 
    } 

    private TextToSpeechController(Context ctx) { 
     context = ctx; 
    } 

    public void speak(String text) { 
     textToSpeak = text; 

     if (myTTS == null) { 
      // currently can't change Locale until speech ends 
      try { 
       // Initialize text-to-speech. This is an asynchronous operation. 
       // The OnInitListener (second argument) is called after 
       // initialization completes. 
       myTTS = new TextToSpeech(context, this); 

      } catch (Exception e) {    
       e.printStackTrace(); 
      } 
     } 

     sayText(); 

    } 

    public void onInit(int initStatus) { 
     if (initStatus == TextToSpeech.SUCCESS) { 
      if (myTTS.isLanguageAvailable(Locale.UK) == TextToSpeech.LANG_AVAILABLE) 
       myTTS.setLanguage(Locale.UK); 
     } 

     // status can be either TextToSpeech.SUCCESS or TextToSpeech.ERROR. 
     if (initStatus == TextToSpeech.SUCCESS) { 
      int result = myTTS.setLanguage(Locale.UK); 
      if (result == TextToSpeech.LANG_MISSING_DATA 
        || result == TextToSpeech.LANG_NOT_SUPPORTED) { 
       Log.e(TAG, "TTS missing or not supported (" + result + ")"); 
       // Language data is missing or the language is not supported. 
       // showError(R.string.tts_lang_not_available); 

      } else { 
       // Initialization failed. 
       Log.e(TAG, "Error occured"); 
      } 

     } 
    } 

    private void sayText() { 
     // ask TTs to say the text 
     myTTS.speak(this.textToSpeak, TextToSpeech.QUEUE_FLUSH,  null); 
    } 

    public void stopTTS() { 
     if (myTTS != null) { 
      myTTS.shutdown(); 
      myTTS.stop(); 
      myTTS = null; 
     } 
    } 

} 

estoy usando esta clase de ayuda como este.

TextToSpeechController.getInstance(this).speak(readableMessage); 

Pero a veces veo un error como beloew línea en LogCat.

"speak:failed not bound to tts engine" 

Ninguna excepción arrojado pero nada leído por TTS. Me di cuenta de que si activaba la actividad de BroadcastReceiver, obtuve este error. De lo contrario, si la actividad de apertura manual del código de la aplicación funciona sin problemas.

Este es el código BroadcastReceiver

private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);    
     String readableMessage = intent.getExtras().getString(READABLE_MESSAGE);  

     Bundle b = new Bundle(); 
     b.putString(EXTRA_MESSAGE, newMessage); 
     b.putString(READABLE_MESSAGE, readableMessage); 
     Intent newIntent = new Intent("android.intent.action.MAIN"); 
     newIntent.setClass(context, Speak.class); 
     newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 
     newIntent.putExtra("MessageReceived", b); 
     newIntent.putExtra("CallType", CallType.NOTIFICATION); 
     context.startActivity(newIntent);   
    } 
}; 

Respuesta

6

El código no está esperando el regreso asynch desde el constructor de la clase de síntesis de voz. Incluso tiene un comentario que dice que es asincrónico. Por qué siempre falla en el Receptor, pero no en la Actividad. No estoy seguro. Luego, tal vez la Actividad como una tarea en primer plano tenga una prioridad más alta y se complete antes de llamar a decirTexto.

Debe esperar para llamar a sayText hasta que la llamada init regrese en caso de que tenga que actualizar un nuevo objeto TTS.

+0

Entonces, ¿cómo puedo hacer esto? Thread.Sleep? No sé cómo puedo decir, espera hasta que termine el discurso. –

+0

Hola. ¿Podemos comenzar este hilo TTS en paralelo? –

3

Aquí está el código que uso para texto a voz. Para mi código simplemente escriba speakWords ("decir algo"); en cualquier actividad.

public class VoiceRecognition extends Activity implements OnClickListener, 
     OnInitListener { 

    public static final int VOICE_RECOGNITION_REQUEST_CODE = 1234; 

    public Button speakButton; 
    // TTS object 
    public TextToSpeech myTTS; 
    // status check code 
    public int MY_DATA_CHECK_CODE = 0; 

    // setup TTS 
    public void onInit(int initStatus) { 

     // check for successful instantiation 
     if (initStatus == TextToSpeech.SUCCESS) { 
      if (myTTS.isLanguageAvailable(Locale.US) == TextToSpeech.LANG_AVAILABLE) 
       myTTS.setLanguage(Locale.US); 
     } else if (initStatus == TextToSpeech.ERROR) { 
      Toast.makeText(this, "Sorry! Text To Speech failed...", 
        Toast.LENGTH_LONG).show(); 
     } 
    } 

    /** 
    * Called with the activity is first created. 
    */ 
    @Override 
    public void onCreate(Bundle voiceinput) { 
     super.onCreate(voiceinput); 

     // Inflate our UI from its XML layout description. 
     setContentView(R.layout.voice_recognition); 

     // check for TTS data 
     Intent checkTTSIntent = new Intent(); 
     checkTTSIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA); 
     startActivityForResult(checkTTSIntent, MY_DATA_CHECK_CODE); 

    } 

    // speak the user text 
    public void speakWords(String speech) { 

     // speak straight away 
     myTTS.speak(speech, TextToSpeech.QUEUE_FLUSH, null); 
    } 


    public void onClick(View v) { 
     speakWords("hello"; 
    } 


    /** 
    * Handle the results from the recognition activity. 
    */ 
    @Override 
    public void onActivityResult(int requestCode, int resultCode, Intent data) { 

     if (requestCode == MY_DATA_CHECK_CODE) { 
      if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { 
       // the user has the necessary data - create the TTS 
       myTTS = new TextToSpeech(this, this); 
      } else { 
       // no data - install it now 
       Intent installTTSIntent = new Intent(); 
       installTTSIntent 
         .setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA); 
       startActivity(installTTSIntent); 
      } 
     } 

     super.onActivityResult(requestCode, resultCode, data); 

    } 

    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     myTTS.shutdown(); 
    } 
+0

Sé que probablemente prefiera arreglar su código pero creo que esto podría ser más simple de usar. Además, intente utilizar la sección onInit del código colocado encima del onCreate Bundle. Le salvará de errores futuros. \ –

+1

no hay ningún problema al implementar en la Actividad. Quiero crear un sistema TTS global –

Cuestiones relacionadas