eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CheckVoiceData.java 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /*
  2. * Copyright (C) 2012 Reece H. Dunn
  3. * Copyright (C) 2009 The Android Open Source Project
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /*
  18. * This Activity is used by Android to get the list of languages to display
  19. * to the user when selecting the text-to-speech language. This is by locale,
  20. * not voice name.
  21. */
  22. package com.reecedunn.espeak;
  23. import android.app.Activity;
  24. import android.content.Context;
  25. import android.content.Intent;
  26. import android.os.Bundle;
  27. import android.speech.tts.TextToSpeech;
  28. import android.speech.tts.TextToSpeech.Engine;
  29. import android.util.Log;
  30. import com.reecedunn.espeak.SpeechSynthesis.SynthReadyCallback;
  31. import com.reecedunn.espeak.SpeechSynthesis.Voice;
  32. import java.io.ByteArrayOutputStream;
  33. import java.io.File;
  34. import java.io.FileInputStream;
  35. import java.io.IOException;
  36. import java.io.InputStream;
  37. import java.util.ArrayList;
  38. import java.util.HashSet;
  39. import java.util.List;
  40. import java.util.Locale;
  41. import java.util.Set;
  42. public class CheckVoiceData extends Activity {
  43. private static final String TAG = "eSpeakTTS";
  44. private static final int REQUEST_DOWNLOAD = 1;
  45. /** Resources required for eSpeak to run correctly. */
  46. private static final String[] BASE_RESOURCES = {
  47. "version",
  48. "intonations",
  49. "phondata",
  50. "phonindex",
  51. "phontab",
  52. "en_dict",
  53. };
  54. public static File getDataPath(Context context) {
  55. return new File(context.getDir("voices", MODE_PRIVATE), "espeak-data");
  56. }
  57. public static boolean hasBaseResources(Context context) {
  58. final File dataPath = getDataPath(context);
  59. for (String resource : BASE_RESOURCES) {
  60. final File resourceFile = new File(dataPath, resource);
  61. if (!resourceFile.exists()) {
  62. Log.e(TAG, "Missing base resource: " + resourceFile.getPath());
  63. return false;
  64. }
  65. }
  66. return true;
  67. }
  68. public static String readContent(InputStream stream) throws IOException {
  69. ByteArrayOutputStream content = new ByteArrayOutputStream();
  70. int c = stream.read();
  71. while (c != -1)
  72. {
  73. content.write((byte)c);
  74. c = stream.read();
  75. }
  76. return content.toString();
  77. }
  78. public static boolean canUpgradeResources(Context context) {
  79. try {
  80. final String version = readContent(context.getResources().openRawResource(R.raw.espeakdata_version));
  81. final String installedVersion = readContent(new FileInputStream(new File(getDataPath(context), "version")));
  82. return !version.equals(installedVersion);
  83. } catch (Exception e) {
  84. return false;
  85. }
  86. }
  87. @Override
  88. protected void onCreate(Bundle savedInstanceState) {
  89. super.onCreate(savedInstanceState);
  90. checkForVoices(false);
  91. }
  92. @Override
  93. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  94. switch (requestCode) {
  95. case REQUEST_DOWNLOAD:
  96. checkForVoices(true);
  97. break;
  98. }
  99. }
  100. private void checkForVoices(boolean attemptedInstall) {
  101. final File dataPath = getDataPath(this);
  102. ArrayList<String> availableLanguages = new ArrayList<String>();
  103. ArrayList<String> unavailableLanguages = new ArrayList<String>();
  104. if (!hasBaseResources(this) || canUpgradeResources(this)) {
  105. if (!attemptedInstall) {
  106. downloadVoiceData();
  107. return;
  108. }
  109. // No base resource, can't load available voices.
  110. unavailableLanguages.add(Locale.ENGLISH.toString());
  111. returnResults(Engine.CHECK_VOICE_DATA_MISSING_DATA, dataPath, availableLanguages,
  112. unavailableLanguages);
  113. return;
  114. }
  115. final SpeechSynthesis engine = new SpeechSynthesis(this, mSynthReadyCallback);
  116. final List<Voice> voices = engine.getAvailableVoices();
  117. for (Voice voice : voices) {
  118. availableLanguages.add(voice.toString());
  119. }
  120. final ArrayList<String> checkFor = getIntent().getStringArrayListExtra(
  121. TextToSpeech.Engine.EXTRA_CHECK_VOICE_DATA_FOR);
  122. if (checkFor != null && !checkFor.isEmpty()) {
  123. final Set<String> checkForSet = new HashSet<String>(checkFor);
  124. availableLanguages = filter(availableLanguages, checkForSet);
  125. unavailableLanguages = filter(unavailableLanguages, checkForSet);
  126. }
  127. returnResults(Engine.CHECK_VOICE_DATA_PASS, dataPath, availableLanguages,
  128. unavailableLanguages);
  129. }
  130. /**
  131. * Launches the voice data installer.
  132. */
  133. private void downloadVoiceData() {
  134. final Intent checkIntent = new Intent(this, DownloadVoiceData.class);
  135. startActivityForResult(checkIntent, REQUEST_DOWNLOAD);
  136. }
  137. private void returnResults(int result, File dataPath, ArrayList<String> availableLanguages,
  138. ArrayList<String> unavailableLanguages) {
  139. final Intent returnData = new Intent();
  140. returnData.putStringArrayListExtra(Engine.EXTRA_AVAILABLE_VOICES, availableLanguages);
  141. returnData.putStringArrayListExtra(Engine.EXTRA_UNAVAILABLE_VOICES, unavailableLanguages);
  142. // Don't bother returning Engine.EXTRA_VOICE_DATA_FILES,
  143. // Engine.EXTRA_VOICE_DATA_FILES_INFO, or
  144. // Engine.EXTRA_VOICE_DATA_ROOT_DIRECTORY
  145. // because they're don't seem necessary.
  146. setResult(result, returnData);
  147. finish();
  148. }
  149. /**
  150. * Filters a given array list, maintaining only elements that are in the
  151. * constraint. Returns a new list containing only the filtered elements.
  152. */
  153. private ArrayList<String> filter(ArrayList<String> in, Set<String> constraint) {
  154. final ArrayList<String> out = new ArrayList<String>(constraint.size());
  155. for (String s : in) {
  156. if (constraint.contains(s)) {
  157. out.add(s);
  158. }
  159. }
  160. return out;
  161. }
  162. private final SynthReadyCallback mSynthReadyCallback = new SynthReadyCallback() {
  163. @Override
  164. public void onSynthDataReady(byte[] audioData) {
  165. // Do nothing.
  166. }
  167. @Override
  168. public void onSynthDataComplete() {
  169. // Do nothing.
  170. }
  171. };
  172. }