TtsService.java revision d478cf09dff93015bc332f2707068f08bf603cfd
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.tts; 17 18import android.app.Service; 19import android.content.ContentResolver; 20import android.content.Context; 21import android.content.Intent; 22import android.content.SharedPreferences; 23import android.content.pm.PackageManager; 24import android.content.pm.PackageManager.NameNotFoundException; 25import android.media.MediaPlayer; 26import android.media.MediaPlayer.OnCompletionListener; 27import android.net.Uri; 28import android.os.IBinder; 29import android.os.RemoteCallbackList; 30import android.os.RemoteException; 31import android.preference.PreferenceManager; 32import android.speech.tts.ITts.Stub; 33import android.speech.tts.ITtsCallback; 34import android.speech.tts.TextToSpeech; 35import android.util.Log; 36import java.util.ArrayList; 37import java.util.Arrays; 38import java.util.HashMap; 39import java.util.Locale; 40import java.util.concurrent.locks.ReentrantLock; 41 42/** 43 * @hide Synthesizes speech from text. This is implemented as a service so that 44 * other applications can call the TTS without needing to bundle the TTS 45 * in the build. 46 * 47 */ 48public class TtsService extends Service implements OnCompletionListener { 49 50 private static class SpeechItem { 51 public static final int TEXT = 0; 52 public static final int EARCON = 1; 53 public static final int SILENCE = 2; 54 public static final int TEXT_TO_FILE = 3; 55 public String mText = null; 56 public ArrayList<String> mParams = null; 57 public int mType = TEXT; 58 public long mDuration = 0; 59 public String mFilename = null; 60 61 public SpeechItem(String text, ArrayList<String> params, int itemType) { 62 mText = text; 63 mParams = params; 64 mType = itemType; 65 } 66 67 public SpeechItem(long silenceTime) { 68 mDuration = silenceTime; 69 } 70 71 public SpeechItem(String text, ArrayList<String> params, int itemType, String filename) { 72 mText = text; 73 mParams = params; 74 mType = itemType; 75 mFilename = filename; 76 } 77 78 } 79 80 /** 81 * Contains the information needed to access a sound resource; the name of 82 * the package that contains the resource and the resID of the resource 83 * within that package. 84 */ 85 private static class SoundResource { 86 public String mSourcePackageName = null; 87 public int mResId = -1; 88 public String mFilename = null; 89 90 public SoundResource(String packageName, int id) { 91 mSourcePackageName = packageName; 92 mResId = id; 93 mFilename = null; 94 } 95 96 public SoundResource(String file) { 97 mSourcePackageName = null; 98 mResId = -1; 99 mFilename = file; 100 } 101 } 102 103 private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000; 104 private static final int MAX_FILENAME_LENGTH = 250; 105 106 private static final String ACTION = "android.intent.action.START_TTS_SERVICE"; 107 private static final String CATEGORY = "android.intent.category.TTS"; 108 private static final String PKGNAME = "android.tts"; 109 110 final RemoteCallbackList<android.speech.tts.ITtsCallback> mCallbacks = new RemoteCallbackList<ITtsCallback>(); 111 112 private Boolean mIsSpeaking; 113 private ArrayList<SpeechItem> mSpeechQueue; 114 private HashMap<String, SoundResource> mEarcons; 115 private HashMap<String, SoundResource> mUtterances; 116 private MediaPlayer mPlayer; 117 private TtsService mSelf; 118 119 private ContentResolver mResolver; 120 121 private final ReentrantLock speechQueueLock = new ReentrantLock(); 122 private final ReentrantLock synthesizerLock = new ReentrantLock(); 123 124 private SynthProxy nativeSynth; 125 @Override 126 public void onCreate() { 127 super.onCreate(); 128 Log.i("TTS", "TTS starting"); 129 130 mResolver = getContentResolver(); 131 132 String soLibPath = "/system/lib/libttspico.so"; 133 nativeSynth = new SynthProxy(soLibPath); 134 135 mSelf = this; 136 mIsSpeaking = false; 137 138 mEarcons = new HashMap<String, SoundResource>(); 139 mUtterances = new HashMap<String, SoundResource>(); 140 141 mSpeechQueue = new ArrayList<SpeechItem>(); 142 mPlayer = null; 143 144 setDefaultSettings(); 145 } 146 147 @Override 148 public void onDestroy() { 149 super.onDestroy(); 150 // Don't hog the media player 151 cleanUpPlayer(); 152 153 nativeSynth.shutdown(); 154 155 // Unregister all callbacks. 156 mCallbacks.kill(); 157 } 158 159 160 private void setDefaultSettings() { 161 setLanguage(this.getDefaultLanguage(), getDefaultCountry(), getDefaultLocVariant()); 162 163 // speech rate 164 setSpeechRate(getDefaultRate()); 165 } 166 167 168 private boolean isDefaultEnforced() { 169 return (android.provider.Settings.Secure.getInt(mResolver, 170 android.provider.Settings.Secure.TTS_USE_DEFAULTS, 171 TextToSpeech.Engine.FALLBACK_TTS_USE_DEFAULTS) 172 == 1 ); 173 } 174 175 176 private int getDefaultRate() { 177 return android.provider.Settings.Secure.getInt(mResolver, 178 android.provider.Settings.Secure.TTS_DEFAULT_RATE, 179 TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_RATE); 180 } 181 182 183 private String getDefaultLanguage() { 184 String defaultLang = android.provider.Settings.Secure.getString(mResolver, 185 android.provider.Settings.Secure.TTS_DEFAULT_LANG); 186 if (defaultLang == null) { 187 // no setting found, use the current Locale to determine the default language 188 return Locale.getDefault().getISO3Language(); 189 } else { 190 return defaultLang; 191 } 192 } 193 194 195 private String getDefaultCountry() { 196 String defaultCountry = android.provider.Settings.Secure.getString(mResolver, 197 android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY); 198 if (defaultCountry == null) { 199 // no setting found, use the current Locale to determine the default country 200 return Locale.getDefault().getISO3Country(); 201 } else { 202 return defaultCountry; 203 } 204 } 205 206 207 private String getDefaultLocVariant() { 208 String defaultVar = android.provider.Settings.Secure.getString(mResolver, 209 android.provider.Settings.Secure.TTS_DEFAULT_VARIANT); 210 if (defaultVar == null) { 211 // no setting found, use the current Locale to determine the default variant 212 return Locale.getDefault().getVariant(); 213 } else { 214 return defaultVar; 215 } 216 } 217 218 219 private int setSpeechRate(int rate) { 220 if (isDefaultEnforced()) { 221 return nativeSynth.setSpeechRate(getDefaultRate()); 222 } else { 223 return nativeSynth.setSpeechRate(rate); 224 } 225 } 226 227 228 private int setPitch(int pitch) { 229 return nativeSynth.setPitch(pitch); 230 } 231 232 233 private int isLanguageAvailable(String lang, String country, String variant) { 234 Log.v("TTS", "TtsService.isLanguageAvailable(" + lang + ", " + country + ", " +variant+")"); 235 return nativeSynth.isLanguageAvailable(lang, country, variant); 236 } 237 238 239 private String[] getLanguage() { 240 return nativeSynth.getLanguage(); 241 } 242 243 244 private int setLanguage(String lang, String country, String variant) { 245 Log.v("TTS", "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")"); 246 if (isDefaultEnforced()) { 247 return nativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(), 248 getDefaultLocVariant()); 249 } else { 250 return nativeSynth.setLanguage(lang, country, variant); 251 } 252 } 253 254 255 /** 256 * Adds a sound resource to the TTS. 257 * 258 * @param text 259 * The text that should be associated with the sound resource 260 * @param packageName 261 * The name of the package which has the sound resource 262 * @param resId 263 * The resource ID of the sound within its package 264 */ 265 private void addSpeech(String text, String packageName, int resId) { 266 mUtterances.put(text, new SoundResource(packageName, resId)); 267 } 268 269 /** 270 * Adds a sound resource to the TTS. 271 * 272 * @param text 273 * The text that should be associated with the sound resource 274 * @param filename 275 * The filename of the sound resource. This must be a complete 276 * path like: (/sdcard/mysounds/mysoundbite.mp3). 277 */ 278 private void addSpeech(String text, String filename) { 279 mUtterances.put(text, new SoundResource(filename)); 280 } 281 282 /** 283 * Adds a sound resource to the TTS as an earcon. 284 * 285 * @param earcon 286 * The text that should be associated with the sound resource 287 * @param packageName 288 * The name of the package which has the sound resource 289 * @param resId 290 * The resource ID of the sound within its package 291 */ 292 private void addEarcon(String earcon, String packageName, int resId) { 293 mEarcons.put(earcon, new SoundResource(packageName, resId)); 294 } 295 296 /** 297 * Adds a sound resource to the TTS as an earcon. 298 * 299 * @param earcon 300 * The text that should be associated with the sound resource 301 * @param filename 302 * The filename of the sound resource. This must be a complete 303 * path like: (/sdcard/mysounds/mysoundbite.mp3). 304 */ 305 private void addEarcon(String earcon, String filename) { 306 mEarcons.put(earcon, new SoundResource(filename)); 307 } 308 309 /** 310 * Speaks the given text using the specified queueing mode and parameters. 311 * 312 * @param text 313 * The text that should be spoken 314 * @param queueMode 315 * 0 for no queue (interrupts all previous utterances), 1 for 316 * queued 317 * @param params 318 * An ArrayList of parameters. This is not implemented for all 319 * engines. 320 */ 321 private int speak(String text, int queueMode, ArrayList<String> params) { 322 if (queueMode == 0) { 323 stop(); 324 } 325 mSpeechQueue.add(new SpeechItem(text, params, SpeechItem.TEXT)); 326 if (!mIsSpeaking) { 327 processSpeechQueue(); 328 } 329 return TextToSpeech.TTS_SUCCESS; 330 } 331 332 /** 333 * Plays the earcon using the specified queueing mode and parameters. 334 * 335 * @param earcon 336 * The earcon that should be played 337 * @param queueMode 338 * 0 for no queue (interrupts all previous utterances), 1 for 339 * queued 340 * @param params 341 * An ArrayList of parameters. This is not implemented for all 342 * engines. 343 */ 344 private int playEarcon(String earcon, int queueMode, 345 ArrayList<String> params) { 346 if (queueMode == 0) { 347 stop(); 348 } 349 mSpeechQueue.add(new SpeechItem(earcon, params, SpeechItem.EARCON)); 350 if (!mIsSpeaking) { 351 processSpeechQueue(); 352 } 353 return TextToSpeech.TTS_SUCCESS; 354 } 355 356 /** 357 * Stops all speech output and removes any utterances still in the queue. 358 */ 359 private int stop() { 360 Log.i("TTS", "Stopping"); 361 mSpeechQueue.clear(); 362 363 int result = nativeSynth.stop(); 364 mIsSpeaking = false; 365 if (mPlayer != null) { 366 try { 367 mPlayer.stop(); 368 } catch (IllegalStateException e) { 369 // Do nothing, the player is already stopped. 370 } 371 } 372 Log.i("TTS", "Stopped"); 373 return result; 374 } 375 376 public void onCompletion(MediaPlayer arg0) { 377 processSpeechQueue(); 378 } 379 380 private int playSilence(long duration, int queueMode, 381 ArrayList<String> params) { 382 if (queueMode == 0) { 383 stop(); 384 } 385 mSpeechQueue.add(new SpeechItem(duration)); 386 if (!mIsSpeaking) { 387 processSpeechQueue(); 388 } 389 return TextToSpeech.TTS_SUCCESS; 390 } 391 392 private void silence(final long duration) { 393 class SilenceThread implements Runnable { 394 public void run() { 395 try { 396 Thread.sleep(duration); 397 } catch (InterruptedException e) { 398 e.printStackTrace(); 399 } finally { 400 processSpeechQueue(); 401 } 402 } 403 } 404 Thread slnc = (new Thread(new SilenceThread())); 405 slnc.setPriority(Thread.MIN_PRIORITY); 406 slnc.start(); 407 } 408 409 private void speakInternalOnly(final String text, 410 final ArrayList<String> params) { 411 class SynthThread implements Runnable { 412 public void run() { 413 boolean synthAvailable = false; 414 try { 415 synthAvailable = synthesizerLock.tryLock(); 416 if (!synthAvailable) { 417 Thread.sleep(100); 418 Thread synth = (new Thread(new SynthThread())); 419 synth.setPriority(Thread.MIN_PRIORITY); 420 synth.start(); 421 return; 422 } 423 if (params != null){ 424 String language = ""; 425 String country = ""; 426 String variant = ""; 427 for (int i = 0; i < params.size() - 1; i = i + 2){ 428 String param = params.get(i); 429 if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)){ 430 setSpeechRate(Integer.parseInt(params.get(i+1))); 431 } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){ 432 language = params.get(i+1); 433 } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){ 434 country = params.get(i+1); 435 } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ 436 variant = params.get(i+1); 437 } 438 } 439 if (language.length() > 0){ 440 setLanguage(language, country, variant); 441 } 442 } 443 nativeSynth.speak(text); 444 } catch (InterruptedException e) { 445 e.printStackTrace(); 446 } finally { 447 // This check is needed because finally will always run; 448 // even if the 449 // method returns somewhere in the try block. 450 if (synthAvailable) { 451 synthesizerLock.unlock(); 452 } 453 processSpeechQueue(); 454 } 455 } 456 } 457 Thread synth = (new Thread(new SynthThread())); 458 synth.setPriority(Thread.MIN_PRIORITY); 459 synth.start(); 460 } 461 462 private void synthToFileInternalOnly(final String text, 463 final ArrayList<String> params, final String filename) { 464 class SynthThread implements Runnable { 465 public void run() { 466 Log.i("TTS", "Synthesizing to " + filename); 467 boolean synthAvailable = false; 468 try { 469 synthAvailable = synthesizerLock.tryLock(); 470 if (!synthAvailable) { 471 Thread.sleep(100); 472 Thread synth = (new Thread(new SynthThread())); 473 synth.setPriority(Thread.MIN_PRIORITY); 474 synth.start(); 475 return; 476 } 477 if (params != null){ 478 String language = ""; 479 String country = ""; 480 String variant = ""; 481 for (int i = 0; i < params.size() - 1; i = i + 2){ 482 String param = params.get(i); 483 if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)){ 484 setSpeechRate(Integer.parseInt(params.get(i+1))); 485 } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){ 486 language = params.get(i+1); 487 } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){ 488 country = params.get(i+1); 489 } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ 490 variant = params.get(i+1); 491 } 492 } 493 if (language.length() > 0){ 494 setLanguage(language, country, variant); 495 } 496 } 497 nativeSynth.synthesizeToFile(text, filename); 498 } catch (InterruptedException e) { 499 e.printStackTrace(); 500 } finally { 501 // This check is needed because finally will always run; 502 // even if the 503 // method returns somewhere in the try block. 504 if (synthAvailable) { 505 synthesizerLock.unlock(); 506 } 507 processSpeechQueue(); 508 } 509 } 510 } 511 Thread synth = (new Thread(new SynthThread())); 512 synth.setPriority(Thread.MIN_PRIORITY); 513 synth.start(); 514 } 515 516 private SoundResource getSoundResource(SpeechItem speechItem) { 517 SoundResource sr = null; 518 String text = speechItem.mText; 519 if (speechItem.mType == SpeechItem.SILENCE) { 520 // Do nothing if this is just silence 521 } else if (speechItem.mType == SpeechItem.EARCON) { 522 sr = mEarcons.get(text); 523 } else { 524 sr = mUtterances.get(text); 525 } 526 return sr; 527 } 528 529 private void broadcastTtsQueueProcessingCompleted(){ 530 Intent i = new Intent(Intent.ACTION_TTS_QUEUE_PROCESSING_COMPLETED); 531 sendBroadcast(i); 532 } 533 534 private void dispatchSpeechCompletedCallbacks(String mark) { 535 Log.i("TTS callback", "dispatch started"); 536 // Broadcast to all clients the new value. 537 final int N = mCallbacks.beginBroadcast(); 538 for (int i = 0; i < N; i++) { 539 try { 540 mCallbacks.getBroadcastItem(i).markReached(mark); 541 } catch (RemoteException e) { 542 // The RemoteCallbackList will take care of removing 543 // the dead object for us. 544 } 545 } 546 mCallbacks.finishBroadcast(); 547 Log.i("TTS callback", "dispatch completed to " + N); 548 } 549 550 private SpeechItem splitCurrentTextIfNeeded(SpeechItem currentSpeechItem){ 551 if (currentSpeechItem.mText.length() < MAX_SPEECH_ITEM_CHAR_LENGTH){ 552 return currentSpeechItem; 553 } else { 554 ArrayList<SpeechItem> splitItems = new ArrayList<SpeechItem>(); 555 int start = 0; 556 int end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1; 557 String splitText; 558 SpeechItem splitItem; 559 while (end < currentSpeechItem.mText.length()){ 560 splitText = currentSpeechItem.mText.substring(start, end); 561 splitItem = new SpeechItem(splitText, null, SpeechItem.TEXT); 562 splitItems.add(splitItem); 563 start = end; 564 end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1; 565 } 566 splitText = currentSpeechItem.mText.substring(start); 567 splitItem = new SpeechItem(splitText, null, SpeechItem.TEXT); 568 splitItems.add(splitItem); 569 mSpeechQueue.remove(0); 570 for (int i = splitItems.size() - 1; i >= 0; i--){ 571 mSpeechQueue.add(0, splitItems.get(i)); 572 } 573 return mSpeechQueue.get(0); 574 } 575 } 576 577 private void processSpeechQueue() { 578 boolean speechQueueAvailable = false; 579 try { 580 speechQueueAvailable = speechQueueLock.tryLock(); 581 if (!speechQueueAvailable) { 582 return; 583 } 584 if (mSpeechQueue.size() < 1) { 585 mIsSpeaking = false; 586 broadcastTtsQueueProcessingCompleted(); 587 return; 588 } 589 590 SpeechItem currentSpeechItem = mSpeechQueue.get(0); 591 mIsSpeaking = true; 592 SoundResource sr = getSoundResource(currentSpeechItem); 593 // Synth speech as needed - synthesizer should call 594 // processSpeechQueue to continue running the queue 595 Log.i("TTS processing: ", currentSpeechItem.mText); 596 if (sr == null) { 597 if (currentSpeechItem.mType == SpeechItem.TEXT) { 598 currentSpeechItem = splitCurrentTextIfNeeded(currentSpeechItem); 599 speakInternalOnly(currentSpeechItem.mText, 600 currentSpeechItem.mParams); 601 } else if (currentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) { 602 synthToFileInternalOnly(currentSpeechItem.mText, 603 currentSpeechItem.mParams, currentSpeechItem.mFilename); 604 } else { 605 // This is either silence or an earcon that was missing 606 silence(currentSpeechItem.mDuration); 607 } 608 } else { 609 cleanUpPlayer(); 610 if (sr.mSourcePackageName == PKGNAME) { 611 // Utterance is part of the TTS library 612 mPlayer = MediaPlayer.create(this, sr.mResId); 613 } else if (sr.mSourcePackageName != null) { 614 // Utterance is part of the app calling the library 615 Context ctx; 616 try { 617 ctx = this.createPackageContext(sr.mSourcePackageName, 618 0); 619 } catch (NameNotFoundException e) { 620 e.printStackTrace(); 621 mSpeechQueue.remove(0); // Remove it from the queue and 622 // move on 623 mIsSpeaking = false; 624 return; 625 } 626 mPlayer = MediaPlayer.create(ctx, sr.mResId); 627 } else { 628 // Utterance is coming from a file 629 mPlayer = MediaPlayer.create(this, Uri.parse(sr.mFilename)); 630 } 631 632 // Check if Media Server is dead; if it is, clear the queue and 633 // give up for now - hopefully, it will recover itself. 634 if (mPlayer == null) { 635 mSpeechQueue.clear(); 636 mIsSpeaking = false; 637 return; 638 } 639 mPlayer.setOnCompletionListener(this); 640 try { 641 mPlayer.start(); 642 } catch (IllegalStateException e) { 643 mSpeechQueue.clear(); 644 mIsSpeaking = false; 645 cleanUpPlayer(); 646 return; 647 } 648 } 649 if (mSpeechQueue.size() > 0) { 650 mSpeechQueue.remove(0); 651 } 652 } finally { 653 // This check is needed because finally will always run; even if the 654 // method returns somewhere in the try block. 655 if (speechQueueAvailable) { 656 speechQueueLock.unlock(); 657 } 658 } 659 } 660 661 private void cleanUpPlayer() { 662 if (mPlayer != null) { 663 mPlayer.release(); 664 mPlayer = null; 665 } 666 } 667 668 /** 669 * Synthesizes the given text to a file using the specified parameters. 670 * 671 * @param text 672 * The String of text that should be synthesized 673 * @param params 674 * An ArrayList of parameters. The first element of this array 675 * controls the type of voice to use. 676 * @param filename 677 * The string that gives the full output filename; it should be 678 * something like "/sdcard/myappsounds/mysound.wav". 679 * @return A boolean that indicates if the synthesis succeeded 680 */ 681 private boolean synthesizeToFile(String text, ArrayList<String> params, 682 String filename) { 683 // Don't allow a filename that is too long 684 if (filename.length() > MAX_FILENAME_LENGTH) { 685 return false; 686 } 687 // Don't allow anything longer than the max text length; since this 688 // is synthing to a file, don't even bother splitting it. 689 if (text.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH){ 690 return false; 691 } 692 mSpeechQueue.add(new SpeechItem(text, params, SpeechItem.TEXT_TO_FILE, filename)); 693 if (!mIsSpeaking) { 694 processSpeechQueue(); 695 } 696 return true; 697 } 698 699 @Override 700 public IBinder onBind(Intent intent) { 701 if (ACTION.equals(intent.getAction())) { 702 for (String category : intent.getCategories()) { 703 if (category.equals(CATEGORY)) { 704 return mBinder; 705 } 706 } 707 } 708 return null; 709 } 710 711 private final android.speech.tts.ITts.Stub mBinder = new Stub() { 712 713 public void registerCallback(ITtsCallback cb) { 714 if (cb != null) 715 mCallbacks.register(cb); 716 } 717 718 public void unregisterCallback(ITtsCallback cb) { 719 if (cb != null) 720 mCallbacks.unregister(cb); 721 } 722 723 /** 724 * Speaks the given text using the specified queueing mode and 725 * parameters. 726 * 727 * @param text 728 * The text that should be spoken 729 * @param queueMode 730 * 0 for no queue (interrupts all previous utterances), 1 for 731 * queued 732 * @param params 733 * An ArrayList of parameters. The first element of this 734 * array controls the type of voice to use. 735 */ 736 public int speak(String text, int queueMode, String[] params) { 737 ArrayList<String> speakingParams = new ArrayList<String>(); 738 if (params != null) { 739 speakingParams = new ArrayList<String>(Arrays.asList(params)); 740 } 741 return mSelf.speak(text, queueMode, speakingParams); 742 } 743 744 /** 745 * Plays the earcon using the specified queueing mode and parameters. 746 * 747 * @param earcon 748 * The earcon that should be played 749 * @param queueMode 750 * 0 for no queue (interrupts all previous utterances), 1 for 751 * queued 752 * @param params 753 * An ArrayList of parameters. 754 */ 755 public int playEarcon(String earcon, int queueMode, String[] params) { 756 ArrayList<String> speakingParams = new ArrayList<String>(); 757 if (params != null) { 758 speakingParams = new ArrayList<String>(Arrays.asList(params)); 759 } 760 return mSelf.playEarcon(earcon, queueMode, speakingParams); 761 } 762 763 /** 764 * Plays the silence using the specified queueing mode and parameters. 765 * 766 * @param duration 767 * The duration of the silence that should be played 768 * @param queueMode 769 * 0 for no queue (interrupts all previous utterances), 1 for 770 * queued 771 * @param params 772 * An ArrayList of parameters. 773 */ 774 public int playSilence(long duration, int queueMode, String[] params) { 775 ArrayList<String> speakingParams = new ArrayList<String>(); 776 if (params != null) { 777 speakingParams = new ArrayList<String>(Arrays.asList(params)); 778 } 779 return mSelf.playSilence(duration, queueMode, speakingParams); 780 } 781 782 /** 783 * Stops all speech output and removes any utterances still in the 784 * queue. 785 */ 786 public int stop() { 787 return mSelf.stop(); 788 } 789 790 /** 791 * Returns whether or not the TTS is speaking. 792 * 793 * @return Boolean to indicate whether or not the TTS is speaking 794 */ 795 public boolean isSpeaking() { 796 return (mSelf.mIsSpeaking && (mSpeechQueue.size() < 1)); 797 } 798 799 /** 800 * Adds a sound resource to the TTS. 801 * 802 * @param text 803 * The text that should be associated with the sound resource 804 * @param packageName 805 * The name of the package which has the sound resource 806 * @param resId 807 * The resource ID of the sound within its package 808 */ 809 public void addSpeech(String text, String packageName, int resId) { 810 mSelf.addSpeech(text, packageName, resId); 811 } 812 813 /** 814 * Adds a sound resource to the TTS. 815 * 816 * @param text 817 * The text that should be associated with the sound resource 818 * @param filename 819 * The filename of the sound resource. This must be a 820 * complete path like: (/sdcard/mysounds/mysoundbite.mp3). 821 */ 822 public void addSpeechFile(String text, String filename) { 823 mSelf.addSpeech(text, filename); 824 } 825 826 /** 827 * Adds a sound resource to the TTS as an earcon. 828 * 829 * @param earcon 830 * The text that should be associated with the sound resource 831 * @param packageName 832 * The name of the package which has the sound resource 833 * @param resId 834 * The resource ID of the sound within its package 835 */ 836 public void addEarcon(String earcon, String packageName, int resId) { 837 mSelf.addEarcon(earcon, packageName, resId); 838 } 839 840 /** 841 * Adds a sound resource to the TTS as an earcon. 842 * 843 * @param earcon 844 * The text that should be associated with the sound resource 845 * @param filename 846 * The filename of the sound resource. This must be a 847 * complete path like: (/sdcard/mysounds/mysoundbite.mp3). 848 */ 849 public void addEarconFile(String earcon, String filename) { 850 mSelf.addEarcon(earcon, filename); 851 } 852 853 /** 854 * Sets the speech rate for the TTS. Note that this will only have an 855 * effect on synthesized speech; it will not affect pre-recorded speech. 856 * 857 * @param speechRate 858 * The speech rate that should be used 859 */ 860 public int setSpeechRate(int speechRate) { 861 return mSelf.setSpeechRate(speechRate); 862 } 863 864 /** 865 * Sets the pitch for the TTS. Note that this will only have an 866 * effect on synthesized speech; it will not affect pre-recorded speech. 867 * 868 * @param pitch 869 * The pitch that should be used for the synthesized voice 870 */ 871 public int setPitch(int pitch) { 872 return mSelf.setPitch(pitch); 873 } 874 875 /** 876 * Returns the level of support for the specified language. 877 * 878 * @param lang the three letter ISO language code. 879 * @param country the three letter ISO country code. 880 * @param variant the variant code associated with the country and language pair. 881 * @return one of TTS_LANG_NOT_SUPPORTED, TTS_LANG_MISSING_DATA, TTS_LANG_AVAILABLE, 882 * TTS_LANG_COUNTRY_AVAILABLE, TTS_LANG_COUNTRY_VAR_AVAILABLE as defined in 883 * android.speech.tts.TextToSpeech. 884 */ 885 public int isLanguageAvailable(String lang, String country, String variant) { 886 return mSelf.isLanguageAvailable(lang, country, variant); 887 } 888 889 /** 890 * Returns the currently set language / country / variant strings representing the 891 * language used by the TTS engine. 892 * @return null is no language is set, or an array of 3 string containing respectively 893 * the language, country and variant. 894 */ 895 public String[] getLanguage() { 896 return mSelf.getLanguage(); 897 } 898 899 /** 900 * Sets the speech rate for the TTS, which affects the synthesized voice. 901 * 902 * @param lang the three letter ISO language code. 903 * @param country the three letter ISO country code. 904 * @param variant the variant code associated with the country and language pair. 905 */ 906 public int setLanguage(String lang, String country, String variant) { 907 return mSelf.setLanguage(lang, country, variant); 908 } 909 910 /** 911 * Synthesizes the given text to a file using the specified 912 * parameters. 913 * 914 * @param text 915 * The String of text that should be synthesized 916 * @param params 917 * An ArrayList of parameters. The first element of this 918 * array controls the type of voice to use. 919 * @param filename 920 * The string that gives the full output filename; it should 921 * be something like "/sdcard/myappsounds/mysound.wav". 922 * @return A boolean that indicates if the synthesis succeeded 923 */ 924 public boolean synthesizeToFile(String text, String[] params, 925 String filename) { 926 ArrayList<String> speakingParams = new ArrayList<String>(); 927 if (params != null) { 928 speakingParams = new ArrayList<String>(Arrays.asList(params)); 929 } 930 return mSelf.synthesizeToFile(text, speakingParams, filename); 931 } 932 933 }; 934 935} 936