1 /*
2  * Copyright (C) 2014 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 
17 package com.android.server.soundtrigger;
18 
19 import android.hardware.soundtrigger.SoundTrigger.ConfidenceLevel;
20 import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
21 import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
22 import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
23 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
24 import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
25 import android.hardware.soundtrigger.SoundTrigger;
26 import android.media.AudioFormat;
27 import android.os.Parcel;
28 import android.test.InstrumentationTestCase;
29 import android.test.suitebuilder.annotation.LargeTest;
30 import android.test.suitebuilder.annotation.SmallTest;
31 import android.os.Binder;
32 
33 import java.util.Arrays;
34 import java.util.Locale;
35 import java.util.Random;
36 import java.util.UUID;
37 
38 public class SoundTriggerTest extends InstrumentationTestCase {
39     private Random mRandom = new Random();
40 
41     @SmallTest
testKeyphraseParcelUnparcel_noUsers()42     public void testKeyphraseParcelUnparcel_noUsers() throws Exception {
43         Keyphrase keyphrase = new Keyphrase(1, 0,
44                 Locale.forLanguageTag("en-US"), "hello", null);
45 
46         // Write to a parcel
47         Parcel parcel = Parcel.obtain();
48         keyphrase.writeToParcel(parcel, 0);
49 
50         // Read from it
51         parcel.setDataPosition(0);
52         Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel);
53 
54         // Verify that they are the same
55         assertEquals(keyphrase, unparceled);
56     }
57 
58     @SmallTest
testKeyphraseParcelUnparcel_zeroUsers()59     public void testKeyphraseParcelUnparcel_zeroUsers() throws Exception {
60         Keyphrase keyphrase = new Keyphrase(1, 0,
61                 Locale.forLanguageTag("en-US"), "hello", new int[0]);
62 
63         // Write to a parcel
64         Parcel parcel = Parcel.obtain();
65         keyphrase.writeToParcel(parcel, 0);
66 
67         // Read from it
68         parcel.setDataPosition(0);
69         Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel);
70 
71         // Verify that they are the same
72         assertEquals(keyphrase.getId(), unparceled.getId());
73         assertTrue(Arrays.equals(keyphrase.getUsers(), unparceled.getUsers()));
74         assertEquals(keyphrase.getLocale(), unparceled.getLocale());
75         assertEquals(keyphrase.getText(), unparceled.getText());
76     }
77 
78     @SmallTest
testKeyphraseParcelUnparcel_pos()79     public void testKeyphraseParcelUnparcel_pos() throws Exception {
80         Keyphrase keyphrase = new Keyphrase(1, 0,
81                 Locale.forLanguageTag("en-US"), "hello", new int[] {1, 2, 3, 4, 5});
82 
83         // Write to a parcel
84         Parcel parcel = Parcel.obtain();
85         keyphrase.writeToParcel(parcel, 0);
86 
87         // Read from it
88         parcel.setDataPosition(0);
89         Keyphrase unparceled = Keyphrase.CREATOR.createFromParcel(parcel);
90 
91         // Verify that they are the same
92         assertEquals(keyphrase.getId(), unparceled.getId());
93         assertTrue(Arrays.equals(keyphrase.getUsers(), unparceled.getUsers()));
94         assertEquals(keyphrase.getLocale(), unparceled.getLocale());
95         assertEquals(keyphrase.getText(), unparceled.getText());
96     }
97 
98     @SmallTest
testKeyphraseSoundModelParcelUnparcel_noData()99     public void testKeyphraseSoundModelParcelUnparcel_noData() throws Exception {
100         Keyphrase[] keyphrases = new Keyphrase[2];
101         keyphrases[0] = new Keyphrase(1, 0, Locale.forLanguageTag("en-US"),
102                 "hello", new int[] {0});
103         keyphrases[1] = new Keyphrase(2, 0, Locale.forLanguageTag("fr-FR"),
104                 "there", new int[] {1, 2});
105         KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(),
106                 null, keyphrases);
107 
108         // Write to a parcel
109         Parcel parcel = Parcel.obtain();
110         ksm.writeToParcel(parcel, 0);
111 
112         // Read from it
113         parcel.setDataPosition(0);
114         KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
115 
116         // Verify that they are the same
117         assertEquals(ksm, unparceled);
118     }
119 
120     @SmallTest
testKeyphraseSoundModelParcelUnparcel_zeroData()121     public void testKeyphraseSoundModelParcelUnparcel_zeroData() throws Exception {
122         Keyphrase[] keyphrases = new Keyphrase[2];
123         keyphrases[0] = new Keyphrase(1, 0, Locale.forLanguageTag("en-US"),
124                 "hello", new int[] {0});
125         keyphrases[1] = new Keyphrase(2, 0, Locale.forLanguageTag("fr-FR"),
126                 "there", new int[] {1, 2});
127         KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(),
128                 new byte[0], keyphrases);
129 
130         // Write to a parcel
131         Parcel parcel = Parcel.obtain();
132         ksm.writeToParcel(parcel, 0);
133 
134         // Read from it
135         parcel.setDataPosition(0);
136         KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
137 
138         // Verify that they are the same
139         assertEquals(ksm.getUuid(), unparceled.getUuid());
140         assertEquals(ksm.getType(), unparceled.getType());
141         assertTrue(Arrays.equals(ksm.getKeyphrases(), unparceled.getKeyphrases()));
142         assertTrue(Arrays.equals(ksm.getData(), unparceled.getData()));
143     }
144 
145     @SmallTest
testKeyphraseSoundModelParcelUnparcel_noKeyphrases()146     public void testKeyphraseSoundModelParcelUnparcel_noKeyphrases() throws Exception {
147         byte[] data = new byte[10];
148         mRandom.nextBytes(data);
149         KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(),
150                 data, null);
151 
152         // Write to a parcel
153         Parcel parcel = Parcel.obtain();
154         ksm.writeToParcel(parcel, 0);
155 
156         // Read from it
157         parcel.setDataPosition(0);
158         KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
159 
160         // Verify that they are the same
161         assertEquals(ksm, unparceled);
162     }
163 
164     @SmallTest
testKeyphraseSoundModelParcelUnparcel_zeroKeyphrases()165     public void testKeyphraseSoundModelParcelUnparcel_zeroKeyphrases() throws Exception {
166         byte[] data = new byte[10];
167         mRandom.nextBytes(data);
168         KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(),
169                 data, new Keyphrase[0]);
170 
171         // Write to a parcel
172         Parcel parcel = Parcel.obtain();
173         ksm.writeToParcel(parcel, 0);
174 
175         // Read from it
176         parcel.setDataPosition(0);
177         KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
178 
179         // Verify that they are the same
180         assertEquals(ksm.getUuid(), unparceled.getUuid());
181         assertEquals(ksm.getType(), unparceled.getType());
182         assertTrue(Arrays.equals(ksm.getKeyphrases(), unparceled.getKeyphrases()));
183         assertTrue(Arrays.equals(ksm.getData(), unparceled.getData()));
184     }
185 
186     @LargeTest
testKeyphraseSoundModelParcelUnparcel_largeData()187     public void testKeyphraseSoundModelParcelUnparcel_largeData() throws Exception {
188         Keyphrase[] keyphrases = new Keyphrase[2];
189         keyphrases[0] = new Keyphrase(1, 0, Locale.forLanguageTag("en-US"),
190                 "hello", new int[] {0});
191         keyphrases[1] = new Keyphrase(2, 0, Locale.forLanguageTag("fr-FR"),
192                 "there", new int[] {1, 2});
193         byte[] data = new byte[200 * 1024];
194         mRandom.nextBytes(data);
195         KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(),
196                 data, keyphrases);
197 
198         // Write to a parcel
199         Parcel parcel = Parcel.obtain();
200         ksm.writeToParcel(parcel, 0);
201 
202         // Read from it
203         parcel.setDataPosition(0);
204         KeyphraseSoundModel unparceled = KeyphraseSoundModel.CREATOR.createFromParcel(parcel);
205 
206         // Verify that they are the same
207         assertEquals(ksm.getUuid(), unparceled.getUuid());
208         assertEquals(ksm.getType(), unparceled.getType());
209         assertTrue(Arrays.equals(ksm.getData(), unparceled.getData()));
210         assertTrue(Arrays.equals(ksm.getKeyphrases(), unparceled.getKeyphrases()));
211     }
212 
213     @SmallTest
testRecognitionEventParcelUnparcel_noData()214     public void testRecognitionEventParcelUnparcel_noData() throws Exception {
215         RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_SUCCESS,
216                 1 /* soundModelHandle */,
217                 true /* captureAvailable */,
218                 2 /* captureSession */,
219                 3 /* captureDelayMs */,
220                 4 /* capturePreambleMs */,
221                 false /* triggerInData */,
222                 new AudioFormat.Builder()
223                         .setSampleRate(16000)
224                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
225                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
226                         .build(),
227                 null /* data */,
228                 12345678 /* halEventReceivedMillis */);
229 
230                 // Write to a parcel
231         Parcel parcel = Parcel.obtain();
232         re.writeToParcel(parcel, 0);
233 
234         // Read from it
235         parcel.setDataPosition(0);
236         RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel);
237 
238         // Verify that they are the same
239         assertEquals(re, unparceled);
240     }
241 
242     @SmallTest
testRecognitionEventParcelUnparcel_zeroData()243     public void testRecognitionEventParcelUnparcel_zeroData() throws Exception {
244         RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_FAILURE,
245                 1 /* soundModelHandle */,
246                 true /* captureAvailable */,
247                 2 /* captureSession */,
248                 3 /* captureDelayMs */,
249                 4 /* capturePreambleMs */,
250                 false /* triggerInData */,
251                 new AudioFormat.Builder()
252                         .setSampleRate(16000)
253                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
254                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
255                         .build(),
256                 new byte[1] /* data */,
257                 12345678 /* halEventReceivedMillis */);
258 
259                 // Write to a parcel
260         Parcel parcel = Parcel.obtain();
261         re.writeToParcel(parcel, 0);
262 
263         // Read from it
264         parcel.setDataPosition(0);
265         RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel);
266 
267         // Verify that they are the same
268         assertEquals(re, unparceled);
269     }
270 
271     @SmallTest
testRecognitionEventParcelUnparcel_largeData()272     public void testRecognitionEventParcelUnparcel_largeData() throws Exception {
273         byte[] data = new byte[200 * 1024];
274         mRandom.nextBytes(data);
275         RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT,
276                 1 /* soundModelHandle */,
277                 false /* captureAvailable */,
278                 2 /* captureSession */,
279                 3 /* captureDelayMs */,
280                 4 /* capturePreambleMs */,
281                 false /* triggerInData */,
282                 new AudioFormat.Builder()
283                         .setSampleRate(16000)
284                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
285                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
286                         .build(),
287                 data,
288                 12345678 /* halEventReceivedMillis */);
289 
290                 // Write to a parcel
291         Parcel parcel = Parcel.obtain();
292         re.writeToParcel(parcel, 0);
293 
294         // Read from it
295         parcel.setDataPosition(0);
296         RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel);
297 
298         // Verify that they are the same
299         assertEquals(re, unparceled);
300     }
301 
302     @SmallTest
testRecognitionEventParcelUnparcel_largeAudioData()303     public void testRecognitionEventParcelUnparcel_largeAudioData() throws Exception {
304         byte[] data = new byte[200 * 1024];
305         mRandom.nextBytes(data);
306         RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT,
307                 1 /* soundModelHandle */,
308                 false /* captureAvailable */,
309                 2 /* captureSession */,
310                 3 /* captureDelayMs */,
311                 4 /* capturePreambleMs */,
312                 true /* triggerInData */,
313                 new AudioFormat.Builder()
314                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
315                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
316                         .setSampleRate(16000)
317                         .build(),
318                 data,
319                 12345678 /* halEventReceivedMillis */);
320 
321         // Write to a parcel
322         Parcel parcel = Parcel.obtain();
323         re.writeToParcel(parcel, 0);
324 
325         // Read from it
326         parcel.setDataPosition(0);
327         RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel);
328 
329         // Verify that they are the same
330         assertEquals(re, unparceled);
331     }
332 
333     @SmallTest
testKeyphraseRecognitionEventParcelUnparcel_noKeyphrases()334     public void testKeyphraseRecognitionEventParcelUnparcel_noKeyphrases() throws Exception {
335         KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
336                 SoundTrigger.RECOGNITION_STATUS_SUCCESS,
337                 1 /* soundModelHandle */,
338                 true /* captureAvailable */,
339                 2 /* captureSession */,
340                 3 /* captureDelayMs */,
341                 4 /* capturePreambleMs */,
342                 false /* triggerInData */,
343                 new AudioFormat.Builder()
344                         .setSampleRate(16000)
345                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
346                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
347                         .build(),
348                 null /* data */,
349                 null /* keyphraseExtras */,
350                 12345678 /* halEventReceivedMillis */,
351                 new Binder() /* token */);
352 
353         // Write to a parcel
354         Parcel parcel = Parcel.obtain();
355         re.writeToParcel(parcel, 0);
356 
357         // Read from it
358         parcel.setDataPosition(0);
359         KeyphraseRecognitionEvent unparceled =
360                 KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel);
361 
362         // Verify that they are the same
363         assertEquals(re, unparceled);
364     }
365 
366     @SmallTest
testKeyphraseRecognitionEventParcelUnparcel_zeroData()367     public void testKeyphraseRecognitionEventParcelUnparcel_zeroData() throws Exception {
368         KeyphraseRecognitionExtra[] kpExtra = new KeyphraseRecognitionExtra[0];
369         KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
370                 SoundTrigger.RECOGNITION_STATUS_FAILURE,
371                 2 /* soundModelHandle */,
372                 true /* captureAvailable */,
373                 2 /* captureSession */,
374                 3 /* captureDelayMs */,
375                 4 /* capturePreambleMs */,
376                 false /* triggerInData */,
377                 new AudioFormat.Builder()
378                         .setSampleRate(16000)
379                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
380                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
381                         .build(),
382                 new byte[1] /* data */,
383                 kpExtra,
384                 12345678 /* halEventReceivedMillis */,
385                 new Binder() /* token */);
386 
387         // Write to a parcel
388         Parcel parcel = Parcel.obtain();
389         re.writeToParcel(parcel, 0);
390 
391         // Read from it
392         parcel.setDataPosition(0);
393         KeyphraseRecognitionEvent unparceled =
394                 KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel);
395 
396         // Verify that they are the same
397         assertEquals(re, unparceled);
398     }
399 
400     @LargeTest
testKeyphraseRecognitionEventParcelUnparcel_largeData()401     public void testKeyphraseRecognitionEventParcelUnparcel_largeData() throws Exception {
402         byte[] data = new byte[200 * 1024];
403         mRandom.nextBytes(data);
404         KeyphraseRecognitionExtra[] kpExtra = new KeyphraseRecognitionExtra[4];
405         ConfidenceLevel cl1 = new ConfidenceLevel(1, 90);
406         ConfidenceLevel cl2 = new ConfidenceLevel(2, 30);
407         kpExtra[0] = new KeyphraseRecognitionExtra(1,
408                 SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION, 0,
409                 new ConfidenceLevel[] {cl1, cl2});
410         kpExtra[1] = new KeyphraseRecognitionExtra(1,
411                 SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0,
412                 new ConfidenceLevel[] {cl2});
413         kpExtra[2] = new KeyphraseRecognitionExtra(1,
414                 SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0, null);
415         kpExtra[3] = new KeyphraseRecognitionExtra(1,
416                 SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0,
417                 new ConfidenceLevel[0]);
418 
419         KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent(
420                 SoundTrigger.RECOGNITION_STATUS_FAILURE,
421                 1 /* soundModelHandle */,
422                 true /* captureAvailable */,
423                 2 /* captureSession */,
424                 3 /* captureDelayMs */,
425                 4 /* capturePreambleMs */,
426                 false /* triggerInData */,
427                 new AudioFormat.Builder()
428                         .setSampleRate(16000)
429                         .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
430                         .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
431                         .build(),
432                 data,
433                 kpExtra,
434                 12345678 /* halEventReceivedMillis */,
435                 new Binder() /* token */);
436 
437         // Write to a parcel
438         Parcel parcel = Parcel.obtain();
439         re.writeToParcel(parcel, 0);
440 
441         // Read from it
442         parcel.setDataPosition(0);
443         KeyphraseRecognitionEvent unparceled =
444                 KeyphraseRecognitionEvent.CREATOR.createFromParcel(parcel);
445 
446         // Verify that they are the same
447         assertEquals(re, unparceled);
448     }
449 }
450