TextToSpeech.java revision ddb0a803fd353fbaf0139cc8804499bc9dce7403
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.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.ServiceConnection;
25import android.os.IBinder;
26import android.os.RemoteException;
27import android.util.Log;
28
29import java.util.HashMap;
30import java.util.Locale;
31
32/**
33 *
34 * Synthesizes speech from text.
35 *
36 * {@hide}
37 */
38//TODO #TTS# review + complete javadoc + add links to constants
39public class TextToSpeech {
40
41    /**
42     * Denotes a successful operation.
43     */
44    public static final int TTS_SUCCESS                = 0;
45    /**
46     * Denotes a generic operation failure.
47     */
48    public static final int TTS_ERROR                  = -1;
49
50    /**
51     * Queue mode where all entries in the playback queue (media to be played
52     * and text to be synthesized) are dropped and replaced by the new entry.
53     */
54    public static final int TTS_QUEUE_FLUSH = 0;
55    /**
56     * Queue mode where the new entry is added at the end of the playback queue.
57     */
58    public static final int TTS_QUEUE_ADD = 1;
59
60
61    /**
62     * Denotes the language is available exactly as specified by the locale
63     */
64    public static final int TTS_LANG_COUNTRY_VAR_AVAILABLE = 2;
65
66
67    /**
68     * Denotes the language is available for the language and country specified
69     * by the locale, but not the variant.
70     */
71    public static final int TTS_LANG_COUNTRY_AVAILABLE = 1;
72
73
74    /**
75     * Denotes the language is available for the language by the locale,
76     * but not the country and variant.
77     */
78    public static final int TTS_LANG_AVAILABLE = 0;
79
80    /**
81     * Denotes the language data is missing.
82     */
83    public static final int TTS_LANG_MISSING_DATA = -1;
84
85    /**
86     * Denotes the language is not supported by the current TTS engine.
87     */
88    public static final int TTS_LANG_NOT_SUPPORTED = -2;
89
90
91    /**
92     * Called when the TTS has initialized.
93     *
94     * The InitListener must implement the onInit function. onInit is passed a
95     * status code indicating the result of the TTS initialization.
96     */
97    public interface OnInitListener {
98        public void onInit(int status);
99    }
100
101    /**
102     * Internal constants for the TTS functionality
103     *
104     * {@hide}
105     */
106    public class Engine {
107        // default values for a TTS engine when settings are not found in the provider
108        public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x
109        public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x
110        public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false
111        public static final String FALLBACK_TTS_DEFAULT_LANG = "eng";
112        public static final String FALLBACK_TTS_DEFAULT_COUNTRY = "";
113        public static final String FALLBACK_TTS_DEFAULT_VARIANT = "";
114
115        // return codes for a TTS engine's check data activity
116        public static final int CHECK_VOICE_DATA_PASS = 1;
117        public static final int CHECK_VOICE_DATA_FAIL = 0;
118        public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
119        public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
120        public static final int CHECK_VOICE_DATA_MISSING_DATA_NO_SDCARD = -3;
121
122        // keys for the parameters passed with speak commands
123        public static final String TTS_KEY_PARAM_RATE = "rate";
124        public static final String TTS_KEY_PARAM_LANGUAGE = "language";
125        public static final String TTS_KEY_PARAM_COUNTRY = "country";
126        public static final String TTS_KEY_PARAM_VARIANT = "variant";
127        public static final int TTS_PARAM_POSITION_RATE = 0;
128        public static final int TTS_PARAM_POSITION_LANGUAGE = 2;
129        public static final int TTS_PARAM_POSITION_COUNTRY = 4;
130        public static final int TTS_PARAM_POSITION_VARIANT = 6;
131    }
132
133    /**
134     * Connection needed for the TTS.
135     */
136    private ServiceConnection mServiceConnection;
137
138    private ITts mITts = null;
139    private Context mContext = null;
140    private OnInitListener mInitListener = null;
141    private boolean mStarted = false;
142    private final Object mStartLock = new Object();
143    private int mCachedRate = Engine.FALLBACK_TTS_DEFAULT_RATE;
144    private String mCachedLang = Engine.FALLBACK_TTS_DEFAULT_LANG;
145    private String mCachedCountry = Engine.FALLBACK_TTS_DEFAULT_COUNTRY;
146    private String mCachedVariant = Engine.FALLBACK_TTS_DEFAULT_VARIANT;
147    private String[] mCachedParams;
148
149    /**
150     * The constructor for the TTS.
151     *
152     * @param context
153     *            The context
154     * @param listener
155     *            The InitListener that will be called when the TTS has
156     *            initialized successfully.
157     */
158    public TextToSpeech(Context context, OnInitListener listener) {
159        mContext = context;
160        mInitListener = listener;
161
162        mCachedParams = new String[2*4]; //4 parameters, store key and value
163        mCachedParams[Engine.TTS_PARAM_POSITION_RATE] = Engine.TTS_KEY_PARAM_RATE;
164        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE] = Engine.TTS_KEY_PARAM_LANGUAGE;
165        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY] = Engine.TTS_KEY_PARAM_COUNTRY;
166        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT] = Engine.TTS_KEY_PARAM_VARIANT;
167        updateCachedParamArray();
168
169        initTts();
170    }
171
172
173    private void updateCachedParamArray() {
174        mCachedParams[Engine.TTS_PARAM_POSITION_RATE+1] = String.valueOf(mCachedRate);
175        mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE+1] = mCachedLang;
176        mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY+1] = mCachedCountry;
177        mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT+1] = mCachedVariant;
178    }
179
180
181    private void initTts() {
182        mStarted = false;
183
184        // Initialize the TTS, run the callback after the binding is successful
185        mServiceConnection = new ServiceConnection() {
186            public void onServiceConnected(ComponentName name, IBinder service) {
187                synchronized(mStartLock) {
188                    mITts = ITts.Stub.asInterface(service);
189                    mStarted = true;
190                    if (mInitListener != null) {
191                        // TODO manage failures and missing resources
192                        mInitListener.onInit(TTS_SUCCESS);
193                    }
194                }
195            }
196
197            public void onServiceDisconnected(ComponentName name) {
198                synchronized(mStartLock) {
199                    mITts = null;
200                    mInitListener = null;
201                    mStarted = false;
202                }
203            }
204        };
205
206        Intent intent = new Intent("android.intent.action.USE_TTS");
207        intent.addCategory("android.intent.category.TTS");
208        mContext.bindService(intent, mServiceConnection,
209                Context.BIND_AUTO_CREATE);
210        // TODO handle case where the binding works (should always work) but
211        //      the plugin fails
212    }
213
214
215    /**
216     * Shuts down the TTS. It is good practice to call this in the onDestroy
217     * method of the Activity that is using the TTS so that the TTS is stopped
218     * cleanly.
219     */
220    public void shutdown() {
221        try {
222            mContext.unbindService(mServiceConnection);
223        } catch (IllegalArgumentException e) {
224            // Do nothing and fail silently since an error here indicates that
225            // binding never succeeded in the first place.
226        }
227    }
228
229
230    /**
231     * Adds a mapping between a string of text and a sound resource in a
232     * package.
233     *
234     * @see #TTS.speak(String text, int queueMode, String[] params)
235     *
236     * @param text
237     *            Example: <b><code>"south_south_east"</code></b><br/>
238     *
239     * @param packagename
240     *            Pass the packagename of the application that contains the
241     *            resource. If the resource is in your own application (this is
242     *            the most common case), then put the packagename of your
243     *            application here.<br/>
244     *            Example: <b>"com.google.marvin.compass"</b><br/>
245     *            The packagename can be found in the AndroidManifest.xml of
246     *            your application.
247     *            <p>
248     *            <code>&lt;manifest xmlns:android=&quot;...&quot;
249     *      package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
250     *            </p>
251     *
252     * @param resourceId
253     *            Example: <b><code>R.raw.south_south_east</code></b>
254     *
255     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
256     */
257    public int addSpeech(String text, String packagename, int resourceId) {
258        synchronized(mStartLock) {
259            if (!mStarted) {
260                return TTS_ERROR;
261            }
262            try {
263                mITts.addSpeech(text, packagename, resourceId);
264                return TTS_SUCCESS;
265            } catch (RemoteException e) {
266                // TTS died; restart it.
267                mStarted = false;
268                initTts();
269            } catch (NullPointerException e) {
270                // TTS died; restart it.
271                mStarted = false;
272                initTts();
273            } catch (IllegalStateException e) {
274                // TTS died; restart it.
275                mStarted = false;
276                initTts();
277            }
278            return TTS_ERROR;
279        }
280    }
281
282
283    /**
284     * Adds a mapping between a string of text and a sound file. Using this, it
285     * is possible to add custom pronounciations for text.
286     *
287     * @param text
288     *            The string of text
289     * @param filename
290     *            The full path to the sound file (for example:
291     *            "/sdcard/mysounds/hello.wav")
292     *
293     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
294     */
295    public int addSpeech(String text, String filename) {
296        synchronized (mStartLock) {
297            if (!mStarted) {
298                return TTS_ERROR;
299            }
300            try {
301                mITts.addSpeechFile(text, filename);
302                return TTS_SUCCESS;
303            } catch (RemoteException e) {
304                // TTS died; restart it.
305                mStarted = false;
306                initTts();
307            } catch (NullPointerException e) {
308                // TTS died; restart it.
309                mStarted = false;
310                initTts();
311            } catch (IllegalStateException e) {
312                // TTS died; restart it.
313                mStarted = false;
314                initTts();
315            }
316            return TTS_ERROR;
317        }
318    }
319
320
321    /**
322     * Speaks the string using the specified queuing strategy and speech
323     * parameters. Note that the speech parameters are not universally supported
324     * by all engines and will be treated as a hint. The TTS library will try to
325     * fulfill these parameters as much as possible, but there is no guarantee
326     * that the voice used will have the properties specified.
327     *
328     * @param text
329     *            The string of text to be spoken.
330     * @param queueMode
331     *            The queuing strategy to use.
332     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
333     * @param params
334     *            The hashmap of speech parameters to be used.
335     *
336     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
337     */
338    public int speak(String text, int queueMode, HashMap<String,String> params)
339    {
340        synchronized (mStartLock) {
341            Log.i("TTS received: ", text);
342            if (!mStarted) {
343                return TTS_ERROR;
344            }
345            try {
346                // TODO support extra parameters, passing cache of current parameters for the moment
347                mITts.speak(text, queueMode, mCachedParams);
348                return TTS_SUCCESS;
349            } catch (RemoteException e) {
350                // TTS died; restart it.
351                mStarted = false;
352                initTts();
353            } catch (NullPointerException e) {
354                // TTS died; restart it.
355                mStarted = false;
356                initTts();
357            } catch (IllegalStateException e) {
358                // TTS died; restart it.
359                mStarted = false;
360                initTts();
361            }
362            return TTS_ERROR;
363        }
364    }
365
366
367    /**
368     * Speaks the IPA string using the specified queuing strategy and speech
369     * parameters. Note that the speech parameters are not universally supported
370     * by all engines and will be treated as a hint. The TTS library will try to
371     * fulfill these parameters as much as possible, but there is no guarantee
372     * that the voice used will have the properties specified.
373     *
374     * @param ipaText
375     *            The string of IPA text to be spoken.
376     * @param queueMode
377     *            The queuing strategy to use.
378     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
379     * @param params
380     *            The hashmap of speech parameters to be used.
381     *
382     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
383     *
384     * {@hide}
385     */
386    public int speakIpa(String ipaText, int queueMode, HashMap<String,String> params)
387    {
388        synchronized (mStartLock) {
389            Log.i("TTS received: ", ipaText);
390            if (!mStarted) {
391                return TTS_ERROR;
392            }
393            try {
394                // TODO support extra parameters, passing cache of current parameters for the moment
395                mITts.speakIpa(ipaText, queueMode, mCachedParams);
396                return TTS_SUCCESS;
397            } catch (RemoteException e) {
398                // TTS died; restart it.
399                mStarted = false;
400                initTts();
401            } catch (NullPointerException e) {
402                // TTS died; restart it.
403                mStarted = false;
404                initTts();
405            } catch (IllegalStateException e) {
406                // TTS died; restart it.
407                mStarted = false;
408                initTts();
409            }
410            return TTS_ERROR;
411        }
412    }
413
414
415    /**
416     * Plays the earcon using the specified queueing mode and parameters.
417     *
418     * @param earcon
419     *            The earcon that should be played
420     * @param queueMode
421     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
422     * @param params
423     *            The hashmap of parameters to be used.
424     *
425     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
426     */
427    public int playEarcon(String earcon, int queueMode,
428            HashMap<String,String> params) {
429        synchronized (mStartLock) {
430            if (!mStarted) {
431                return TTS_ERROR;
432            }
433            try {
434                // TODO support extra parameters, passing null for the moment
435                mITts.playEarcon(earcon, queueMode, null);
436                return TTS_SUCCESS;
437            } catch (RemoteException e) {
438                // TTS died; restart it.
439                mStarted = false;
440                initTts();
441            } catch (NullPointerException e) {
442                // TTS died; restart it.
443                mStarted = false;
444                initTts();
445            } catch (IllegalStateException e) {
446                // TTS died; restart it.
447                mStarted = false;
448                initTts();
449            }
450            return TTS_ERROR;
451        }
452    }
453
454    /**
455     * Plays silence for the specified amount of time using the specified
456     * queue mode.
457     *
458     * @param durationInMs
459     *            A long that indicates how long the silence should last.
460     * @param queueMode
461     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
462     *
463     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
464     */
465    public int playSilence(long durationInMs, int queueMode) {
466        synchronized (mStartLock) {
467            if (!mStarted) {
468                return TTS_ERROR;
469            }
470            try {
471                // TODO support extra parameters, passing cache of current parameters for the moment
472                mITts.playSilence(durationInMs, queueMode, mCachedParams);
473                return TTS_SUCCESS;
474            } catch (RemoteException e) {
475                // TTS died; restart it.
476                mStarted = false;
477                initTts();
478            } catch (NullPointerException e) {
479                // TTS died; restart it.
480                mStarted = false;
481                initTts();
482            } catch (IllegalStateException e) {
483                // TTS died; restart it.
484                mStarted = false;
485                initTts();
486            }
487            return TTS_ERROR;
488        }
489    }
490
491
492    /**
493     * Returns whether or not the TTS is busy speaking.
494     *
495     * @return Whether or not the TTS is busy speaking.
496     */
497    public boolean isSpeaking() {
498        synchronized (mStartLock) {
499            if (!mStarted) {
500                return false;
501            }
502            try {
503                return mITts.isSpeaking();
504            } catch (RemoteException e) {
505                // TTS died; restart it.
506                mStarted = false;
507                initTts();
508            } catch (NullPointerException e) {
509                // TTS died; restart it.
510                mStarted = false;
511                initTts();
512            } catch (IllegalStateException e) {
513                // TTS died; restart it.
514                mStarted = false;
515                initTts();
516            }
517            return false;
518        }
519    }
520
521
522    /**
523     * Stops speech from the TTS.
524     *
525     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
526     */
527    public int stop() {
528        synchronized (mStartLock) {
529            if (!mStarted) {
530                return TTS_ERROR;
531            }
532            try {
533                mITts.stop();
534                return TTS_SUCCESS;
535            } catch (RemoteException e) {
536                // TTS died; restart it.
537                mStarted = false;
538                initTts();
539            } catch (NullPointerException e) {
540                // TTS died; restart it.
541                mStarted = false;
542                initTts();
543            } catch (IllegalStateException e) {
544                // TTS died; restart it.
545                mStarted = false;
546                initTts();
547            }
548            return TTS_ERROR;
549        }
550    }
551
552
553    /**
554     * Sets the speech rate for the TTS engine.
555     *
556     * Note that the speech rate is not universally supported by all engines and
557     * will be treated as a hint. The TTS library will try to use the specified
558     * speech rate, but there is no guarantee.
559     * This has no effect on any pre-recorded speech.
560     *
561     * @param speechRate
562     *            The speech rate for the TTS engine. 1 is the normal speed,
563     *            lower values slow down the speech (0.5 is half the normal speech rate),
564     *            greater values accelerate it (2 is twice the normal speech rate).
565     *
566     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
567     */
568    public int setSpeechRate(float speechRate) {
569        synchronized (mStartLock) {
570            if (!mStarted) {
571                return TTS_SUCCESS;
572            }
573            try {
574                if (speechRate > 0) {
575                    mCachedRate = (int)(speechRate*100);
576                    updateCachedParamArray();
577                    mITts.setSpeechRate(mCachedRate);
578                    return TTS_SUCCESS;
579                }
580            } catch (RemoteException e) {
581                // TTS died; restart it.
582                mStarted = false;
583                initTts();
584            }
585            return TTS_ERROR;
586        }
587    }
588
589
590    /**
591     * Sets the speech pitch for the TTS engine.
592     *
593     * Note that the pitch is not universally supported by all engines and
594     * will be treated as a hint. The TTS library will try to use the specified
595     * pitch, but there is no guarantee.
596     * This has no effect on any pre-recorded speech.
597     *
598     * @param pitch
599     *            The pitch for the TTS engine. 1 is the normal pitch,
600     *            lower values lower the tone of the synthesized voice,
601     *            greater values increase it.
602     *
603     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
604     */
605    public int setPitch(float pitch) {
606        synchronized (mStartLock) {
607            if (!mStarted) {
608                return TTS_ERROR;
609            }
610            try {
611                if (pitch > 0) {
612                    mITts.setPitch((int)(pitch*100));
613                    return TTS_SUCCESS;
614                }
615            } catch (RemoteException e) {
616                // TTS died; restart it.
617                mStarted = false;
618                initTts();
619            }
620            return TTS_ERROR;
621        }
622    }
623
624
625    /**
626     * Sets the language for the TTS engine.
627     *
628     * Note that the language is not universally supported by all engines and
629     * will be treated as a hint. The TTS library will try to use the specified
630     * language as represented by the Locale, but there is no guarantee.
631     *
632     * @param loc
633     *            The locale describing the language to be used.
634     *
635     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
636     */
637    public int setLanguage(Locale loc) {
638        synchronized (mStartLock) {
639            if (!mStarted) {
640                return TTS_ERROR;
641            }
642            try {
643                mCachedLang = loc.getISO3Language();
644                mCachedCountry = loc.getISO3Country();
645                mCachedVariant = loc.getVariant();
646                updateCachedParamArray();
647                mITts.setLanguage(mCachedLang, mCachedCountry, mCachedVariant);
648                return TTS_SUCCESS;
649            } catch (RemoteException e) {
650                // TTS died; restart it.
651                mStarted = false;
652                initTts();
653            }
654            return TTS_ERROR;
655        }
656    }
657
658
659    /**
660     * Returns a Locale instance describing the language currently being used by the TTS engine.
661     * @return language, country (if any) and variant (if any) used by the engine stored in a Locale
662     *     instance, or null is the TTS engine has failed.
663     */
664    public Locale getLanguage() {
665        synchronized (mStartLock) {
666            if (!mStarted) {
667                return null;
668            }
669            try {
670                String[] locStrings =  mITts.getLanguage();
671                if (locStrings.length == 3) {
672                    return new Locale(locStrings[0], locStrings[1], locStrings[2]);
673                } else {
674                    return null;
675                }
676            } catch (RemoteException e) {
677                // TTS died; restart it.
678                mStarted = false;
679                initTts();
680            }
681            return null;
682        }
683    }
684
685    /**
686     * Checks if the specified language as represented by the Locale is available.
687     *
688     * @param loc
689     *            The Locale describing the language to be used.
690     *
691     * @return one of TTS_LANG_NOT_SUPPORTED, TTS_LANG_MISSING_DATA, TTS_LANG_AVAILABLE,
692     *         TTS_LANG_COUNTRY_AVAILABLE, TTS_LANG_COUNTRY_VAR_AVAILABLE.
693     */
694    public int isLanguageAvailable(Locale loc) {
695        synchronized (mStartLock) {
696            if (!mStarted) {
697                return TTS_LANG_NOT_SUPPORTED;
698            }
699            try {
700                return mITts.isLanguageAvailable(loc.getISO3Language(), loc.getISO3Country(),
701                        loc.getVariant());
702            } catch (RemoteException e) {
703                // TTS died; restart it.
704                mStarted = false;
705                initTts();
706            }
707            return TTS_LANG_NOT_SUPPORTED;
708        }
709    }
710
711
712    /**
713     * Synthesizes the given text to a file using the specified parameters.
714     *
715     * @param text
716     *            The String of text that should be synthesized
717     * @param params
718     *            A hashmap of parameters.
719     * @param filename
720     *            The string that gives the full output filename; it should be
721     *            something like "/sdcard/myappsounds/mysound.wav".
722     *
723     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
724     */
725    public int synthesizeToFile(String text, HashMap<String,String> params,
726            String filename) {
727        synchronized (mStartLock) {
728            if (!mStarted) {
729                return TTS_ERROR;
730            }
731            try {
732                // TODO support extra parameters, passing null for the moment
733                if (mITts.synthesizeToFile(text, null, filename)){
734                    return TTS_SUCCESS;
735                }
736            } catch (RemoteException e) {
737                // TTS died; restart it.
738                mStarted = false;
739                initTts();
740            } catch (NullPointerException e) {
741                // TTS died; restart it.
742                mStarted = false;
743                initTts();
744            } catch (IllegalStateException e) {
745                // TTS died; restart it.
746                mStarted = false;
747                initTts();
748            }
749            return TTS_ERROR;
750        }
751    }
752
753
754    /**
755     * Synthesizes the given IPA text to a file using the specified parameters.
756     *
757     * @param text
758     *            The String of text that should be synthesized
759     * @param params
760     *            A hashmap of parameters.
761     * @param filename
762     *            The string that gives the full output filename; it should be
763     *            something like "/sdcard/myappsounds/mysound.wav".
764     *
765     * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS.
766     *
767     * {@hide}
768     */
769    public int synthesizeIpaToFile(String ipaText,
770            HashMap<String,String> params, String filename) {
771        synchronized (mStartLock) {
772            if (!mStarted) {
773                return TTS_ERROR;
774            }
775            try {
776                // TODO support extra parameters, passing null for the moment
777                if (mITts.synthesizeIpaToFile(ipaText, null, filename)){
778                    return TTS_SUCCESS;
779                }
780            } catch (RemoteException e) {
781                // TTS died; restart it.
782                mStarted = false;
783                initTts();
784            } catch (NullPointerException e) {
785                // TTS died; restart it.
786                mStarted = false;
787                initTts();
788            } catch (IllegalStateException e) {
789                // TTS died; restart it.
790                mStarted = false;
791                initTts();
792            }
793            return TTS_ERROR;
794        }
795    }
796
797}
798