Home | History | Annotate | Download | only in audio
      1 /*
      2  * Copyright (C) 2017 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 "media_omx_hidl_audio_enc_test"
     18 #ifdef __LP64__
     19 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
     20 #endif
     21 
     22 #include <android-base/logging.h>
     23 
     24 #include <android/hardware/media/omx/1.0/IOmx.h>
     25 #include <android/hardware/media/omx/1.0/IOmxNode.h>
     26 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
     27 #include <android/hardware/media/omx/1.0/types.h>
     28 #include <android/hidl/allocator/1.0/IAllocator.h>
     29 #include <android/hidl/memory/1.0/IMapper.h>
     30 #include <android/hidl/memory/1.0/IMemory.h>
     31 
     32 using ::android::hardware::media::omx::V1_0::IOmx;
     33 using ::android::hardware::media::omx::V1_0::IOmxObserver;
     34 using ::android::hardware::media::omx::V1_0::IOmxNode;
     35 using ::android::hardware::media::omx::V1_0::Message;
     36 using ::android::hardware::media::omx::V1_0::CodecBuffer;
     37 using ::android::hardware::media::omx::V1_0::PortMode;
     38 using ::android::hidl::allocator::V1_0::IAllocator;
     39 using ::android::hidl::memory::V1_0::IMemory;
     40 using ::android::hidl::memory::V1_0::IMapper;
     41 using ::android::hardware::Return;
     42 using ::android::hardware::Void;
     43 using ::android::hardware::hidl_vec;
     44 using ::android::hardware::hidl_string;
     45 using ::android::sp;
     46 
     47 #include <VtsHalHidlTargetTestBase.h>
     48 #include <getopt.h>
     49 #include <media_audio_hidl_test_common.h>
     50 #include <media_hidl_test_common.h>
     51 #include <fstream>
     52 
     53 static ComponentTestEnvironment* gEnv = nullptr;
     54 
     55 // audio encoder test fixture class
     56 class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
     57    private:
     58     typedef ::testing::VtsHalHidlTargetTestBase Super;
     59    public:
     60     ::std::string getTestCaseInfo() const override {
     61         return ::std::string() +
     62                 "Component: " + gEnv->getComponent().c_str() + " | " +
     63                 "Role: " + gEnv->getRole().c_str() + " | " +
     64                 "Instance: " + gEnv->getInstance().c_str() + " | " +
     65                 "Res: " + gEnv->getRes().c_str();
     66     }
     67 
     68     virtual void SetUp() override {
     69         Super::SetUp();
     70         disableTest = false;
     71         android::hardware::media::omx::V1_0::Status status;
     72         omx = Super::getService<IOmx>(gEnv->getInstance());
     73         ASSERT_NE(omx, nullptr);
     74         observer =
     75             new CodecObserver([this](Message msg, const BufferInfo* buffer) {
     76                 handleMessage(msg, buffer);
     77             });
     78         ASSERT_NE(observer, nullptr);
     79         if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0)
     80             disableTest = true;
     81         EXPECT_TRUE(omx->allocateNode(
     82                            gEnv->getComponent(), observer,
     83                            [&](android::hardware::media::omx::V1_0::Status _s,
     84                                sp<IOmxNode> const& _nl) {
     85                                status = _s;
     86                                this->omxNode = _nl;
     87                            })
     88                         .isOk());
     89         if (status == android::hardware::media::omx::V1_0::Status::NAME_NOT_FOUND) {
     90             disableTest = true;
     91             std::cout << "[   WARN   ] Test Disabled, component not present\n";
     92             return;
     93         }
     94         ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
     95         ASSERT_NE(omxNode, nullptr);
     96         ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
     97         struct StringToName {
     98             const char* Name;
     99             standardComp CompName;
    100         };
    101         const StringToName kStringToName[] = {
    102             {"amrnb", amrnb}, {"amrwb", amrwb}, {"aac", aac}, {"flac", flac},
    103         };
    104         const size_t kNumStringToName =
    105             sizeof(kStringToName) / sizeof(kStringToName[0]);
    106         const char* pch;
    107         char substring[OMX_MAX_STRINGNAME_SIZE];
    108         strcpy(substring, gEnv->getRole().c_str());
    109         pch = strchr(substring, '.');
    110         ASSERT_NE(pch, nullptr);
    111         compName = unknown_comp;
    112         for (size_t i = 0; i < kNumStringToName; ++i) {
    113             if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
    114                 compName = kStringToName[i].CompName;
    115                 break;
    116             }
    117         }
    118         if (compName == unknown_comp) disableTest = true;
    119         struct CompToCoding {
    120             standardComp CompName;
    121             OMX_AUDIO_CODINGTYPE eEncoding;
    122         };
    123         static const CompToCoding kCompToCoding[] = {
    124             {amrnb, OMX_AUDIO_CodingAMR},
    125             {amrwb, OMX_AUDIO_CodingAMR},
    126             {aac, OMX_AUDIO_CodingAAC},
    127             {flac, OMX_AUDIO_CodingFLAC},
    128         };
    129         static const size_t kNumCompToCoding =
    130             sizeof(kCompToCoding) / sizeof(kCompToCoding[0]);
    131         size_t i;
    132         for (i = 0; i < kNumCompToCoding; ++i) {
    133             if (kCompToCoding[i].CompName == compName) {
    134                 eEncoding = kCompToCoding[i].eEncoding;
    135                 break;
    136             }
    137         }
    138         if (i == kNumCompToCoding) disableTest = true;
    139         eosFlag = false;
    140         if (disableTest) std::cout << "[   WARN   ] Test Disabled \n";
    141     }
    142 
    143     virtual void TearDown() override {
    144         if (omxNode != nullptr) {
    145             // If you have encountered a fatal failure, it is possible that
    146             // freeNode() will not go through. Instead of hanging the app.
    147             // let it pass through and report errors
    148             if (::testing::Test::HasFatalFailure()) return;
    149             EXPECT_TRUE((omxNode->freeNode()).isOk());
    150             omxNode = nullptr;
    151         }
    152         Super::TearDown();
    153     }
    154 
    155     // callback function to process messages received by onMessages() from IL
    156     // client.
    157     void handleMessage(Message msg, const BufferInfo* buffer) {
    158         (void)buffer;
    159 
    160         if (msg.type == Message::Type::FILL_BUFFER_DONE) {
    161             if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) {
    162                 eosFlag = true;
    163             }
    164             if (msg.data.extendedBufferData.rangeLength != 0) {
    165 #define WRITE_OUTPUT 0
    166 #if WRITE_OUTPUT
    167                 static int count = 0;
    168                 FILE* ofp = nullptr;
    169                 if (count)
    170                     ofp = fopen("out.bin", "ab");
    171                 else
    172                     ofp = fopen("out.bin", "wb");
    173                 if (ofp != nullptr) {
    174                     fwrite(static_cast<void*>(buffer->mMemory->getPointer()),
    175                            sizeof(char),
    176                            msg.data.extendedBufferData.rangeLength, ofp);
    177                     fclose(ofp);
    178                     count++;
    179                 }
    180 #endif
    181             }
    182         }
    183     }
    184 
    185     enum standardComp {
    186         amrnb,
    187         amrwb,
    188         aac,
    189         flac,
    190         unknown_comp,
    191     };
    192 
    193     sp<IOmx> omx;
    194     sp<CodecObserver> observer;
    195     sp<IOmxNode> omxNode;
    196     standardComp compName;
    197     OMX_AUDIO_CODINGTYPE eEncoding;
    198     bool disableTest;
    199     bool eosFlag;
    200 
    201    protected:
    202     static void description(const std::string& description) {
    203         RecordProperty("description", description);
    204     }
    205 };
    206 
    207 // Set Default port param.
    208 void setDefaultPortParam(sp<IOmxNode> omxNode, OMX_U32 portIndex,
    209                          OMX_AUDIO_CODINGTYPE eEncoding,
    210                          AudioEncHidlTest::standardComp comp, int32_t nChannels,
    211                          int32_t nSampleRate, int32_t nBitRate) {
    212     android::hardware::media::omx::V1_0::Status status;
    213 
    214     OMX_PARAM_PORTDEFINITIONTYPE portDef;
    215     status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
    216                           &portDef);
    217     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    218 
    219     portDef.format.audio.bFlagErrorConcealment = OMX_TRUE;
    220     portDef.format.audio.eEncoding = eEncoding;
    221     status = setPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
    222                           &portDef);
    223     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    224 
    225     std::vector<int32_t> arrProfile;
    226     int32_t profile;
    227     if ((int)eEncoding == OMX_AUDIO_CodingAAC) {
    228         enumerateProfile(omxNode, portIndex, &arrProfile);
    229         if (arrProfile.empty() == true) ASSERT_TRUE(false);
    230         profile = arrProfile[0];
    231     }
    232 
    233     switch ((int)eEncoding) {
    234         case OMX_AUDIO_CodingFLAC:
    235             setupFLACPort(omxNode, portIndex, nChannels, nSampleRate,
    236                           5 /* nCompressionLevel */);
    237             break;
    238         case OMX_AUDIO_CodingAMR:
    239             setupAMRPort(omxNode, portIndex, nBitRate,
    240                          (comp == AudioEncHidlTest::standardComp::amrwb));
    241             break;
    242         case OMX_AUDIO_CodingAAC:
    243             setupAACPort(omxNode, portIndex,
    244                          static_cast<OMX_AUDIO_AACPROFILETYPE>(profile),
    245                          OMX_AUDIO_AACStreamFormatMP4FF, nChannels, nBitRate,
    246                          nSampleRate);
    247             break;
    248         default:
    249             break;
    250     }
    251 }
    252 
    253 // LookUpTable of clips and metadata for component testing
    254 void GetURLForComponent(AudioEncHidlTest::standardComp comp, char* mURL) {
    255     struct CompToURL {
    256         AudioEncHidlTest::standardComp comp;
    257         const char* mURL;
    258     };
    259     static const CompToURL kCompToURL[] = {
    260         {AudioEncHidlTest::standardComp::aac, "bbb_raw_2ch_48khz_s16le.raw"},
    261         {AudioEncHidlTest::standardComp::amrnb, "bbb_raw_1ch_8khz_s16le.raw"},
    262         {AudioEncHidlTest::standardComp::amrwb, "bbb_raw_1ch_16khz_s16le.raw"},
    263         {AudioEncHidlTest::standardComp::flac, "bbb_raw_2ch_48khz_s16le.raw"},
    264     };
    265 
    266     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
    267         if (kCompToURL[i].comp == comp) {
    268             strcat(mURL, kCompToURL[i].mURL);
    269             return;
    270         }
    271     }
    272 }
    273 
    274 // blocking call to ensures application to Wait till all the inputs are consumed
    275 void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    276                             android::Vector<BufferInfo>* iBuffer,
    277                             android::Vector<BufferInfo>* oBuffer) {
    278     android::hardware::media::omx::V1_0::Status status;
    279     Message msg;
    280     int timeOut = TIMEOUT_COUNTER_Q;
    281 
    282     while (timeOut--) {
    283         size_t i = 0;
    284         status =
    285             observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
    286         ASSERT_EQ(status,
    287                   android::hardware::media::omx::V1_0::Status::TIMED_OUT);
    288         // status == TIMED_OUT, it could be due to process time being large
    289         // than DEFAULT_TIMEOUT or component needs output buffers to start
    290         // processing.
    291         for (; i < iBuffer->size(); i++) {
    292             if ((*iBuffer)[i].owner != client) break;
    293         }
    294         if (i == iBuffer->size()) break;
    295 
    296         // Dispatch an output buffer assuming outQueue.empty() is true
    297         size_t index;
    298         if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
    299             ASSERT_NO_FATAL_FAILURE(
    300                 dispatchOutputBuffer(omxNode, oBuffer, index));
    301             timeOut = TIMEOUT_COUNTER_Q;
    302         }
    303     }
    304 }
    305 
    306 // Encode N Frames
    307 void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    308                    android::Vector<BufferInfo>* iBuffer,
    309                    android::Vector<BufferInfo>* oBuffer, uint32_t nFrames,
    310                    int32_t samplesPerFrame, int32_t nChannels,
    311                    int32_t nSampleRate, std::ifstream& eleStream,
    312                    bool signalEOS = true) {
    313     android::hardware::media::omx::V1_0::Status status;
    314     Message msg;
    315     size_t index;
    316     int bytesCount = samplesPerFrame * nChannels * 2;
    317     int32_t timestampIncr =
    318         (int)(((float)samplesPerFrame / nSampleRate) * 1000000);
    319     uint64_t timestamp = 0;
    320     uint32_t flags = 0;
    321     int timeOut = TIMEOUT_COUNTER_Q;
    322     bool iQueued, oQueued;
    323 
    324     while (1) {
    325         iQueued = oQueued = false;
    326         status =
    327             observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
    328         if (status == android::hardware::media::omx::V1_0::Status::OK)
    329             ASSERT_TRUE(false);
    330 
    331         if (nFrames == 0) break;
    332 
    333         // Dispatch input buffer
    334         if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
    335             char* ipBuffer = static_cast<char*>(
    336                 static_cast<void*>((*iBuffer)[index].mMemory->getPointer()));
    337             ASSERT_LE(bytesCount,
    338                       static_cast<int>((*iBuffer)[index].mMemory->getSize()));
    339             eleStream.read(ipBuffer, bytesCount);
    340             if (eleStream.gcount() != bytesCount) break;
    341             flags = OMX_BUFFERFLAG_ENDOFFRAME;
    342             if (signalEOS && (nFrames == 1)) flags |= OMX_BUFFERFLAG_EOS;
    343             ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer(
    344                 omxNode, iBuffer, index, bytesCount, flags, timestamp));
    345             timestamp += timestampIncr;
    346             nFrames--;
    347             iQueued = true;
    348         }
    349         // Dispatch output buffer
    350         if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
    351             ASSERT_NO_FATAL_FAILURE(
    352                 dispatchOutputBuffer(omxNode, oBuffer, index));
    353             oQueued = true;
    354         }
    355         // Reset Counters when either input or output buffer is dispatched
    356         if (iQueued || oQueued)
    357             timeOut = TIMEOUT_COUNTER_Q;
    358         else
    359             timeOut--;
    360         if (timeOut == 0) {
    361             ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite";
    362         }
    363     }
    364 }
    365 
    366 // set component role
    367 TEST_F(AudioEncHidlTest, SetRole) {
    368     description("Test Set Component Role");
    369     if (disableTest) return;
    370     android::hardware::media::omx::V1_0::Status status;
    371     status = setRole(omxNode, gEnv->getRole().c_str());
    372     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    373 }
    374 
    375 // port format enumeration
    376 TEST_F(AudioEncHidlTest, EnumeratePortFormat) {
    377     description("Test Component on Mandatory Port Parameters (Port Format)");
    378     if (disableTest) return;
    379     android::hardware::media::omx::V1_0::Status status;
    380     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
    381     status = setRole(omxNode, gEnv->getRole().c_str());
    382     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    383     OMX_PORT_PARAM_TYPE params;
    384     status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
    385     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
    386         ASSERT_EQ(params.nPorts, 2U);
    387         kPortIndexInput = params.nStartPortNumber;
    388         kPortIndexOutput = kPortIndexInput + 1;
    389     }
    390     status = setAudioPortFormat(omxNode, kPortIndexInput, OMX_AUDIO_CodingPCM);
    391     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    392     status = setAudioPortFormat(omxNode, kPortIndexOutput, eEncoding);
    393     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    394 }
    395 
    396 // test raw stream encode
    397 TEST_F(AudioEncHidlTest, SimpleEncodeTest) {
    398     description("Tests Basic encoding and EOS");
    399     if (disableTest) return;
    400     android::hardware::media::omx::V1_0::Status status;
    401     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
    402     status = setRole(omxNode, gEnv->getRole().c_str());
    403     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    404     OMX_PORT_PARAM_TYPE params;
    405     status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
    406     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
    407         ASSERT_EQ(params.nPorts, 2U);
    408         kPortIndexInput = params.nStartPortNumber;
    409         kPortIndexOutput = kPortIndexInput + 1;
    410     }
    411     char mURL[512];
    412     strcpy(mURL, gEnv->getRes().c_str());
    413     GetURLForComponent(compName, mURL);
    414 
    415     std::ifstream eleStream;
    416 
    417     // Configure input port
    418     int32_t nChannels = 2;
    419     int32_t nSampleRate = 44100;
    420     int32_t samplesPerFrame = 1024;
    421     int32_t nBitRate = 128000;
    422     switch (compName) {
    423         case amrnb:
    424             nChannels = 1;
    425             nSampleRate = 8000;
    426             samplesPerFrame = 160;
    427             nBitRate = 7400;
    428             break;
    429         case amrwb:
    430             nChannels = 1;
    431             nSampleRate = 16000;
    432             samplesPerFrame = 160;
    433             nBitRate = 15850;
    434             break;
    435         case aac:
    436             nChannels = 2;
    437             nSampleRate = 48000;
    438             samplesPerFrame = 1024;
    439             nBitRate = 128000;
    440             break;
    441         case flac:
    442             nChannels = 2;
    443             nSampleRate = 48000;
    444             samplesPerFrame = 1152;
    445             nBitRate = 128000;
    446             break;
    447         default:
    448             ASSERT_TRUE(false);
    449     }
    450     setupPCMPort(omxNode, kPortIndexInput, nChannels, OMX_NumericalDataSigned,
    451                  16, nSampleRate, OMX_AUDIO_PCMModeLinear);
    452 
    453     // Configure output port
    454     ASSERT_NO_FATAL_FAILURE(setDefaultPortParam(omxNode, kPortIndexOutput,
    455                                                 eEncoding, compName, nChannels,
    456                                                 nSampleRate, nBitRate));
    457 
    458     android::Vector<BufferInfo> iBuffer, oBuffer;
    459 
    460     // set state to idle
    461     ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer,
    462                                                     &oBuffer, kPortIndexInput,
    463                                                     kPortIndexOutput));
    464     // set state to executing
    465     ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
    466 
    467     eleStream.open(mURL, std::ifstream::binary);
    468     ASSERT_EQ(eleStream.is_open(), true);
    469     ASSERT_NO_FATAL_FAILURE(encodeNFrames(omxNode, observer, &iBuffer, &oBuffer,
    470                                           128, samplesPerFrame, nChannels,
    471                                           nSampleRate, eleStream));
    472     eleStream.close();
    473 
    474     ASSERT_NO_FATAL_FAILURE(
    475         waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer));
    476     ASSERT_NO_FATAL_FAILURE(
    477         testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag));
    478     // set state to idle
    479     ASSERT_NO_FATAL_FAILURE(
    480         changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
    481     // set state to executing
    482     ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer,
    483                                                     &oBuffer, kPortIndexInput,
    484                                                     kPortIndexOutput));
    485 }
    486 
    487 int main(int argc, char** argv) {
    488     gEnv = new ComponentTestEnvironment();
    489     ::testing::AddGlobalTestEnvironment(gEnv);
    490     ::testing::InitGoogleTest(&argc, argv);
    491     gEnv->init(&argc, argv);
    492     int status = gEnv->initFromOptions(argc, argv);
    493     if (status == 0) {
    494         status = RUN_ALL_TESTS();
    495         ALOGI("Test result = %d", status);
    496     }
    497     return status;
    498 }
    499