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