TextToSpeech.java revision ad6df74ada7c478257425b746588f22eeec199a6
1/* 2 * Copyright (C) 2009 The Android Open Source Project 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.annotation.SdkConstant; 19import android.annotation.SdkConstant.SdkConstantType; 20import android.content.ComponentName; 21import android.content.ContentResolver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.ServiceConnection; 25import android.media.AudioManager; 26import android.net.Uri; 27import android.os.AsyncTask; 28import android.os.Bundle; 29import android.os.IBinder; 30import android.os.ParcelFileDescriptor; 31import android.os.RemoteException; 32import android.provider.Settings; 33import android.text.TextUtils; 34import android.util.Log; 35 36import java.io.File; 37import java.io.FileNotFoundException; 38import java.io.IOException; 39import java.util.ArrayList; 40import java.util.Collections; 41import java.util.HashMap; 42import java.util.HashSet; 43import java.util.List; 44import java.util.Locale; 45import java.util.Map; 46import java.util.MissingResourceException; 47import java.util.Set; 48import java.util.TreeSet; 49 50/** 51 * 52 * Synthesizes speech from text for immediate playback or to create a sound file. 53 * <p>A TextToSpeech instance can only be used to synthesize text once it has completed its 54 * initialization. Implement the {@link TextToSpeech.OnInitListener} to be 55 * notified of the completion of the initialization.<br> 56 * When you are done using the TextToSpeech instance, call the {@link #shutdown()} method 57 * to release the native resources used by the TextToSpeech engine. 58 */ 59public class TextToSpeech { 60 61 private static final String TAG = "TextToSpeech"; 62 63 /** 64 * Denotes a successful operation. 65 */ 66 public static final int SUCCESS = 0; 67 /** 68 * Denotes a generic operation failure. 69 */ 70 public static final int ERROR = -1; 71 72 /** 73 * Denotes a stop requested by a client. It's used only on the service side of the API, 74 * client should never expect to see this result code. 75 */ 76 public static final int STOPPED = -2; 77 78 /** 79 * Denotes a failure of a TTS engine to synthesize the given input. 80 */ 81 public static final int ERROR_SYNTHESIS = -3; 82 83 /** 84 * Denotes a failure of a TTS service. 85 */ 86 public static final int ERROR_SERVICE = -4; 87 88 /** 89 * Denotes a failure related to the output (audio device or a file). 90 */ 91 public static final int ERROR_OUTPUT = -5; 92 93 /** 94 * Denotes a failure caused by a network connectivity problems. 95 */ 96 public static final int ERROR_NETWORK = -6; 97 98 /** 99 * Denotes a failure caused by network timeout. 100 */ 101 public static final int ERROR_NETWORK_TIMEOUT = -7; 102 103 /** 104 * Denotes a failure caused by an invalid request. 105 */ 106 public static final int ERROR_INVALID_REQUEST = -8; 107 108 /** 109 * Denotes a failure caused by an unfinished download of the voice data. 110 * @see Engine#KEY_FEATURE_NOT_INSTALLED 111 */ 112 public static final int ERROR_NOT_INSTALLED_YET = -9; 113 114 /** 115 * Queue mode where all entries in the playback queue (media to be played 116 * and text to be synthesized) are dropped and replaced by the new entry. 117 * Queues are flushed with respect to a given calling app. Entries in the queue 118 * from other callees are not discarded. 119 */ 120 public static final int QUEUE_FLUSH = 0; 121 /** 122 * Queue mode where the new entry is added at the end of the playback queue. 123 */ 124 public static final int QUEUE_ADD = 1; 125 /** 126 * Queue mode where the entire playback queue is purged. This is different 127 * from {@link #QUEUE_FLUSH} in that all entries are purged, not just entries 128 * from a given caller. 129 * 130 * @hide 131 */ 132 static final int QUEUE_DESTROY = 2; 133 134 /** 135 * Denotes the language is available exactly as specified by the locale. 136 */ 137 public static final int LANG_COUNTRY_VAR_AVAILABLE = 2; 138 139 /** 140 * Denotes the language is available for the language and country specified 141 * by the locale, but not the variant. 142 */ 143 public static final int LANG_COUNTRY_AVAILABLE = 1; 144 145 /** 146 * Denotes the language is available for the language by the locale, 147 * but not the country and variant. 148 */ 149 public static final int LANG_AVAILABLE = 0; 150 151 /** 152 * Denotes the language data is missing. 153 */ 154 public static final int LANG_MISSING_DATA = -1; 155 156 /** 157 * Denotes the language is not supported. 158 */ 159 public static final int LANG_NOT_SUPPORTED = -2; 160 161 /** 162 * Broadcast Action: The TextToSpeech synthesizer has completed processing 163 * of all the text in the speech queue. 164 * 165 * Note that this notifies callers when the <b>engine</b> has finished has 166 * processing text data. Audio playback might not have completed (or even started) 167 * at this point. If you wish to be notified when this happens, see 168 * {@link OnUtteranceCompletedListener}. 169 */ 170 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 171 public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED = 172 "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED"; 173 174 /** 175 * Interface definition of a callback to be invoked indicating the completion of the 176 * TextToSpeech engine initialization. 177 */ 178 public interface OnInitListener { 179 /** 180 * Called to signal the completion of the TextToSpeech engine initialization. 181 * 182 * @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. 183 */ 184 public void onInit(int status); 185 } 186 187 /** 188 * Listener that will be called when the TTS service has 189 * completed synthesizing an utterance. This is only called if the utterance 190 * has an utterance ID (see {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}). 191 * 192 * @deprecated Use {@link UtteranceProgressListener} instead. 193 */ 194 @Deprecated 195 public interface OnUtteranceCompletedListener { 196 /** 197 * Called when an utterance has been synthesized. 198 * 199 * @param utteranceId the identifier of the utterance. 200 */ 201 public void onUtteranceCompleted(String utteranceId); 202 } 203 204 /** 205 * Constants and parameter names for controlling text-to-speech. These include: 206 * 207 * <ul> 208 * <li> 209 * Intents to ask engine to install data or check its data and 210 * extras for a TTS engine's check data activity. 211 * </li> 212 * <li> 213 * Keys for the parameters passed with speak commands, e.g. 214 * {@link Engine#KEY_PARAM_UTTERANCE_ID}, {@link Engine#KEY_PARAM_STREAM}. 215 * </li> 216 * <li> 217 * A list of feature strings that engines might support, e.g 218 * {@link Engine#KEY_FEATURE_NETWORK_SYNTHESIS}). These values may be passed in to 219 * {@link TextToSpeech#speak} and {@link TextToSpeech#synthesizeToFile} to modify 220 * engine behaviour. The engine can be queried for the set of features it supports 221 * through {@link TextToSpeech#getFeatures(java.util.Locale)}. 222 * </li> 223 * </ul> 224 */ 225 public class Engine { 226 227 /** 228 * Default speech rate. 229 * @hide 230 */ 231 public static final int DEFAULT_RATE = 100; 232 233 /** 234 * Default pitch. 235 * @hide 236 */ 237 public static final int DEFAULT_PITCH = 100; 238 239 /** 240 * Default volume. 241 * @hide 242 */ 243 public static final float DEFAULT_VOLUME = 1.0f; 244 245 /** 246 * Default pan (centered). 247 * @hide 248 */ 249 public static final float DEFAULT_PAN = 0.0f; 250 251 /** 252 * Default value for {@link Settings.Secure#TTS_USE_DEFAULTS}. 253 * @hide 254 */ 255 public static final int USE_DEFAULTS = 0; // false 256 257 /** 258 * Package name of the default TTS engine. 259 * 260 * @hide 261 * @deprecated No longer in use, the default engine is determined by 262 * the sort order defined in {@link TtsEngines}. Note that 263 * this doesn't "break" anything because there is no guarantee that 264 * the engine specified below is installed on a given build, let 265 * alone be the default. 266 */ 267 @Deprecated 268 public static final String DEFAULT_ENGINE = "com.svox.pico"; 269 270 /** 271 * Default audio stream used when playing synthesized speech. 272 */ 273 public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC; 274 275 /** 276 * Indicates success when checking the installation status of the resources used by the 277 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 278 */ 279 public static final int CHECK_VOICE_DATA_PASS = 1; 280 281 /** 282 * Indicates failure when checking the installation status of the resources used by the 283 * TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 284 */ 285 public static final int CHECK_VOICE_DATA_FAIL = 0; 286 287 /** 288 * Indicates erroneous data when checking the installation status of the resources used by 289 * the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 290 * 291 * @deprecated Use CHECK_VOICE_DATA_FAIL instead. 292 */ 293 @Deprecated 294 public static final int CHECK_VOICE_DATA_BAD_DATA = -1; 295 296 /** 297 * Indicates missing resources when checking the installation status of the resources used 298 * by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 299 * 300 * @deprecated Use CHECK_VOICE_DATA_FAIL instead. 301 */ 302 @Deprecated 303 public static final int CHECK_VOICE_DATA_MISSING_DATA = -2; 304 305 /** 306 * Indicates missing storage volume when checking the installation status of the resources 307 * used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. 308 * 309 * @deprecated Use CHECK_VOICE_DATA_FAIL instead. 310 */ 311 @Deprecated 312 public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3; 313 314 /** 315 * Intent for starting a TTS service. Services that handle this intent must 316 * extend {@link TextToSpeechService}. Normal applications should not use this intent 317 * directly, instead they should talk to the TTS service using the the methods in this 318 * class. 319 */ 320 @SdkConstant(SdkConstantType.SERVICE_ACTION) 321 public static final String INTENT_ACTION_TTS_SERVICE = 322 "android.intent.action.TTS_SERVICE"; 323 324 /** 325 * Name under which a text to speech engine publishes information about itself. 326 * This meta-data should reference an XML resource containing a 327 * <code><{@link android.R.styleable#TextToSpeechEngine tts-engine}></code> 328 * tag. 329 */ 330 public static final String SERVICE_META_DATA = "android.speech.tts"; 331 332 // intents to ask engine to install data or check its data 333 /** 334 * Activity Action: Triggers the platform TextToSpeech engine to 335 * start the activity that installs the resource files on the device 336 * that are required for TTS to be operational. Since the installation 337 * of the data can be interrupted or declined by the user, the application 338 * shouldn't expect successful installation upon return from that intent, 339 * and if need be, should check installation status with 340 * {@link #ACTION_CHECK_TTS_DATA}. 341 */ 342 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 343 public static final String ACTION_INSTALL_TTS_DATA = 344 "android.speech.tts.engine.INSTALL_TTS_DATA"; 345 346 /** 347 * Broadcast Action: broadcast to signal the change in the list of available 348 * languages or/and their features. 349 */ 350 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 351 public static final String ACTION_TTS_DATA_INSTALLED = 352 "android.speech.tts.engine.TTS_DATA_INSTALLED"; 353 354 /** 355 * Activity Action: Starts the activity from the platform TextToSpeech 356 * engine to verify the proper installation and availability of the 357 * resource files on the system. Upon completion, the activity will 358 * return one of the following codes: 359 * {@link #CHECK_VOICE_DATA_PASS}, 360 * {@link #CHECK_VOICE_DATA_FAIL}, 361 * <p> Moreover, the data received in the activity result will contain the following 362 * fields: 363 * <ul> 364 * <li>{@link #EXTRA_AVAILABLE_VOICES} which contains an ArrayList<String> of all the 365 * available voices. The format of each voice is: lang-COUNTRY-variant where COUNTRY and 366 * variant are optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").</li> 367 * <li>{@link #EXTRA_UNAVAILABLE_VOICES} which contains an ArrayList<String> of all the 368 * unavailable voices (ones that user can install). The format of each voice is: 369 * lang-COUNTRY-variant where COUNTRY and variant are optional (ie, "eng" or 370 * "eng-USA" or "eng-USA-FEMALE").</li> 371 * </ul> 372 */ 373 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 374 public static final String ACTION_CHECK_TTS_DATA = 375 "android.speech.tts.engine.CHECK_TTS_DATA"; 376 377 /** 378 * Activity intent for getting some sample text to use for demonstrating TTS. Specific 379 * locale have to be requested by passing following extra parameters: 380 * <ul> 381 * <li>language</li> 382 * <li>country</li> 383 * <li>variant</li> 384 * </ul> 385 * 386 * Upon completion, the activity result may contain the following fields: 387 * <ul> 388 * <li>{@link #EXTRA_SAMPLE_TEXT} which contains an String with sample text.</li> 389 * </ul> 390 */ 391 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 392 public static final String ACTION_GET_SAMPLE_TEXT = 393 "android.speech.tts.engine.GET_SAMPLE_TEXT"; 394 395 /** 396 * Extra information received with the {@link #ACTION_GET_SAMPLE_TEXT} intent result where 397 * the TextToSpeech engine returns an String with sample text for requested voice 398 */ 399 public static final String EXTRA_SAMPLE_TEXT = "sampleText"; 400 401 402 // extras for a TTS engine's check data activity 403 /** 404 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where 405 * the TextToSpeech engine returns an ArrayList<String> of all the available voices. 406 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 407 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 408 */ 409 public static final String EXTRA_AVAILABLE_VOICES = "availableVoices"; 410 411 /** 412 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where 413 * the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices. 414 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 415 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 416 */ 417 public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices"; 418 419 /** 420 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where 421 * the TextToSpeech engine specifies the path to its resources. 422 * 423 * It may be used by language packages to find out where to put their data. 424 * 425 * @deprecated TTS engine implementation detail, this information has no use for 426 * text-to-speech API client. 427 */ 428 @Deprecated 429 public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot"; 430 431 /** 432 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where 433 * the TextToSpeech engine specifies the file names of its resources under the 434 * resource path. 435 * 436 * @deprecated TTS engine implementation detail, this information has no use for 437 * text-to-speech API client. 438 */ 439 @Deprecated 440 public static final String EXTRA_VOICE_DATA_FILES = "dataFiles"; 441 442 /** 443 * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent result where 444 * the TextToSpeech engine specifies the locale associated with each resource file. 445 * 446 * @deprecated TTS engine implementation detail, this information has no use for 447 * text-to-speech API client. 448 */ 449 @Deprecated 450 public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo"; 451 452 /** 453 * Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the 454 * caller indicates to the TextToSpeech engine which specific sets of voice data to 455 * check for by sending an ArrayList<String> of the voices that are of interest. 456 * The format of each voice is: lang-COUNTRY-variant where COUNTRY and variant are 457 * optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE"). 458 * 459 * @deprecated Redundant functionality, checking for existence of specific sets of voice 460 * data can be done on client side. 461 */ 462 @Deprecated 463 public static final String EXTRA_CHECK_VOICE_DATA_FOR = "checkVoiceDataFor"; 464 465 // extras for a TTS engine's data installation 466 /** 467 * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent result. 468 * It indicates whether the data files for the synthesis engine were successfully 469 * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA} 470 * intent. The possible values for this extra are 471 * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}. 472 * 473 * @deprecated No longer in use. If client ise interested in information about what 474 * changed, is should send ACTION_CHECK_TTS_DATA intent to discover available voices. 475 */ 476 @Deprecated 477 public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled"; 478 479 // keys for the parameters passed with speak commands. Hidden keys are used internally 480 // to maintain engine state for each TextToSpeech instance. 481 /** 482 * @hide 483 */ 484 public static final String KEY_PARAM_RATE = "rate"; 485 486 /** 487 * @hide 488 */ 489 public static final String KEY_PARAM_VOICE_NAME = "voiceName"; 490 491 /** 492 * @hide 493 */ 494 public static final String KEY_PARAM_LANGUAGE = "language"; 495 496 /** 497 * @hide 498 */ 499 public static final String KEY_PARAM_COUNTRY = "country"; 500 501 /** 502 * @hide 503 */ 504 public static final String KEY_PARAM_VARIANT = "variant"; 505 506 /** 507 * @hide 508 */ 509 public static final String KEY_PARAM_ENGINE = "engine"; 510 511 /** 512 * @hide 513 */ 514 public static final String KEY_PARAM_PITCH = "pitch"; 515 516 /** 517 * Parameter key to specify the audio stream type to be used when speaking text 518 * or playing back a file. The value should be one of the STREAM_ constants 519 * defined in {@link AudioManager}. 520 * 521 * @see TextToSpeech#speak(String, int, HashMap) 522 * @see TextToSpeech#playEarcon(String, int, HashMap) 523 */ 524 public static final String KEY_PARAM_STREAM = "streamType"; 525 526 /** 527 * Parameter key to identify an utterance in the 528 * {@link TextToSpeech.OnUtteranceCompletedListener} after text has been 529 * spoken, a file has been played back or a silence duration has elapsed. 530 * 531 * @see TextToSpeech#speak(String, int, HashMap) 532 * @see TextToSpeech#playEarcon(String, int, HashMap) 533 * @see TextToSpeech#synthesizeToFile(String, HashMap, String) 534 */ 535 public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId"; 536 537 /** 538 * Parameter key to specify the speech volume relative to the current stream type 539 * volume used when speaking text. Volume is specified as a float ranging from 0 to 1 540 * where 0 is silence, and 1 is the maximum volume (the default behavior). 541 * 542 * @see TextToSpeech#speak(String, int, HashMap) 543 * @see TextToSpeech#playEarcon(String, int, HashMap) 544 */ 545 public static final String KEY_PARAM_VOLUME = "volume"; 546 547 /** 548 * Parameter key to specify how the speech is panned from left to right when speaking text. 549 * Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan, 550 * 0 to center (the default behavior), and +1 to hard-right. 551 * 552 * @see TextToSpeech#speak(String, int, HashMap) 553 * @see TextToSpeech#playEarcon(String, int, HashMap) 554 */ 555 public static final String KEY_PARAM_PAN = "pan"; 556 557 /** 558 * Feature key for network synthesis. See {@link TextToSpeech#getFeatures(Locale)} 559 * for a description of how feature keys work. If set (and supported by the engine 560 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must 561 * use network based synthesis. 562 * 563 * @see TextToSpeech#speak(String, int, java.util.HashMap) 564 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String) 565 * @see TextToSpeech#getFeatures(java.util.Locale) 566 * 567 * @deprecated Starting from API level 20, to select network synthesis, call 568 * ({@link TextToSpeech#getVoices()}, find a suitable network voice 569 * ({@link Voice#getRequiresNetworkConnection()}) and pass it 570 * to {@link TextToSpeech#setVoice(Voice)}). 571 */ 572 @Deprecated 573 public static final String KEY_FEATURE_NETWORK_SYNTHESIS = "networkTts"; 574 575 /** 576 * Feature key for embedded synthesis. See {@link TextToSpeech#getFeatures(Locale)} 577 * for a description of how feature keys work. If set and supported by the engine 578 * as per {@link TextToSpeech#getFeatures(Locale)}, the engine must synthesize 579 * text on-device (without making network requests). 580 * 581 * @see TextToSpeech#speak(String, int, java.util.HashMap) 582 * @see TextToSpeech#synthesizeToFile(String, java.util.HashMap, String) 583 * @see TextToSpeech#getFeatures(java.util.Locale) 584 585 * @deprecated Starting from API level 20, to select embedded synthesis, call 586 * ({@link TextToSpeech#getVoices()}, find a suitable embedded voice 587 * ({@link Voice#getRequiresNetworkConnection()}) and pass it 588 * to {@link TextToSpeech#setVoice(Voice)}). 589 */ 590 @Deprecated 591 public static final String KEY_FEATURE_EMBEDDED_SYNTHESIS = "embeddedTts"; 592 593 /** 594 * Parameter key to specify an audio session identifier (obtained from 595 * {@link AudioManager#allocateAudioSessionId()}) that will be used by the request audio 596 * output. It can be used to associate one of the {@link android.media.audiofx.AudioEffect} 597 * objects with the synthesis (or earcon) output. 598 * 599 * @see TextToSpeech#speak(String, int, HashMap) 600 * @see TextToSpeech#playEarcon(String, int, HashMap) 601 */ 602 public static final String KEY_PARAM_SESSION_ID = "sessionId"; 603 604 /** 605 * Feature key that indicates that the voice may need to download additional data to be fully 606 * functional. The download will be triggered by calling 607 * {@link TextToSpeech#setVoice(Voice)} or {@link TextToSpeech#setLanguage(Locale)}. 608 * Until download is complete, each synthesis request will either report 609 * {@link TextToSpeech#ERROR_NOT_INSTALLED_YET} error, or use a different voice to synthesize 610 * the request. This feature should NOT be used as a key of a request parameter. 611 * 612 * @see TextToSpeech#getFeatures(java.util.Locale) 613 * @see Voice#getFeatures() 614 */ 615 public static final String KEY_FEATURE_NOT_INSTALLED = "notInstalled"; 616 617 /** 618 * Feature key that indicate that a network timeout can be set for the request. If set and 619 * supported as per {@link TextToSpeech#getFeatures(Locale)} or {@link Voice#getFeatures()}, 620 * it can be used as request parameter to set the maximum allowed time for a single 621 * request attempt, in milliseconds, before synthesis fails. When used as a key of 622 * a request parameter, its value should be a string with an integer value. 623 * 624 * @see TextToSpeech#getFeatures(java.util.Locale) 625 * @see Voice#getFeatures() 626 */ 627 public static final String KEY_FEATURE_NETWORK_TIMEOUT_MS = "networkTimeoutMs"; 628 629 /** 630 * Feature key that indicates that network request retries count can be set for the request. 631 * If set and supported as per {@link TextToSpeech#getFeatures(Locale)} or 632 * {@link Voice#getFeatures()}, it can be used as a request parameter to set the 633 * number of network request retries that are attempted in case of failure. When used as 634 * a key of a request parameter, its value should be a string with an integer value. 635 * 636 * @see TextToSpeech#getFeatures(java.util.Locale) 637 * @see Voice#getFeatures() 638 */ 639 public static final String KEY_FEATURE_NETWORK_RETRIES_COUNT = "networkRetriesCount"; 640 } 641 642 private final Context mContext; 643 private Connection mConnectingServiceConnection; 644 private Connection mServiceConnection; 645 private OnInitListener mInitListener; 646 // Written from an unspecified application thread, read from 647 // a binder thread. 648 private volatile UtteranceProgressListener mUtteranceProgressListener; 649 private final Object mStartLock = new Object(); 650 651 private String mRequestedEngine; 652 // Whether to initialize this TTS object with the default engine, 653 // if the requested engine is not available. Valid only if mRequestedEngine 654 // is not null. Used only for testing, though potentially useful API wise 655 // too. 656 private final boolean mUseFallback; 657 private final Map<String, Uri> mEarcons; 658 private final Map<CharSequence, Uri> mUtterances; 659 private final Bundle mParams = new Bundle(); 660 private final TtsEngines mEnginesHelper; 661 private volatile String mCurrentEngine = null; 662 663 /** 664 * The constructor for the TextToSpeech class, using the default TTS engine. 665 * This will also initialize the associated TextToSpeech engine if it isn't already running. 666 * 667 * @param context 668 * The context this instance is running in. 669 * @param listener 670 * The {@link TextToSpeech.OnInitListener} that will be called when the 671 * TextToSpeech engine has initialized. In a case of a failure the listener 672 * may be called immediately, before TextToSpeech instance is fully constructed. 673 */ 674 public TextToSpeech(Context context, OnInitListener listener) { 675 this(context, listener, null); 676 } 677 678 /** 679 * The constructor for the TextToSpeech class, using the given TTS engine. 680 * This will also initialize the associated TextToSpeech engine if it isn't already running. 681 * 682 * @param context 683 * The context this instance is running in. 684 * @param listener 685 * The {@link TextToSpeech.OnInitListener} that will be called when the 686 * TextToSpeech engine has initialized. In a case of a failure the listener 687 * may be called immediately, before TextToSpeech instance is fully constructed. 688 * @param engine Package name of the TTS engine to use. 689 */ 690 public TextToSpeech(Context context, OnInitListener listener, String engine) { 691 this(context, listener, engine, null, true); 692 } 693 694 /** 695 * Used by the framework to instantiate TextToSpeech objects with a supplied 696 * package name, instead of using {@link android.content.Context#getPackageName()} 697 * 698 * @hide 699 */ 700 public TextToSpeech(Context context, OnInitListener listener, String engine, 701 String packageName, boolean useFallback) { 702 mContext = context; 703 mInitListener = listener; 704 mRequestedEngine = engine; 705 mUseFallback = useFallback; 706 707 mEarcons = new HashMap<String, Uri>(); 708 mUtterances = new HashMap<CharSequence, Uri>(); 709 mUtteranceProgressListener = null; 710 711 mEnginesHelper = new TtsEngines(mContext); 712 initTts(); 713 } 714 715 private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method, 716 boolean onlyEstablishedConnection) { 717 return runAction(action, errorResult, method, false, onlyEstablishedConnection); 718 } 719 720 private <R> R runAction(Action<R> action, R errorResult, String method) { 721 return runAction(action, errorResult, method, true, true); 722 } 723 724 private <R> R runAction(Action<R> action, R errorResult, String method, 725 boolean reconnect, boolean onlyEstablishedConnection) { 726 synchronized (mStartLock) { 727 if (mServiceConnection == null) { 728 Log.w(TAG, method + " failed: not bound to TTS engine"); 729 return errorResult; 730 } 731 return mServiceConnection.runAction(action, errorResult, method, reconnect, 732 onlyEstablishedConnection); 733 } 734 } 735 736 private int initTts() { 737 // Step 1: Try connecting to the engine that was requested. 738 if (mRequestedEngine != null) { 739 if (mEnginesHelper.isEngineInstalled(mRequestedEngine)) { 740 if (connectToEngine(mRequestedEngine)) { 741 mCurrentEngine = mRequestedEngine; 742 return SUCCESS; 743 } else if (!mUseFallback) { 744 mCurrentEngine = null; 745 dispatchOnInit(ERROR); 746 return ERROR; 747 } 748 } else if (!mUseFallback) { 749 Log.i(TAG, "Requested engine not installed: " + mRequestedEngine); 750 mCurrentEngine = null; 751 dispatchOnInit(ERROR); 752 return ERROR; 753 } 754 } 755 756 // Step 2: Try connecting to the user's default engine. 757 final String defaultEngine = getDefaultEngine(); 758 if (defaultEngine != null && !defaultEngine.equals(mRequestedEngine)) { 759 if (connectToEngine(defaultEngine)) { 760 mCurrentEngine = defaultEngine; 761 return SUCCESS; 762 } 763 } 764 765 // Step 3: Try connecting to the highest ranked engine in the 766 // system. 767 final String highestRanked = mEnginesHelper.getHighestRankedEngineName(); 768 if (highestRanked != null && !highestRanked.equals(mRequestedEngine) && 769 !highestRanked.equals(defaultEngine)) { 770 if (connectToEngine(highestRanked)) { 771 mCurrentEngine = highestRanked; 772 return SUCCESS; 773 } 774 } 775 776 // NOTE: The API currently does not allow the caller to query whether 777 // they are actually connected to any engine. This might fail for various 778 // reasons like if the user disables all her TTS engines. 779 780 mCurrentEngine = null; 781 dispatchOnInit(ERROR); 782 return ERROR; 783 } 784 785 private boolean connectToEngine(String engine) { 786 Connection connection = new Connection(); 787 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE); 788 intent.setPackage(engine); 789 boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE); 790 if (!bound) { 791 Log.e(TAG, "Failed to bind to " + engine); 792 return false; 793 } else { 794 Log.i(TAG, "Sucessfully bound to " + engine); 795 mConnectingServiceConnection = connection; 796 return true; 797 } 798 } 799 800 private void dispatchOnInit(int result) { 801 synchronized (mStartLock) { 802 if (mInitListener != null) { 803 mInitListener.onInit(result); 804 mInitListener = null; 805 } 806 } 807 } 808 809 private IBinder getCallerIdentity() { 810 return mServiceConnection.getCallerIdentity(); 811 } 812 813 /** 814 * Releases the resources used by the TextToSpeech engine. 815 * It is good practice for instance to call this method in the onDestroy() method of an Activity 816 * so the TextToSpeech engine can be cleanly stopped. 817 */ 818 public void shutdown() { 819 // Special case, we are asked to shutdown connection that did finalize its connection. 820 synchronized (mStartLock) { 821 if (mConnectingServiceConnection != null) { 822 mContext.unbindService(mConnectingServiceConnection); 823 mConnectingServiceConnection = null; 824 return; 825 } 826 } 827 828 // Post connection case 829 runActionNoReconnect(new Action<Void>() { 830 @Override 831 public Void run(ITextToSpeechService service) throws RemoteException { 832 service.setCallback(getCallerIdentity(), null); 833 service.stop(getCallerIdentity()); 834 mServiceConnection.disconnect(); 835 // Context#unbindService does not result in a call to 836 // ServiceConnection#onServiceDisconnected. As a result, the 837 // service ends up being destroyed (if there are no other open 838 // connections to it) but the process lives on and the 839 // ServiceConnection continues to refer to the destroyed service. 840 // 841 // This leads to tons of log spam about SynthThread being dead. 842 mServiceConnection = null; 843 mCurrentEngine = null; 844 return null; 845 } 846 }, null, "shutdown", false); 847 } 848 849 /** 850 * Adds a mapping between a string of text and a sound resource in a 851 * package. After a call to this method, subsequent calls to 852 * {@link #speak(String, int, HashMap)} will play the specified sound resource 853 * if it is available, or synthesize the text it is missing. 854 * 855 * @param text 856 * The string of text. Example: <code>"south_south_east"</code> 857 * 858 * @param packagename 859 * Pass the packagename of the application that contains the 860 * resource. If the resource is in your own application (this is 861 * the most common case), then put the packagename of your 862 * application here.<br/> 863 * Example: <b>"com.google.marvin.compass"</b><br/> 864 * The packagename can be found in the AndroidManifest.xml of 865 * your application. 866 * <p> 867 * <code><manifest xmlns:android="..." 868 * package="<b>com.google.marvin.compass</b>"></code> 869 * </p> 870 * 871 * @param resourceId 872 * Example: <code>R.raw.south_south_east</code> 873 * 874 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 875 */ 876 public int addSpeech(String text, String packagename, int resourceId) { 877 synchronized (mStartLock) { 878 mUtterances.put(text, makeResourceUri(packagename, resourceId)); 879 return SUCCESS; 880 } 881 } 882 883 /** 884 * Adds a mapping between a CharSequence (may be spanned with TtsSpans) of text 885 * and a sound resource in a package. After a call to this method, subsequent calls to 886 * {@link #speak(String, int, HashMap)} will play the specified sound resource 887 * if it is available, or synthesize the text it is missing. 888 * 889 * @param text 890 * The string of text. Example: <code>"south_south_east"</code> 891 * 892 * @param packagename 893 * Pass the packagename of the application that contains the 894 * resource. If the resource is in your own application (this is 895 * the most common case), then put the packagename of your 896 * application here.<br/> 897 * Example: <b>"com.google.marvin.compass"</b><br/> 898 * The packagename can be found in the AndroidManifest.xml of 899 * your application. 900 * <p> 901 * <code><manifest xmlns:android="..." 902 * package="<b>com.google.marvin.compass</b>"></code> 903 * </p> 904 * 905 * @param resourceId 906 * Example: <code>R.raw.south_south_east</code> 907 * 908 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 909 */ 910 public int addSpeech(CharSequence text, String packagename, int resourceId) { 911 synchronized (mStartLock) { 912 mUtterances.put(text, makeResourceUri(packagename, resourceId)); 913 return SUCCESS; 914 } 915 } 916 917 /** 918 * Adds a mapping between a string of text and a sound file. Using this, it 919 * is possible to add custom pronounciations for a string of text. 920 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)} 921 * will play the specified sound resource if it is available, or synthesize the text it is 922 * missing. 923 * 924 * @param text 925 * The string of text. Example: <code>"south_south_east"</code> 926 * @param filename 927 * The full path to the sound file (for example: 928 * "/sdcard/mysounds/hello.wav") 929 * 930 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 931 */ 932 public int addSpeech(String text, String filename) { 933 synchronized (mStartLock) { 934 mUtterances.put(text, Uri.parse(filename)); 935 return SUCCESS; 936 } 937 } 938 939 /** 940 * Adds a mapping between a CharSequence (may be spanned with TtsSpans and a sound file. 941 * Using this, it is possible to add custom pronounciations for a string of text. 942 * After a call to this method, subsequent calls to {@link #speak(String, int, HashMap)} 943 * will play the specified sound resource if it is available, or synthesize the text it is 944 * missing. 945 * 946 * @param text 947 * The string of text. Example: <code>"south_south_east"</code> 948 * @param filename 949 * The full path to the sound file (for example: 950 * "/sdcard/mysounds/hello.wav") 951 * 952 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 953 */ 954 public int addSpeech(CharSequence text, String filename) { 955 synchronized (mStartLock) { 956 mUtterances.put(text, Uri.parse(filename)); 957 return SUCCESS; 958 } 959 } 960 961 962 /** 963 * Adds a mapping between a string of text and a sound resource in a 964 * package. Use this to add custom earcons. 965 * 966 * @see #playEarcon(String, int, HashMap) 967 * 968 * @param earcon The name of the earcon. 969 * Example: <code>"[tick]"</code><br/> 970 * 971 * @param packagename 972 * the package name of the application that contains the 973 * resource. This can for instance be the package name of your own application. 974 * Example: <b>"com.google.marvin.compass"</b><br/> 975 * The package name can be found in the AndroidManifest.xml of 976 * the application containing the resource. 977 * <p> 978 * <code><manifest xmlns:android="..." 979 * package="<b>com.google.marvin.compass</b>"></code> 980 * </p> 981 * 982 * @param resourceId 983 * Example: <code>R.raw.tick_snd</code> 984 * 985 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 986 */ 987 public int addEarcon(String earcon, String packagename, int resourceId) { 988 synchronized(mStartLock) { 989 mEarcons.put(earcon, makeResourceUri(packagename, resourceId)); 990 return SUCCESS; 991 } 992 } 993 994 /** 995 * Adds a mapping between a string of text and a sound file. 996 * Use this to add custom earcons. 997 * 998 * @see #playEarcon(String, int, HashMap) 999 * 1000 * @param earcon 1001 * The name of the earcon. 1002 * Example: <code>"[tick]"</code> 1003 * @param filename 1004 * The full path to the sound file (for example: 1005 * "/sdcard/mysounds/tick.wav") 1006 * 1007 * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. 1008 */ 1009 public int addEarcon(String earcon, String filename) { 1010 synchronized(mStartLock) { 1011 mEarcons.put(earcon, Uri.parse(filename)); 1012 return SUCCESS; 1013 } 1014 } 1015 1016 private Uri makeResourceUri(String packageName, int resourceId) { 1017 return new Uri.Builder() 1018 .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) 1019 .encodedAuthority(packageName) 1020 .appendEncodedPath(String.valueOf(resourceId)) 1021 .build(); 1022 } 1023 1024 /** 1025 * Speaks the text using the specified queuing strategy and speech parameters, the text may 1026 * be spanned with TtsSpans. 1027 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1028 * requests and then returns. The synthesis might not have finished (or even started!) at the 1029 * time when this method returns. In order to reliably detect errors during synthesis, 1030 * we recommend setting an utterance progress listener (see 1031 * {@link #setOnUtteranceProgressListener}) and using the 1032 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 1033 * 1034 * @param text The string of text to be spoken. No longer than 1035 * {@link #getMaxSpeechInputLength()} characters. 1036 * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 1037 * @param params Parameters for the request. Can be null. 1038 * Supported parameter names: 1039 * {@link Engine#KEY_PARAM_STREAM}, 1040 * {@link Engine#KEY_PARAM_VOLUME}, 1041 * {@link Engine#KEY_PARAM_PAN}. 1042 * Engine specific parameters may be passed in but the parameter keys 1043 * must be prefixed by the name of the engine they are intended for. For example 1044 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1045 * engine named "com.svox.pico" if it is being used. 1046 * @param utteranceId An unique identifier for this request. 1047 * 1048 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation. 1049 */ 1050 public int speak(final CharSequence text, 1051 final int queueMode, 1052 final HashMap<String, String> params, 1053 final String utteranceId) { 1054 return runAction(new Action<Integer>() { 1055 @Override 1056 public Integer run(ITextToSpeechService service) throws RemoteException { 1057 Uri utteranceUri = mUtterances.get(text); 1058 if (utteranceUri != null) { 1059 return service.playAudio(getCallerIdentity(), utteranceUri, queueMode, 1060 getParams(params), utteranceId); 1061 } else { 1062 return service.speak(getCallerIdentity(), text, queueMode, getParams(params), 1063 utteranceId); 1064 } 1065 } 1066 }, ERROR, "speak"); 1067 } 1068 1069 /** 1070 * Speaks the string using the specified queuing strategy and speech parameters. 1071 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1072 * requests and then returns. The synthesis might not have finished (or even started!) at the 1073 * time when this method returns. In order to reliably detect errors during synthesis, 1074 * we recommend setting an utterance progress listener (see 1075 * {@link #setOnUtteranceProgressListener}) and using the 1076 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 1077 * 1078 * @param text The string of text to be spoken. No longer than 1079 * {@link #getMaxSpeechInputLength()} characters. 1080 * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 1081 * @param params Parameters for the request. Can be null. 1082 * Supported parameter names: 1083 * {@link Engine#KEY_PARAM_STREAM}, 1084 * {@link Engine#KEY_PARAM_UTTERANCE_ID}, 1085 * {@link Engine#KEY_PARAM_VOLUME}, 1086 * {@link Engine#KEY_PARAM_PAN}. 1087 * Engine specific parameters may be passed in but the parameter keys 1088 * must be prefixed by the name of the engine they are intended for. For example 1089 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1090 * engine named "com.svox.pico" if it is being used. 1091 * 1092 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the speak operation. 1093 * @deprecated As of API level 20, replaced by 1094 * {@link #speak(CharSequence, int, HashMap, String)}. 1095 */ 1096 @Deprecated 1097 public int speak(final String text, final int queueMode, final HashMap<String, String> params) { 1098 return speak(text, queueMode, params, 1099 params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID)); 1100 } 1101 1102 /** 1103 * Plays the earcon using the specified queueing mode and parameters. 1104 * The earcon must already have been added with {@link #addEarcon(String, String)} or 1105 * {@link #addEarcon(String, String, int)}. 1106 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1107 * requests and then returns. The synthesis might not have finished (or even started!) at the 1108 * time when this method returns. In order to reliably detect errors during synthesis, 1109 * we recommend setting an utterance progress listener (see 1110 * {@link #setOnUtteranceProgressListener}) and using the 1111 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 1112 * 1113 * @param earcon The earcon that should be played 1114 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 1115 * @param params Parameters for the request. Can be null. 1116 * Supported parameter names: 1117 * {@link Engine#KEY_PARAM_STREAM}, 1118 * Engine specific parameters may be passed in but the parameter keys 1119 * must be prefixed by the name of the engine they are intended for. For example 1120 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1121 * engine named "com.svox.pico" if it is being used. 1122 * 1123 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation. 1124 */ 1125 public int playEarcon(final String earcon, final int queueMode, 1126 final HashMap<String, String> params, final String utteranceId) { 1127 return runAction(new Action<Integer>() { 1128 @Override 1129 public Integer run(ITextToSpeechService service) throws RemoteException { 1130 Uri earconUri = mEarcons.get(earcon); 1131 if (earconUri == null) { 1132 return ERROR; 1133 } 1134 return service.playAudio(getCallerIdentity(), earconUri, queueMode, 1135 getParams(params), utteranceId); 1136 } 1137 }, ERROR, "playEarcon"); 1138 } 1139 1140 /** 1141 * Plays the earcon using the specified queueing mode and parameters. 1142 * The earcon must already have been added with {@link #addEarcon(String, String)} or 1143 * {@link #addEarcon(String, String, int)}. 1144 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1145 * requests and then returns. The synthesis might not have finished (or even started!) at the 1146 * time when this method returns. In order to reliably detect errors during synthesis, 1147 * we recommend setting an utterance progress listener (see 1148 * {@link #setOnUtteranceProgressListener}) and using the 1149 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 1150 * 1151 * @param earcon The earcon that should be played 1152 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 1153 * @param params Parameters for the request. Can be null. 1154 * Supported parameter names: 1155 * {@link Engine#KEY_PARAM_STREAM}, 1156 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 1157 * Engine specific parameters may be passed in but the parameter keys 1158 * must be prefixed by the name of the engine they are intended for. For example 1159 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1160 * engine named "com.svox.pico" if it is being used. 1161 * 1162 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playEarcon operation. 1163 * @deprecated As of API level 20, replaced by 1164 * {@link #playEarcon(String, int, HashMap, String)}. 1165 */ 1166 @Deprecated 1167 public int playEarcon(final String earcon, final int queueMode, 1168 final HashMap<String, String> params) { 1169 return playEarcon(earcon, queueMode, params, 1170 params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID)); 1171 } 1172 1173 /** 1174 * Plays silence for the specified amount of time using the specified 1175 * queue mode. 1176 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1177 * requests and then returns. The synthesis might not have finished (or even started!) at the 1178 * time when this method returns. In order to reliably detect errors during synthesis, 1179 * we recommend setting an utterance progress listener (see 1180 * {@link #setOnUtteranceProgressListener}) and using the 1181 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 1182 * 1183 * @param durationInMs The duration of the silence. 1184 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 1185 * @param params Parameters for the request. Can be null. 1186 * Engine specific parameters may be passed in but the parameter keys 1187 * must be prefixed by the name of the engine they are intended for. For example 1188 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1189 * engine named "com.svox.pico" if it is being used. 1190 * @param utteranceId An unique identifier for this request. 1191 * 1192 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation. 1193 */ 1194 public int playSilence(final long durationInMs, final int queueMode, 1195 final HashMap<String, String> params, final String utteranceId) { 1196 return runAction(new Action<Integer>() { 1197 @Override 1198 public Integer run(ITextToSpeechService service) throws RemoteException { 1199 return service.playSilence(getCallerIdentity(), durationInMs, 1200 queueMode, utteranceId); 1201 } 1202 }, ERROR, "playSilence"); 1203 } 1204 1205 /** 1206 * Plays silence for the specified amount of time using the specified 1207 * queue mode. 1208 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1209 * requests and then returns. The synthesis might not have finished (or even started!) at the 1210 * time when this method returns. In order to reliably detect errors during synthesis, 1211 * we recommend setting an utterance progress listener (see 1212 * {@link #setOnUtteranceProgressListener}) and using the 1213 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 1214 * 1215 * @param durationInMs The duration of the silence. 1216 * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}. 1217 * @param params Parameters for the request. Can be null. 1218 * Supported parameter names: 1219 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 1220 * Engine specific parameters may be passed in but the parameter keys 1221 * must be prefixed by the name of the engine they are intended for. For example 1222 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1223 * engine named "com.svox.pico" if it is being used. 1224 * 1225 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the playSilence operation. 1226 * @deprecated As of API level 20, replaced by 1227 * {@link #playSilence(long, int, HashMap, String)}. 1228 */ 1229 @Deprecated 1230 public int playSilence(final long durationInMs, final int queueMode, 1231 final HashMap<String, String> params) { 1232 return playSilence(durationInMs, queueMode, params, 1233 params == null ? null : params.get(Engine.KEY_PARAM_UTTERANCE_ID)); 1234 } 1235 1236 /** 1237 * Queries the engine for the set of features it supports for a given locale. 1238 * Features can either be framework defined, e.g. 1239 * {@link TextToSpeech.Engine#KEY_FEATURE_NETWORK_SYNTHESIS} or engine specific. 1240 * Engine specific keys must be prefixed by the name of the engine they 1241 * are intended for. These keys can be used as parameters to 1242 * {@link TextToSpeech#speak(String, int, java.util.HashMap)} and 1243 * {@link TextToSpeech#synthesizeToFile(String, java.util.HashMap, String)}. 1244 * 1245 * Features values are strings and their values must meet restrictions described in their 1246 * documentation. 1247 * 1248 * @param locale The locale to query features for. 1249 * @return Set instance. May return {@code null} on error. 1250 * @deprecated As of API level 20, please use voices. In order to query features of the voice, 1251 * call {@link #getVoices()} to retrieve the list of available voices and 1252 * {@link Voice#getFeatures()} to retrieve the set of features. 1253 */ 1254 @Deprecated 1255 public Set<String> getFeatures(final Locale locale) { 1256 return runAction(new Action<Set<String>>() { 1257 @Override 1258 public Set<String> run(ITextToSpeechService service) throws RemoteException { 1259 String[] features = null; 1260 try { 1261 features = service.getFeaturesForLanguage( 1262 locale.getISO3Language(), locale.getISO3Country(), locale.getVariant()); 1263 } catch(MissingResourceException e) { 1264 Log.w(TAG, "Couldn't retrieve 3 letter ISO 639-2/T language and/or ISO 3166 " + 1265 "country code for locale: " + locale, e); 1266 return null; 1267 } 1268 1269 if (features != null) { 1270 final Set<String> featureSet = new HashSet<String>(); 1271 Collections.addAll(featureSet, features); 1272 return featureSet; 1273 } 1274 return null; 1275 } 1276 }, null, "getFeatures"); 1277 } 1278 1279 /** 1280 * Checks whether the TTS engine is busy speaking. Note that a speech item is 1281 * considered complete once it's audio data has been sent to the audio mixer, or 1282 * written to a file. There might be a finite lag between this point, and when 1283 * the audio hardware completes playback. 1284 * 1285 * @return {@code true} if the TTS engine is speaking. 1286 */ 1287 public boolean isSpeaking() { 1288 return runAction(new Action<Boolean>() { 1289 @Override 1290 public Boolean run(ITextToSpeechService service) throws RemoteException { 1291 return service.isSpeaking(); 1292 } 1293 }, false, "isSpeaking"); 1294 } 1295 1296 /** 1297 * Interrupts the current utterance (whether played or rendered to file) and discards other 1298 * utterances in the queue. 1299 * 1300 * @return {@link #ERROR} or {@link #SUCCESS}. 1301 */ 1302 public int stop() { 1303 return runAction(new Action<Integer>() { 1304 @Override 1305 public Integer run(ITextToSpeechService service) throws RemoteException { 1306 return service.stop(getCallerIdentity()); 1307 } 1308 }, ERROR, "stop"); 1309 } 1310 1311 /** 1312 * Sets the speech rate. 1313 * 1314 * This has no effect on any pre-recorded speech. 1315 * 1316 * @param speechRate Speech rate. {@code 1.0} is the normal speech rate, 1317 * lower values slow down the speech ({@code 0.5} is half the normal speech rate), 1318 * greater values accelerate it ({@code 2.0} is twice the normal speech rate). 1319 * 1320 * @return {@link #ERROR} or {@link #SUCCESS}. 1321 */ 1322 public int setSpeechRate(float speechRate) { 1323 if (speechRate > 0.0f) { 1324 int intRate = (int)(speechRate * 100); 1325 if (intRate > 0) { 1326 synchronized (mStartLock) { 1327 mParams.putInt(Engine.KEY_PARAM_RATE, intRate); 1328 } 1329 return SUCCESS; 1330 } 1331 } 1332 return ERROR; 1333 } 1334 1335 /** 1336 * Sets the speech pitch for the TextToSpeech engine. 1337 * 1338 * This has no effect on any pre-recorded speech. 1339 * 1340 * @param pitch Speech pitch. {@code 1.0} is the normal pitch, 1341 * lower values lower the tone of the synthesized voice, 1342 * greater values increase it. 1343 * 1344 * @return {@link #ERROR} or {@link #SUCCESS}. 1345 */ 1346 public int setPitch(float pitch) { 1347 if (pitch > 0.0f) { 1348 int intPitch = (int)(pitch * 100); 1349 if (intPitch > 0) { 1350 synchronized (mStartLock) { 1351 mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch); 1352 } 1353 return SUCCESS; 1354 } 1355 } 1356 return ERROR; 1357 } 1358 1359 /** 1360 * @return the engine currently in use by this TextToSpeech instance. 1361 * @hide 1362 */ 1363 public String getCurrentEngine() { 1364 return mCurrentEngine; 1365 } 1366 1367 /** 1368 * Returns a Locale instance describing the language currently being used as the default 1369 * Text-to-speech language. 1370 * 1371 * The locale object returned by this method is NOT a valid one. It has identical form to the 1372 * one in {@link #getLanguage()}. Please refer to {@link #getLanguage()} for more information. 1373 * 1374 * @return language, country (if any) and variant (if any) used by the client stored in a 1375 * Locale instance, or {@code null} on error. 1376 * @deprecated As of API Level 20, use <code>getDefaultVoice().getLocale()</code> ({@link 1377 * #getDefaultVoice()}) 1378 */ 1379 @Deprecated 1380 public Locale getDefaultLanguage() { 1381 return runAction(new Action<Locale>() { 1382 @Override 1383 public Locale run(ITextToSpeechService service) throws RemoteException { 1384 String[] defaultLanguage = service.getClientDefaultLanguage(); 1385 1386 return new Locale(defaultLanguage[0], defaultLanguage[1], defaultLanguage[2]); 1387 } 1388 }, null, "getDefaultLanguage"); 1389 } 1390 1391 /** 1392 * Sets the text-to-speech language. 1393 * The TTS engine will try to use the closest match to the specified 1394 * language as represented by the Locale, but there is no guarantee that the exact same Locale 1395 * will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support 1396 * before choosing the language to use for the next utterances. 1397 * 1398 * This method sets the current voice to the default one for the given Locale; 1399 * {@link #getVoice()} can be used to retrieve it. 1400 * 1401 * @param loc The locale describing the language to be used. 1402 * 1403 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE}, 1404 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE}, 1405 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}. 1406 */ 1407 public int setLanguage(final Locale loc) { 1408 return runAction(new Action<Integer>() { 1409 @Override 1410 public Integer run(ITextToSpeechService service) throws RemoteException { 1411 if (loc == null) { 1412 return LANG_NOT_SUPPORTED; 1413 } 1414 String language = null, country = null; 1415 try { 1416 language = loc.getISO3Language(); 1417 } catch (MissingResourceException e) { 1418 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e); 1419 return LANG_NOT_SUPPORTED; 1420 } 1421 1422 try { 1423 country = loc.getISO3Country(); 1424 } catch (MissingResourceException e) { 1425 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e); 1426 return LANG_NOT_SUPPORTED; 1427 } 1428 1429 String variant = loc.getVariant(); 1430 1431 // As of API level 20, setLanguage is implemented using setVoice. 1432 // (which, in the default implementation, will call loadLanguage on the service 1433 // interface). 1434 1435 // Sanitize locale using isLanguageAvailable. 1436 int result = service.isLanguageAvailable( language, country, variant); 1437 if (result >= LANG_AVAILABLE){ 1438 if (result < LANG_COUNTRY_VAR_AVAILABLE) { 1439 variant = ""; 1440 if (result < LANG_COUNTRY_AVAILABLE) { 1441 country = ""; 1442 } 1443 } 1444 // Get the default voice for the locale. 1445 String voiceName = service.getDefaultVoiceNameFor(language, country, variant); 1446 if (TextUtils.isEmpty(voiceName)) { 1447 Log.w(TAG, "Couldn't find the default voice for " + language + "/" + 1448 country + "/" + variant); 1449 return LANG_NOT_SUPPORTED; 1450 } 1451 1452 // Load it. 1453 if (service.loadVoice(getCallerIdentity(), voiceName) == TextToSpeech.ERROR) { 1454 return LANG_NOT_SUPPORTED; 1455 } 1456 1457 mParams.putString(Engine.KEY_PARAM_VOICE_NAME, voiceName); 1458 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language); 1459 mParams.putString(Engine.KEY_PARAM_COUNTRY, country); 1460 mParams.putString(Engine.KEY_PARAM_VARIANT, variant); 1461 } 1462 return result; 1463 } 1464 }, LANG_NOT_SUPPORTED, "setLanguage"); 1465 } 1466 1467 /** 1468 * Returns a Locale instance describing the language currently being used for synthesis 1469 * requests sent to the TextToSpeech engine. 1470 * 1471 * In Android 4.2 and before (API <= 17) this function returns the language that is currently 1472 * being used by the TTS engine. That is the last language set by this or any other 1473 * client by a {@link TextToSpeech#setLanguage} call to the same engine. 1474 * 1475 * In Android versions after 4.2 this function returns the language that is currently being 1476 * used for the synthesis requests sent from this client. That is the last language set 1477 * by a {@link TextToSpeech#setLanguage} call on this instance. 1478 * 1479 * If a voice is set (by {@link #setVoice(Voice)}), getLanguage will return the language of 1480 * the currently set voice. 1481 * 1482 * Please note that the Locale object returned by this method is NOT a valid Locale object. Its 1483 * language field contains a three-letter ISO 639-2/T code (where a proper Locale would use 1484 * a two-letter ISO 639-1 code), and the country field contains a three-letter ISO 3166 country 1485 * code (where a proper Locale would use a two-letter ISO 3166-1 code). 1486 * 1487 * @return language, country (if any) and variant (if any) used by the client stored in a 1488 * Locale instance, or {@code null} on error. 1489 * 1490 * @deprecated As of API level 20, please use <code>getVoice().getLocale()</code> 1491 * ({@link #getVoice()}). 1492 */ 1493 @Deprecated 1494 public Locale getLanguage() { 1495 return runAction(new Action<Locale>() { 1496 @Override 1497 public Locale run(ITextToSpeechService service) { 1498 /* No service call, but we're accessing mParams, hence need for 1499 wrapping it as an Action instance */ 1500 String lang = mParams.getString(Engine.KEY_PARAM_LANGUAGE, ""); 1501 String country = mParams.getString(Engine.KEY_PARAM_COUNTRY, ""); 1502 String variant = mParams.getString(Engine.KEY_PARAM_VARIANT, ""); 1503 return new Locale(lang, country, variant); 1504 } 1505 }, null, "getLanguage"); 1506 } 1507 1508 /** 1509 * Query the engine about the set of available languages. 1510 */ 1511 public Set<Locale> getAvailableLanguages() { 1512 return runAction(new Action<Set<Locale>>() { 1513 @Override 1514 public Set<Locale> run(ITextToSpeechService service) throws RemoteException { 1515 List<Voice> voices = service.getVoices(); 1516 if (voices != null) { 1517 return new TreeSet<Locale>(); 1518 } 1519 TreeSet<Locale> locales = new TreeSet<Locale>(); 1520 for (Voice voice : voices) { 1521 locales.add(voice.getLocale()); 1522 } 1523 return locales; 1524 } 1525 }, null, "getAvailableLanguages"); 1526 } 1527 1528 /** 1529 * Query the engine about the set of available voices. 1530 * 1531 * Each TTS Engine can expose multiple voices for each locale, each with a different set of 1532 * features. 1533 * 1534 * @see #setVoice(Voice) 1535 * @see Voice 1536 */ 1537 public Set<Voice> getVoices() { 1538 return runAction(new Action<Set<Voice>>() { 1539 @Override 1540 public Set<Voice> run(ITextToSpeechService service) throws RemoteException { 1541 List<Voice> voices = service.getVoices(); 1542 return (voices != null) ? new TreeSet<Voice>(voices) : new TreeSet<Voice>(); 1543 } 1544 }, null, "getVoices"); 1545 } 1546 1547 /** 1548 * Sets the text-to-speech voice. 1549 * 1550 * @param voice One of objects returned by {@link #getVoices()}. 1551 * 1552 * @return {@link #ERROR} or {@link #SUCCESS}. 1553 * 1554 * @see #getVoices 1555 * @see Voice 1556 */ 1557 public int setVoice(final Voice voice) { 1558 return runAction(new Action<Integer>() { 1559 @Override 1560 public Integer run(ITextToSpeechService service) throws RemoteException { 1561 int result = service.loadVoice(getCallerIdentity(), voice.getName()); 1562 if (result == SUCCESS) { 1563 mParams.putString(Engine.KEY_PARAM_VOICE_NAME, voice.getName()); 1564 1565 // Set the language/country/variant, so #getLanguage will return the voice 1566 // locale when called. 1567 String language = ""; 1568 try { 1569 language = voice.getLocale().getISO3Language(); 1570 } catch (MissingResourceException e) { 1571 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + 1572 voice.getLocale(), e); 1573 } 1574 1575 String country = ""; 1576 try { 1577 country = voice.getLocale().getISO3Country(); 1578 } catch (MissingResourceException e) { 1579 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + 1580 voice.getLocale(), e); 1581 } 1582 mParams.putString(Engine.KEY_PARAM_LANGUAGE, language); 1583 mParams.putString(Engine.KEY_PARAM_COUNTRY, country); 1584 mParams.putString(Engine.KEY_PARAM_VARIANT, voice.getLocale().getVariant()); 1585 } 1586 return result; 1587 } 1588 }, LANG_NOT_SUPPORTED, "setVoice"); 1589 } 1590 1591 /** 1592 * Returns a Voice instance describing the voice currently being used for synthesis 1593 * requests sent to the TextToSpeech engine. 1594 * 1595 * @return Voice instance used by the client, or {@code null} if not set or on error. 1596 * 1597 * @see #getVoices 1598 * @see #setVoice 1599 * @see Voice 1600 */ 1601 public Voice getVoice() { 1602 return runAction(new Action<Voice>() { 1603 @Override 1604 public Voice run(ITextToSpeechService service) throws RemoteException { 1605 String voiceName = mParams.getString(Engine.KEY_PARAM_VOICE_NAME, ""); 1606 if (TextUtils.isEmpty(voiceName)) { 1607 return null; 1608 } 1609 List<Voice> voices = service.getVoices(); 1610 if (voices == null) { 1611 return null; 1612 } 1613 for (Voice voice : voices) { 1614 if (voice.getName().equals(voiceName)) { 1615 return voice; 1616 } 1617 } 1618 return null; 1619 } 1620 }, null, "getVoice"); 1621 } 1622 1623 /** 1624 * Returns a Voice instance that's the default voice for the default Text-to-speech language. 1625 * @return The default voice instance for the default language, or {@code null} if not set or 1626 * on error. 1627 */ 1628 public Voice getDefaultVoice() { 1629 return runAction(new Action<Voice>() { 1630 @Override 1631 public Voice run(ITextToSpeechService service) throws RemoteException { 1632 1633 String[] defaultLanguage = service.getClientDefaultLanguage(); 1634 1635 if (defaultLanguage == null || defaultLanguage.length == 0) { 1636 Log.e(TAG, "service.getClientDefaultLanguage() returned empty array"); 1637 return null; 1638 } 1639 String language = defaultLanguage[0]; 1640 String country = (defaultLanguage.length > 1) ? defaultLanguage[1] : ""; 1641 String variant = (defaultLanguage.length > 2) ? defaultLanguage[2] : ""; 1642 1643 // Sanitize the locale using isLanguageAvailable. 1644 int result = service.isLanguageAvailable(language, country, variant); 1645 if (result >= LANG_AVAILABLE){ 1646 if (result < LANG_COUNTRY_VAR_AVAILABLE) { 1647 variant = ""; 1648 if (result < LANG_COUNTRY_AVAILABLE) { 1649 country = ""; 1650 } 1651 } 1652 } else { 1653 // The default language is not supported. 1654 return null; 1655 } 1656 1657 // Get the default voice name 1658 String voiceName = service.getDefaultVoiceNameFor(language, country, variant); 1659 if (TextUtils.isEmpty(voiceName)) { 1660 return null; 1661 } 1662 1663 // Find it 1664 List<Voice> voices = service.getVoices(); 1665 if (voices == null) { 1666 return null; 1667 } 1668 for (Voice voice : voices) { 1669 if (voice.getName().equals(voiceName)) { 1670 return voice; 1671 } 1672 } 1673 return null; 1674 } 1675 }, null, "getDefaultVoice"); 1676 } 1677 1678 1679 1680 /** 1681 * Checks if the specified language as represented by the Locale is available and supported. 1682 * 1683 * @param loc The Locale describing the language to be used. 1684 * 1685 * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE}, 1686 * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE}, 1687 * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}. 1688 */ 1689 public int isLanguageAvailable(final Locale loc) { 1690 return runAction(new Action<Integer>() { 1691 @Override 1692 public Integer run(ITextToSpeechService service) throws RemoteException { 1693 String language = null, country = null; 1694 1695 try { 1696 language = loc.getISO3Language(); 1697 } catch (MissingResourceException e) { 1698 Log.w(TAG, "Couldn't retrieve ISO 639-2/T language code for locale: " + loc, e); 1699 return LANG_NOT_SUPPORTED; 1700 } 1701 1702 try { 1703 country = loc.getISO3Country(); 1704 } catch (MissingResourceException e) { 1705 Log.w(TAG, "Couldn't retrieve ISO 3166 country code for locale: " + loc, e); 1706 return LANG_NOT_SUPPORTED; 1707 } 1708 1709 return service.isLanguageAvailable(language, country, loc.getVariant()); 1710 } 1711 }, LANG_NOT_SUPPORTED, "isLanguageAvailable"); 1712 } 1713 1714 /** 1715 * Synthesizes the given text to a file using the specified parameters. 1716 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1717 * requests and then returns. The synthesis might not have finished (or even started!) at the 1718 * time when this method returns. In order to reliably detect errors during synthesis, 1719 * we recommend setting an utterance progress listener (see 1720 * {@link #setOnUtteranceProgressListener}). 1721 * 1722 * @param text The text that should be synthesized. No longer than 1723 * {@link #getMaxSpeechInputLength()} characters. 1724 * @param params Parameters for the request. Can be null. 1725 * Engine specific parameters may be passed in but the parameter keys 1726 * must be prefixed by the name of the engine they are intended for. For example 1727 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1728 * engine named "com.svox.pico" if it is being used. 1729 * @param filename Absolute file filename to write the generated audio data to.It should be 1730 * something like "/sdcard/myappsounds/mysound.wav". 1731 * @param utteranceId An unique identifier for this request. 1732 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation. 1733 */ 1734 public int synthesizeToFile(final CharSequence text, final HashMap<String, String> params, 1735 final String filename, final String utteranceId) { 1736 return runAction(new Action<Integer>() { 1737 @Override 1738 public Integer run(ITextToSpeechService service) throws RemoteException { 1739 ParcelFileDescriptor fileDescriptor; 1740 int returnValue; 1741 try { 1742 File file = new File(filename); 1743 if(file.exists() && !file.canWrite()) { 1744 Log.e(TAG, "Can't write to " + filename); 1745 return ERROR; 1746 } 1747 fileDescriptor = ParcelFileDescriptor.open(file, 1748 ParcelFileDescriptor.MODE_WRITE_ONLY | 1749 ParcelFileDescriptor.MODE_CREATE | 1750 ParcelFileDescriptor.MODE_TRUNCATE); 1751 returnValue = service.synthesizeToFileDescriptor(getCallerIdentity(), text, 1752 fileDescriptor, getParams(params), utteranceId); 1753 fileDescriptor.close(); 1754 return returnValue; 1755 } catch (FileNotFoundException e) { 1756 Log.e(TAG, "Opening file " + filename + " failed", e); 1757 return ERROR; 1758 } catch (IOException e) { 1759 Log.e(TAG, "Closing file " + filename + " failed", e); 1760 return ERROR; 1761 } 1762 } 1763 }, ERROR, "synthesizeToFile"); 1764 } 1765 1766 /** 1767 * Synthesizes the given text to a file using the specified parameters. 1768 * This method is asynchronous, i.e. the method just adds the request to the queue of TTS 1769 * requests and then returns. The synthesis might not have finished (or even started!) at the 1770 * time when this method returns. In order to reliably detect errors during synthesis, 1771 * we recommend setting an utterance progress listener (see 1772 * {@link #setOnUtteranceProgressListener}) and using the 1773 * {@link Engine#KEY_PARAM_UTTERANCE_ID} parameter. 1774 * 1775 * @param text The text that should be synthesized. No longer than 1776 * {@link #getMaxSpeechInputLength()} characters. 1777 * @param params Parameters for the request. Can be null. 1778 * Supported parameter names: 1779 * {@link Engine#KEY_PARAM_UTTERANCE_ID}. 1780 * Engine specific parameters may be passed in but the parameter keys 1781 * must be prefixed by the name of the engine they are intended for. For example 1782 * the keys "com.svox.pico_foo" and "com.svox.pico:bar" will be passed to the 1783 * engine named "com.svox.pico" if it is being used. 1784 * @param filename Absolute file filename to write the generated audio data to.It should be 1785 * something like "/sdcard/myappsounds/mysound.wav". 1786 * 1787 * @return {@link #ERROR} or {@link #SUCCESS} of <b>queuing</b> the synthesizeToFile operation. 1788 * @deprecated As of API level 20, replaced by 1789 * {@link #synthesizeToFile(CharSequence, HashMap, String, String)}. 1790 */ 1791 public int synthesizeToFile(final String text, final HashMap<String, String> params, 1792 final String filename) { 1793 return synthesizeToFile(text, params, filename, params.get(Engine.KEY_PARAM_UTTERANCE_ID)); 1794 } 1795 1796 private Bundle getParams(HashMap<String, String> params) { 1797 if (params != null && !params.isEmpty()) { 1798 Bundle bundle = new Bundle(mParams); 1799 copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM); 1800 copyIntParam(bundle, params, Engine.KEY_PARAM_SESSION_ID); 1801 copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID); 1802 copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME); 1803 copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN); 1804 1805 // Copy feature strings defined by the framework. 1806 copyStringParam(bundle, params, Engine.KEY_FEATURE_NETWORK_SYNTHESIS); 1807 copyStringParam(bundle, params, Engine.KEY_FEATURE_EMBEDDED_SYNTHESIS); 1808 copyIntParam(bundle, params, Engine.KEY_FEATURE_NETWORK_TIMEOUT_MS); 1809 copyIntParam(bundle, params, Engine.KEY_FEATURE_NETWORK_RETRIES_COUNT); 1810 1811 // Copy over all parameters that start with the name of the 1812 // engine that we are currently connected to. The engine is 1813 // free to interpret them as it chooses. 1814 if (!TextUtils.isEmpty(mCurrentEngine)) { 1815 for (Map.Entry<String, String> entry : params.entrySet()) { 1816 final String key = entry.getKey(); 1817 if (key != null && key.startsWith(mCurrentEngine)) { 1818 bundle.putString(key, entry.getValue()); 1819 } 1820 } 1821 } 1822 1823 return bundle; 1824 } else { 1825 return mParams; 1826 } 1827 } 1828 1829 private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) { 1830 String value = params.get(key); 1831 if (value != null) { 1832 bundle.putString(key, value); 1833 } 1834 } 1835 1836 private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) { 1837 String valueString = params.get(key); 1838 if (!TextUtils.isEmpty(valueString)) { 1839 try { 1840 int value = Integer.parseInt(valueString); 1841 bundle.putInt(key, value); 1842 } catch (NumberFormatException ex) { 1843 // don't set the value in the bundle 1844 } 1845 } 1846 } 1847 1848 private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) { 1849 String valueString = params.get(key); 1850 if (!TextUtils.isEmpty(valueString)) { 1851 try { 1852 float value = Float.parseFloat(valueString); 1853 bundle.putFloat(key, value); 1854 } catch (NumberFormatException ex) { 1855 // don't set the value in the bundle 1856 } 1857 } 1858 } 1859 1860 /** 1861 * Sets the listener that will be notified when synthesis of an utterance completes. 1862 * 1863 * @param listener The listener to use. 1864 * 1865 * @return {@link #ERROR} or {@link #SUCCESS}. 1866 * 1867 * @deprecated Use {@link #setOnUtteranceProgressListener(UtteranceProgressListener)} 1868 * instead. 1869 */ 1870 @Deprecated 1871 public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) { 1872 mUtteranceProgressListener = UtteranceProgressListener.from(listener); 1873 return TextToSpeech.SUCCESS; 1874 } 1875 1876 /** 1877 * Sets the listener that will be notified of various events related to the 1878 * synthesis of a given utterance. 1879 * 1880 * See {@link UtteranceProgressListener} and 1881 * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}. 1882 * 1883 * @param listener the listener to use. 1884 * @return {@link #ERROR} or {@link #SUCCESS} 1885 */ 1886 public int setOnUtteranceProgressListener(UtteranceProgressListener listener) { 1887 mUtteranceProgressListener = listener; 1888 return TextToSpeech.SUCCESS; 1889 } 1890 1891 /** 1892 * Sets the TTS engine to use. 1893 * 1894 * @deprecated This doesn't inform callers when the TTS engine has been 1895 * initialized. {@link #TextToSpeech(Context, OnInitListener, String)} 1896 * can be used with the appropriate engine name. Also, there is no 1897 * guarantee that the engine specified will be loaded. If it isn't 1898 * installed or disabled, the user / system wide defaults will apply. 1899 * 1900 * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico") 1901 * 1902 * @return {@link #ERROR} or {@link #SUCCESS}. 1903 */ 1904 @Deprecated 1905 public int setEngineByPackageName(String enginePackageName) { 1906 mRequestedEngine = enginePackageName; 1907 return initTts(); 1908 } 1909 1910 /** 1911 * Gets the package name of the default speech synthesis engine. 1912 * 1913 * @return Package name of the TTS engine that the user has chosen 1914 * as their default. 1915 */ 1916 public String getDefaultEngine() { 1917 return mEnginesHelper.getDefaultEngine(); 1918 } 1919 1920 /** 1921 * Checks whether the user's settings should override settings requested 1922 * by the calling application. As of the Ice cream sandwich release, 1923 * user settings never forcibly override the app's settings. 1924 */ 1925 @Deprecated 1926 public boolean areDefaultsEnforced() { 1927 return false; 1928 } 1929 1930 /** 1931 * Gets a list of all installed TTS engines. 1932 * 1933 * @return A list of engine info objects. The list can be empty, but never {@code null}. 1934 */ 1935 public List<EngineInfo> getEngines() { 1936 return mEnginesHelper.getEngines(); 1937 } 1938 1939 private class Connection implements ServiceConnection { 1940 private ITextToSpeechService mService; 1941 1942 private SetupConnectionAsyncTask mOnSetupConnectionAsyncTask; 1943 1944 private boolean mEstablished; 1945 1946 private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() { 1947 public void onStop(String utteranceId) throws RemoteException { 1948 // do nothing 1949 }; 1950 1951 @Override 1952 public void onFallback(String utteranceId) throws RemoteException { 1953 // do nothing 1954 } 1955 1956 @Override 1957 public void onSuccess(String utteranceId) { 1958 UtteranceProgressListener listener = mUtteranceProgressListener; 1959 if (listener != null) { 1960 listener.onDone(utteranceId); 1961 } 1962 } 1963 1964 @Override 1965 public void onError(String utteranceId, int errorCode) { 1966 UtteranceProgressListener listener = mUtteranceProgressListener; 1967 if (listener != null) { 1968 listener.onError(utteranceId); 1969 } 1970 } 1971 1972 @Override 1973 public void onStart(String utteranceId) { 1974 UtteranceProgressListener listener = mUtteranceProgressListener; 1975 if (listener != null) { 1976 listener.onStart(utteranceId); 1977 } 1978 } 1979 }; 1980 1981 private class SetupConnectionAsyncTask extends AsyncTask<Void, Void, Integer> { 1982 private final ComponentName mName; 1983 1984 public SetupConnectionAsyncTask(ComponentName name) { 1985 mName = name; 1986 } 1987 1988 @Override 1989 protected Integer doInBackground(Void... params) { 1990 synchronized(mStartLock) { 1991 if (isCancelled()) { 1992 return null; 1993 } 1994 1995 try { 1996 mService.setCallback(getCallerIdentity(), mCallback); 1997 1998 if (mParams.getString(Engine.KEY_PARAM_LANGUAGE) == null) { 1999 String[] defaultLanguage = mService.getClientDefaultLanguage(); 2000 mParams.putString(Engine.KEY_PARAM_LANGUAGE, defaultLanguage[0]); 2001 mParams.putString(Engine.KEY_PARAM_COUNTRY, defaultLanguage[1]); 2002 mParams.putString(Engine.KEY_PARAM_VARIANT, defaultLanguage[2]); 2003 } 2004 2005 Log.i(TAG, "Set up connection to " + mName); 2006 return SUCCESS; 2007 } catch (RemoteException re) { 2008 Log.e(TAG, "Error connecting to service, setCallback() failed"); 2009 return ERROR; 2010 } 2011 } 2012 } 2013 2014 @Override 2015 protected void onPostExecute(Integer result) { 2016 synchronized(mStartLock) { 2017 if (mOnSetupConnectionAsyncTask == this) { 2018 mOnSetupConnectionAsyncTask = null; 2019 } 2020 mEstablished = true; 2021 dispatchOnInit(result); 2022 } 2023 } 2024 } 2025 2026 @Override 2027 public void onServiceConnected(ComponentName name, IBinder service) { 2028 synchronized(mStartLock) { 2029 mConnectingServiceConnection = null; 2030 2031 Log.i(TAG, "Connected to " + name); 2032 2033 if (mOnSetupConnectionAsyncTask != null) { 2034 mOnSetupConnectionAsyncTask.cancel(false); 2035 } 2036 2037 mService = ITextToSpeechService.Stub.asInterface(service); 2038 mServiceConnection = Connection.this; 2039 2040 mEstablished = false; 2041 mOnSetupConnectionAsyncTask = new SetupConnectionAsyncTask(name); 2042 mOnSetupConnectionAsyncTask.execute(); 2043 } 2044 } 2045 2046 public IBinder getCallerIdentity() { 2047 return mCallback; 2048 } 2049 2050 /** 2051 * Clear connection related fields and cancel mOnServiceConnectedAsyncTask if set. 2052 * 2053 * @return true if we cancel mOnSetupConnectionAsyncTask in progress. 2054 */ 2055 private boolean clearServiceConnection() { 2056 synchronized(mStartLock) { 2057 boolean result = false; 2058 if (mOnSetupConnectionAsyncTask != null) { 2059 result = mOnSetupConnectionAsyncTask.cancel(false); 2060 mOnSetupConnectionAsyncTask = null; 2061 } 2062 2063 mService = null; 2064 // If this is the active connection, clear it 2065 if (mServiceConnection == this) { 2066 mServiceConnection = null; 2067 } 2068 return result; 2069 } 2070 } 2071 2072 @Override 2073 public void onServiceDisconnected(ComponentName name) { 2074 Log.i(TAG, "Asked to disconnect from " + name); 2075 if (clearServiceConnection()) { 2076 /* We need to protect against a rare case where engine 2077 * dies just after successful connection - and we process onServiceDisconnected 2078 * before OnServiceConnectedAsyncTask.onPostExecute. onServiceDisconnected cancels 2079 * OnServiceConnectedAsyncTask.onPostExecute and we don't call dispatchOnInit 2080 * with ERROR as argument. 2081 */ 2082 dispatchOnInit(ERROR); 2083 } 2084 } 2085 2086 public void disconnect() { 2087 mContext.unbindService(this); 2088 clearServiceConnection(); 2089 } 2090 2091 public boolean isEstablished() { 2092 return mService != null && mEstablished; 2093 } 2094 2095 public <R> R runAction(Action<R> action, R errorResult, String method, 2096 boolean reconnect, boolean onlyEstablishedConnection) { 2097 synchronized (mStartLock) { 2098 try { 2099 if (mService == null) { 2100 Log.w(TAG, method + " failed: not connected to TTS engine"); 2101 return errorResult; 2102 } 2103 if (onlyEstablishedConnection && !isEstablished()) { 2104 Log.w(TAG, method + " failed: TTS engine connection not fully set up"); 2105 return errorResult; 2106 } 2107 return action.run(mService); 2108 } catch (RemoteException ex) { 2109 Log.e(TAG, method + " failed", ex); 2110 if (reconnect) { 2111 disconnect(); 2112 initTts(); 2113 } 2114 return errorResult; 2115 } 2116 } 2117 } 2118 } 2119 2120 private interface Action<R> { 2121 R run(ITextToSpeechService service) throws RemoteException; 2122 } 2123 2124 /** 2125 * Information about an installed text-to-speech engine. 2126 * 2127 * @see TextToSpeech#getEngines 2128 */ 2129 public static class EngineInfo { 2130 /** 2131 * Engine package name.. 2132 */ 2133 public String name; 2134 /** 2135 * Localized label for the engine. 2136 */ 2137 public String label; 2138 /** 2139 * Icon for the engine. 2140 */ 2141 public int icon; 2142 /** 2143 * Whether this engine is a part of the system 2144 * image. 2145 * 2146 * @hide 2147 */ 2148 public boolean system; 2149 /** 2150 * The priority the engine declares for the the intent filter 2151 * {@code android.intent.action.TTS_SERVICE} 2152 * 2153 * @hide 2154 */ 2155 public int priority; 2156 2157 @Override 2158 public String toString() { 2159 return "EngineInfo{name=" + name + "}"; 2160 } 2161 2162 } 2163 2164 /** 2165 * Limit of length of input string passed to speak and synthesizeToFile. 2166 * 2167 * @see #speak 2168 * @see #synthesizeToFile 2169 */ 2170 public static int getMaxSpeechInputLength() { 2171 return 4000; 2172 } 2173} 2174