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