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