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