1a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen/*
2a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * Copyright (C) 2009 Google Inc.
3a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen *
4a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * use this file except in compliance with the License. You may obtain a copy of
6a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * the License at
7a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen *
8a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * http://www.apache.org/licenses/LICENSE-2.0
9a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen *
10a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * Unless required by applicable law or agreed to in writing, software
11a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * License for the specific language governing permissions and limitations under
14a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * the License.
15a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen */
16a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenpackage android.tts;
17a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
18a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.app.Service;
19605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Triviimport android.content.ContentResolver;
20a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.content.Context;
21a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.content.Intent;
22a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.content.SharedPreferences;
23a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.content.pm.PackageManager;
24a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.content.pm.PackageManager.NameNotFoundException;
259440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Triviimport android.media.AudioManager;
26a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.media.MediaPlayer;
27a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.media.MediaPlayer.OnCompletionListener;
28a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.net.Uri;
29a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.os.IBinder;
30a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.os.RemoteCallbackList;
31a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.os.RemoteException;
32a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.preference.PreferenceManager;
33d146874d7341bc9602c93719582b4209e7b81f01Jean-Michel Triviimport android.speech.tts.ITts.Stub;
34d146874d7341bc9602c93719582b4209e7b81f01Jean-Michel Triviimport android.speech.tts.ITtsCallback;
35d146874d7341bc9602c93719582b4209e7b81f01Jean-Michel Triviimport android.speech.tts.TextToSpeech;
36a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport android.util.Log;
37a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi
38a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Triviimport java.io.File;
39a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport java.util.ArrayList;
40a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport java.util.Arrays;
41a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport java.util.HashMap;
42d478cf09dff93015bc332f2707068f08bf603cfdJean-Michel Triviimport java.util.Locale;
43a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenimport java.util.concurrent.locks.ReentrantLock;
440a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chenimport java.util.concurrent.TimeUnit;
450a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen
46a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
47a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen/**
48a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen * @hide Synthesizes speech from text. This is implemented as a service so that
49a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen *       other applications can call the TTS without needing to bundle the TTS
50a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen *       in the build.
51a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen *
52a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen */
53a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chenpublic class TtsService extends Service implements OnCompletionListener {
54a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
5578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private static class SpeechItem {
56741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen        public static final int TEXT = 0;
574bca97ecaf04c50d5ed49920d119f9ffa6c29402Charles Chen        public static final int EARCON = 1;
584bca97ecaf04c50d5ed49920d119f9ffa6c29402Charles Chen        public static final int SILENCE = 2;
594bca97ecaf04c50d5ed49920d119f9ffa6c29402Charles Chen        public static final int TEXT_TO_FILE = 3;
60b02ced7e454ae195c53993fe310ee38de6452dedCharles Chen        public String mText = "";
6178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        public ArrayList<String> mParams = null;
62741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen        public int mType = TEXT;
6378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        public long mDuration = 0;
64ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        public String mFilename = null;
6578c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        public String mCallingApp = "";
6678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
67a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public SpeechItem(String source, String text, ArrayList<String> params, int itemType) {
6878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mText = text;
6978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mParams = params;
7078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mType = itemType;
7178c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            mCallingApp = source;
7278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
73a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
743ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        public SpeechItem(String source, long silenceTime, ArrayList<String> params) {
7578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mDuration = silenceTime;
763ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen            mParams = params;
77b02ced7e454ae195c53993fe310ee38de6452dedCharles Chen            mType = SILENCE;
7878c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            mCallingApp = source;
7978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
80ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen
81edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen        public SpeechItem(String source, String text, ArrayList<String> params,
82edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                int itemType, String filename) {
83ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            mText = text;
84ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            mParams = params;
85ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            mType = itemType;
86ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            mFilename = filename;
8778c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            mCallingApp = source;
88ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        }
89ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen
90a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
91a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
9278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    /**
9378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * Contains the information needed to access a sound resource; the name of
9478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * the package that contains the resource and the resID of the resource
9578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * within that package.
9678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     */
9778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private static class SoundResource {
9878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        public String mSourcePackageName = null;
9978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        public int mResId = -1;
10078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        public String mFilename = null;
10178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
10278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        public SoundResource(String packageName, int id) {
10378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mSourcePackageName = packageName;
10478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mResId = id;
10578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mFilename = null;
10678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
107a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
10878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        public SoundResource(String file) {
10978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mSourcePackageName = null;
11078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mResId = -1;
11178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mFilename = file;
11278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
11378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
1140dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen    // If the speech queue is locked for more than 5 seconds, something has gone
1150dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen    // very wrong with processSpeechQueue.
1160dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen    private static final int SPEECHQUEUELOCK_TIMEOUT = 5000;
1171aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen    private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
11803454f8932b7fd79471ae6f95f2de7b75b0ded8aCharles Chen    private static final int MAX_FILENAME_LENGTH = 250;
1199440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi    // TODO use the TTS stream type when available
1209440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi    private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;
1211aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen
12252ae06521a8d4c48757b126cff233f037d0a16baCharles Chen    private static final String ACTION = "android.intent.action.START_TTS_SERVICE";
12378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private static final String CATEGORY = "android.intent.category.TTS";
12478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private static final String PKGNAME = "android.tts";
125b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi    protected static final String SERVICE_TAG = "TtsService";
126a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
127edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen    private final RemoteCallbackList<ITtsCallback> mCallbacks
128edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen            = new RemoteCallbackList<ITtsCallback>();
129edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen
130edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen    private HashMap<String, ITtsCallback> mCallbacksMap;
131a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
13278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private Boolean mIsSpeaking;
13378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private ArrayList<SpeechItem> mSpeechQueue;
13478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private HashMap<String, SoundResource> mEarcons;
13578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private HashMap<String, SoundResource> mUtterances;
13678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private MediaPlayer mPlayer;
1373ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen    private SpeechItem mCurrentSpeechItem;
138c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen    private HashMap<SpeechItem, Boolean> mKillList; // Used to ensure that in-flight synth calls
139c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen                                                    // are killed when stop is used.
14078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private TtsService mSelf;
141a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
142605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi    private ContentResolver mResolver;
143a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
144a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi    // lock for the speech queue (mSpeechQueue) and the current speech item (mCurrentSpeechItem)
14578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private final ReentrantLock speechQueueLock = new ReentrantLock();
14678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private final ReentrantLock synthesizerLock = new ReentrantLock();
147a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
148a73d5cd05550310c3e6cedf0759210c255f4a6aaJean-Michel Trivi    private static SynthProxy sNativeSynth = null;
14978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    @Override
15078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    public void onCreate() {
15178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        super.onCreate();
152ab6ed2c2b9cebd97cb501da58d386f59e4a99103Jean-Michel Trivi        Log.v("TtsService", "TtsService.onCreate()");
153a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
154605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi        mResolver = getContentResolver();
155a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
156b3c5a8785bc643843117752d37769a1edfe9a9e2Jean-Michel Trivi        String soLibPath = "/system/lib/libttspico.so";
157a73d5cd05550310c3e6cedf0759210c255f4a6aaJean-Michel Trivi        if (sNativeSynth == null) {
158a73d5cd05550310c3e6cedf0759210c255f4a6aaJean-Michel Trivi            sNativeSynth = new SynthProxy(soLibPath);
159a73d5cd05550310c3e6cedf0759210c255f4a6aaJean-Michel Trivi        }
160a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
16178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mSelf = this;
16278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mIsSpeaking = false;
163a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
16478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mEarcons = new HashMap<String, SoundResource>();
16578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mUtterances = new HashMap<String, SoundResource>();
16678c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        mCallbacksMap = new HashMap<String, android.speech.tts.ITtsCallback>();
167a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
16878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mSpeechQueue = new ArrayList<SpeechItem>();
16978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mPlayer = null;
1703ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        mCurrentSpeechItem = null;
171c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen        mKillList = new HashMap<SpeechItem, Boolean>();
172a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
173605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi        setDefaultSettings();
174a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
175a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
17678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    @Override
17778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    public void onDestroy() {
17878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        super.onDestroy();
17969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi
180a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi        killAllUtterances();
18169e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi
18278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        // Don't hog the media player
18378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        cleanUpPlayer();
184a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
18569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        if (sNativeSynth != null) {
18669e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            sNativeSynth.shutdown();
18769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        }
188cee3bd4d68bf40d36fee3f0f5ce03f9edae87b51Jean-Michel Trivi        sNativeSynth = null;
189a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
19078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        // Unregister all callbacks.
19178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mCallbacks.kill();
19209f8db7ad3963f5fa15f2b99880b2f70e89c30aeJean-Michel Trivi
193b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi        Log.v(SERVICE_TAG, "onDestroy() completed");
194a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
195a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
196605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi
197605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi    private void setDefaultSettings() {
198a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        setLanguage("", this.getDefaultLanguage(), getDefaultCountry(), getDefaultLocVariant());
199605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi
200605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi        // speech rate
201a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        setSpeechRate("", getDefaultRate());
202605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi    }
203605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi
204605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi
205605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi    private boolean isDefaultEnforced() {
206605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi        return (android.provider.Settings.Secure.getInt(mResolver,
207d146874d7341bc9602c93719582b4209e7b81f01Jean-Michel Trivi                    android.provider.Settings.Secure.TTS_USE_DEFAULTS,
208ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                    TextToSpeech.Engine.USE_DEFAULTS)
209605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi                == 1 );
210605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi    }
211605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi
212605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi
213605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi    private int getDefaultRate() {
214605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi        return android.provider.Settings.Secure.getInt(mResolver,
215d146874d7341bc9602c93719582b4209e7b81f01Jean-Michel Trivi                android.provider.Settings.Secure.TTS_DEFAULT_RATE,
216ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                TextToSpeech.Engine.DEFAULT_RATE);
217605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi    }
218605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi
219605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi
2206a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi    private String getDefaultLanguage() {
2216a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        String defaultLang = android.provider.Settings.Secure.getString(mResolver,
2226a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi                android.provider.Settings.Secure.TTS_DEFAULT_LANG);
2236a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        if (defaultLang == null) {
224d478cf09dff93015bc332f2707068f08bf603cfdJean-Michel Trivi            // no setting found, use the current Locale to determine the default language
225d478cf09dff93015bc332f2707068f08bf603cfdJean-Michel Trivi            return Locale.getDefault().getISO3Language();
2266a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        } else {
2276a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi            return defaultLang;
2286a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        }
2296a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi    }
2306a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi
2316a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi
2326a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi    private String getDefaultCountry() {
2336a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        String defaultCountry = android.provider.Settings.Secure.getString(mResolver,
2346a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi                android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY);
2356a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        if (defaultCountry == null) {
236d478cf09dff93015bc332f2707068f08bf603cfdJean-Michel Trivi            // no setting found, use the current Locale to determine the default country
237d478cf09dff93015bc332f2707068f08bf603cfdJean-Michel Trivi            return Locale.getDefault().getISO3Country();
2386a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        } else {
2396a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi            return defaultCountry;
2406a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        }
2416a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi    }
2426a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi
2436a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi
2446a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi    private String getDefaultLocVariant() {
2456a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        String defaultVar = android.provider.Settings.Secure.getString(mResolver,
2466a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi                android.provider.Settings.Secure.TTS_DEFAULT_VARIANT);
2476a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        if (defaultVar == null) {
248d478cf09dff93015bc332f2707068f08bf603cfdJean-Michel Trivi            // no setting found, use the current Locale to determine the default variant
249d478cf09dff93015bc332f2707068f08bf603cfdJean-Michel Trivi            return Locale.getDefault().getVariant();
2506a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        } else {
2516a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi            return defaultVar;
2526a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi        }
2536a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi    }
2546a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi
2556a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi
256a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private int setSpeechRate(String callingApp, int rate) {
25769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        int res = TextToSpeech.ERROR;
25869e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        try {
25969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            if (isDefaultEnforced()) {
26069e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                res = sNativeSynth.setSpeechRate(getDefaultRate());
26169e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            } else {
26269e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                res = sNativeSynth.setSpeechRate(rate);
26369e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            }
26469e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        } catch (NullPointerException e) {
26569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            // synth will become null during onDestroy()
26669e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            res = TextToSpeech.ERROR;
267a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen        }
26869e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        return res;
269a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
270a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
2712ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi
272a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private int setPitch(String callingApp, int pitch) {
27369e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        int res = TextToSpeech.ERROR;
27469e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        try {
27569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            res = sNativeSynth.setPitch(pitch);
27669e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        } catch (NullPointerException e) {
27769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            // synth will become null during onDestroy()
27869e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            res = TextToSpeech.ERROR;
27969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        }
28069e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        return res;
2812ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi    }
2822ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi
2832ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi
284ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi    private int isLanguageAvailable(String lang, String country, String variant) {
28569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        int res = TextToSpeech.LANG_NOT_SUPPORTED;
28669e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        try {
28769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            res = sNativeSynth.isLanguageAvailable(lang, country, variant);
28869e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        } catch (NullPointerException e) {
28969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            // synth will become null during onDestroy()
29069e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            res = TextToSpeech.LANG_NOT_SUPPORTED;
29169e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        }
29269e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        return res;
293ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi    }
294ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi
295ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi
296ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi    private String[] getLanguage() {
29769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        try {
29869e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            return sNativeSynth.getLanguage();
29969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        } catch (Exception e) {
30069e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            return null;
30169e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        }
302ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi    }
303ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi
304ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi
305a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private int setLanguage(String callingApp, String lang, String country, String variant) {
306b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi        Log.v(SERVICE_TAG, "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
30769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        int res = TextToSpeech.ERROR;
30869e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        try {
30969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            if (isDefaultEnforced()) {
31069e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                res = sNativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
31169e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        getDefaultLocVariant());
31269e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            } else {
31369e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                res = sNativeSynth.setLanguage(lang, country, variant);
31469e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            }
31569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        } catch (NullPointerException e) {
31669e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            // synth will become null during onDestroy()
31769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi            res = TextToSpeech.ERROR;
318605a66bd56f01713f240ee8bc1435512500498e0Jean-Michel Trivi        }
31969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi        return res;
320a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
321a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
3226a0e293c84de02e819c1b402141bd3f7684ea164Jean-Michel Trivi
323a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    /**
324a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * Adds a sound resource to the TTS.
325a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *
326a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param text
327a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The text that should be associated with the sound resource
328a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param packageName
329a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The name of the package which has the sound resource
330a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param resId
331a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The resource ID of the sound within its package
332a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     */
333a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private void addSpeech(String callingApp, String text, String packageName, int resId) {
33478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mUtterances.put(text, new SoundResource(packageName, resId));
335a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
336a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
337a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    /**
338a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * Adds a sound resource to the TTS.
339a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *
340a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param text
341a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The text that should be associated with the sound resource
342a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param filename
34378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            The filename of the sound resource. This must be a complete
34478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            path like: (/sdcard/mysounds/mysoundbite.mp3).
345a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     */
346a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private void addSpeech(String callingApp, String text, String filename) {
34778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mUtterances.put(text, new SoundResource(filename));
348a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
349a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
350a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    /**
351a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * Adds a sound resource to the TTS as an earcon.
352a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *
353a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param earcon
354a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The text that should be associated with the sound resource
355a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param packageName
356a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The name of the package which has the sound resource
357a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param resId
358a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The resource ID of the sound within its package
359a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     */
360a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private void addEarcon(String callingApp, String earcon, String packageName, int resId) {
36178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mEarcons.put(earcon, new SoundResource(packageName, resId));
362a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
363a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
364a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    /**
365a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * Adds a sound resource to the TTS as an earcon.
366a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *
367a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param earcon
368a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The text that should be associated with the sound resource
369a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param filename
37078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            The filename of the sound resource. This must be a complete
37178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            path like: (/sdcard/mysounds/mysoundbite.mp3).
372a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     */
373a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private void addEarcon(String callingApp, String earcon, String filename) {
37478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mEarcons.put(earcon, new SoundResource(filename));
375a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
376a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
377a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    /**
37878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * Speaks the given text using the specified queueing mode and parameters.
379a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *
38078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * @param text
38178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            The text that should be spoken
38278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * @param queueMode
383d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi     *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances),
384d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi     *            TextToSpeech.TTS_QUEUE_ADD for queued
38578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * @param params
38678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            An ArrayList of parameters. This is not implemented for all
38778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            engines.
388a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     */
389a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private int speak(String callingApp, String text, int queueMode, ArrayList<String> params) {
390b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi        Log.v(SERVICE_TAG, "TTS service received " + text);
391ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        if (queueMode == TextToSpeech.QUEUE_FLUSH) {
392a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            stop(callingApp);
3936f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen        } else if (queueMode == 2) {
3946f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            stopAll(callingApp);
39578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
396a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT));
397741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen        if (!mIsSpeaking) {
398741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen            processSpeechQueue();
399741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen        }
400ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        return TextToSpeech.SUCCESS;
401741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen    }
402741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen
403741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen    /**
40478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * Plays the earcon using the specified queueing mode and parameters.
405a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *
40678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * @param earcon
40778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            The earcon that should be played
40878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * @param queueMode
409d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi     *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances),
410d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi     *            TextToSpeech.TTS_QUEUE_ADD for queued
41178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     * @param params
41278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            An ArrayList of parameters. This is not implemented for all
41378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            engines.
414a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     */
415a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private int playEarcon(String callingApp, String earcon, int queueMode,
41678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            ArrayList<String> params) {
417ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        if (queueMode == TextToSpeech.QUEUE_FLUSH) {
418a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            stop(callingApp);
4196f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen        } else if (queueMode == 2) {
4206f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            stopAll(callingApp);
42178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
422a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        mSpeechQueue.add(new SpeechItem(callingApp, earcon, params, SpeechItem.EARCON));
42378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        if (!mIsSpeaking) {
42478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            processSpeechQueue();
42578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
426ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        return TextToSpeech.SUCCESS;
42778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
42878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
42978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    /**
4306f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen     * Stops all speech output and removes any utterances still in the queue for the calling app.
43178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     */
432a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private int stop(String callingApp) {
433ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        int result = TextToSpeech.ERROR;
4340a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen        boolean speechQueueAvailable = false;
4350a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen        try{
4360dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen            speechQueueAvailable =
4370dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen                    speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
4380a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen            if (speechQueueAvailable) {
439b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                Log.i(SERVICE_TAG, "Stopping");
440a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen                for (int i = mSpeechQueue.size() - 1; i > -1; i--){
44178c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen                    if (mSpeechQueue.get(i).mCallingApp.equals(callingApp)){
442a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen                        mSpeechQueue.remove(i);
443a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen                    }
444a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen                }
4456f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                if ((mCurrentSpeechItem != null) &&
4466f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                     mCurrentSpeechItem.mCallingApp.equals(callingApp)) {
44769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                    try {
44869e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        result = sNativeSynth.stop();
44969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                    } catch (NullPointerException e1) {
45069e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        // synth will become null during onDestroy()
45169e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        result = TextToSpeech.ERROR;
45269e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                    }
453c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen                    mKillList.put(mCurrentSpeechItem, true);
4546f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    if (mPlayer != null) {
4556f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        try {
4566f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                            mPlayer.stop();
4576f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        } catch (IllegalStateException e) {
4586f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                            // Do nothing, the player is already stopped.
4596f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        }
4600a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen                    }
4616f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    mIsSpeaking = false;
4626f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    mCurrentSpeechItem = null;
4636f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                } else {
464ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                    result = TextToSpeech.SUCCESS;
4650a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen                }
466b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                Log.i(SERVICE_TAG, "Stopped");
467ab6ed2c2b9cebd97cb501da58d386f59e4a99103Jean-Michel Trivi            } else {
468b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                Log.e(SERVICE_TAG, "TTS stop(): queue locked longer than expected");
469ab6ed2c2b9cebd97cb501da58d386f59e4a99103Jean-Michel Trivi                result = TextToSpeech.ERROR;
4700a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen            }
4710a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen        } catch (InterruptedException e) {
472b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi          Log.e(SERVICE_TAG, "TTS stop: tryLock interrupted");
4730a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen          e.printStackTrace();
4740a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen        } finally {
4750a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen            // This check is needed because finally will always run; even if the
4760a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen            // method returns somewhere in the try block.
4776f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            if (speechQueueAvailable) {
4786f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                speechQueueLock.unlock();
4796f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            }
4806f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            return result;
4816f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen        }
4826f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen    }
4836f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen
4846f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen
485a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi    /**
486a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi     * Stops all speech output, both rendered to a file and directly spoken, and removes any
487a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi     * utterances still in the queue globally. Files that were being written are deleted.
488a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi     */
489a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi    @SuppressWarnings("finally")
490a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi    private int killAllUtterances() {
491a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi        int result = TextToSpeech.ERROR;
492a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi        boolean speechQueueAvailable = false;
493a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi
494a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi        try {
495a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            speechQueueAvailable = speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT,
496a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                    TimeUnit.MILLISECONDS);
497a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            if (speechQueueAvailable) {
498a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                // remove every single entry in the speech queue
499a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                mSpeechQueue.clear();
500a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi
501a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                // clear the current speech item
502a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                if (mCurrentSpeechItem != null) {
50309f8db7ad3963f5fa15f2b99880b2f70e89c30aeJean-Michel Trivi                    result = sNativeSynth.stopSync();
504a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                    mKillList.put(mCurrentSpeechItem, true);
505a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                    mIsSpeaking = false;
506a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi
507a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                    // was the engine writing to a file?
508a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                    if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) {
509a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                        // delete the file that was being written
510a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                        if (mCurrentSpeechItem.mFilename != null) {
511a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                            File tempFile = new File(mCurrentSpeechItem.mFilename);
512b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                            Log.v(SERVICE_TAG, "Leaving behind " + mCurrentSpeechItem.mFilename);
513a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                            if (tempFile.exists()) {
514b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                                Log.v(SERVICE_TAG, "About to delete "
515a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                                        + mCurrentSpeechItem.mFilename);
516a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                                if (tempFile.delete()) {
517b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                                    Log.v(SERVICE_TAG, "file successfully deleted");
518a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                                }
519a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                            }
520a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                        }
521a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                    }
522a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi
523a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                    mCurrentSpeechItem = null;
524a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                }
525a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            } else {
526b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                Log.e(SERVICE_TAG, "TTS killAllUtterances(): queue locked longer than expected");
527a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                result = TextToSpeech.ERROR;
528a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            }
529a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi        } catch (InterruptedException e) {
530b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi            Log.e(SERVICE_TAG, "TTS killAllUtterances(): tryLock interrupted");
531a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            result = TextToSpeech.ERROR;
532a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi        } finally {
533a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            // This check is needed because finally will always run, even if the
534a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            // method returns somewhere in the try block.
535a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            if (speechQueueAvailable) {
536a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi                speechQueueLock.unlock();
537a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            }
538a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi            return result;
539a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi        }
540a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi    }
541a3046b6f7f81cc16afeba9aee880c2ed643ccfbfJean-Michel Trivi
5426f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen
5436f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen    /**
54469e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi     * Stops all speech output and removes any utterances still in the queue globally, except
54569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi     * those intended to be synthesized to file.
5466f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen     */
5476f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen    private int stopAll(String callingApp) {
548ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        int result = TextToSpeech.ERROR;
5496f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen        boolean speechQueueAvailable = false;
5506f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen        try{
5510dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen            speechQueueAvailable =
5520dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen                    speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
5536f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            if (speechQueueAvailable) {
5546f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                for (int i = mSpeechQueue.size() - 1; i > -1; i--){
5556f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    if (mSpeechQueue.get(i).mType != SpeechItem.TEXT_TO_FILE){
5566f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        mSpeechQueue.remove(i);
5576f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    }
5586f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                }
5596f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                if ((mCurrentSpeechItem != null) &&
5606f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    ((mCurrentSpeechItem.mType != SpeechItem.TEXT_TO_FILE) ||
5616f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                      mCurrentSpeechItem.mCallingApp.equals(callingApp))) {
56269e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                    try {
56369e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        result = sNativeSynth.stop();
56469e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                    } catch (NullPointerException e1) {
56569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        // synth will become null during onDestroy()
56669e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        result = TextToSpeech.ERROR;
56769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                    }
568c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen                    mKillList.put(mCurrentSpeechItem, true);
5696f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    if (mPlayer != null) {
5706f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        try {
5716f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                            mPlayer.stop();
5726f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        } catch (IllegalStateException e) {
5736f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                            // Do nothing, the player is already stopped.
5746f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        }
5756f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    }
5766f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    mIsSpeaking = false;
5776f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    mCurrentSpeechItem = null;
5786f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                } else {
579ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                    result = TextToSpeech.SUCCESS;
5806f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                }
581b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                Log.i(SERVICE_TAG, "Stopped all");
582ab6ed2c2b9cebd97cb501da58d386f59e4a99103Jean-Michel Trivi            } else {
583b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                Log.e(SERVICE_TAG, "TTS stopAll(): queue locked longer than expected");
584ab6ed2c2b9cebd97cb501da58d386f59e4a99103Jean-Michel Trivi                result = TextToSpeech.ERROR;
5856f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            }
5866f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen        } catch (InterruptedException e) {
587b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi          Log.e(SERVICE_TAG, "TTS stopAll: tryLock interrupted");
5886f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen          e.printStackTrace();
5896f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen        } finally {
5906f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            // This check is needed because finally will always run; even if the
5916f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen            // method returns somewhere in the try block.
5920a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen            if (speechQueueAvailable) {
5930a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen                speechQueueLock.unlock();
59478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
5950a3d8744feb8ef5714b6c341ebcaa7ce326de908Charles Chen            return result;
59678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
59778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
59878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
59978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    public void onCompletion(MediaPlayer arg0) {
6003ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        String callingApp = mCurrentSpeechItem.mCallingApp;
6013ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        ArrayList<String> params = mCurrentSpeechItem.mParams;
6023ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        String utteranceId = "";
6033ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        if (params != null){
6043ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen            for (int i = 0; i < params.size() - 1; i = i + 2){
6053ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen            String param = params.get(i);
606ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
6073ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    utteranceId = params.get(i+1);
6083ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                }
6093ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen            }
6103ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        }
6113ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        if (utteranceId.length() > 0){
6123ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen            dispatchUtteranceCompletedCallback(utteranceId, callingApp);
6133ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        }
61478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        processSpeechQueue();
61578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
61678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
617a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private int playSilence(String callingApp, long duration, int queueMode,
61878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            ArrayList<String> params) {
619ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        if (queueMode == TextToSpeech.QUEUE_FLUSH) {
620a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            stop(callingApp);
62178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
6223ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen        mSpeechQueue.add(new SpeechItem(callingApp, duration, params));
62378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        if (!mIsSpeaking) {
62478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            processSpeechQueue();
62578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
626ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        return TextToSpeech.SUCCESS;
62778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
62878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
6293ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen    private void silence(final SpeechItem speechItem) {
63078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        class SilenceThread implements Runnable {
63178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            public void run() {
6323ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                String utteranceId = "";
633edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                if (speechItem.mParams != null){
634edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                    for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
635edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                        String param = speechItem.mParams.get(i);
636ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                        if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
637edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                            utteranceId = speechItem.mParams.get(i+1);
6383ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                        }
6393ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    }
6403ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                }
64178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                try {
642edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                    Thread.sleep(speechItem.mDuration);
64378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                } catch (InterruptedException e) {
64478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    e.printStackTrace();
64578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                } finally {
6463ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    if (utteranceId.length() > 0){
647edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                        dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
6483ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    }
64978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    processSpeechQueue();
65078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                }
65178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
65278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
65378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        Thread slnc = (new Thread(new SilenceThread()));
65478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        slnc.setPriority(Thread.MIN_PRIORITY);
65578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        slnc.start();
65678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
65778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
65878c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen    private void speakInternalOnly(final SpeechItem speechItem) {
65978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        class SynthThread implements Runnable {
66078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            public void run() {
66178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                boolean synthAvailable = false;
66278c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen                String utteranceId = "";
66378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                try {
66478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    synthAvailable = synthesizerLock.tryLock();
66578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    if (!synthAvailable) {
66678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        Thread.sleep(100);
66778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        Thread synth = (new Thread(new SynthThread()));
6685e11a6ad00b062d604b30578e0fb412ae4586989Jean-Michel Trivi                        //synth.setPriority(Thread.MIN_PRIORITY);
66978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        synth.start();
67078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        return;
67178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    }
6729440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                    int streamType = DEFAULT_STREAM_TYPE;
673b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    String language = "";
674b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    String country = "";
675b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    String variant = "";
676b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    String speechRate = "";
677edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                    if (speechItem.mParams != null){
678edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                        for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
679edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                            String param = speechItem.mParams.get(i);
6809440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                            if (param != null) {
681ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) {
682b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                                    speechRate = speechItem.mParams.get(i+1);
683ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){
684edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                    language = speechItem.mParams.get(i+1);
685ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){
686edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                    country = speechItem.mParams.get(i+1);
687ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){
688edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                    variant = speechItem.mParams.get(i+1);
689ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
690edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                    utteranceId = speechItem.mParams.get(i+1);
691ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM)) {
6929440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                                    try {
693edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                        streamType
694edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                                = Integer.parseInt(speechItem.mParams.get(i + 1));
6959440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                                    } catch (NumberFormatException e) {
6969440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                                        streamType = DEFAULT_STREAM_TYPE;
6979440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                                    }
698630a8de44fa0ca855c4a87d939432f831e8ed531Charles Chen                                }
69903454f8932b7fd79471ae6f95f2de7b75b0ded8aCharles Chen                            }
70003454f8932b7fd79471ae6f95f2de7b75b0ded8aCharles Chen                        }
701b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    }
702b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    // Only do the synthesis if it has not been killed by a subsequent utterance.
703b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    if (mKillList.get(speechItem) == null) {
70403454f8932b7fd79471ae6f95f2de7b75b0ded8aCharles Chen                        if (language.length() > 0){
705a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen                            setLanguage("", language, country, variant);
70603454f8932b7fd79471ae6f95f2de7b75b0ded8aCharles Chen                        }
707b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                        if (speechRate.length() > 0){
708b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                            setSpeechRate("", Integer.parseInt(speechRate));
709b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                        }
71069e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        try {
71169e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                            sNativeSynth.speak(speechItem.mText, streamType);
71269e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        } catch (NullPointerException e) {
71369e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                            // synth will become null during onDestroy()
714b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                            Log.v(SERVICE_TAG, " null synth, can't speak");
71569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        }
716c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen                    }
71778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                } catch (InterruptedException e) {
718b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                    Log.e(SERVICE_TAG, "TTS speakInternalOnly(): tryLock interrupted");
71978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    e.printStackTrace();
72078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                } finally {
72178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    // This check is needed because finally will always run;
72278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    // even if the
72378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    // method returns somewhere in the try block.
72478c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen                    if (utteranceId.length() > 0){
725edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                        dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
72678c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen                    }
7276f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    if (synthAvailable) {
7286f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        synthesizerLock.unlock();
7296f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    }
7307af9e196a33ac1d7fe3d5030fa42bbcaf2038020Charles Chen                    processSpeechQueue();
73178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                }
73278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
73378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
73478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        Thread synth = (new Thread(new SynthThread()));
735ab6ed2c2b9cebd97cb501da58d386f59e4a99103Jean-Michel Trivi        synth.setPriority(Thread.MAX_PRIORITY);
73678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        synth.start();
73778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
73878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
7393ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen    private void synthToFileInternalOnly(final SpeechItem speechItem) {
740ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        class SynthThread implements Runnable {
741ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            public void run() {
742ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                boolean synthAvailable = false;
7433ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                String utteranceId = "";
744b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                Log.i(SERVICE_TAG, "Synthesizing to " + speechItem.mFilename);
745ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                try {
746ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    synthAvailable = synthesizerLock.tryLock();
747ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    if (!synthAvailable) {
748ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                        Thread.sleep(100);
749ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                        Thread synth = (new Thread(new SynthThread()));
7505e11a6ad00b062d604b30578e0fb412ae4586989Jean-Michel Trivi                        //synth.setPriority(Thread.MIN_PRIORITY);
751ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                        synth.start();
752ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                        return;
753ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    }
754b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    String language = "";
755b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    String country = "";
756b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    String variant = "";
757b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                    String speechRate = "";
758edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                    if (speechItem.mParams != null){
759edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                        for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
760edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                            String param = speechItem.mParams.get(i);
761b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                            if (param != null) {
762ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) {
763b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                                    speechRate = speechItem.mParams.get(i+1);
764ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){
765edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                    language = speechItem.mParams.get(i+1);
766ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){
767edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                    country = speechItem.mParams.get(i+1);
768ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){
769edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                    variant = speechItem.mParams.get(i+1);
770ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                                } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
771edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                                    utteranceId = speechItem.mParams.get(i+1);
772630a8de44fa0ca855c4a87d939432f831e8ed531Charles Chen                                }
773ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                            }
774ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                        }
775ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    }
776c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen                    // Only do the synthesis if it has not been killed by a subsequent utterance.
777c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen                    if (mKillList.get(speechItem) == null){
778b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                        if (language.length() > 0){
779b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                            setLanguage("", language, country, variant);
780b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                        }
781b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                        if (speechRate.length() > 0){
782b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                            setSpeechRate("", Integer.parseInt(speechRate));
783b79370aad730949543bccf01b2c3d9ed64f493f5Charles Chen                        }
78469e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        try {
78569e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                            sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename);
78669e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        } catch (NullPointerException e) {
78769e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                            // synth will become null during onDestroy()
788b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                            Log.v(SERVICE_TAG, " null synth, can't synthesize to file");
78969e67a3e2e863fa8828151ef3a488bfcaa504f7aJean-Michel Trivi                        }
790c231fd0fe7814a025aeb05796542048a51d0236bCharles Chen                    }
791ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                } catch (InterruptedException e) {
792b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                    Log.e(SERVICE_TAG, "TTS synthToFileInternalOnly(): tryLock interrupted");
793ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    e.printStackTrace();
794ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                } finally {
795ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    // This check is needed because finally will always run;
796ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    // even if the
797ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    // method returns somewhere in the try block.
7983ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    if (utteranceId.length() > 0){
799edb4fc3076622393ac25fafda24e4bbe78ec44e4Charles Chen                        dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
8003ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    }
8016f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    if (synthAvailable) {
8026f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                        synthesizerLock.unlock();
8036f624239dc6c62ac9f18c4c8c65c2fbf1c78bdbdCharles Chen                    }
804ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                    processSpeechQueue();
805ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen                }
806ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            }
807ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        }
808ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        Thread synth = (new Thread(new SynthThread()));
809ab6ed2c2b9cebd97cb501da58d386f59e4a99103Jean-Michel Trivi        synth.setPriority(Thread.MAX_PRIORITY);
810ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        synth.start();
811ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen    }
812ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen
81378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private SoundResource getSoundResource(SpeechItem speechItem) {
81478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        SoundResource sr = null;
81578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        String text = speechItem.mText;
81678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        if (speechItem.mType == SpeechItem.SILENCE) {
81778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            // Do nothing if this is just silence
81878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        } else if (speechItem.mType == SpeechItem.EARCON) {
81978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            sr = mEarcons.get(text);
82078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        } else {
82178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            sr = mUtterances.get(text);
82278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
82378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        return sr;
82478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
82578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
82628dbae7df43ee683ba1bf468ad9924092bb9c569Charles Chen    private void broadcastTtsQueueProcessingCompleted(){
827ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi        Intent i = new Intent(TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
82828dbae7df43ee683ba1bf468ad9924092bb9c569Charles Chen        sendBroadcast(i);
82928dbae7df43ee683ba1bf468ad9924092bb9c569Charles Chen    }
83028dbae7df43ee683ba1bf468ad9924092bb9c569Charles Chen
83178c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen
83278c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen    private void dispatchUtteranceCompletedCallback(String utteranceId, String packageName) {
83378c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        ITtsCallback cb = mCallbacksMap.get(packageName);
83478c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        if (cb == null){
83578c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            return;
83678c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        }
837b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi        Log.v(SERVICE_TAG, "TTS callback: dispatch started");
83878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        // Broadcast to all clients the new value.
83978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        final int N = mCallbacks.beginBroadcast();
84078c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        try {
84178c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            cb.utteranceCompleted(utteranceId);
84278c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        } catch (RemoteException e) {
84378c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            // The RemoteCallbackList will take care of removing
84478c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            // the dead object for us.
84578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
84678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        mCallbacks.finishBroadcast();
847b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi        Log.v(SERVICE_TAG, "TTS callback: dispatch completed to " + N);
84878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
84978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
8501aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen    private SpeechItem splitCurrentTextIfNeeded(SpeechItem currentSpeechItem){
8511aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen        if (currentSpeechItem.mText.length() < MAX_SPEECH_ITEM_CHAR_LENGTH){
8521aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            return currentSpeechItem;
8531aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen        } else {
85478c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            String callingApp = currentSpeechItem.mCallingApp;
8551aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            ArrayList<SpeechItem> splitItems = new ArrayList<SpeechItem>();
8561aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            int start = 0;
8571aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            int end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1;
8581aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            String splitText;
8591aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            SpeechItem splitItem;
8601aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            while (end < currentSpeechItem.mText.length()){
8611aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen                splitText = currentSpeechItem.mText.substring(start, end);
862a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen                splitItem = new SpeechItem(callingApp, splitText, null, SpeechItem.TEXT);
8631aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen                splitItems.add(splitItem);
8641aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen                start = end;
8651aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen                end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1;
8661aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            }
8671aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            splitText = currentSpeechItem.mText.substring(start);
868a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            splitItem = new SpeechItem(callingApp, splitText, null, SpeechItem.TEXT);
8691aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            splitItems.add(splitItem);
8701aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            mSpeechQueue.remove(0);
8711aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            for (int i = splitItems.size() - 1; i >= 0; i--){
8721aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen                mSpeechQueue.add(0, splitItems.get(i));
8731aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            }
8741aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen            return mSpeechQueue.get(0);
8751aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen        }
8761aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen    }
8771aacdcfaa9233995fe78017c2a342258a69123a4Charles Chen
87878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private void processSpeechQueue() {
87978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        boolean speechQueueAvailable = false;
88078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        try {
8810dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen            speechQueueAvailable =
8820dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen                    speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
88378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (!speechQueueAvailable) {
884b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi                Log.e(SERVICE_TAG, "processSpeechQueue - Speech queue is unavailable.");
88578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                return;
88678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
88778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (mSpeechQueue.size() < 1) {
88878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                mIsSpeaking = false;
88909f8db7ad3963f5fa15f2b99880b2f70e89c30aeJean-Michel Trivi                mKillList.clear();
89028dbae7df43ee683ba1bf468ad9924092bb9c569Charles Chen                broadcastTtsQueueProcessingCompleted();
89178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                return;
89278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
89378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
8943ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen            mCurrentSpeechItem = mSpeechQueue.get(0);
89578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mIsSpeaking = true;
8963ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen            SoundResource sr = getSoundResource(mCurrentSpeechItem);
89778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            // Synth speech as needed - synthesizer should call
89878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            // processSpeechQueue to continue running the queue
899b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi            Log.v(SERVICE_TAG, "TTS processing: " + mCurrentSpeechItem.mText);
90078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (sr == null) {
9013ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                if (mCurrentSpeechItem.mType == SpeechItem.TEXT) {
9023ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    mCurrentSpeechItem = splitCurrentTextIfNeeded(mCurrentSpeechItem);
9033ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    speakInternalOnly(mCurrentSpeechItem);
9043ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                } else if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) {
9053ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    synthToFileInternalOnly(mCurrentSpeechItem);
90678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                } else {
90778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    // This is either silence or an earcon that was missing
9083ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    silence(mCurrentSpeechItem);
90978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                }
91078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            } else {
91178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                cleanUpPlayer();
91278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                if (sr.mSourcePackageName == PKGNAME) {
91378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    // Utterance is part of the TTS library
91478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    mPlayer = MediaPlayer.create(this, sr.mResId);
91578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                } else if (sr.mSourcePackageName != null) {
91678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    // Utterance is part of the app calling the library
91778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    Context ctx;
91878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    try {
9199440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                        ctx = this.createPackageContext(sr.mSourcePackageName, 0);
92078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    } catch (NameNotFoundException e) {
92178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        e.printStackTrace();
92278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        mSpeechQueue.remove(0); // Remove it from the queue and
92378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        // move on
92478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        mIsSpeaking = false;
92578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                        return;
92678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    }
92778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    mPlayer = MediaPlayer.create(ctx, sr.mResId);
92878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                } else {
92978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    // Utterance is coming from a file
93078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    mPlayer = MediaPlayer.create(this, Uri.parse(sr.mFilename));
93178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                }
93278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
93378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                // Check if Media Server is dead; if it is, clear the queue and
93478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                // give up for now - hopefully, it will recover itself.
93578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                if (mPlayer == null) {
93678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    mSpeechQueue.clear();
93778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    mIsSpeaking = false;
93878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    return;
93978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                }
94078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                mPlayer.setOnCompletionListener(this);
94178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                try {
9423ab2076d65b86a69f6c5de220082c2fbace575e2Charles Chen                    mPlayer.setAudioStreamType(getStreamTypeFromParams(mCurrentSpeechItem.mParams));
94378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    mPlayer.start();
94478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                } catch (IllegalStateException e) {
94578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    mSpeechQueue.clear();
94678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    mIsSpeaking = false;
94778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    cleanUpPlayer();
94878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    return;
94978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                }
95078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
95178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (mSpeechQueue.size() > 0) {
95278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                mSpeechQueue.remove(0);
95378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
9540dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen        } catch (InterruptedException e) {
955b00941804890858ddc3b680c7a8e171c7dfdfb5fJean-Michel Trivi          Log.e(SERVICE_TAG, "TTS processSpeechQueue: tryLock interrupted");
9560dbc6a44bb76631911552bc5b356391dac6f38a4Charles Chen          e.printStackTrace();
95778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        } finally {
95878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            // This check is needed because finally will always run; even if the
95978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            // method returns somewhere in the try block.
96078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (speechQueueAvailable) {
96178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                speechQueueLock.unlock();
96278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
96378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
96478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
96578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
9669440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi    private int getStreamTypeFromParams(ArrayList<String> paramList) {
9679440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi        int streamType = DEFAULT_STREAM_TYPE;
9689440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi        if (paramList == null) {
9699440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi            return streamType;
9709440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi        }
9719440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi        for (int i = 0; i < paramList.size() - 1; i = i + 2) {
9729440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi            String param = paramList.get(i);
973ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi            if ((param != null) && (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM))) {
9749440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                try {
9759440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                    streamType = Integer.parseInt(paramList.get(i + 1));
9769440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                } catch (NumberFormatException e) {
9779440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                    streamType = DEFAULT_STREAM_TYPE;
9789440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi                }
9799440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi            }
9809440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi        }
9819440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi        return streamType;
9829440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi    }
9839440bce8553a82e420e06ded3fcccc6971d1ff79Jean-Michel Trivi
98478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    private void cleanUpPlayer() {
98578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        if (mPlayer != null) {
98678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mPlayer.release();
98778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            mPlayer = null;
98878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
989a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
990a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
991a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    /**
992741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen     * Synthesizes the given text to a file using the specified parameters.
993a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *
994a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param text
995a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     *            The String of text that should be synthesized
996a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param params
99778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            An ArrayList of parameters. The first element of this array
99878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            controls the type of voice to use.
999a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @param filename
100078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            The string that gives the full output filename; it should be
100178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi     *            something like "/sdcard/myappsounds/mysound.wav".
1002a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     * @return A boolean that indicates if the synthesis succeeded
1003a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen     */
1004a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen    private boolean synthesizeToFile(String callingApp, String text, ArrayList<String> params,
1005ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            String filename) {
1006ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        // Don't allow a filename that is too long
1007ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        if (filename.length() > MAX_FILENAME_LENGTH) {
1008ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            return false;
100978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
1010ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        // Don't allow anything longer than the max text length; since this
1011ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        // is synthing to a file, don't even bother splitting it.
1012ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        if (text.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH){
1013ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            return false;
1014ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        }
1015a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT_TO_FILE, filename));
1016ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen        if (!mIsSpeaking) {
1017ebb814bbaeacbdc04faa5683f25b12d40609548cCharles Chen            processSpeechQueue();
101878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
101978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        return true;
102078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    }
102178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
102278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    @Override
102378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    public IBinder onBind(Intent intent) {
102478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        if (ACTION.equals(intent.getAction())) {
102578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            for (String category : intent.getCategories()) {
102678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                if (category.equals(CATEGORY)) {
102778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                    return mBinder;
102878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                }
102978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
103078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
103178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        return null;
1032a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen    }
103378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
1034f85aa5a4d4e6f1ef7e07638568e27d709b8085c6Charles Chen    private final android.speech.tts.ITts.Stub mBinder = new Stub() {
103578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
103678c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        public int registerCallback(String packageName, ITtsCallback cb) {
103778c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            if (cb != null) {
103878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                mCallbacks.register(cb);
103978c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen                mCallbacksMap.put(packageName, cb);
1040ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                return TextToSpeech.SUCCESS;
104178c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            }
1042ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi            return TextToSpeech.ERROR;
104378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
104478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
104578c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen        public int unregisterCallback(String packageName, ITtsCallback cb) {
104678c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            if (cb != null) {
104778c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen                mCallbacksMap.remove(packageName);
104878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                mCallbacks.unregister(cb);
1049ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi                return TextToSpeech.SUCCESS;
105078c9d0d2c5eb4d5687ae7cbe41155159329ad68fCharles Chen            }
1051ed06578eddde07abe325fa4c92910bb7246cd49fJean-Michel Trivi            return TextToSpeech.ERROR;
105278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
105378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
105478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
105578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Speaks the given text using the specified queueing mode and
105678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * parameters.
105778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
105878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param text
105978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The text that should be spoken
106078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param queueMode
1061d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi         *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
1062d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi         *            TextToSpeech.TTS_QUEUE_ADD for queued
106378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param params
106478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            An ArrayList of parameters. The first element of this
106578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            array controls the type of voice to use.
106678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1067a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public int speak(String callingApp, String text, int queueMode, String[] params) {
106878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            ArrayList<String> speakingParams = new ArrayList<String>();
106978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (params != null) {
107078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                speakingParams = new ArrayList<String>(Arrays.asList(params));
107178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
1072a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            return mSelf.speak(callingApp, text, queueMode, speakingParams);
107378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
107478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
107578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
107678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Plays the earcon using the specified queueing mode and parameters.
107778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
107878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param earcon
107978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The earcon that should be played
108078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param queueMode
1081d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi         *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
1082d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi         *            TextToSpeech.TTS_QUEUE_ADD for queued
108378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param params
108478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            An ArrayList of parameters.
108578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1086a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public int playEarcon(String callingApp, String earcon, int queueMode, String[] params) {
108778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            ArrayList<String> speakingParams = new ArrayList<String>();
108878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (params != null) {
108978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                speakingParams = new ArrayList<String>(Arrays.asList(params));
109078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
1091a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            return mSelf.playEarcon(callingApp, earcon, queueMode, speakingParams);
109278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
109378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
109478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
109578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Plays the silence using the specified queueing mode and parameters.
109678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
109778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param duration
109878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The duration of the silence that should be played
109978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param queueMode
1100d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi         *            TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
1101d48ca22b9fcea38b112aedb4126f3d030594af47Jean-Michel Trivi         *            TextToSpeech.TTS_QUEUE_ADD for queued
110278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param params
110378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            An ArrayList of parameters.
110478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1105a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public int playSilence(String callingApp, long duration, int queueMode, String[] params) {
110678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            ArrayList<String> speakingParams = new ArrayList<String>();
110778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (params != null) {
110878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                speakingParams = new ArrayList<String>(Arrays.asList(params));
110978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
1110a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            return mSelf.playSilence(callingApp, duration, queueMode, speakingParams);
111178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
111278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
111378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
111478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Stops all speech output and removes any utterances still in the
111578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * queue.
111678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1117a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public int stop(String callingApp) {
1118a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            return mSelf.stop(callingApp);
111978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
112078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
112178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
112278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Returns whether or not the TTS is speaking.
112378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
112478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @return Boolean to indicate whether or not the TTS is speaking
112578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
112678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        public boolean isSpeaking() {
112778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            return (mSelf.mIsSpeaking && (mSpeechQueue.size() < 1));
112878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
112978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
113078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
113178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Adds a sound resource to the TTS.
113278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
113378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param text
113478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The text that should be associated with the sound resource
113578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param packageName
113678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The name of the package which has the sound resource
113778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param resId
113878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The resource ID of the sound within its package
113978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1140a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public void addSpeech(String callingApp, String text, String packageName, int resId) {
1141a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            mSelf.addSpeech(callingApp, text, packageName, resId);
114278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
114378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
114478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
114578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Adds a sound resource to the TTS.
114678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
114778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param text
114878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The text that should be associated with the sound resource
114978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param filename
115078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The filename of the sound resource. This must be a
115178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            complete path like: (/sdcard/mysounds/mysoundbite.mp3).
115278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1153a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public void addSpeechFile(String callingApp, String text, String filename) {
1154a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            mSelf.addSpeech(callingApp, text, filename);
115578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
115678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
115778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
115878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Adds a sound resource to the TTS as an earcon.
115978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
116078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param earcon
116178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The text that should be associated with the sound resource
116278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param packageName
116378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The name of the package which has the sound resource
116478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param resId
116578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The resource ID of the sound within its package
116678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1167a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public void addEarcon(String callingApp, String earcon, String packageName, int resId) {
1168a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            mSelf.addEarcon(callingApp, earcon, packageName, resId);
116978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
117078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
117178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
117278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Adds a sound resource to the TTS as an earcon.
117378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
117478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param earcon
117578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The text that should be associated with the sound resource
117678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param filename
117778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The filename of the sound resource. This must be a
117878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            complete path like: (/sdcard/mysounds/mysoundbite.mp3).
117978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1180a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public void addEarconFile(String callingApp, String earcon, String filename) {
1181a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            mSelf.addEarcon(callingApp, earcon, filename);
118278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
118378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
118478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
118578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * Sets the speech rate for the TTS. Note that this will only have an
118678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * effect on synthesized speech; it will not affect pre-recorded speech.
118778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
118878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param speechRate
118978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The speech rate that should be used
119078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1191a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public int setSpeechRate(String callingApp, int speechRate) {
1192a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            return mSelf.setSpeechRate(callingApp, speechRate);
119378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
119478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
119578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
11962ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi         * Sets the pitch for the TTS. Note that this will only have an
11972ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi         * effect on synthesized speech; it will not affect pre-recorded speech.
11982ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi         *
11992ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi         * @param pitch
12002ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi         *            The pitch that should be used for the synthesized voice
12012ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi         */
1202a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public int setPitch(String callingApp, int pitch) {
1203a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            return mSelf.setPitch(callingApp, pitch);
12042ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi        }
12052ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi
12062ea5349583de4a505501530d04133524bb6d5d38Jean-Michel Trivi        /**
1207ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         * Returns the level of support for the specified language.
1208ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         *
1209ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         * @param lang  the three letter ISO language code.
1210ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         * @param country  the three letter ISO country code.
1211ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         * @param variant  the variant code associated with the country and language pair.
1212ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         * @return one of TTS_LANG_NOT_SUPPORTED, TTS_LANG_MISSING_DATA, TTS_LANG_AVAILABLE,
1213ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         *      TTS_LANG_COUNTRY_AVAILABLE, TTS_LANG_COUNTRY_VAR_AVAILABLE as defined in
1214ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         *      android.speech.tts.TextToSpeech.
1215ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         */
1216ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi        public int isLanguageAvailable(String lang, String country, String variant) {
1217ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi            return mSelf.isLanguageAvailable(lang, country, variant);
1218ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi        }
1219ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi
1220ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi        /**
1221ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         * Returns the currently set language / country / variant strings representing the
1222ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         * language used by the TTS engine.
1223ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         * @return null is no language is set, or an array of 3 string containing respectively
1224ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         *      the language, country and variant.
1225ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi         */
1226ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi        public String[] getLanguage() {
1227ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi            return mSelf.getLanguage();
1228ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi        }
1229ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi
1230ddb0a803fd353fbaf0139cc8804499bc9dce7403Jean-Michel Trivi        /**
1231679d728f09eeab2f8b882e42f6e081db1ac74996Jean-Michel Trivi         * Sets the speech rate for the TTS, which affects the synthesized voice.
123278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
1233679d728f09eeab2f8b882e42f6e081db1ac74996Jean-Michel Trivi         * @param lang  the three letter ISO language code.
1234679d728f09eeab2f8b882e42f6e081db1ac74996Jean-Michel Trivi         * @param country  the three letter ISO country code.
1235679d728f09eeab2f8b882e42f6e081db1ac74996Jean-Michel Trivi         * @param variant  the variant code associated with the country and language pair.
123678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1237a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public int setLanguage(String callingApp, String lang, String country, String variant) {
1238a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            return mSelf.setLanguage(callingApp, lang, country, variant);
123978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
124078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi
124178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        /**
1242741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen         * Synthesizes the given text to a file using the specified
124378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * parameters.
124478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *
124578ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param text
124678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The String of text that should be synthesized
124778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param params
124878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            An ArrayList of parameters. The first element of this
124978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            array controls the type of voice to use.
125078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @param filename
125178ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            The string that gives the full output filename; it should
125278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         *            be something like "/sdcard/myappsounds/mysound.wav".
125378ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         * @return A boolean that indicates if the synthesis succeeded
125478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi         */
1255a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen        public boolean synthesizeToFile(String callingApp, String text, String[] params,
125678ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                String filename) {
125778ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            ArrayList<String> speakingParams = new ArrayList<String>();
125878ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            if (params != null) {
125978ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi                speakingParams = new ArrayList<String>(Arrays.asList(params));
126078ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi            }
1261a9c5e4bf2639f8f09be8bace4230613b7b689f0eCharles Chen            return mSelf.synthesizeToFile(callingApp, text, speakingParams, filename);
126278ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi        }
1263741c25b164d132ddc6ef662ddf854ebedcd0e389Charles Chen
126478ebbabfe18f2c6fb4825e4bdbb1613e0901f0f3Jean-Michel Trivi    };
1265a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen
1266a042a740d37453a1974147ebe6ee206bbd85f17dCharles Chen}
1267