1 /*
2 * Copyright (C) 2018 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 #define LOG_TAG "SoundTriggerHidlHalTest"
18 #include <stdlib.h>
19 #include <time.h>
20
21 #include <condition_variable>
22 #include <mutex>
23
24 #include <android/log.h>
25 #include <cutils/native_handle.h>
26 #include <log/log.h>
27
28 #include <android/hardware/audio/common/2.0/types.h>
29 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
30 #include <android/hardware/soundtrigger/2.0/types.h>
31 #include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
32 #include <android/hidl/allocator/1.0/IAllocator.h>
33 #include <hidlmemory/mapping.h>
34
35 #include <VtsHalHidlTargetTestBase.h>
36 #include <VtsHalHidlTargetTestEnvBase.h>
37
38 #define SHORT_TIMEOUT_PERIOD (1)
39
40 using ::android::sp;
41 using ::android::hardware::hidl_memory;
42 using ::android::hardware::hidl_string;
43 using ::android::hardware::hidl_vec;
44 using ::android::hardware::Return;
45 using ::android::hardware::Void;
46 using ::android::hardware::audio::common::V2_0::AudioDevice;
47 using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
48 using ::android::hardware::soundtrigger::V2_0::RecognitionMode;
49 using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
50 using ::android::hardware::soundtrigger::V2_0::SoundModelType;
51 using V2_0_ISoundTriggerHw = ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
52 using V2_0_ISoundTriggerHwCallback =
53 ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
54 using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHw;
55 using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
56 using ::android::hidl::allocator::V1_0::IAllocator;
57 using ::android::hidl::memory::V1_0::IMemory;
58
59 /**
60 * Test code uses this class to wait for notification from callback.
61 */
62 class Monitor {
63 public:
Monitor()64 Monitor() : mCount(0) {}
65
66 /**
67 * Adds 1 to the internal counter and unblocks one of the waiting threads.
68 */
notify()69 void notify() {
70 std::unique_lock<std::mutex> lock(mMtx);
71 mCount++;
72 mCv.notify_one();
73 }
74
75 /**
76 * Blocks until the internal counter becomes greater than 0.
77 *
78 * If notified, this method decreases the counter by 1 and returns true.
79 * If timeout, returns false.
80 */
wait(int timeoutSeconds)81 bool wait(int timeoutSeconds) {
82 auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(timeoutSeconds);
83 std::unique_lock<std::mutex> lock(mMtx);
84 if (!mCv.wait_until(lock, deadline, [& count = mCount] { return count > 0; })) {
85 return false;
86 }
87 mCount--;
88 return true;
89 }
90
91 private:
92 std::mutex mMtx;
93 std::condition_variable mCv;
94 int mCount;
95 };
96
97 // Test environment for SoundTrigger HIDL HAL.
98 class SoundTriggerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
99 public:
100 // get the test environment singleton
Instance()101 static SoundTriggerHidlEnvironment* Instance() {
102 static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment;
103 return instance;
104 }
105
registerTestServices()106 virtual void registerTestServices() override { registerTestService<ISoundTriggerHw>(); }
107
108 private:
SoundTriggerHidlEnvironment()109 SoundTriggerHidlEnvironment() {}
110 };
111
112 // The main test class for Sound Trigger HIDL HAL.
113 class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
114 public:
SetUp()115 virtual void SetUp() override {
116 mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>(
117 SoundTriggerHidlEnvironment::Instance()->getServiceName<ISoundTriggerHw>());
118 ASSERT_NE(nullptr, mSoundTriggerHal.get());
119 mCallback = new SoundTriggerHwCallback(*this);
120 ASSERT_NE(nullptr, mCallback.get());
121 }
122
SetUpTestCase()123 static void SetUpTestCase() { srand(1234); }
124
125 class SoundTriggerHwCallback : public ISoundTriggerHwCallback {
126 private:
127 SoundTriggerHidlTest& mParent;
128
129 public:
SoundTriggerHwCallback(SoundTriggerHidlTest & parent)130 SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {}
131
recognitionCallback(const V2_0_ISoundTriggerHwCallback::RecognitionEvent & event __unused,int32_t cookie __unused)132 Return<void> recognitionCallback(const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event
133 __unused,
134 int32_t cookie __unused) override {
135 ALOGI("%s", __FUNCTION__);
136 return Void();
137 };
138
phraseRecognitionCallback(const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent & event __unused,int32_t cookie __unused)139 Return<void> phraseRecognitionCallback(
140 const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
141 int32_t cookie __unused) override {
142 ALOGI("%s", __FUNCTION__);
143 return Void();
144 };
145
soundModelCallback(const V2_0_ISoundTriggerHwCallback::ModelEvent & event,int32_t cookie __unused)146 Return<void> soundModelCallback(const V2_0_ISoundTriggerHwCallback::ModelEvent& event,
147 int32_t cookie __unused) override {
148 ALOGI("%s", __FUNCTION__);
149 mParent.lastModelEvent_2_0 = event;
150 mParent.monitor.notify();
151 return Void();
152 }
153
recognitionCallback_2_1(const ISoundTriggerHwCallback::RecognitionEvent & event __unused,int32_t cookie __unused)154 Return<void> recognitionCallback_2_1(const ISoundTriggerHwCallback::RecognitionEvent& event
155 __unused,
156 int32_t cookie __unused) override {
157 ALOGI("%s", __FUNCTION__);
158 return Void();
159 }
160
phraseRecognitionCallback_2_1(const ISoundTriggerHwCallback::PhraseRecognitionEvent & event __unused,int32_t cookie __unused)161 Return<void> phraseRecognitionCallback_2_1(
162 const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
163 int32_t cookie __unused) override {
164 ALOGI("%s", __FUNCTION__);
165 return Void();
166 }
167
soundModelCallback_2_1(const ISoundTriggerHwCallback::ModelEvent & event,int32_t cookie __unused)168 Return<void> soundModelCallback_2_1(const ISoundTriggerHwCallback::ModelEvent& event,
169 int32_t cookie __unused) {
170 ALOGI("%s", __FUNCTION__);
171 mParent.lastModelEvent = event;
172 mParent.monitor.notify();
173 return Void();
174 }
175 };
176
TearDown()177 virtual void TearDown() override {}
178
179 Monitor monitor;
180 // updated by soundModelCallback()
181 V2_0_ISoundTriggerHwCallback::ModelEvent lastModelEvent_2_0;
182 // updated by soundModelCallback_2_1()
183 ISoundTriggerHwCallback::ModelEvent lastModelEvent;
184
185 protected:
186 sp<ISoundTriggerHw> mSoundTriggerHal;
187 sp<SoundTriggerHwCallback> mCallback;
188 };
189
190 /**
191 * Test ISoundTriggerHw::getProperties() method
192 *
193 * Verifies that:
194 * - the implementation implements the method
195 * - the method returns 0 (no error)
196 * - the implementation supports at least one sound model and one key phrase
197 * - the implementation supports at least VOICE_TRIGGER recognition mode
198 */
TEST_F(SoundTriggerHidlTest,GetProperties)199 TEST_F(SoundTriggerHidlTest, GetProperties) {
200 ISoundTriggerHw::Properties halProperties;
201 Return<void> hidlReturn;
202 int ret = -ENODEV;
203
204 hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) {
205 ret = rc;
206 halProperties = res;
207 });
208
209 EXPECT_TRUE(hidlReturn.isOk());
210 EXPECT_EQ(0, ret);
211 EXPECT_GT(halProperties.maxSoundModels, 0u);
212 EXPECT_GT(halProperties.maxKeyPhrases, 0u);
213 EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
214 }
215
216 /**
217 * Test ISoundTriggerHw::loadPhraseSoundModel() method
218 *
219 * Verifies that:
220 * - the implementation implements the method
221 * - the implementation returns an error when passed a malformed sound model
222 *
223 * There is no way to verify that implementation actually can load a sound model because each
224 * sound model is vendor specific.
225 */
TEST_F(SoundTriggerHidlTest,LoadInvalidModelFail)226 TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
227 Return<void> hidlReturn;
228 int ret = -ENODEV;
229 V2_0_ISoundTriggerHw::PhraseSoundModel model;
230 SoundModelHandle handle;
231
232 model.common.type = SoundModelType::UNKNOWN;
233
234 hidlReturn =
235 mSoundTriggerHal->loadPhraseSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
236 ret = retval;
237 handle = res;
238 });
239
240 EXPECT_TRUE(hidlReturn.isOk());
241 EXPECT_NE(0, ret);
242 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
243 }
244
245 /**
246 * Test ISoundTriggerHw::loadPhraseSoundModel_2_1() method
247 *
248 * Verifies that:
249 * - the implementation implements the method
250 * - the implementation returns an error when passed a malformed sound model
251 *
252 * There is no way to verify that implementation actually can load a sound model because each
253 * sound model is vendor specific.
254 */
TEST_F(SoundTriggerHidlTest,LoadInvalidModelFail_2_1)255 TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
256 Return<void> hidlReturn;
257 int ret = -ENODEV;
258 ISoundTriggerHw::PhraseSoundModel model;
259 SoundModelHandle handle;
260
261 model.common.header.type = SoundModelType::UNKNOWN;
262
263 hidlReturn = mSoundTriggerHal->loadPhraseSoundModel_2_1(model, mCallback, 0,
264 [&](int32_t retval, auto res) {
265 ret = retval;
266 handle = res;
267 });
268
269 EXPECT_TRUE(hidlReturn.isOk());
270 EXPECT_NE(0, ret);
271 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
272 }
273
274 /**
275 * Test ISoundTriggerHw::loadSoundModel() method
276 *
277 * Verifies that:
278 * - the implementation returns an error when passed an empty sound model
279 */
TEST_F(SoundTriggerHidlTest,LoadEmptyGenericSoundModelFail)280 TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
281 int ret = -ENODEV;
282 V2_0_ISoundTriggerHw::SoundModel model;
283 SoundModelHandle handle = 0;
284
285 model.type = SoundModelType::GENERIC;
286
287 Return<void> loadReturn =
288 mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
289 ret = retval;
290 handle = res;
291 });
292
293 EXPECT_TRUE(loadReturn.isOk());
294 EXPECT_NE(0, ret);
295 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
296 }
297
298 /**
299 * Test ISoundTriggerHw::loadSoundModel() method
300 *
301 * Verifies that:
302 * - the implementation returns error when passed a sound model with random data.
303 */
TEST_F(SoundTriggerHidlTest,LoadGenericSoundModelFail)304 TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
305 int ret = -ENODEV;
306 V2_0_ISoundTriggerHw::SoundModel model;
307 SoundModelHandle handle = 0;
308
309 model.type = SoundModelType::GENERIC;
310 model.data.resize(100);
311 for (auto& d : model.data) {
312 d = rand();
313 }
314
315 Return<void> loadReturn =
316 mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
317 ret = retval;
318 handle = res;
319 });
320
321 EXPECT_TRUE(loadReturn.isOk());
322 EXPECT_NE(0, ret);
323 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
324 }
325
326 /**
327 * Test ISoundTriggerHw::loadSoundModel_2_1() method
328 *
329 * Verifies that:
330 * - the implementation returns error when passed a sound model with random data.
331 */
TEST_F(SoundTriggerHidlTest,LoadEmptyGenericSoundModelFail_2_1)332 TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
333 int ret = -ENODEV;
334 ISoundTriggerHw::SoundModel model;
335 SoundModelHandle handle = 0;
336
337 model.header.type = SoundModelType::GENERIC;
338
339 Return<void> loadReturn =
340 mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
341 ret = retval;
342 handle = res;
343 });
344
345 EXPECT_TRUE(loadReturn.isOk());
346 EXPECT_NE(0, ret);
347 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
348 }
349
350 /**
351 * Test ISoundTriggerHw::loadSoundModel_2_1() method
352 *
353 * Verifies that:
354 * - the implementation returns error when passed a sound model with random data.
355 */
TEST_F(SoundTriggerHidlTest,LoadGenericSoundModelFail_2_1)356 TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
357 int ret = -ENODEV;
358 ISoundTriggerHw::SoundModel model;
359 SoundModelHandle handle = 0;
360
361 model.header.type = SoundModelType::GENERIC;
362 sp<IAllocator> ashmem = IAllocator::getService("ashmem");
363 ASSERT_NE(nullptr, ashmem.get());
364 hidl_memory hmemory;
365 int size = 100;
366 Return<void> allocReturn = ashmem->allocate(size, [&](bool success, const hidl_memory& m) {
367 ASSERT_TRUE(success);
368 hmemory = m;
369 });
370 sp<IMemory> memory = ::android::hardware::mapMemory(hmemory);
371 ASSERT_NE(nullptr, memory.get());
372 memory->update();
373 for (uint8_t *p = static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())); size >= 0;
374 p++, size--) {
375 *p = rand();
376 }
377
378 Return<void> loadReturn =
379 mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
380 ret = retval;
381 handle = res;
382 });
383
384 EXPECT_TRUE(loadReturn.isOk());
385 EXPECT_NE(0, ret);
386 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
387 }
388
389 /**
390 * Test ISoundTriggerHw::unloadSoundModel() method
391 *
392 * Verifies that:
393 * - the implementation implements the method
394 * - the implementation returns an error when called without a valid loaded sound model
395 *
396 */
TEST_F(SoundTriggerHidlTest,UnloadModelNoModelFail)397 TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
398 Return<int32_t> hidlReturn(0);
399 SoundModelHandle halHandle = 0;
400
401 hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle);
402
403 EXPECT_TRUE(hidlReturn.isOk());
404 EXPECT_NE(0, hidlReturn);
405 }
406
407 /**
408 * Test ISoundTriggerHw::startRecognition() method
409 *
410 * Verifies that:
411 * - the implementation implements the method
412 * - the implementation returns an error when called without a valid loaded sound model
413 *
414 * There is no way to verify that implementation actually starts recognition because no model can
415 * be loaded.
416 */
TEST_F(SoundTriggerHidlTest,StartRecognitionNoModelFail)417 TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
418 Return<int32_t> hidlReturn(0);
419 SoundModelHandle handle = 0;
420 PhraseRecognitionExtra phrase;
421 V2_0_ISoundTriggerHw::RecognitionConfig config;
422
423 config.captureHandle = 0;
424 config.captureDevice = AudioDevice::IN_BUILTIN_MIC;
425 phrase.id = 0;
426 phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
427 phrase.confidenceLevel = 0;
428
429 config.phrases.setToExternal(&phrase, 1);
430
431 hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0);
432
433 EXPECT_TRUE(hidlReturn.isOk());
434 EXPECT_NE(0, hidlReturn);
435 }
436
437 /**
438 * Test ISoundTriggerHw::startRecognition_2_1() method
439 *
440 * Verifies that:
441 * - the implementation implements the method
442 * - the implementation returns an error when called without a valid loaded sound model
443 *
444 * There is no way to verify that implementation actually starts recognition because no model can
445 * be loaded.
446 */
TEST_F(SoundTriggerHidlTest,StartRecognitionNoModelFail_2_1)447 TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
448 Return<int32_t> hidlReturn(0);
449 SoundModelHandle handle = 0;
450 PhraseRecognitionExtra phrase;
451 ISoundTriggerHw::RecognitionConfig config;
452
453 config.header.captureHandle = 0;
454 config.header.captureDevice = AudioDevice::IN_BUILTIN_MIC;
455 phrase.id = 0;
456 phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
457 phrase.confidenceLevel = 0;
458
459 config.header.phrases.setToExternal(&phrase, 1);
460
461 hidlReturn = mSoundTriggerHal->startRecognition_2_1(handle, config, mCallback, 0);
462
463 EXPECT_TRUE(hidlReturn.isOk());
464 EXPECT_NE(0, hidlReturn);
465 }
466
467 /**
468 * Test ISoundTriggerHw::stopRecognition() method
469 *
470 * Verifies that:
471 * - the implementation implements the method
472 * - the implementation returns an error when called without an active recognition running
473 *
474 */
TEST_F(SoundTriggerHidlTest,StopRecognitionNoAStartFail)475 TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
476 Return<int32_t> hidlReturn(0);
477 SoundModelHandle handle = 0;
478
479 hidlReturn = mSoundTriggerHal->stopRecognition(handle);
480
481 EXPECT_TRUE(hidlReturn.isOk());
482 EXPECT_NE(0, hidlReturn);
483 }
484
485 /**
486 * Test ISoundTriggerHw::stopAllRecognitions() method
487 *
488 * Verifies that:
489 * - the implementation implements this optional method or indicates it is not supported by
490 * returning -ENOSYS
491 */
TEST_F(SoundTriggerHidlTest,stopAllRecognitions)492 TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
493 Return<int32_t> hidlReturn(0);
494
495 hidlReturn = mSoundTriggerHal->stopAllRecognitions();
496
497 EXPECT_TRUE(hidlReturn.isOk());
498 EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
499 }
500
main(int argc,char ** argv)501 int main(int argc, char** argv) {
502 ::testing::AddGlobalTestEnvironment(SoundTriggerHidlEnvironment::Instance());
503 ::testing::InitGoogleTest(&argc, argv);
504 SoundTriggerHidlEnvironment::Instance()->init(&argc, argv);
505 int status = RUN_ALL_TESTS();
506 ALOGI("Test result = %d", status);
507 return status;
508 }
509