TextToSpeech.java revision 679d728f09eeab2f8b882e42f6e081db1ac74996
1/* 2 * Copyright (C) 2009 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16package android.speech.tts; 17 18import android.speech.tts.ITts; 19import android.speech.tts.ITtsCallback; 20 21import android.content.ComponentName; 22import android.content.Context; 23import android.content.Intent; 24import android.content.ServiceConnection; 25import android.os.IBinder; 26import android.os.RemoteException; 27import android.util.Log; 28 29import java.util.HashMap; 30import java.util.Locale; 31 32/** 33 * 34 * Synthesizes speech from text. 35 * 36 * {@hide} 37 */ 38//TODO #TTS# review + complete javadoc + add links to constants 39public class TextToSpeech { 40 41 /** 42 * Denotes a successful operation. 43 */ 44 public static final int TTS_SUCCESS = 0; 45 /** 46 * Denotes a generic operation failure. 47 */ 48 public static final int TTS_ERROR = -1; 49 /** 50 * Denotes a failure due to a missing resource. 51 */ 52 public static final int TTS_ERROR_MISSING_RESOURCE = -2; 53 54 /** 55 * Queue mode where all entries in the playback queue (media to be played 56 * and text to be synthesized) are dropped and replaced by the new entry. 57 */ 58 public static final int TTS_QUEUE_FLUSH = 0; 59 /** 60 * Queue mode where the new entry is added at the end of the playback queue. 61 */ 62 public static final int TTS_QUEUE_ADD = 1; 63 64 /** 65 * Called when the TTS has initialized. 66 * 67 * The InitListener must implement the onInit function. onInit is passed a 68 * status code indicating the result of the TTS initialization. 69 */ 70 public interface OnInitListener { 71 public void onInit(int status); 72 } 73 74 /** 75 * Called when the TTS has finished speaking by itself (speaking 76 * finished without being canceled). 77 * 78 */ 79 public interface OnSpeechCompletedListener { 80 public void onSpeechCompleted(); 81 } 82 83 /** 84 * Connection needed for the TTS. 85 */ 86 private ServiceConnection mServiceConnection; 87 88 private ITts mITts = null; 89 private Context mContext = null; 90 private OnInitListener mInitListener = null; 91 private boolean mStarted = false; 92 private final Object mStartLock = new Object(); 93 private ITtsCallback mITtsCallback; 94 private OnSpeechCompletedListener mSpeechCompListener = null; 95 private final Object mSpeechCompListenerLock = new Object(); 96 97 98 99 /** 100 * The constructor for the TTS. 101 * 102 * @param context 103 * The context 104 * @param listener 105 * The InitListener that will be called when the TTS has 106 * initialized successfully. 107 */ 108 public TextToSpeech(Context context, OnInitListener listener) { 109 mContext = context; 110 mInitListener = listener; 111 initTts(); 112 } 113 114 115 public void setOnSpeechCompletedListener(final OnSpeechCompletedListener listener) { 116 synchronized(mSpeechCompListenerLock) { 117 mSpeechCompListener = listener; 118 } 119 } 120 121 122 private boolean dataFilesCheck() { 123 // TODO #TTS# config manager will be in settings 124 Log.i("TTS_FIXME", "FIXME in Tts: config manager will be in settings"); 125 // TODO #TTS# implement checking of the correct installation of 126 // the data files. 127 128 return true; 129 } 130 131 132 private void initTts() { 133 mStarted = false; 134 135 // Initialize the TTS, run the callback after the binding is successful 136 mServiceConnection = new ServiceConnection() { 137 public void onServiceConnected(ComponentName name, IBinder service) { 138 synchronized(mStartLock) { 139 mITts = ITts.Stub.asInterface(service); 140 try { 141 mITtsCallback = new ITtsCallback.Stub() { 142 public void markReached(String mark) 143 throws RemoteException { 144 // call the listener of that event, but not 145 // while locked. 146 OnSpeechCompletedListener listener = null; 147 synchronized(mSpeechCompListenerLock) { 148 listener = mSpeechCompListener; 149 } 150 if (listener != null) { 151 listener.onSpeechCompleted(); 152 } 153 } 154 }; 155 mITts.registerCallback(mITtsCallback); 156 157 } catch (RemoteException e) { 158 initTts(); 159 return; 160 } 161 162 mStarted = true; 163 // The callback can become null if the Android OS decides to 164 // restart the TTS process as well as whatever is using it. 165 // In such cases, do nothing - the error handling from the 166 // speaking calls will kick in and force a proper restart of 167 // the TTS. 168 if (mInitListener != null) { 169 // TODO manage failures and missing resources 170 mInitListener.onInit(TTS_SUCCESS); 171 } 172 } 173 } 174 175 public void onServiceDisconnected(ComponentName name) { 176 synchronized(mStartLock) { 177 mITts = null; 178 mInitListener = null; 179 mStarted = false; 180 } 181 } 182 }; 183 184 Intent intent = new Intent("android.intent.action.USE_TTS"); 185 intent.addCategory("android.intent.category.TTS"); 186 mContext.bindService(intent, mServiceConnection, 187 Context.BIND_AUTO_CREATE); 188 // TODO handle case where the binding works (should always work) but 189 // the plugin fails 190 } 191 192 193 /** 194 * Shuts down the TTS. It is good practice to call this in the onDestroy 195 * method of the Activity that is using the TTS so that the TTS is stopped 196 * cleanly. 197 */ 198 public void shutdown() { 199 try { 200 mContext.unbindService(mServiceConnection); 201 } catch (IllegalArgumentException e) { 202 // Do nothing and fail silently since an error here indicates that 203 // binding never succeeded in the first place. 204 } 205 } 206 207 208 /** 209 * Adds a mapping between a string of text and a sound resource in a 210 * package. 211 * 212 * @see #TTS.speak(String text, int queueMode, String[] params) 213 * 214 * @param text 215 * Example: <b><code>"south_south_east"</code></b><br/> 216 * 217 * @param packagename 218 * Pass the packagename of the application that contains the 219 * resource. If the resource is in your own application (this is 220 * the most common case), then put the packagename of your 221 * application here.<br/> 222 * Example: <b>"com.google.marvin.compass"</b><br/> 223 * The packagename can be found in the AndroidManifest.xml of 224 * your application. 225 * <p> 226 * <code><manifest xmlns:android="..." 227 * package="<b>com.google.marvin.compass</b>"></code> 228 * </p> 229 * 230 * @param resourceId 231 * Example: <b><code>R.raw.south_south_east</code></b> 232 */ 233 public void addSpeech(String text, String packagename, int resourceId) { 234 synchronized(mStartLock) { 235 if (!mStarted) { 236 return; 237 } 238 try { 239 mITts.addSpeech(text, packagename, resourceId); 240 } catch (RemoteException e) { 241 // TTS died; restart it. 242 mStarted = false; 243 initTts(); 244 } catch (NullPointerException e) { 245 // TTS died; restart it. 246 mStarted = false; 247 initTts(); 248 } catch (IllegalStateException e) { 249 // TTS died; restart it. 250 mStarted = false; 251 initTts(); 252 } 253 } 254 } 255 256 257 /** 258 * Adds a mapping between a string of text and a sound file. Using this, it 259 * is possible to add custom pronounciations for text. 260 * 261 * @param text 262 * The string of text 263 * @param filename 264 * The full path to the sound file (for example: 265 * "/sdcard/mysounds/hello.wav") 266 */ 267 public void addSpeech(String text, String filename) { 268 synchronized (mStartLock) { 269 if (!mStarted) { 270 return; 271 } 272 try { 273 mITts.addSpeechFile(text, filename); 274 } catch (RemoteException e) { 275 // TTS died; restart it. 276 mStarted = false; 277 initTts(); 278 } catch (NullPointerException e) { 279 // TTS died; restart it. 280 mStarted = false; 281 initTts(); 282 } catch (IllegalStateException e) { 283 // TTS died; restart it. 284 mStarted = false; 285 initTts(); 286 } 287 } 288 } 289 290 291 /** 292 * Speaks the string using the specified queuing strategy and speech 293 * parameters. Note that the speech parameters are not universally supported 294 * by all engines and will be treated as a hint. The TTS library will try to 295 * fulfill these parameters as much as possible, but there is no guarantee 296 * that the voice used will have the properties specified. 297 * 298 * @param text 299 * The string of text to be spoken. 300 * @param queueMode 301 * The queuing strategy to use. 302 * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH. 303 * @param params 304 * The hashmap of speech parameters to be used. 305 */ 306 public void speak(String text, int queueMode, HashMap<String,String> params) 307 { 308 synchronized (mStartLock) { 309 Log.i("TTS received: ", text); 310 if (!mStarted) { 311 return; 312 } 313 try { 314 // TODO support extra parameters, passing null for the moment 315 mITts.speak(text, queueMode, null); 316 } catch (RemoteException e) { 317 // TTS died; restart it. 318 mStarted = false; 319 initTts(); 320 } catch (NullPointerException e) { 321 // TTS died; restart it. 322 mStarted = false; 323 initTts(); 324 } catch (IllegalStateException e) { 325 // TTS died; restart it. 326 mStarted = false; 327 initTts(); 328 } 329 } 330 } 331 332 333 /** 334 * Plays the earcon using the specified queueing mode and parameters. 335 * 336 * @param earcon 337 * The earcon that should be played 338 * @param queueMode 339 * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH. 340 * @param params 341 * The hashmap of parameters to be used. 342 */ 343 public void playEarcon(String earcon, int queueMode, 344 HashMap<String,String> params) { 345 synchronized (mStartLock) { 346 if (!mStarted) { 347 return; 348 } 349 try { 350 // TODO support extra parameters, passing null for the moment 351 mITts.playEarcon(earcon, queueMode, null); 352 } catch (RemoteException e) { 353 // TTS died; restart it. 354 mStarted = false; 355 initTts(); 356 } catch (NullPointerException e) { 357 // TTS died; restart it. 358 mStarted = false; 359 initTts(); 360 } catch (IllegalStateException e) { 361 // TTS died; restart it. 362 mStarted = false; 363 initTts(); 364 } 365 } 366 } 367 368 369 public void playSilence(long durationInMs, int queueMode) { 370 // TODO implement, already present in TTS service 371 } 372 373 374 /** 375 * Returns whether or not the TTS is busy speaking. 376 * 377 * @return Whether or not the TTS is busy speaking. 378 */ 379 public boolean isSpeaking() { 380 synchronized (mStartLock) { 381 if (!mStarted) { 382 return false; 383 } 384 try { 385 return mITts.isSpeaking(); 386 } catch (RemoteException e) { 387 // TTS died; restart it. 388 mStarted = false; 389 initTts(); 390 } catch (NullPointerException e) { 391 // TTS died; restart it. 392 mStarted = false; 393 initTts(); 394 } catch (IllegalStateException e) { 395 // TTS died; restart it. 396 mStarted = false; 397 initTts(); 398 } 399 return false; 400 } 401 } 402 403 404 /** 405 * Stops speech from the TTS. 406 */ 407 public void stop() { 408 synchronized (mStartLock) { 409 if (!mStarted) { 410 return; 411 } 412 try { 413 mITts.stop(); 414 } catch (RemoteException e) { 415 // TTS died; restart it. 416 mStarted = false; 417 initTts(); 418 } catch (NullPointerException e) { 419 // TTS died; restart it. 420 mStarted = false; 421 initTts(); 422 } catch (IllegalStateException e) { 423 // TTS died; restart it. 424 mStarted = false; 425 initTts(); 426 } 427 } 428 } 429 430 431 432 /** 433 * Sets the speech rate for the TTS engine. 434 * 435 * Note that the speech rate is not universally supported by all engines and 436 * will be treated as a hint. The TTS library will try to use the specified 437 * speech rate, but there is no guarantee. 438 * This has no effect on any pre-recorded speech. 439 * 440 * @param speechRate 441 * The speech rate for the TTS engine. 1 is the normal speed, 442 * lower values slow down the speech (0.5 is half the normal speech rate), 443 * greater values accelerate it (2 is twice the normal speech rate). 444 */ 445 public void setSpeechRate(float speechRate) { 446 synchronized (mStartLock) { 447 if (!mStarted) { 448 return; 449 } 450 try { 451 if (speechRate > 0) { 452 mITts.setSpeechRate((int)(speechRate*100)); 453 } 454 } catch (RemoteException e) { 455 // TTS died; restart it. 456 mStarted = false; 457 initTts(); 458 } 459 } 460 } 461 462 463 /** 464 * Sets the language for the TTS engine. 465 * 466 * Note that the language is not universally supported by all engines and 467 * will be treated as a hint. The TTS library will try to use the specified 468 * language as represented by the Locale, but there is no guarantee. 469 * 470 * @param loc 471 * The locale describing the language to be used. 472 */ 473 public void setLanguage(Locale loc) { 474 synchronized (mStartLock) { 475 if (!mStarted) { 476 return; 477 } 478 try { 479 mITts.setLanguage(loc.getISO3Language(), loc.getISO3Country(), loc.getVariant()); 480 } catch (RemoteException e) { 481 // TTS died; restart it. 482 mStarted = false; 483 initTts(); 484 } 485 } 486 } 487 488 489 /** 490 * Speaks the given text using the specified queueing mode and parameters. 491 * 492 * @param text 493 * The String of text that should be synthesized 494 * @param params 495 * A hashmap of parameters. 496 * @param filename 497 * The string that gives the full output filename; it should be 498 * something like "/sdcard/myappsounds/mysound.wav". 499 * @return A boolean that indicates if the synthesis succeeded 500 */ 501 public boolean synthesizeToFile(String text, HashMap<String,String> params, 502 String filename) { 503 synchronized (mStartLock) { 504 if (!mStarted) { 505 return false; 506 } 507 try { 508 // TODO support extra parameters, passing null for the moment 509 return mITts.synthesizeToFile(text, null, filename); 510 } catch (RemoteException e) { 511 // TTS died; restart it. 512 mStarted = false; 513 initTts(); 514 } catch (NullPointerException e) { 515 // TTS died; restart it. 516 mStarted = false; 517 initTts(); 518 } catch (IllegalStateException e) { 519 // TTS died; restart it. 520 mStarted = false; 521 initTts(); 522 } 523 return false; 524 } 525 } 526 527 528} 529