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: 64 Monitor() : mCount(0) {} 65 66 /** 67 * Adds 1 to the internal counter and unblocks one of the waiting threads. 68 */ 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 */ 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 101 static SoundTriggerHidlEnvironment* Instance() { 102 static SoundTriggerHidlEnvironment* instance = new SoundTriggerHidlEnvironment; 103 return instance; 104 } 105 106 virtual void registerTestServices() override { registerTestService<ISoundTriggerHw>(); } 107 108 private: 109 SoundTriggerHidlEnvironment() {} 110 }; 111 112 // The main test class for Sound Trigger HIDL HAL. 113 class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase { 114 public: 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 123 static void SetUpTestCase() { srand(1234); } 124 125 class SoundTriggerHwCallback : public ISoundTriggerHwCallback { 126 private: 127 SoundTriggerHidlTest& mParent; 128 129 public: 130 SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {} 131 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 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 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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