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