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