1fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta/* 2fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * Copyright (C) 2014 The Android Open Source Project 3fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * 4fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * Licensed under the Apache License, Version 2.0 (the "License"); 5fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * you may not use this file except in compliance with the License. 6fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * You may obtain a copy of the License at 7fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * 8fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * http://www.apache.org/licenses/LICENSE-2.0 9fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * 10fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * Unless required by applicable law or agreed to in writing, software 11fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * distributed under the License is distributed on an "AS IS" BASIS, 12fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * See the License for the specific language governing permissions and 14fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta * limitations under the License. 15fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta */ 16fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 17fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettapackage android.hardware.soundtrigger; 18fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 19c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport static org.mockito.Matchers.any; 20c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport static org.mockito.Matchers.eq; 21a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavettaimport static org.mockito.Mockito.reset; 22c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport static org.mockito.Mockito.spy; 23c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport static org.mockito.Mockito.timeout; 24c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport static org.mockito.Mockito.verify; 25fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 26fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport android.content.Context; 27c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport android.hardware.soundtrigger.SoundTrigger.GenericRecognitionEvent; 28fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; 29c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent; 30c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; 31fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport android.media.soundtrigger.SoundTriggerManager; 32fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport android.os.ParcelUuid; 33fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport android.os.ServiceManager; 34fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport android.test.AndroidTestCase; 35c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport android.test.suitebuilder.annotation.LargeTest; 36fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport android.test.suitebuilder.annotation.SmallTest; 37fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 38fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport com.android.internal.app.ISoundTriggerService; 39fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 40c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport java.io.DataOutputStream; 41c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport java.net.InetAddress; 42c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport java.net.Socket; 43c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport java.util.ArrayList; 44a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavettaimport java.util.HashSet; 45fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport java.util.Random; 46fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettaimport java.util.UUID; 47fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 48c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavettaimport org.mockito.MockitoAnnotations; 49c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 50fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavettapublic class GenericSoundModelTest extends AndroidTestCase { 51c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta static final int MSG_DETECTION_ERROR = -1; 52c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta static final int MSG_DETECTION_RESUME = 0; 53c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta static final int MSG_DETECTION_PAUSE = 1; 54c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta static final int MSG_KEYPHRASE_TRIGGER = 2; 55c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta static final int MSG_GENERIC_TRIGGER = 4; 56c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 57c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta private Random random = new Random(); 58a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta private HashSet<UUID> loadedModelUuids; 59c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta private ISoundTriggerService soundTriggerService; 60c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta private SoundTriggerManager soundTriggerManager; 61c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 62c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @Override 63c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void setUp() throws Exception { 64c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta super.setUp(); 65c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta MockitoAnnotations.initMocks(this); 66fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 67fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta Context context = getContext(); 68c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService = ISoundTriggerService.Stub.asInterface( 69c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE)); 70c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerManager = (SoundTriggerManager) context.getSystemService( 71c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta Context.SOUND_TRIGGER_SERVICE); 72c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 73a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta loadedModelUuids = new HashSet<UUID>(); 74c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 75c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 76c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @Override 77c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void tearDown() throws Exception { 78c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta for (UUID modelUuid : loadedModelUuids) { 79c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.deleteSoundModel(new ParcelUuid(modelUuid)); 80c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 81c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta super.tearDown(); 82c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 83fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 84c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta GenericSoundModel new_sound_model() { 85c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Create sound model 86fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta byte[] data = new byte[1024]; 87c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta random.nextBytes(data); 88fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta UUID modelUuid = UUID.randomUUID(); 89fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta UUID mVendorUuid = UUID.randomUUID(); 90c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta return new GenericSoundModel(modelUuid, mVendorUuid, data); 91c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 92fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 93c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @SmallTest 94c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void testUpdateGenericSoundModel() throws Exception { 95c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta GenericSoundModel model = new_sound_model(); 96fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 97c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Update sound model 98c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.updateSoundModel(model); 99c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta loadedModelUuids.add(model.uuid); 100fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 101c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Confirm it was updated 102c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta GenericSoundModel returnedModel = 103c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.getSoundModel(new ParcelUuid(model.uuid)); 104c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta assertEquals(model, returnedModel); 105fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta } 106fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 107fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta @SmallTest 108fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta public void testDeleteGenericSoundModel() throws Exception { 109c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta GenericSoundModel model = new_sound_model(); 110fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 111c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Update sound model 112c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.updateSoundModel(model); 113c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta loadedModelUuids.add(model.uuid); 114fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 115c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Delete sound model 116c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.deleteSoundModel(new ParcelUuid(model.uuid)); 117c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta loadedModelUuids.remove(model.uuid); 118fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta 119c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Confirm it was deleted 120fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta GenericSoundModel returnedModel = 121c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.getSoundModel(new ParcelUuid(model.uuid)); 122fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta assertEquals(null, returnedModel); 123fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta } 124c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 125c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @LargeTest 126c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void testStartStopGenericSoundModel() throws Exception { 127c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta GenericSoundModel model = new_sound_model(); 128c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 129c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta boolean captureTriggerAudio = true; 130c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta boolean allowMultipleTriggers = true; 131c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers, 132c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta null, null); 133c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback()); 134c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 135c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Update and start sound model recognition 136c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.updateSoundModel(model); 137c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta loadedModelUuids.add(model.uuid); 138c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta int r = soundTriggerService.startRecognition(new ParcelUuid(model.uuid), spyCallback, 139c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta config); 140c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta assertEquals("Could Not Start Recognition with code: " + r, 141c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r); 142c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 143c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Stop recognition 144c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta r = soundTriggerService.stopRecognition(new ParcelUuid(model.uuid), spyCallback); 145c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta assertEquals("Could Not Stop Recognition with code: " + r, 146c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r); 147c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 148c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 149c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @LargeTest 150c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void testTriggerGenericSoundModel() throws Exception { 151c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta GenericSoundModel model = new_sound_model(); 152c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 153c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta boolean captureTriggerAudio = true; 154c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta boolean allowMultipleTriggers = true; 155c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers, 156c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta null, null); 157c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback()); 158c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 159c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Update and start sound model 160c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.updateSoundModel(model); 161c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta loadedModelUuids.add(model.uuid); 162c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta soundTriggerService.startRecognition(new ParcelUuid(model.uuid), spyCallback, config); 163c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 164c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Send trigger to stub HAL 165c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta Socket socket = new Socket(InetAddress.getLocalHost(), 14035); 166c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta DataOutputStream out = new DataOutputStream(socket.getOutputStream()); 167c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta out.writeBytes("trig " + model.uuid.toString() + "\r\n"); 168c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta out.flush(); 169c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta socket.close(); 170c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 171c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta // Verify trigger was received 172c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any()); 173c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 174c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 175a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta /** 176a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta * Tests a more complicated pattern of loading, unloading, triggering, starting and stopping 177a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta * recognition. Intended to find unexpected errors that occur in unexpected states. 178a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta */ 179a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta @LargeTest 180a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta public void testFuzzGenericSoundModel() throws Exception { 181a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta int numModels = 2; 182a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 183a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta final int STATUS_UNLOADED = 0; 184a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta final int STATUS_LOADED = 1; 185a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta final int STATUS_STARTED = 2; 186a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 187a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta class ModelInfo { 188a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta int status; 189a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta GenericSoundModel model; 190a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 191a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta public ModelInfo(GenericSoundModel model, int status) { 192a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta this.status = status; 193a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta this.model = model; 194a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } 195a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } 196a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 197a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta Random predictableRandom = new Random(100); 198a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 199a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta ArrayList modelInfos = new ArrayList<ModelInfo>(); 200a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta for(int i=0; i<numModels; i++) { 201a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Create sound model 202a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta byte[] data = new byte[1024]; 203a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta predictableRandom.nextBytes(data); 204a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta UUID modelUuid = UUID.randomUUID(); 205a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta UUID mVendorUuid = UUID.randomUUID(); 206a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data); 207a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta ModelInfo modelInfo = new ModelInfo(model, STATUS_UNLOADED); 208a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta modelInfos.add(modelInfo); 209a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } 210a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 211a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta boolean captureTriggerAudio = true; 212a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta boolean allowMultipleTriggers = true; 213a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta RecognitionConfig config = new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers, 214a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta null, null); 215a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta TestRecognitionStatusCallback spyCallback = spy(new TestRecognitionStatusCallback()); 216a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 217a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 218a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta int numOperationsToRun = 100; 219a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta for(int i=0; i<numOperationsToRun; i++) { 220a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Select a random model 221a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta int modelInfoIndex = predictableRandom.nextInt(modelInfos.size()); 222a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta ModelInfo modelInfo = (ModelInfo) modelInfos.get(modelInfoIndex); 223a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 224a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Perform a random operation 225a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta int operation = predictableRandom.nextInt(5); 226a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 227a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta if (operation == 0 && modelInfo.status == STATUS_UNLOADED) { 228a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Update and start sound model 229a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta soundTriggerService.updateSoundModel(modelInfo.model); 230a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta loadedModelUuids.add(modelInfo.model.uuid); 231a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta modelInfo.status = STATUS_LOADED; 232a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } else if (operation == 1 && modelInfo.status == STATUS_LOADED) { 233a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Start the sound model 234a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta int r = soundTriggerService.startRecognition(new ParcelUuid(modelInfo.model.uuid), 235a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta spyCallback, config); 236a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta assertEquals("Could Not Start Recognition with code: " + r, 237a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r); 238a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta modelInfo.status = STATUS_STARTED; 239a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } else if (operation == 2 && modelInfo.status == STATUS_STARTED) { 240a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Send trigger to stub HAL 241a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta Socket socket = new Socket(InetAddress.getLocalHost(), 14035); 242a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta DataOutputStream out = new DataOutputStream(socket.getOutputStream()); 243a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta out.writeBytes("trig " + modelInfo.model.uuid + "\r\n"); 244a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta out.flush(); 245a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta socket.close(); 246a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 247a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Verify trigger was received 248a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta verify(spyCallback, timeout(100)).onGenericSoundTriggerDetected(any()); 249a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta reset(spyCallback); 250a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } else if (operation == 3 && modelInfo.status == STATUS_STARTED) { 251a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Stop recognition 252a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta int r = soundTriggerService.stopRecognition(new ParcelUuid(modelInfo.model.uuid), 253a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta spyCallback); 254a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta assertEquals("Could Not Stop Recognition with code: " + r, 255a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta android.hardware.soundtrigger.SoundTrigger.STATUS_OK, r); 256a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta modelInfo.status = STATUS_LOADED; 257a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } else if (operation == 4 && modelInfo.status != STATUS_UNLOADED) { 258a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Delete sound model 259a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta soundTriggerService.deleteSoundModel(new ParcelUuid(modelInfo.model.uuid)); 260a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta loadedModelUuids.remove(modelInfo.model.uuid); 261a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta 262a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta // Confirm it was deleted 263a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta GenericSoundModel returnedModel = 264a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta soundTriggerService.getSoundModel(new ParcelUuid(modelInfo.model.uuid)); 265a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta assertEquals(null, returnedModel); 266a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta modelInfo.status = STATUS_UNLOADED; 267a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } 268a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } 269a0319cb5c48a36953eff33664a429dc1a9c6dbdaRyan Bavetta } 270c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 271c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public class TestRecognitionStatusCallback extends IRecognitionStatusCallback.Stub { 272c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @Override 273c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void onGenericSoundTriggerDetected(GenericRecognitionEvent recognitionEvent) { 274c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 275c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 276c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @Override 277c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void onKeyphraseDetected(KeyphraseRecognitionEvent recognitionEvent) { 278c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 279c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 280c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @Override 281c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void onError(int status) { 282c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 283c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 284c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @Override 285c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void onRecognitionPaused() { 286c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 287c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta 288c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta @Override 289c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta public void onRecognitionResumed() { 290c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 291c92bbd7cdb9fba1438695d57307b1e94688b296dRyan Bavetta } 292fc3ad3e4abeb83a679b5515a7f6ec618b8bcdca4Ryan Bavetta} 293