TextToSpeech.java revision def7185cf19d48c95b50c2b83503d5cd21a613bf
1/*
2 * Copyright (C) 2009 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16package android.speech.tts;
17
18import android.speech.tts.ITts;
19import android.speech.tts.ITtsCallback;
20
21import android.annotation.SdkConstant;
22import android.annotation.SdkConstant.SdkConstantType;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.content.ServiceConnection;
27import android.media.AudioManager;
28import android.os.IBinder;
29import android.os.RemoteException;
30import android.util.Log;
31
32import java.util.HashMap;
33import java.util.Locale;
34
35/**
36 *
37 * Synthesizes speech from text for immediate playback or to create a sound file.
38 * <p>A TextToSpeech instance can only be used to synthesize text once it has completed its
39 * initialization. Implement the {@link TextToSpeech.OnInitListener} to be
40 * notified of the completion of the initialization.<br>
41 * When you are done using the TextToSpeech instance, call the {@link #shutdown()} method
42 * to release the native resources used by the TextToSpeech engine.
43 *
44 */
45public class TextToSpeech {
46
47    /**
48     * Denotes a successful operation.
49     */
50    public static final int SUCCESS                = 0;
51    /**
52     * Denotes a generic operation failure.
53     */
54    public static final int ERROR                  = -1;
55
56    /**
57     * Queue mode where all entries in the playback queue (media to be played
58     * and text to be synthesized) are dropped and replaced by the new entry.
59     */
60    public static final int QUEUE_FLUSH = 0;
61    /**
62     * Queue mode where the new entry is added at the end of the playback queue.
63     */
64    public static final int QUEUE_ADD = 1;
65
66
67    /**
68     * Denotes the language is available exactly as specified by the locale.
69     */
70    public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
71
72
73    /**
74     * Denotes the language is available for the language and country specified
75     * by the locale, but not the variant.
76     */
77    public static final int LANG_COUNTRY_AVAILABLE = 1;
78
79
80    /**
81     * Denotes the language is available for the language by the locale,
82     * but not the country and variant.
83     */
84    public static final int LANG_AVAILABLE = 0;
85
86    /**
87     * Denotes the language data is missing.
88     */
89    public static final int LANG_MISSING_DATA = -1;
90
91    /**
92     * Denotes the language is not supported.
93     */
94    public static final int LANG_NOT_SUPPORTED = -2;
95
96
97    /**
98     * Broadcast Action: The TextToSpeech synthesizer has completed processing
99     * of all the text in the speech queue.
100     */
101    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
102    public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
103            "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
104
105
106    /**
107     * Interface definition of a callback to be invoked indicating the completion of the
108     * TextToSpeech engine initialization.
109     */
110    public interface OnInitListener {
111        /**
112         * Called to signal the completion of the TextToSpeech engine initialization.
113         * @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
114         */
115        public void onInit(int status);
116    }
117
118    /**
119     * Interface definition of a callback to be invoked indicating the TextToSpeech engine has
120     * completed synthesizing an utterance with an utterance ID set.
121     *
122     */
123    public interface OnUtteranceCompletedListener {
124        /**
125         * Called to signal the completion of the synthesis of the utterance that was identified
126         * with the string parameter. This identifier is the one originally passed in the
127         * parameter hashmap of the synthesis request in
128         * {@link TextToSpeech#speak(String, int, HashMap)} or
129         * {@link TextToSpeech#synthesizeToFile(String, HashMap, String)} with the
130         * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID} key.
131         * @param utteranceId the identifier of the utterance.
132         */
133        public void onUtteranceCompleted(String utteranceId);
134    }
135
136
137    /**
138     * Internal constants for the TextToSpeech functionality
139     *
140     */
141    public class Engine {
142        // default values for a TTS engine when settings are not found in the provider
143        /**
144         * {@hide}
145         */
146        public static final int DEFAULT_RATE = 100; // 1x
147        /**
148         * {@hide}
149         */
150        public static final int DEFAULT_PITCH = 100;// 1x
151        /**
152         * {@hide}
153         */
154        public static final int USE_DEFAULTS = 0; // false
155        /**
156         * {@hide}
157         */
158        public static final String DEFAULT_SYNTH = "com.svox.pico";
159
160        // default values for rendering
161        /**
162         * Default audio stream used when playing synthesized speech.
163         */
164        public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
165
166        // return codes for a TTS engine's check data activity
167        /**
168         * Indicates success when checking the installation status of the resources used by the
169         * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
170         */
171        public static final int CHECK_VOICE_DATA_PASS = 1;
172        /**
173         * Indicates failure when checking the installation status of the resources used by the
174         * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
175         */
176        public static final int CHECK_VOICE_DATA_FAIL = 0;
177        /**
178         * Indicates erroneous data when checking the installation status of the resources used by
179         * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
180         */
181        public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
182        /**
183         * Indicates missing resources when checking the installation status of the resources used
184         * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
185         */
186        public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
187        /**
188         * Indicates missing storage volume when checking the installation status of the resources
189         * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
190         */
191        public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
192
193        // intents to ask engine to install data or check its data
194        /**
195         * Activity Action: Triggers the platform TextToSpeech engine to
196         * start the activity that installs the resource files on the device
197         * that are required for TTS to be operational. Since the installation
198         * of the data can be interrupted or declined by the user, the application
199         * shouldn't expect successful installation upon return from that intent,
200         * and if need be, should check installation status with
201         * {@link #ACTION_CHECK_TTS_DATA}.
202         */
203        @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
204        public static final String ACTION_INSTALL_TTS_DATA =
205                "android.speech.tts.engine.INSTALL_TTS_DATA";
206
207        /**
208         * Broadcast Action: broadcast to signal the completion of the installation of
209         * the data files used by the synthesis engine. Success or failure is indicated in the
210         * {@link #EXTRA_TTS_DATA_INSTALLED} extra.
211         */
212        @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
213        public static final String ACTION_TTS_DATA_INSTALLED =
214                "android.speech.tts.engine.TTS_DATA_INSTALLED";
215        /**
216         * Activity Action: Starts the activity from the platform TextToSpeech
217         * engine to verify the proper installation and availability of the
218         * resource files on the system. Upon completion, the activity will
219         * return one of the following codes:
220         * {@link #CHECK_VOICE_DATA_PASS},
221         * {@link #CHECK_VOICE_DATA_FAIL},
222         * {@link #CHECK_VOICE_DATA_BAD_DATA},
223         * {@link #CHECK_VOICE_DATA_MISSING_DATA}, or
224         * {@link #CHECK_VOICE_DATA_MISSING_VOLUME}.
225         * <p> Moreover, the data received in the activity result will contain the following
226         * fields:
227         * <ul>
228         *   <li>{@link #EXTRA_VOICE_DATA_ROOT_DIRECTORY} which
229         *       indicates the path to the location of the resource files,</li>
230         *   <li>{@link #EXTRA_VOICE_DATA_FILES} which contains
231         *       the list of all the resource files,</li>
232         *   <li>and {@link #EXTRA_VOICE_DATA_FILES_INFO} which
233         *       contains, for each resource file, the description of the language covered by
234         *       the file in the xxx-YYY format, where xxx is the 3-letter ISO language code,
235         *       and YYY is the 3-letter ISO country code.</li>
236         * </ul>
237         */
238        @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
239        public static final String ACTION_CHECK_TTS_DATA =
240                "android.speech.tts.engine.CHECK_TTS_DATA";
241
242        // extras for a TTS engine's check data activity
243        /**
244         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
245         * the TextToSpeech engine specifies the path to its resources.
246         */
247        public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
248        /**
249         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
250         * the TextToSpeech engine specifies the file names of its resources under the
251         * resource path.
252         */
253        public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
254        /**
255         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
256         * the TextToSpeech engine specifies the locale associated with each resource file.
257         */
258        public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
259        /**
260         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
261         * the TextToSpeech engine returns an ArrayList<String> of all the available voices.
262         * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
263         * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
264         * {@hide}
265         */
266        public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
267        /**
268         * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
269         * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices.
270         * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
271         * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
272         * {@hide}
273         */
274        public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
275        /**
276         * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the
277         * caller indicates to the TextToSpeech engine which specific sets of voice data to
278         * check for by sending an ArrayList<String> of the voices that are of interest.
279         * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are
280         * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
281         * {@hide}
282         */
283        public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor";
284
285        // extras for a TTS engine's data installation
286        /**
287         * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent.
288         * It indicates whether the data files for the synthesis engine were successfully
289         * installed. The installation was initiated with the  {@link #ACTION_INSTALL_TTS_DATA}
290         * intent. The possible values for this extra are
291         * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}.
292         */
293        public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled";
294
295        // keys for the parameters passed with speak commands. Hidden keys are used internally
296        // to maintain engine state for each TextToSpeech instance.
297        /**
298         * {@hide}
299         */
300        public static final String KEY_PARAM_RATE = "rate";
301        /**
302         * {@hide}
303         */
304        public static final String KEY_PARAM_LANGUAGE = "language";
305        /**
306         * {@hide}
307         */
308        public static final String KEY_PARAM_COUNTRY = "country";
309        /**
310         * {@hide}
311         */
312        public static final String KEY_PARAM_VARIANT = "variant";
313        /**
314         * {@hide}
315         */
316        public static final String KEY_PARAM_ENGINE = "engine";
317        /**
318         * Parameter key to specify the audio stream type to be used when speaking text
319         * or playing back a file.
320         * @see TextToSpeech#speak(String, int, HashMap)
321         * @see TextToSpeech#playEarcon(String, int, HashMap)
322         */
323        public static final String KEY_PARAM_STREAM = "streamType";
324        /**
325         * Parameter key to identify an utterance in the
326         * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
327         * spoken, a file has been played back or a silence duration has elapsed.
328         * @see TextToSpeech#speak(String, int, HashMap)
329         * @see TextToSpeech#playEarcon(String, int, HashMap)
330         * @see TextToSpeech#synthesizeToFile(String, HashMap, String)
331         */
332        public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
333
334        // key positions in the array of cached parameters
335        /**
336         * {@hide}
337         */
338        protected static final int PARAM_POSITION_RATE = 0;
339        /**
340         * {@hide}
341         */
342        protected static final int PARAM_POSITION_LANGUAGE = 2;
343        /**
344         * {@hide}
345         */
346        protected static final int PARAM_POSITION_COUNTRY = 4;
347        /**
348         * {@hide}
349         */
350        protected static final int PARAM_POSITION_VARIANT = 6;
351        /**
352         * {@hide}
353         */
354        protected static final int PARAM_POSITION_STREAM = 8;
355        /**
356         * {@hide}
357         */
358        protected static final int PARAM_POSITION_UTTERANCE_ID = 10;
359
360        /**
361         * {@hide}
362         */
363        protected static final int PARAM_POSITION_ENGINE = 12;
364
365        /**
366         * {@hide}
367         */
368        protected static final int NB_CACHED_PARAMS = 7;
369    }
370
371    /**
372     * Connection needed for the TTS.
373     */
374    private ServiceConnection mServiceConnection;
375
376    private ITts mITts = null;
377    private ITtsCallback mITtscallback = null;
378    private Context mContext = null;
379    private String mPackageName = "";
380    private OnInitListener mInitListener = null;
381    private boolean mStarted = false;
382    private final Object mStartLock = new Object();
383    /**
384     * Used to store the cached parameters sent along with each synthesis request to the
385     * TTS service.
386     */
387    private String[] mCachedParams;
388
389    /**
390     * The constructor for the TextToSpeech class.
391     * This will also initialize the associated TextToSpeech engine if it isn't already running.
392     *
393     * @param context
394     *            The context this instance is running in.
395     * @param listener
396     *            The {@link TextToSpeech.OnInitListener} that will be called when the
397     *            TextToSpeech engine has initialized.
398     */
399    public TextToSpeech(Context context, OnInitListener listener) {
400        mContext = context;
401        mPackageName = mContext.getPackageName();
402        mInitListener = listener;
403
404        mCachedParams = new String[2*Engine.NB_CACHED_PARAMS]; // store key and value
405        mCachedParams[Engine.PARAM_POSITION_RATE] = Engine.KEY_PARAM_RATE;
406        mCachedParams[Engine.PARAM_POSITION_LANGUAGE] = Engine.KEY_PARAM_LANGUAGE;
407        mCachedParams[Engine.PARAM_POSITION_COUNTRY] = Engine.KEY_PARAM_COUNTRY;
408        mCachedParams[Engine.PARAM_POSITION_VARIANT] = Engine.KEY_PARAM_VARIANT;
409        mCachedParams[Engine.PARAM_POSITION_STREAM] = Engine.KEY_PARAM_STREAM;
410        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID] = Engine.KEY_PARAM_UTTERANCE_ID;
411        mCachedParams[Engine.PARAM_POSITION_ENGINE] = Engine.KEY_PARAM_ENGINE;
412
413        // Leave all defaults that are shown in Settings uninitialized so that
414        // the values set in Settings will take effect if the application does
415        // not try to change these settings itself.
416        mCachedParams[Engine.PARAM_POSITION_RATE + 1] = "";
417        mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = "";
418        mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = "";
419        mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = "";
420        mCachedParams[Engine.PARAM_POSITION_STREAM + 1] =
421                String.valueOf(Engine.DEFAULT_STREAM);
422        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = "";
423        mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = "";
424
425        initTts();
426    }
427
428
429    private void initTts() {
430        mStarted = false;
431
432        // Initialize the TTS, run the callback after the binding is successful
433        mServiceConnection = new ServiceConnection() {
434            public void onServiceConnected(ComponentName name, IBinder service) {
435                synchronized(mStartLock) {
436                    mITts = ITts.Stub.asInterface(service);
437                    mStarted = true;
438                    if (mInitListener != null) {
439                        // TODO manage failures and missing resources
440                        mInitListener.onInit(SUCCESS);
441                    }
442                }
443            }
444
445            public void onServiceDisconnected(ComponentName name) {
446                synchronized(mStartLock) {
447                    mITts = null;
448                    mInitListener = null;
449                    mStarted = false;
450                }
451            }
452        };
453
454        Intent intent = new Intent("android.intent.action.START_TTS_SERVICE");
455        intent.addCategory("android.intent.category.TTS");
456        mContext.bindService(intent, mServiceConnection,
457                Context.BIND_AUTO_CREATE);
458        // TODO handle case where the binding works (should always work) but
459        //      the plugin fails
460    }
461
462
463    /**
464     * Releases the resources used by the TextToSpeech engine.
465     * It is good practice for instance to call this method in the onDestroy() method of an Activity
466     * so the TextToSpeech engine can be cleanly stopped.
467     */
468    public void shutdown() {
469        try {
470            mContext.unbindService(mServiceConnection);
471        } catch (IllegalArgumentException e) {
472            // Do nothing and fail silently since an error here indicates that
473            // binding never succeeded in the first place.
474        }
475    }
476
477
478    /**
479     * Adds a mapping between a string of text and a sound resource in a
480     * package. After a call to this method, subsequent calls to
481     * {@link #speak(String, int, HashMap)} will play the specified sound resource
482     * if it is available, or synthesize the text it is missing.
483     *
484     * @param text
485     *            The string of text. Example: <code>"south_south_east"</code>
486     *
487     * @param packagename
488     *            Pass the packagename of the application that contains the
489     *            resource. If the resource is in your own application (this is
490     *            the most common case), then put the packagename of your
491     *            application here.<br/>
492     *            Example: <b>"com.google.marvin.compass"</b><br/>
493     *            The packagename can be found in the AndroidManifest.xml of
494     *            your application.
495     *            <p>
496     *            <code>&lt;manifest xmlns:android=&quot;...&quot;
497     *      package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
498     *            </p>
499     *
500     * @param resourceId
501     *            Example: <code>R.raw.south_south_east</code>
502     *
503     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
504     */
505    public int addSpeech(String text, String packagename, int resourceId) {
506        synchronized(mStartLock) {
507            if (!mStarted) {
508                return ERROR;
509            }
510            try {
511                mITts.addSpeech(mPackageName, text, packagename, resourceId);
512                return SUCCESS;
513            } catch (RemoteException e) {
514                // TTS died; restart it.
515                Log.e("TextToSpeech.java - addSpeech", "RemoteException");
516                e.printStackTrace();
517                mStarted = false;
518                initTts();
519            } catch (NullPointerException e) {
520                // TTS died; restart it.
521                Log.e("TextToSpeech.java - addSpeech", "NullPointerException");
522                e.printStackTrace();
523                mStarted = false;
524                initTts();
525            } catch (IllegalStateException e) {
526                // TTS died; restart it.
527                Log.e("TextToSpeech.java - addSpeech", "IllegalStateException");
528                e.printStackTrace();
529                mStarted = false;
530                initTts();
531            }
532            return ERROR;
533        }
534    }
535
536
537    /**
538     * Adds a mapping between a string of text and a sound file. Using this, it
539     * is possible to add custom pronounciations for a string of text.
540     * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)}
541     * will play the specified sound resource if it is available, or synthesize the text it is
542     * missing.
543     *
544     * @param text
545     *            The string of text. Example: <code>"south_south_east"</code>
546     * @param filename
547     *            The full path to the sound file (for example:
548     *            "/sdcard/mysounds/hello.wav")
549     *
550     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
551     */
552    public int addSpeech(String text, String filename) {
553        synchronized (mStartLock) {
554            if (!mStarted) {
555                return ERROR;
556            }
557            try {
558                mITts.addSpeechFile(mPackageName, text, filename);
559                return SUCCESS;
560            } catch (RemoteException e) {
561                // TTS died; restart it.
562                Log.e("TextToSpeech.java - addSpeech", "RemoteException");
563                e.printStackTrace();
564                mStarted = false;
565                initTts();
566            } catch (NullPointerException e) {
567                // TTS died; restart it.
568                Log.e("TextToSpeech.java - addSpeech", "NullPointerException");
569                e.printStackTrace();
570                mStarted = false;
571                initTts();
572            } catch (IllegalStateException e) {
573                // TTS died; restart it.
574                Log.e("TextToSpeech.java - addSpeech", "IllegalStateException");
575                e.printStackTrace();
576                mStarted = false;
577                initTts();
578            }
579            return ERROR;
580        }
581    }
582
583
584    /**
585     * Adds a mapping between a string of text and a sound resource in a
586     * package. Use this to add custom earcons.
587     *
588     * @see #playEarcon(String, int, HashMap)
589     *
590     * @param earcon The name of the earcon.
591     *            Example: <code>"[tick]"</code><br/>
592     *
593     * @param packagename
594     *            the package name of the application that contains the
595     *            resource. This can for instance be the package name of your own application.
596     *            Example: <b>"com.google.marvin.compass"</b><br/>
597     *            The package name can be found in the AndroidManifest.xml of
598     *            the application containing the resource.
599     *            <p>
600     *            <code>&lt;manifest xmlns:android=&quot;...&quot;
601     *      package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
602     *            </p>
603     *
604     * @param resourceId
605     *            Example: <code>R.raw.tick_snd</code>
606     *
607     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
608     */
609    public int addEarcon(String earcon, String packagename, int resourceId) {
610        synchronized(mStartLock) {
611            if (!mStarted) {
612                return ERROR;
613            }
614            try {
615                mITts.addEarcon(mPackageName, earcon, packagename, resourceId);
616                return SUCCESS;
617            } catch (RemoteException e) {
618                // TTS died; restart it.
619                Log.e("TextToSpeech.java - addEarcon", "RemoteException");
620                e.printStackTrace();
621                mStarted = false;
622                initTts();
623            } catch (NullPointerException e) {
624                // TTS died; restart it.
625                Log.e("TextToSpeech.java - addEarcon", "NullPointerException");
626                e.printStackTrace();
627                mStarted = false;
628                initTts();
629            } catch (IllegalStateException e) {
630                // TTS died; restart it.
631                Log.e("TextToSpeech.java - addEarcon", "IllegalStateException");
632                e.printStackTrace();
633                mStarted = false;
634                initTts();
635            }
636            return ERROR;
637        }
638    }
639
640
641    /**
642     * Adds a mapping between a string of text and a sound file.
643     * Use this to add custom earcons.
644     *
645     * @see #playEarcon(String, int, HashMap)
646     *
647     * @param earcon
648     *            The name of the earcon.
649     *            Example: <code>"[tick]"</code>
650     * @param filename
651     *            The full path to the sound file (for example:
652     *            "/sdcard/mysounds/tick.wav")
653     *
654     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
655     */
656    public int addEarcon(String earcon, String filename) {
657        synchronized (mStartLock) {
658            if (!mStarted) {
659                return ERROR;
660            }
661            try {
662                mITts.addEarconFile(mPackageName, earcon, filename);
663                return SUCCESS;
664            } catch (RemoteException e) {
665                // TTS died; restart it.
666                Log.e("TextToSpeech.java - addEarcon", "RemoteException");
667                e.printStackTrace();
668                mStarted = false;
669                initTts();
670            } catch (NullPointerException e) {
671                // TTS died; restart it.
672                Log.e("TextToSpeech.java - addEarcon", "NullPointerException");
673                e.printStackTrace();
674                mStarted = false;
675                initTts();
676            } catch (IllegalStateException e) {
677                // TTS died; restart it.
678                Log.e("TextToSpeech.java - addEarcon", "IllegalStateException");
679                e.printStackTrace();
680                mStarted = false;
681                initTts();
682            }
683            return ERROR;
684        }
685    }
686
687
688    /**
689     * Speaks the string using the specified queuing strategy and speech
690     * parameters.
691     *
692     * @param text
693     *            The string of text to be spoken.
694     * @param queueMode
695     *            The queuing strategy to use.
696     *            {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
697     * @param params
698     *            The list of parameters to be used. Can be null if no parameters are given.
699     *            They are specified using a (key, value) pair, where the key can be
700     *            {@link Engine#KEY_PARAM_STREAM} or
701     *            {@link Engine#KEY_PARAM_UTTERANCE_ID}.
702     *
703     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
704     */
705    public int speak(String text, int queueMode, HashMap<String,String> params)
706    {
707        synchronized (mStartLock) {
708            int result = ERROR;
709            Log.i("TTS received: ", text);
710            if (!mStarted) {
711                return result;
712            }
713            try {
714                if ((params != null) && (!params.isEmpty())) {
715                    String extra = params.get(Engine.KEY_PARAM_STREAM);
716                    if (extra != null) {
717                        mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra;
718                    }
719                    extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID);
720                    if (extra != null) {
721                        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
722                    }
723                    extra = params.get(Engine.KEY_PARAM_ENGINE);
724                    if (extra != null) {
725                        mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = extra;
726                    }
727                }
728                result = mITts.speak(mPackageName, text, queueMode, mCachedParams);
729            } catch (RemoteException e) {
730                // TTS died; restart it.
731                Log.e("TextToSpeech.java - speak", "RemoteException");
732                e.printStackTrace();
733                mStarted = false;
734                initTts();
735            } catch (NullPointerException e) {
736                // TTS died; restart it.
737                Log.e("TextToSpeech.java - speak", "NullPointerException");
738                e.printStackTrace();
739                mStarted = false;
740                initTts();
741            } catch (IllegalStateException e) {
742                // TTS died; restart it.
743                Log.e("TextToSpeech.java - speak", "IllegalStateException");
744                e.printStackTrace();
745                mStarted = false;
746                initTts();
747            } finally {
748                resetCachedParams();
749                return result;
750            }
751        }
752    }
753
754
755    /**
756     * Plays the earcon using the specified queueing mode and parameters.
757     *
758     * @param earcon
759     *            The earcon that should be played
760     * @param queueMode
761     *            {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
762     * @param params
763     *            The list of parameters to be used. Can be null if no parameters are given.
764     *            They are specified using a (key, value) pair, where the key can be
765     *            {@link Engine#KEY_PARAM_STREAM} or
766     *            {@link Engine#KEY_PARAM_UTTERANCE_ID}.
767     *
768     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
769     */
770    public int playEarcon(String earcon, int queueMode,
771            HashMap<String,String> params) {
772        synchronized (mStartLock) {
773            int result = ERROR;
774            if (!mStarted) {
775                return result;
776            }
777            try {
778                if ((params != null) && (!params.isEmpty())) {
779                    String extra = params.get(Engine.KEY_PARAM_STREAM);
780                    if (extra != null) {
781                        mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra;
782                    }
783                    extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID);
784                    if (extra != null) {
785                        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
786                    }
787                }
788                result = mITts.playEarcon(mPackageName, earcon, queueMode, null);
789            } catch (RemoteException e) {
790                // TTS died; restart it.
791                Log.e("TextToSpeech.java - playEarcon", "RemoteException");
792                e.printStackTrace();
793                mStarted = false;
794                initTts();
795            } catch (NullPointerException e) {
796                // TTS died; restart it.
797                Log.e("TextToSpeech.java - playEarcon", "NullPointerException");
798                e.printStackTrace();
799                mStarted = false;
800                initTts();
801            } catch (IllegalStateException e) {
802                // TTS died; restart it.
803                Log.e("TextToSpeech.java - playEarcon", "IllegalStateException");
804                e.printStackTrace();
805                mStarted = false;
806                initTts();
807            } finally {
808                resetCachedParams();
809                return result;
810            }
811        }
812    }
813
814    /**
815     * Plays silence for the specified amount of time using the specified
816     * queue mode.
817     *
818     * @param durationInMs
819     *            A long that indicates how long the silence should last.
820     * @param queueMode
821     *            {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
822     * @param params
823     *            The list of parameters to be used. Can be null if no parameters are given.
824     *            They are specified using a (key, value) pair, where the key can be
825     *            {@link Engine#KEY_PARAM_UTTERANCE_ID}.
826     *
827     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
828     */
829    public int playSilence(long durationInMs, int queueMode, HashMap<String,String> params) {
830        synchronized (mStartLock) {
831            int result = ERROR;
832            if (!mStarted) {
833                return result;
834            }
835            try {
836                if ((params != null) && (!params.isEmpty())) {
837                    String extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID);
838                    if (extra != null) {
839                        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
840                    }
841                }
842                result = mITts.playSilence(mPackageName, durationInMs, queueMode, mCachedParams);
843            } catch (RemoteException e) {
844                // TTS died; restart it.
845                Log.e("TextToSpeech.java - playSilence", "RemoteException");
846                e.printStackTrace();
847                mStarted = false;
848                initTts();
849            } catch (NullPointerException e) {
850                // TTS died; restart it.
851                Log.e("TextToSpeech.java - playSilence", "NullPointerException");
852                e.printStackTrace();
853                mStarted = false;
854                initTts();
855            } catch (IllegalStateException e) {
856                // TTS died; restart it.
857                Log.e("TextToSpeech.java - playSilence", "IllegalStateException");
858                e.printStackTrace();
859                mStarted = false;
860                initTts();
861            } finally {
862                return result;
863            }
864        }
865    }
866
867
868    /**
869     * Returns whether or not the TextToSpeech engine is busy speaking.
870     *
871     * @return Whether or not the TextToSpeech engine is busy speaking.
872     */
873    public boolean isSpeaking() {
874        synchronized (mStartLock) {
875            if (!mStarted) {
876                return false;
877            }
878            try {
879                return mITts.isSpeaking();
880            } catch (RemoteException e) {
881                // TTS died; restart it.
882                Log.e("TextToSpeech.java - isSpeaking", "RemoteException");
883                e.printStackTrace();
884                mStarted = false;
885                initTts();
886            } catch (NullPointerException e) {
887                // TTS died; restart it.
888                Log.e("TextToSpeech.java - isSpeaking", "NullPointerException");
889                e.printStackTrace();
890                mStarted = false;
891                initTts();
892            } catch (IllegalStateException e) {
893                // TTS died; restart it.
894                Log.e("TextToSpeech.java - isSpeaking", "IllegalStateException");
895                e.printStackTrace();
896                mStarted = false;
897                initTts();
898            }
899            return false;
900        }
901    }
902
903
904    /**
905     * Interrupts the current utterance (whether played or rendered to file) and discards other
906     * utterances in the queue.
907     *
908     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
909     */
910    public int stop() {
911        synchronized (mStartLock) {
912            int result = ERROR;
913            if (!mStarted) {
914                return result;
915            }
916            try {
917                result = mITts.stop(mPackageName);
918            } catch (RemoteException e) {
919                // TTS died; restart it.
920                Log.e("TextToSpeech.java - stop", "RemoteException");
921                e.printStackTrace();
922                mStarted = false;
923                initTts();
924            } catch (NullPointerException e) {
925                // TTS died; restart it.
926                Log.e("TextToSpeech.java - stop", "NullPointerException");
927                e.printStackTrace();
928                mStarted = false;
929                initTts();
930            } catch (IllegalStateException e) {
931                // TTS died; restart it.
932                Log.e("TextToSpeech.java - stop", "IllegalStateException");
933                e.printStackTrace();
934                mStarted = false;
935                initTts();
936            } finally {
937                return result;
938            }
939        }
940    }
941
942
943    /**
944     * Sets the speech rate for the TextToSpeech engine.
945     *
946     * This has no effect on any pre-recorded speech.
947     *
948     * @param speechRate
949     *            The speech rate for the TextToSpeech engine. 1 is the normal speed,
950     *            lower values slow down the speech (0.5 is half the normal speech rate),
951     *            greater values accelerate it (2 is twice the normal speech rate).
952     *
953     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
954     */
955    public int setSpeechRate(float speechRate) {
956        synchronized (mStartLock) {
957            int result = ERROR;
958            if (!mStarted) {
959                return result;
960            }
961            try {
962                if (speechRate > 0) {
963                    int rate = (int)(speechRate*100);
964                    mCachedParams[Engine.PARAM_POSITION_RATE + 1] = String.valueOf(rate);
965                    // the rate is not set here, instead it is cached so it will be associated
966                    // with all upcoming utterances.
967                    if (speechRate > 0.0f) {
968                        result = SUCCESS;
969                    } else {
970                        result = ERROR;
971                    }
972                }
973            } catch (NullPointerException e) {
974                // TTS died; restart it.
975                Log.e("TextToSpeech.java - setSpeechRate", "NullPointerException");
976                e.printStackTrace();
977                mStarted = false;
978                initTts();
979            } catch (IllegalStateException e) {
980                // TTS died; restart it.
981                Log.e("TextToSpeech.java - setSpeechRate", "IllegalStateException");
982                e.printStackTrace();
983                mStarted = false;
984                initTts();
985            } finally {
986                return result;
987            }
988        }
989    }
990
991
992    /**
993     * Sets the speech pitch for the TextToSpeech engine.
994     *
995     * This has no effect on any pre-recorded speech.
996     *
997     * @param pitch
998     *            The pitch for the TextToSpeech engine. 1 is the normal pitch,
999     *            lower values lower the tone of the synthesized voice,
1000     *            greater values increase it.
1001     *
1002     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
1003     */
1004    public int setPitch(float pitch) {
1005        synchronized (mStartLock) {
1006            int result = ERROR;
1007            if (!mStarted) {
1008                return result;
1009            }
1010            try {
1011                if (pitch > 0) {
1012                    result = mITts.setPitch(mPackageName, (int)(pitch*100));
1013                }
1014            } catch (RemoteException e) {
1015                // TTS died; restart it.
1016                Log.e("TextToSpeech.java - setPitch", "RemoteException");
1017                e.printStackTrace();
1018                mStarted = false;
1019                initTts();
1020            } catch (NullPointerException e) {
1021                // TTS died; restart it.
1022                Log.e("TextToSpeech.java - setPitch", "NullPointerException");
1023                e.printStackTrace();
1024                mStarted = false;
1025                initTts();
1026            } catch (IllegalStateException e) {
1027                // TTS died; restart it.
1028                Log.e("TextToSpeech.java - setPitch", "IllegalStateException");
1029                e.printStackTrace();
1030                mStarted = false;
1031                initTts();
1032            } finally {
1033                return result;
1034            }
1035        }
1036    }
1037
1038
1039    /**
1040     * Sets the language for the TextToSpeech engine.
1041     * The TextToSpeech engine will try to use the closest match to the specified
1042     * language as represented by the Locale, but there is no guarantee that the exact same Locale
1043     * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support
1044     * before choosing the language to use for the next utterances.
1045     *
1046     * @param loc
1047     *            The locale describing the language to be used.
1048     *
1049     * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
1050     *         {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1051     *         {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
1052     */
1053    public int setLanguage(Locale loc) {
1054        synchronized (mStartLock) {
1055            int result = LANG_NOT_SUPPORTED;
1056            if (!mStarted) {
1057                return result;
1058            }
1059            try {
1060                mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language();
1061                mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country();
1062                mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = loc.getVariant();
1063                // the language is not set here, instead it is cached so it will be associated
1064                // with all upcoming utterances. But we still need to report the language support,
1065                // which is achieved by calling isLanguageAvailable()
1066                result = mITts.isLanguageAvailable(
1067                        mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1],
1068                        mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1],
1069                        mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] );
1070            } catch (RemoteException e) {
1071                // TTS died; restart it.
1072                Log.e("TextToSpeech.java - setLanguage", "RemoteException");
1073                e.printStackTrace();
1074                mStarted = false;
1075                initTts();
1076            } catch (NullPointerException e) {
1077                // TTS died; restart it.
1078                Log.e("TextToSpeech.java - setLanguage", "NullPointerException");
1079                e.printStackTrace();
1080                mStarted = false;
1081                initTts();
1082            } catch (IllegalStateException e) {
1083                // TTS died; restart it.
1084                Log.e("TextToSpeech.java - setLanguage", "IllegalStateException");
1085                e.printStackTrace();
1086                mStarted = false;
1087                initTts();
1088            } finally {
1089                return result;
1090            }
1091        }
1092    }
1093
1094
1095    /**
1096     * Returns a Locale instance describing the language currently being used by the TextToSpeech
1097     * engine.
1098     * @return language, country (if any) and variant (if any) used by the engine stored in a Locale
1099     *     instance, or null is the TextToSpeech engine has failed.
1100     */
1101    public Locale getLanguage() {
1102        synchronized (mStartLock) {
1103            if (!mStarted) {
1104                return null;
1105            }
1106            try {
1107                String[] locStrings = mITts.getLanguage();
1108                if ((locStrings != null) && (locStrings.length == 3)) {
1109                    return new Locale(locStrings[0], locStrings[1], locStrings[2]);
1110                } else {
1111                    return null;
1112                }
1113            } catch (RemoteException e) {
1114                // TTS died; restart it.
1115                Log.e("TextToSpeech.java - getLanguage", "RemoteException");
1116                e.printStackTrace();
1117                mStarted = false;
1118                initTts();
1119            } catch (NullPointerException e) {
1120                // TTS died; restart it.
1121                Log.e("TextToSpeech.java - getLanguage", "NullPointerException");
1122                e.printStackTrace();
1123                mStarted = false;
1124                initTts();
1125            } catch (IllegalStateException e) {
1126                // TTS died; restart it.
1127                Log.e("TextToSpeech.java - getLanguage", "IllegalStateException");
1128                e.printStackTrace();
1129                mStarted = false;
1130                initTts();
1131            }
1132            return null;
1133        }
1134    }
1135
1136    /**
1137     * Checks if the specified language as represented by the Locale is available and supported.
1138     *
1139     * @param loc
1140     *            The Locale describing the language to be used.
1141     *
1142     * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
1143     *         {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
1144     *         {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
1145     */
1146    public int isLanguageAvailable(Locale loc) {
1147        synchronized (mStartLock) {
1148            int result = LANG_NOT_SUPPORTED;
1149            if (!mStarted) {
1150                return result;
1151            }
1152            try {
1153                result = mITts.isLanguageAvailable(loc.getISO3Language(),
1154                        loc.getISO3Country(), loc.getVariant());
1155            } catch (RemoteException e) {
1156                // TTS died; restart it.
1157                Log.e("TextToSpeech.java - isLanguageAvailable", "RemoteException");
1158                e.printStackTrace();
1159                mStarted = false;
1160                initTts();
1161            } catch (NullPointerException e) {
1162                // TTS died; restart it.
1163                Log.e("TextToSpeech.java - isLanguageAvailable", "NullPointerException");
1164                e.printStackTrace();
1165                mStarted = false;
1166                initTts();
1167            } catch (IllegalStateException e) {
1168                // TTS died; restart it.
1169                Log.e("TextToSpeech.java - isLanguageAvailable", "IllegalStateException");
1170                e.printStackTrace();
1171                mStarted = false;
1172                initTts();
1173            } finally {
1174                return result;
1175            }
1176        }
1177    }
1178
1179
1180    /**
1181     * Synthesizes the given text to a file using the specified parameters.
1182     *
1183     * @param text
1184     *            The String of text that should be synthesized
1185     * @param params
1186     *            The list of parameters to be used. Can be null if no parameters are given.
1187     *            They are specified using a (key, value) pair, where the key can be
1188     *            {@link Engine#KEY_PARAM_UTTERANCE_ID}.
1189     * @param filename
1190     *            The string that gives the full output filename; it should be
1191     *            something like "/sdcard/myappsounds/mysound.wav".
1192     *
1193     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
1194     */
1195    public int synthesizeToFile(String text, HashMap<String,String> params,
1196            String filename) {
1197        synchronized (mStartLock) {
1198            int result = ERROR;
1199            if (!mStarted) {
1200                return result;
1201            }
1202            try {
1203                if ((params != null) && (!params.isEmpty())) {
1204                    // no need to read the stream type here
1205                    String extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID);
1206                    if (extra != null) {
1207                        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra;
1208                    }
1209                    extra = params.get(Engine.KEY_PARAM_ENGINE);
1210                    if (extra != null) {
1211                        mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = extra;
1212                    }
1213                }
1214                result = mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename) ?
1215                        SUCCESS : ERROR;
1216            } catch (RemoteException e) {
1217                // TTS died; restart it.
1218                Log.e("TextToSpeech.java - synthesizeToFile", "RemoteException");
1219                e.printStackTrace();
1220                mStarted = false;
1221                initTts();
1222            } catch (NullPointerException e) {
1223                // TTS died; restart it.
1224                Log.e("TextToSpeech.java - synthesizeToFile", "NullPointerException");
1225                e.printStackTrace();
1226                mStarted = false;
1227                initTts();
1228            } catch (IllegalStateException e) {
1229                // TTS died; restart it.
1230                Log.e("TextToSpeech.java - synthesizeToFile", "IllegalStateException");
1231                e.printStackTrace();
1232                mStarted = false;
1233                initTts();
1234            } finally {
1235                resetCachedParams();
1236                return result;
1237            }
1238        }
1239    }
1240
1241
1242    /**
1243     * Convenience method to reset the cached parameters to the current default values
1244     * if they are not persistent between calls to the service.
1245     */
1246    private void resetCachedParams() {
1247        mCachedParams[Engine.PARAM_POSITION_STREAM + 1] =
1248                String.valueOf(Engine.DEFAULT_STREAM);
1249        mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID+ 1] = "";
1250    }
1251
1252    /**
1253     * Sets the OnUtteranceCompletedListener that will fire when an utterance completes.
1254     *
1255     * @param listener
1256     *            The OnUtteranceCompletedListener
1257     *
1258     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
1259     */
1260    public int setOnUtteranceCompletedListener(
1261            final OnUtteranceCompletedListener listener) {
1262        synchronized (mStartLock) {
1263            int result = ERROR;
1264            if (!mStarted) {
1265                return result;
1266            }
1267            mITtscallback = new ITtsCallback.Stub() {
1268                public void utteranceCompleted(String utteranceId) throws RemoteException {
1269                    if (listener != null) {
1270                        listener.onUtteranceCompleted(utteranceId);
1271                    }
1272                }
1273            };
1274            try {
1275                result = mITts.registerCallback(mPackageName, mITtscallback);
1276            } catch (RemoteException e) {
1277                // TTS died; restart it.
1278                Log.e("TextToSpeech.java - registerCallback", "RemoteException");
1279                e.printStackTrace();
1280                mStarted = false;
1281                initTts();
1282            } catch (NullPointerException e) {
1283                // TTS died; restart it.
1284                Log.e("TextToSpeech.java - registerCallback", "NullPointerException");
1285                e.printStackTrace();
1286                mStarted = false;
1287                initTts();
1288            } catch (IllegalStateException e) {
1289                // TTS died; restart it.
1290                Log.e("TextToSpeech.java - registerCallback", "IllegalStateException");
1291                e.printStackTrace();
1292                mStarted = false;
1293                initTts();
1294            } finally {
1295                return result;
1296            }
1297        }
1298    }
1299
1300    /**
1301     * Sets the speech synthesis engine to be used by its packagename.
1302     *
1303     * @param enginePackageName
1304     *            The packagename for the synthesis engine (ie, "com.svox.pico")
1305     *
1306     * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
1307     */
1308    public int setEngineByPackageName(String enginePackageName) {
1309        synchronized (mStartLock) {
1310            int result = TextToSpeech.ERROR;
1311            if (!mStarted) {
1312                return result;
1313            }
1314            try {
1315                result = mITts.setEngineByPackageName(enginePackageName);
1316                if (result == TextToSpeech.SUCCESS){
1317                    mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = enginePackageName;
1318                }
1319            } catch (RemoteException e) {
1320                // TTS died; restart it.
1321                Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException");
1322                e.printStackTrace();
1323                mStarted = false;
1324                initTts();
1325            } catch (NullPointerException e) {
1326                // TTS died; restart it.
1327                Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException");
1328                e.printStackTrace();
1329                mStarted = false;
1330                initTts();
1331            } catch (IllegalStateException e) {
1332                // TTS died; restart it.
1333                Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException");
1334                e.printStackTrace();
1335                mStarted = false;
1336                initTts();
1337            } finally {
1338                return result;
1339            }
1340        }
1341    }
1342
1343
1344    /**
1345     * Gets the packagename of the default speech synthesis engine.
1346     *
1347     * @return Packagename of the TTS engine that the user has chosen as their default.
1348     *
1349     * @hide
1350     */
1351    public String getDefaultEngine() {
1352        synchronized (mStartLock) {
1353            String engineName = "";
1354            if (!mStarted) {
1355                return engineName;
1356            }
1357            try {
1358                engineName = mITts.getDefaultEngine();
1359            } catch (RemoteException e) {
1360                // TTS died; restart it.
1361                Log.e("TextToSpeech.java - setEngineByPackageName", "RemoteException");
1362                e.printStackTrace();
1363                mStarted = false;
1364                initTts();
1365            } catch (NullPointerException e) {
1366                // TTS died; restart it.
1367                Log.e("TextToSpeech.java - setEngineByPackageName", "NullPointerException");
1368                e.printStackTrace();
1369                mStarted = false;
1370                initTts();
1371            } catch (IllegalStateException e) {
1372                // TTS died; restart it.
1373                Log.e("TextToSpeech.java - setEngineByPackageName", "IllegalStateException");
1374                e.printStackTrace();
1375                mStarted = false;
1376                initTts();
1377            } finally {
1378                return engineName;
1379            }
1380        }
1381    }
1382}
1383