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