VtsHalSoundtriggerV2_0TargetTest.cpp revision 4e7a3077309d33a21b08e9380573019cc7a8cffb
1/* 2 * Copyright (C) 2016 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 32#include <VtsHalHidlTargetTestBase.h> 33 34#define SHORT_TIMEOUT_PERIOD (1) 35 36using ::android::hardware::audio::common::V2_0::AudioDevice; 37using ::android::hardware::soundtrigger::V2_0::SoundModelHandle; 38using ::android::hardware::soundtrigger::V2_0::SoundModelType; 39using ::android::hardware::soundtrigger::V2_0::RecognitionMode; 40using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra; 41using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw; 42using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback; 43using ::android::hardware::Return; 44using ::android::hardware::Void; 45using ::android::sp; 46 47/** 48 * Test code uses this class to wait for notification from callback. 49 */ 50class Monitor { 51 public: 52 Monitor() : mCount(0) {} 53 54 /** 55 * Adds 1 to the internal counter and unblocks one of the waiting threads. 56 */ 57 void notify() { 58 std::unique_lock<std::mutex> lock(mMtx); 59 mCount++; 60 mCv.notify_one(); 61 } 62 63 /** 64 * Blocks until the internal counter becomes greater than 0. 65 * 66 * If notified, this method decreases the counter by 1 and returns true. 67 * If timeout, returns false. 68 */ 69 bool wait(int timeoutSeconds) { 70 std::unique_lock<std::mutex> lock(mMtx); 71 auto deadline = std::chrono::system_clock::now() + 72 std::chrono::seconds(timeoutSeconds); 73 while (mCount == 0) { 74 if (mCv.wait_until(lock, deadline) == std::cv_status::timeout) { 75 return false; 76 } 77 } 78 mCount--; 79 return true; 80 } 81 82 private: 83 std::mutex mMtx; 84 std::condition_variable mCv; 85 int mCount; 86}; 87 88// The main test class for Sound Trigger HIDL HAL. 89class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase { 90 public: 91 virtual void SetUp() override { 92 mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>("sound_trigger.primary"); 93 ASSERT_NE(nullptr, mSoundTriggerHal.get()); 94 mCallback = new SoundTriggerHwCallback(*this); 95 ASSERT_NE(nullptr, mCallback.get()); 96 } 97 98 static void SetUpTestCase() { 99 srand(time(nullptr)); 100 } 101 102 class SoundTriggerHwCallback : public ISoundTriggerHwCallback { 103 private: 104 SoundTriggerHidlTest& mParent; 105 106 public: 107 SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {} 108 109 virtual Return<void> recognitionCallback( 110 const ISoundTriggerHwCallback::RecognitionEvent& event __unused, 111 int32_t cookie __unused) { 112 ALOGI("%s", __FUNCTION__); 113 return Void(); 114 } 115 116 virtual Return<void> phraseRecognitionCallback( 117 const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused, 118 int32_t cookie __unused) { 119 ALOGI("%s", __FUNCTION__); 120 return Void(); 121 } 122 123 virtual Return<void> soundModelCallback( 124 const ISoundTriggerHwCallback::ModelEvent& event, 125 int32_t cookie __unused) { 126 ALOGI("%s", __FUNCTION__); 127 mParent.lastModelEvent = event; 128 mParent.monitor.notify(); 129 return Void(); 130 } 131 }; 132 133 virtual void TearDown() override {} 134 135 Monitor monitor; 136 // updated by soundModelCallback() 137 ISoundTriggerHwCallback::ModelEvent lastModelEvent; 138 139 protected: 140 sp<ISoundTriggerHw> mSoundTriggerHal; 141 sp<SoundTriggerHwCallback> mCallback; 142}; 143 144// A class for test environment setup (kept since this file is a template). 145class SoundTriggerHidlEnvironment : public ::testing::Environment { 146 public: 147 virtual void SetUp() {} 148 virtual void TearDown() {} 149 150 private: 151}; 152 153/** 154 * Test ISoundTriggerHw::getProperties() method 155 * 156 * Verifies that: 157 * - the implementation implements the method 158 * - the method returns 0 (no error) 159 * - the implementation supports at least one sound model and one key phrase 160 * - the implementation supports at least VOICE_TRIGGER recognition mode 161 */ 162TEST_F(SoundTriggerHidlTest, GetProperties) { 163 ISoundTriggerHw::Properties halProperties; 164 Return<void> hidlReturn; 165 int ret = -ENODEV; 166 167 hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) { 168 ret = rc; 169 halProperties = res; 170 }); 171 172 EXPECT_TRUE(hidlReturn.isOk()); 173 EXPECT_EQ(0, ret); 174 EXPECT_GT(halProperties.maxSoundModels, 0u); 175 EXPECT_GT(halProperties.maxKeyPhrases, 0u); 176 EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER)); 177} 178 179/** 180 * Test ISoundTriggerHw::loadPhraseSoundModel() method 181 * 182 * Verifies that: 183 * - the implementation implements the method 184 * - the implementation returns an error when passed a malformed sound model 185 * 186 * There is no way to verify that implementation actually can load a sound model because each 187 * sound model is vendor specific. 188 */ 189TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) { 190 Return<void> hidlReturn; 191 int ret = -ENODEV; 192 ISoundTriggerHw::PhraseSoundModel model; 193 SoundModelHandle handle; 194 195 model.common.type = SoundModelType::UNKNOWN; 196 197 hidlReturn = mSoundTriggerHal->loadPhraseSoundModel( 198 model, 199 mCallback, 0, [&](int32_t retval, auto res) { 200 ret = retval; 201 handle = res; 202 }); 203 204 EXPECT_TRUE(hidlReturn.isOk()); 205 EXPECT_NE(0, ret); 206 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD)); 207} 208 209/** 210 * Test ISoundTriggerHw::loadSoundModel() method 211 * 212 * Verifies that: 213 * - the implementation returns error when passed a sound model with random data. 214 */ 215TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) { 216 int ret = -ENODEV; 217 ISoundTriggerHw::SoundModel model; 218 SoundModelHandle handle = 0; 219 220 model.type = SoundModelType::GENERIC; 221 model.data.resize(100); 222 for (auto& d : model.data) { 223 d = rand(); 224 } 225 226 Return<void> loadReturn = mSoundTriggerHal->loadSoundModel( 227 model, 228 mCallback, 0, [&](int32_t retval, auto res) { 229 ret = retval; 230 handle = res; 231 }); 232 233 EXPECT_TRUE(loadReturn.isOk()); 234 EXPECT_NE(0, ret); 235 EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD)); 236} 237 238/** 239 * Test ISoundTriggerHw::unloadSoundModel() method 240 * 241 * Verifies that: 242 * - the implementation implements the method 243 * - the implementation returns an error when called without a valid loaded sound model 244 * 245 */ 246TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) { 247 Return<int32_t> hidlReturn(0); 248 SoundModelHandle halHandle = 0; 249 250 hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle); 251 252 EXPECT_TRUE(hidlReturn.isOk()); 253 EXPECT_NE(0, hidlReturn); 254} 255 256/** 257 * Test ISoundTriggerHw::startRecognition() method 258 * 259 * Verifies that: 260 * - the implementation implements the method 261 * - the implementation returns an error when called without a valid loaded sound model 262 * 263 * There is no way to verify that implementation actually starts recognition because no model can 264 * be loaded. 265 */ 266TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) { 267 Return<int32_t> hidlReturn(0); 268 SoundModelHandle handle = 0; 269 PhraseRecognitionExtra phrase; 270 ISoundTriggerHw::RecognitionConfig config; 271 272 config.captureHandle = 0; 273 config.captureDevice = AudioDevice::IN_BUILTIN_MIC; 274 phrase.id = 0; 275 phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER; 276 phrase.confidenceLevel = 0; 277 278 config.phrases.setToExternal(&phrase, 1); 279 280 hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0); 281 282 EXPECT_TRUE(hidlReturn.isOk()); 283 EXPECT_NE(0, hidlReturn); 284} 285 286/** 287 * Test ISoundTriggerHw::stopRecognition() method 288 * 289 * Verifies that: 290 * - the implementation implements the method 291 * - the implementation returns an error when called without an active recognition running 292 * 293 */ 294TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) { 295 Return<int32_t> hidlReturn(0); 296 SoundModelHandle handle = 0; 297 298 hidlReturn = mSoundTriggerHal->stopRecognition(handle); 299 300 EXPECT_TRUE(hidlReturn.isOk()); 301 EXPECT_NE(0, hidlReturn); 302} 303 304/** 305 * Test ISoundTriggerHw::stopAllRecognitions() method 306 * 307 * Verifies that: 308 * - the implementation implements this optional method or indicates it is not support by 309 * returning -ENOSYS 310 */ 311TEST_F(SoundTriggerHidlTest, stopAllRecognitions) { 312 Return<int32_t> hidlReturn(0); 313 314 hidlReturn = mSoundTriggerHal->stopAllRecognitions(); 315 316 EXPECT_TRUE(hidlReturn.isOk()); 317 EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS); 318} 319 320 321int main(int argc, char** argv) { 322 ::testing::AddGlobalTestEnvironment(new SoundTriggerHidlEnvironment); 323 ::testing::InitGoogleTest(&argc, argv); 324 int status = RUN_ALL_TESTS(); 325 ALOGI("Test result = %d", status); 326 return status; 327} 328