2012-08-02 12 views
18

La mia applicazione Android ha funzionalità di sintesi vocale e più di un'attività utilizza questa funzionalità. Quindi ho creato una classe di helper statico per renderlo semplice.Android "speak failed: non vincolato al motore 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; 
     } 
    } 

} 

Sto usando questa classe di supporto come questa.

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

Ma a volte vedo un errore come la mancanza di righe in LogCat.

"speak:failed not bound to tts engine" 

Nessuna eccezione generata ma nulla letto da TTS. Mi sono reso conto che se ho attivato l'attività da BroadcastReceiver, ho ricevuto questo errore. Altrimenti se l'attività di apertura manuale dal codice dell'applicazione funziona senza problemi.

Ecco il codice 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);   
    } 
}; 

risposta

6

Il codice non è in attesa per il ritorno asincrono dal costruttore della classe TextToSpeech. Hai persino un commento che dice che è asincrono. Perché fallisce sempre nel ricevitore ma non nell'attività che non sono sicuro - altri quindi forse l'attività come attività in primo piano ha una priorità più alta e si verifica prima di chiamare sayText.

È necessario attendere per chiamare sayTesto fino a quando la chiamata di init non viene restituita nel caso in cui deve creare un nuovo oggetto TTS.

+0

così come posso fare questo? Thread.Sleep? Non so come posso dire, aspetta finchè non si parla. –

+0

Ciao. Possiamo iniziare questo thread TTS in parallelo? –

3

Questo è il codice che utilizzo per il text to speech. Per il mio codice basta digitare speakWords ("say something"); in ogni attività.

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

So che probabilmente preferiresti risolvere il tuo codice ma penso che potrebbe essere più semplice da usare. Inoltre, prova a utilizzare la sezione del codice onInit posta sopra il pacchetto onCreate. Ti farà risparmiare dagli errori futuri. \ –

+1

non ci sono problemi durante l'implementazione su Activity. Voglio creare un sistema TTS globale –

Problemi correlati