1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.speech.tts.cts; 17 18 import android.os.ConditionVariable; 19 import android.os.Environment; 20 import android.speech.tts.TextToSpeech; 21 import android.test.AndroidTestCase; 22 23 import java.io.File; 24 import java.io.FileOutputStream; 25 import java.util.HashMap; 26 import java.util.Map; 27 import java.util.List; 28 29 /** 30 * Tests for {@link android.speech.tts.TextToSpeechService} using StubTextToSpeechService. 31 */ 32 public class TextToSpeechServiceTest extends AndroidTestCase { 33 private static final String UTTERANCE = "text to speech cts test"; 34 private static final String SAMPLE_FILE_NAME = "mytts.wav"; 35 36 private TextToSpeechWrapper mTts; 37 38 @Override 39 protected void setUp() throws Exception { 40 super.setUp(); 41 StubTextToSpeechService.sSynthesizeTextWait = null; 42 mTts = TextToSpeechWrapper.createTextToSpeechMockWrapper(getContext()); 43 assertNotNull(mTts); 44 } 45 46 @Override 47 protected void tearDown() throws Exception { 48 super.tearDown(); 49 mTts.shutdown(); 50 } 51 52 private TextToSpeech getTts() { 53 return mTts.getTts(); 54 } 55 56 public void testSynthesizeToFile() throws Exception { 57 File sampleFile = new File(getContext().getExternalFilesDir(null), SAMPLE_FILE_NAME); 58 try { 59 assertFalse(sampleFile.exists()); 60 61 int result = 62 getTts().synthesizeToFile( 63 UTTERANCE, createParams("mocktofile"), sampleFile.getPath()); 64 assertEquals("synthesizeToFile() failed", TextToSpeech.SUCCESS, result); 65 66 assertTrue("synthesizeToFile() completion timeout", mTts.waitForComplete("mocktofile")); 67 assertTrue("synthesizeToFile() didn't produce a file", sampleFile.exists()); 68 assertTrue("synthesizeToFile() produced a non-sound file", 69 TextToSpeechWrapper.isSoundFile(sampleFile.getPath())); 70 } finally { 71 sampleFile.delete(); 72 } 73 mTts.verify("mocktofile"); 74 75 final Map<String, Integer> chunksReceived = mTts.chunksReceived(); 76 final Map<String, List<Integer>> timePointsStart = mTts.timePointsStart(); 77 final Map<String, List<Integer>> timePointsEnd = mTts.timePointsEnd(); 78 final Map<String, List<Integer>> timePointsFrame = mTts.timePointsFrame(); 79 assertEquals(Integer.valueOf(10), chunksReceived.get("mocktofile")); 80 // In the mock we set the start, end and frame to exactly these values for the time points. 81 for (int i = 0; i < 10; i++) { 82 assertEquals(Integer.valueOf(i * 5), timePointsStart.get("mocktofile").get(i)); 83 assertEquals(Integer.valueOf(i * 5 + 5), timePointsEnd.get("mocktofile").get(i)); 84 assertEquals(Integer.valueOf(i * 10), timePointsFrame.get("mocktofile").get(i)); 85 } 86 } 87 88 public void testMaxSpeechInputLength() { 89 File sampleFile = new File(getContext().getExternalFilesDir(null), SAMPLE_FILE_NAME); 90 try { 91 assertFalse(sampleFile.exists()); 92 TextToSpeech tts = getTts(); 93 94 int maxLength = tts.getMaxSpeechInputLength(); 95 StringBuilder sb = new StringBuilder(); 96 for (int i = 0; i < maxLength; i++) { 97 sb.append("c"); 98 } 99 String valid = sb.toString(); 100 sb.append("c"); 101 String invalid = sb.toString(); 102 103 assertEquals(maxLength, valid.length()); 104 assertTrue(invalid.length() > maxLength); 105 assertEquals(TextToSpeech.ERROR, 106 tts.synthesizeToFile(invalid, createParams("mockToFile"), sampleFile.getPath())); 107 assertEquals(TextToSpeech.SUCCESS, 108 tts.synthesizeToFile(valid, createParams("mockToFile"), sampleFile.getPath())); 109 } finally { 110 sampleFile.delete(); 111 } 112 } 113 114 public void testSpeak() throws Exception { 115 int result = getTts().speak(UTTERANCE, TextToSpeech.QUEUE_FLUSH, createParams("mockspeak")); 116 assertEquals("speak() failed", TextToSpeech.SUCCESS, result); 117 assertTrue("speak() completion timeout", waitForUtterance("mockspeak")); 118 mTts.verify("mockspeak"); 119 120 final Map<String, Integer> chunksReceived = mTts.chunksReceived(); 121 assertEquals(Integer.valueOf(10), chunksReceived.get("mockspeak")); 122 } 123 124 public void testSpeakStop() throws Exception { 125 final ConditionVariable synthesizeTextWait = new ConditionVariable(); 126 StubTextToSpeechService.sSynthesizeTextWait = synthesizeTextWait; 127 128 getTts().stop(); 129 final int iterations = 20; 130 for (int i = 0; i < iterations; i++) { 131 int result = getTts().speak(UTTERANCE, TextToSpeech.QUEUE_ADD, null, 132 "stop_" + Integer.toString(i)); 133 assertEquals("speak() failed", TextToSpeech.SUCCESS, result); 134 } 135 getTts().stop(); 136 137 // Wake up the Stubs #onSynthesizeSpeech (one that will be stopped in-progress) 138 synthesizeTextWait.open(); 139 140 for (int i = 0; i < iterations; i++) { 141 assertTrue("speak() stop callback timeout", mTts.waitForStop( 142 "stop_" + Integer.toString(i))); 143 } 144 } 145 146 public void testSpeakStopBehindOtherAudioPlayback() throws Exception { 147 final ConditionVariable synthesizeTextWait = new ConditionVariable(); 148 final ConditionVariable synthesizeTextStartEvent = new ConditionVariable(); 149 StubTextToSpeechService.sSynthesizeTextWait = synthesizeTextWait; 150 StubTextToSpeechService.sSynthesizeTextStartEvent = synthesizeTextStartEvent; 151 152 // Make the audio playback queue busy by putting a 30s of silence. 153 getTts().stop(); 154 getTts().playSilentUtterance(30000, TextToSpeech.QUEUE_ADD, "silence"); 155 156 // speak(), wait it to starting in the service, and stop(). 157 int result = getTts().speak(UTTERANCE, TextToSpeech.QUEUE_ADD, null, "stop"); 158 assertEquals("speak() failed", TextToSpeech.SUCCESS, result); 159 assertTrue("synthesis not started", synthesizeTextStartEvent.block(10000)); 160 getTts().stop(); 161 162 // Wake up the Stubs #onSynthesizeSpeech (one that will be stopped in-progress) 163 synthesizeTextWait.open(); 164 165 assertTrue("speak() stop callback timeout", mTts.waitForStop("stop")); 166 } 167 168 public void testMediaPlayerFails() throws Exception { 169 File sampleFile = new File(getContext().getExternalFilesDir(null), "notsound.wav"); 170 try { 171 assertFalse(TextToSpeechWrapper.isSoundFile(sampleFile.getPath())); 172 FileOutputStream out = new FileOutputStream(sampleFile); 173 out.write(new byte[] { 0x01, 0x02 }); 174 out.close(); 175 assertFalse(TextToSpeechWrapper.isSoundFile(sampleFile.getPath())); 176 } finally { 177 sampleFile.delete(); 178 } 179 } 180 181 private HashMap<String, String> createParams(String utteranceId) { 182 HashMap<String, String> params = new HashMap<>(); 183 params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId); 184 return params; 185 } 186 187 private boolean waitForUtterance(String utteranceId) throws InterruptedException { 188 return mTts.waitForComplete(utteranceId); 189 } 190 191 } 192