/tts/src/com/google/tts/TTS.java

http://eyes-free.googlecode.com/ · Java · 616 lines · 325 code · 38 blank · 253 comment · 35 complexity · a6b50600517640ebf9e22b105fe69d5d MD5 · raw file

  1. /*
  2. * Copyright (C) 2008 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. */
  16. package com.google.tts;
  17. import android.content.ComponentName;
  18. import android.content.Context;
  19. import android.content.Intent;
  20. import android.content.ServiceConnection;
  21. import android.content.pm.PackageManager;
  22. import android.content.pm.ResolveInfo;
  23. import android.content.pm.PackageManager.NameNotFoundException;
  24. import android.os.IBinder;
  25. import android.os.RemoteException;
  26. import android.util.Log;
  27. /**
  28. * Synthesizes speech from text. This abstracts away the complexities of using
  29. * the TTS service such as setting up the IBinder connection and handling
  30. * RemoteExceptions, etc.
  31. *
  32. * The TTS should always be safe the use; if the user does not have the
  33. * necessary TTS apk installed, the behavior is that all calls to the TTS act as
  34. * no-ops.
  35. *
  36. * @author clchen@google.com (Charles L. Chen)
  37. * @deprecated - Use TextToSpeechBeta instead
  38. */
  39. @Deprecated
  40. public class TTS {
  41. // This is the minimum version of the TTS service that is needed by this
  42. // version of the library stub.
  43. private final static int MIN_VER = 10;
  44. /**
  45. * Called when the TTS has initialized
  46. *
  47. * The InitListener must implement the onInit function. onInit is passed the
  48. * version number of the TTS library that the user has installed; since this
  49. * is called when the TTS has started, it is a good time to make sure that the
  50. * user's TTS library is up to date.
  51. */
  52. public interface InitListener {
  53. public void onInit(int version);
  54. }
  55. /**
  56. * Called when the TTS has finished speaking by itself (ie, speaking finished
  57. * without being canceled).
  58. *
  59. * The InitListener must implement the onInit function. onInit is passed the
  60. * version number of the TTS library that the user has installed; since this
  61. * is called when the TTS has started, it is a good time to make sure that the
  62. * user's TTS library is up to date.
  63. */
  64. public interface SpeechCompletedListener {
  65. public void onSpeechCompleted();
  66. }
  67. private ServiceConnection serviceConnection; // Connection needed for the TTS
  68. private ITTS itts;
  69. private Context ctx;
  70. private InitListener cb = null;
  71. private int version = -1;
  72. private boolean started = false;
  73. private boolean showInstaller = false;
  74. private TTSVersionAlert versionAlert = null;
  75. private ITTSCallback ittscallback;
  76. private SpeechCompletedListener speechCompletedCallback = null;
  77. /**
  78. * The constructor for the TTS.
  79. *
  80. * @param context The context
  81. * @param callback The InitListener that should be called when the TTS has
  82. * initialized successfully.
  83. * @param displayInstallMessage Boolean indicating whether or not an
  84. * installation prompt should be displayed to users who do not have the
  85. * TTS library. If this is true, a generic alert asking the user to
  86. * install the TTS will be used. If you wish to specify the exact
  87. * message of that prompt, please use TTS(Context context, InitListener
  88. * callback, TTSVersionAlert alert) as the constructor instead.
  89. */
  90. public TTS(Context context, InitListener callback, boolean displayInstallMessage) {
  91. showInstaller = displayInstallMessage;
  92. ctx = context;
  93. cb = callback;
  94. if (dataFilesCheck()) {
  95. initTts();
  96. }
  97. }
  98. /**
  99. * The constructor for the TTS.
  100. *
  101. * @param context The context
  102. * @param callback The InitListener that should be called when the TTS has
  103. * initialized successfully.
  104. * @param alert The TTSVersionAlert to be displayed
  105. */
  106. public TTS(Context context, InitListener callback, TTSVersionAlert alert) {
  107. showInstaller = true;
  108. versionAlert = alert;
  109. ctx = context;
  110. cb = callback;
  111. if (dataFilesCheck()) {
  112. initTts();
  113. }
  114. }
  115. public void setOnSpeechCompletedListener(final SpeechCompletedListener listener) {
  116. speechCompletedCallback = listener;
  117. }
  118. private boolean dataFilesCheck() {
  119. if (!ConfigurationManager.allFilesExist()) {
  120. // Treat missing voice data as the same as not having the TTS
  121. // installed.
  122. // If the developer wants to fail quietly, then just quit if there
  123. // are
  124. // missing voice data files.
  125. if (!showInstaller) {
  126. return false;
  127. }
  128. try {
  129. int flags = Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY;
  130. Context myContext = ctx.createPackageContext("com.google.tts", flags);
  131. Class<?> appClass =
  132. myContext.getClassLoader().loadClass("com.google.tts.ConfigurationManager");
  133. Intent intent = new Intent(myContext, appClass);
  134. ctx.startActivity(intent);
  135. return false;
  136. } catch (NameNotFoundException e) {
  137. // Just let it fail through; this exception means that the
  138. // TTS apk has not been installed and this case will be handled
  139. // in the initTts function
  140. e.printStackTrace();
  141. } catch (ClassNotFoundException e) {
  142. e.printStackTrace();
  143. }
  144. }
  145. return true;
  146. }
  147. private void initTts() {
  148. started = false;
  149. // Initialize the TTS, run the callback after the binding is successful
  150. serviceConnection = new ServiceConnection() {
  151. public void onServiceConnected(ComponentName name, IBinder service) {
  152. itts = ITTS.Stub.asInterface(service);
  153. try {
  154. version = itts.getVersion();
  155. // The TTS service must be at least the min version needed
  156. // by the
  157. // library stub. Do not try to run the older TTS with the
  158. // newer
  159. // library stub as the newer library may reference methods
  160. // which are
  161. // unavailable and cause a crash.
  162. if (version < MIN_VER) {
  163. if (showInstaller) {
  164. if (versionAlert != null) {
  165. versionAlert.show();
  166. } else {
  167. new TTSVersionAlert(ctx, null, null, null).show();
  168. }
  169. }
  170. return;
  171. }
  172. ittscallback = new ITTSCallback.Stub() {
  173. public void markReached(String mark) throws RemoteException {
  174. if (speechCompletedCallback != null) {
  175. speechCompletedCallback.onSpeechCompleted();
  176. }
  177. }
  178. };
  179. itts.registerCallback(ittscallback);
  180. } catch (RemoteException e) {
  181. initTts();
  182. return;
  183. }
  184. started = true;
  185. // Load all the pre-recorded utterances that used to be a part of
  186. // the old TTS.
  187. // The callback can become null if the Android OS decides to
  188. // restart the
  189. // TTS process as well as whatever is using it. In such cases,
  190. // do
  191. // nothing - the error handling from the speaking calls will
  192. // kick in
  193. // and force a proper restart of the TTS.
  194. if (cb != null) {
  195. cb.onInit(version);
  196. }
  197. }
  198. public void onServiceDisconnected(ComponentName name) {
  199. itts = null;
  200. cb = null;
  201. started = false;
  202. }
  203. };
  204. Intent intent = new Intent("android.intent.action.USE_TTS");
  205. intent.addCategory("android.intent.category.TTS");
  206. // Binding will fail only if the TTS doesn't exist;
  207. // the TTSVersionAlert will give users a chance to install
  208. // the needed TTS.
  209. if (!ctx.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)) {
  210. if (showInstaller) {
  211. if (versionAlert != null) {
  212. versionAlert.show();
  213. } else {
  214. new TTSVersionAlert(ctx, null, null, null).show();
  215. }
  216. }
  217. }
  218. }
  219. /**
  220. * Shuts down the TTS. It is good practice to call this in the onDestroy
  221. * method of the Activity that is using the TTS so that the TTS is stopped
  222. * cleanly.
  223. */
  224. public void shutdown() {
  225. try {
  226. ctx.unbindService(serviceConnection);
  227. } catch (IllegalArgumentException e) {
  228. // Do nothing and fail silently since an error here indicates that
  229. // binding never succeeded in the first place.
  230. }
  231. }
  232. /**
  233. * Adds a mapping between a string of text and a sound resource in a package.
  234. *
  235. * @see #TTS.speak(String text, int queueMode, String[] params)
  236. *
  237. * @param text Example: <b><code>"south_south_east"</code></b><br/>
  238. *
  239. * @param packagename Pass the packagename of the application that contains
  240. * the resource. If the resource is in your own application (this is
  241. * the most common case), then put the packagename of your application
  242. * here.<br/>
  243. * Example: <b>"com.google.marvin.compass"</b><br/>
  244. * The packagename can be found in the AndroidManifest.xml of your
  245. * application.
  246. * <p>
  247. * <code>&lt;manifest xmlns:android=&quot;...&quot;
  248. * package=&quot;<b>com.google.marvin.compass</b>&quot;&gt;</code>
  249. * </p>
  250. *
  251. * @param resourceId Example: <b><code>R.raw.south_south_east</code></b>
  252. */
  253. public void addSpeech(String text, String packagename, int resourceId) {
  254. if (!started) {
  255. return;
  256. }
  257. try {
  258. itts.addSpeech(text, packagename, resourceId);
  259. } catch (RemoteException e) {
  260. // TTS died; restart it.
  261. started = false;
  262. initTts();
  263. } catch (NullPointerException e) {
  264. // TTS died; restart it.
  265. started = false;
  266. initTts();
  267. } catch (IllegalStateException e) {
  268. // TTS died; restart it.
  269. started = false;
  270. initTts();
  271. }
  272. }
  273. /**
  274. * Adds a mapping between a string of text and a sound file. Using this, it is
  275. * possible to add custom pronounciations for text.
  276. *
  277. * @param text The string of text
  278. * @param filename The full path to the sound file (for example:
  279. * "/sdcard/mysounds/hello.wav")
  280. */
  281. public void addSpeech(String text, String filename) {
  282. if (!started) {
  283. return;
  284. }
  285. try {
  286. itts.addSpeechFile(text, filename);
  287. } catch (RemoteException e) {
  288. // TTS died; restart it.
  289. started = false;
  290. initTts();
  291. } catch (NullPointerException e) {
  292. // TTS died; restart it.
  293. started = false;
  294. initTts();
  295. } catch (IllegalStateException e) {
  296. // TTS died; restart it.
  297. started = false;
  298. initTts();
  299. }
  300. }
  301. /**
  302. * Speaks the string using the specified queuing strategy and speech
  303. * parameters. Note that the speech parameters are not universally supported
  304. * by all engines and will be treated as a hint. The TTS library will try to
  305. * fulfill these parameters as much as possible, but there is no guarantee
  306. * that the voice used will have the properties specified.
  307. *
  308. * @param text The string of text to be spoken.
  309. * @param queueMode The queuing strategy to use. Use 0 for no queuing, and 1
  310. * for queuing.
  311. * @param params The array of speech parameters to be used. Currently, only
  312. * params[0] is defined - it is for setting the type of voice if the
  313. * engine allows it. Possible values are "VOICE_MALE", "VOICE_FEMALE",
  314. * and "VOICE_ROBOT". Note that right now only the pre-recorded voice
  315. * has this support - this setting has no effect on eSpeak.
  316. */
  317. public void speak(String text, int queueMode, String[] params) {
  318. Log.i("TTS received: ", text);
  319. if (!started) {
  320. return;
  321. }
  322. try {
  323. itts.speak(text, queueMode, params);
  324. } catch (RemoteException e) {
  325. Log.e("TTS", "RemoteException error.");
  326. // TTS died; restart it.
  327. started = false;
  328. initTts();
  329. } catch (NullPointerException e) {
  330. Log.e("TTS", "NullPointerException error.");
  331. // TTS died; restart it.
  332. started = false;
  333. initTts();
  334. } catch (IllegalStateException e) {
  335. Log.e("TTS", "IllegalStateException error.");
  336. // TTS died; restart it.
  337. started = false;
  338. initTts();
  339. }
  340. }
  341. /**
  342. * Plays the earcon using the specified queueing mode and parameters.
  343. *
  344. * @param earcon The earcon that should be played
  345. * @param queueMode 0 for no queue (interrupts all previous utterances), 1 for
  346. * queued
  347. * @param params An ArrayList of parameters.
  348. */
  349. public void playEarcon(String earcon, int queueMode, String[] params) {
  350. if (!started) {
  351. return;
  352. }
  353. try {
  354. itts.playEarcon(earcon, queueMode, params);
  355. } catch (RemoteException e) {
  356. // TTS died; restart it.
  357. started = false;
  358. initTts();
  359. } catch (NullPointerException e) {
  360. // TTS died; restart it.
  361. started = false;
  362. initTts();
  363. } catch (IllegalStateException e) {
  364. // TTS died; restart it.
  365. started = false;
  366. initTts();
  367. }
  368. }
  369. /**
  370. * Plays the earcon using the specified queueing mode and parameters.
  371. *
  372. * @param earcon The TTSEarcon that should be played
  373. * @param queueMode 0 for no queue (interrupts all previous utterances), 1 for
  374. * queued
  375. * @param params An ArrayList of parameters.
  376. */
  377. public void playEarcon(TTSEarcon earcon, int queueMode, String[] params) {
  378. playEarcon(earcon.name(), queueMode, params);
  379. }
  380. /**
  381. * Returns whether or not the TTS is busy speaking.
  382. *
  383. * @return Whether or not the TTS is busy speaking.
  384. */
  385. public boolean isSpeaking() {
  386. if (!started) {
  387. return false;
  388. }
  389. try {
  390. return itts.isSpeaking();
  391. } catch (RemoteException e) {
  392. // TTS died; restart it.
  393. started = false;
  394. initTts();
  395. } catch (NullPointerException e) {
  396. // TTS died; restart it.
  397. started = false;
  398. initTts();
  399. } catch (IllegalStateException e) {
  400. // TTS died; restart it.
  401. started = false;
  402. initTts();
  403. }
  404. return false;
  405. }
  406. /**
  407. * Stops speech from the TTS.
  408. */
  409. public void stop() {
  410. if (!started) {
  411. return;
  412. }
  413. try {
  414. itts.stop();
  415. } catch (RemoteException e) {
  416. // TTS died; restart it.
  417. started = false;
  418. initTts();
  419. } catch (NullPointerException e) {
  420. // TTS died; restart it.
  421. started = false;
  422. initTts();
  423. } catch (IllegalStateException e) {
  424. // TTS died; restart it.
  425. started = false;
  426. initTts();
  427. }
  428. }
  429. /**
  430. * Returns the version number of the TTS library that the user has installed.
  431. *
  432. * @return The version number of the TTS library that the user has installed.
  433. */
  434. public int getVersion() {
  435. return version;
  436. }
  437. /**
  438. * Sets the TTS engine to be used.
  439. *
  440. * @param selectedEngine The TTS engine that should be used.
  441. */
  442. public void setEngine(TTSEngine selectedEngine) {
  443. if (!started) {
  444. return;
  445. }
  446. try {
  447. itts.setEngine(selectedEngine.toString());
  448. } catch (RemoteException e) {
  449. // TTS died; restart it.
  450. started = false;
  451. initTts();
  452. }
  453. }
  454. public void setEngine(String ttsEngineBinary) {
  455. if (!started) {
  456. return;
  457. }
  458. try {
  459. itts.setEngine(ttsEngineBinary);
  460. } catch (RemoteException e) {
  461. // TTS died; restart it.
  462. started = false;
  463. initTts();
  464. }
  465. }
  466. /**
  467. * Sets the speech rate for the TTS engine.
  468. *
  469. * Note that the speech rate is not universally supported by all engines and
  470. * will be treated as a hint. The TTS library will try to use the specified
  471. * speech rate, but there is no guarantee.
  472. *
  473. * Currently, this will change the speech rate for the espeak engine, but it
  474. * has no effect on any pre-recorded speech.
  475. *
  476. * @param speechRate The speech rate for the TTS engine.
  477. */
  478. public void setSpeechRate(int speechRate) {
  479. if (!started) {
  480. return;
  481. }
  482. try {
  483. itts.setSpeechRate(speechRate);
  484. } catch (RemoteException e) {
  485. // TTS died; restart it.
  486. started = false;
  487. initTts();
  488. }
  489. }
  490. /**
  491. * Sets the language for the TTS engine.
  492. *
  493. * Note that the language is not universally supported by all engines and will
  494. * be treated as a hint. The TTS library will try to use the specified
  495. * language, but there is no guarantee.
  496. *
  497. * Currently, this will change the language for the espeak engine, but it has
  498. * no effect on any pre-recorded speech.
  499. *
  500. * @param language The language to be used. The languages are specified by
  501. * their IETF language tags as defined by BCP 47. This is the same
  502. * standard used for the lang attribute in HTML. See:
  503. * http://en.wikipedia.org/wiki/IETF_language_tag
  504. */
  505. public void setLanguage(String language) {
  506. if (!started) {
  507. return;
  508. }
  509. try {
  510. itts.setLanguage(language);
  511. } catch (RemoteException e) {
  512. // TTS died; restart it.
  513. started = false;
  514. initTts();
  515. }
  516. }
  517. /**
  518. * Speaks the given text using the specified queueing mode and parameters.
  519. *
  520. * @param text The String of text that should be synthesized
  521. * @param params An ArrayList of parameters. The first element of this array
  522. * controls the type of voice to use.
  523. * @param filename The string that gives the full output filename; it should
  524. * be something like "/sdcard/myappsounds/mysound.wav".
  525. * @return A boolean that indicates if the synthesis succeeded
  526. */
  527. public boolean synthesizeToFile(String text, String[] params, String filename) {
  528. if (!started) {
  529. return false;
  530. }
  531. try {
  532. return itts.synthesizeToFile(text, params, filename);
  533. } catch (RemoteException e) {
  534. // TTS died; restart it.
  535. started = false;
  536. initTts();
  537. } catch (NullPointerException e) {
  538. // TTS died; restart it.
  539. started = false;
  540. initTts();
  541. } catch (IllegalStateException e) {
  542. // TTS died; restart it.
  543. started = false;
  544. initTts();
  545. }
  546. return false;
  547. }
  548. /**
  549. * Displays an alert that prompts users to install the TTS that is available
  550. * on the Market. This is useful if the application expects a newer version of
  551. * the TTS than what the user has.
  552. */
  553. public void showVersionAlert() {
  554. if (!started) {
  555. return;
  556. }
  557. if (versionAlert != null) {
  558. versionAlert.show();
  559. } else {
  560. new TTSVersionAlert(ctx, null, null, null).show();
  561. }
  562. }
  563. /**
  564. * Checks if the TTS service is installed or not
  565. *
  566. * @return A boolean that indicates whether the TTS service is installed
  567. */
  568. public static boolean isInstalled(Context ctx) {
  569. PackageManager pm = ctx.getPackageManager();
  570. Intent intent = new Intent("android.intent.action.USE_TTS");
  571. intent.addCategory("android.intent.category.TTS");
  572. ResolveInfo info = pm.resolveService(intent, 0);
  573. if (info == null) {
  574. return false;
  575. }
  576. return true;
  577. }
  578. }