1 /*
2  * Copyright (C) 2018 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_NDEBUG 0
18 #define LOG_TAG "codec2_hidl_hal_audio_dec_test"
19 
20 #include <android-base/logging.h>
21 #include <gtest/gtest.h>
22 #include <hidl/GtestPrinter.h>
23 #include <stdio.h>
24 #include <algorithm>
25 
26 #include <C2AllocatorIon.h>
27 #include <C2Buffer.h>
28 #include <C2BufferPriv.h>
29 #include <C2Config.h>
30 #include <C2Debug.h>
31 #include <codec2/hidl/client.h>
32 
33 using android::C2AllocatorIon;
34 
35 #include "media_c2_hidl_test_common.h"
36 
37 static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
38         kDecodeTestParameters;
39 
40 static std::vector<std::tuple<std::string, std::string, std::string>> kCsdFlushTestParameters;
41 
42 // Resource directory
43 static std::string sResourceDir = "";
44 
45 class LinearBuffer : public C2Buffer {
46   public:
LinearBuffer(const std::shared_ptr<C2LinearBlock> & block)47     explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
48         : C2Buffer({block->share(block->offset(), block->size(), ::C2Fence())}) {}
49 };
50 
51 namespace {
52 
53 class Codec2AudioDecHidlTestBase : public ::testing::Test {
54   public:
55     // google.codec2 Audio test setup
SetUp()56     virtual void SetUp() override {
57         getParams();
58         mDisableTest = false;
59         ALOGV("Codec2AudioDecHidlTest SetUp");
60         mClient = android::Codec2Client::CreateFromService(
61                 mInstanceName.c_str(),
62                 !bool(android::Codec2Client::CreateFromService("default", true)));
63         ASSERT_NE(mClient, nullptr);
64         mListener.reset(new CodecListener([this](std::list<std::unique_ptr<C2Work>>& workItems) {
65             handleWorkDone(workItems);
66         }));
67         ASSERT_NE(mListener, nullptr);
68         for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
69             mWorkQueue.emplace_back(new C2Work);
70         }
71         mClient->createComponent(mComponentName, mListener, &mComponent);
72         ASSERT_NE(mComponent, nullptr);
73 
74         std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
75         CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
76         mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++);
77         ASSERT_NE(mLinearPool, nullptr);
78 
79         mCompName = unknown_comp;
80         struct StringToName {
81             const char* Name;
82             standardComp CompName;
83         };
84         const StringToName kStringToName[] = {
85                 {"xaac", xaac},          {"mp3", mp3}, {"amrnb", amrnb},
86                 {"amrwb", amrwb},        {"aac", aac}, {"vorbis", vorbis},
87                 {"opus", opus},          {"pcm", pcm}, {"g711.alaw", g711alaw},
88                 {"g711.mlaw", g711mlaw}, {"gsm", gsm}, {"raw", raw},
89                 {"flac", flac},
90         };
91         const size_t kNumStringToName = sizeof(kStringToName) / sizeof(kStringToName[0]);
92 
93         // Find the component type
94         for (size_t i = 0; i < kNumStringToName; ++i) {
95             if (strcasestr(mComponentName.c_str(), kStringToName[i].Name)) {
96                 mCompName = kStringToName[i].CompName;
97                 break;
98             }
99         }
100         mEos = false;
101         mFramesReceived = 0;
102         mTimestampUs = 0u;
103         mWorkResult = C2_OK;
104         mTimestampDevTest = false;
105         if (mCompName == unknown_comp) mDisableTest = true;
106         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
107     }
108 
TearDown()109     virtual void TearDown() override {
110         if (mComponent != nullptr) {
111             if (::testing::Test::HasFatalFailure()) return;
112             mComponent->release();
113             mComponent = nullptr;
114         }
115     }
116 
117     // Get the test parameters from GetParam call.
getParams()118     virtual void getParams() {}
119 
120     virtual void validateTimestampList(int32_t* bitStreamInfo);
121 
122     struct outputMetaData {
123         uint64_t timestampUs;
124         uint32_t rangeLength;
125     };
126     // callback function to process onWorkDone received by Listener
handleWorkDone(std::list<std::unique_ptr<C2Work>> & workItems)127     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
128         for (std::unique_ptr<C2Work>& work : workItems) {
129             if (!work->worklets.empty()) {
130                 // For decoder components current timestamp always exceeds
131                 // previous timestamp
132                 mWorkResult |= work->result;
133                 bool codecConfig = ((work->worklets.front()->output.flags &
134                                      C2FrameData::FLAG_CODEC_CONFIG) != 0);
135                 if (!codecConfig && !work->worklets.front()->output.buffers.empty()) {
136                     EXPECT_GE(work->worklets.front()->output.ordinal.timestamp.peeku(),
137                               mTimestampUs);
138                     mTimestampUs = work->worklets.front()->output.ordinal.timestamp.peeku();
139                     uint32_t rangeLength = work->worklets.front()
140                                                    ->output.buffers[0]
141                                                    ->data()
142                                                    .linearBlocks()
143                                                    .front()
144                                                    .map()
145                                                    .get()
146                                                    .capacity();
147                     // List of timestamp values and output size to calculate timestamp
148                     if (mTimestampDevTest) {
149                         outputMetaData meta = {mTimestampUs, rangeLength};
150                         oBufferMetaData.push_back(meta);
151                     }
152                 }
153                 bool mCsd = false;
154                 workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
155                          mEos, mCsd, mFramesReceived);
156                 (void)mCsd;
157             }
158         }
159     }
160 
161     enum standardComp {
162         xaac,
163         mp3,
164         amrnb,
165         amrwb,
166         aac,
167         vorbis,
168         opus,
169         pcm,
170         g711alaw,
171         g711mlaw,
172         gsm,
173         raw,
174         flac,
175         unknown_comp,
176     };
177 
178     std::string mInstanceName;
179     std::string mComponentName;
180     bool mEos;
181     bool mDisableTest;
182     bool mTimestampDevTest;
183     standardComp mCompName;
184 
185     int32_t mWorkResult;
186     uint64_t mTimestampUs;
187     uint32_t mFramesReceived;
188     std::list<uint64_t> mFlushedIndices;
189     std::list<uint64_t> mTimestampUslist;
190     std::list<outputMetaData> oBufferMetaData;
191 
192     C2BlockPool::local_id_t mBlockPoolId;
193     std::shared_ptr<C2BlockPool> mLinearPool;
194     std::shared_ptr<C2Allocator> mLinearAllocator;
195 
196     std::mutex mQueueLock;
197     std::condition_variable mQueueCondition;
198     std::list<std::unique_ptr<C2Work>> mWorkQueue;
199 
200     std::shared_ptr<android::Codec2Client> mClient;
201     std::shared_ptr<android::Codec2Client::Listener> mListener;
202     std::shared_ptr<android::Codec2Client::Component> mComponent;
203 
204   protected:
description(const std::string & description)205     static void description(const std::string& description) {
206         RecordProperty("description", description);
207     }
208 };
209 
210 class Codec2AudioDecHidlTest
211     : public Codec2AudioDecHidlTestBase,
212       public ::testing::WithParamInterface<std::tuple<std::string, std::string>> {
getParams()213     void getParams() {
214         mInstanceName = std::get<0>(GetParam());
215         mComponentName = std::get<1>(GetParam());
216     }
217 };
218 
validateComponent(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2AudioDecHidlTest::standardComp compName,bool & disableTest)219 void validateComponent(const std::shared_ptr<android::Codec2Client::Component>& component,
220                        Codec2AudioDecHidlTest::standardComp compName, bool& disableTest) {
221     // Validate its a C2 Component
222     if (component->getName().find("c2") == std::string::npos) {
223         ALOGE("Not a c2 component");
224         disableTest = true;
225         return;
226     }
227 
228     // Validate its not an encoder and the component to be tested is audio
229     if (component->getName().find("encoder") != std::string::npos) {
230         ALOGE("Expected Decoder, given Encoder");
231         disableTest = true;
232         return;
233     }
234     std::vector<std::unique_ptr<C2Param>> queried;
235     c2_status_t c2err = component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
236                                          C2_DONT_BLOCK, &queried);
237     if (c2err != C2_OK && queried.size() == 0) {
238         ALOGE("Query media type failed => %d", c2err);
239     } else {
240         std::string inputDomain = ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
241         if (inputDomain.find("audio/") == std::string::npos) {
242             ALOGE("Expected Audio Component");
243             disableTest = true;
244             return;
245         }
246     }
247 
248     // Validates component name
249     if (compName == Codec2AudioDecHidlTest::unknown_comp) {
250         ALOGE("Component InValid");
251         disableTest = true;
252         return;
253     }
254     ALOGV("Component Valid");
255 }
256 
257 // Set Default config param.
setupConfigParam(const std::shared_ptr<android::Codec2Client::Component> & component,int32_t * bitStreamInfo)258 bool setupConfigParam(const std::shared_ptr<android::Codec2Client::Component>& component,
259                       int32_t* bitStreamInfo) {
260     std::vector<std::unique_ptr<C2SettingResult>> failures;
261     C2StreamSampleRateInfo::output sampleRateInfo(0u, bitStreamInfo[0]);
262     C2StreamChannelCountInfo::output channelCountInfo(0u, bitStreamInfo[1]);
263 
264     std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
265     c2_status_t status = component->config(configParam, C2_DONT_BLOCK, &failures);
266     if (status == C2_OK && failures.size() == 0u) return true;
267     return false;
268 }
269 
270 // In decoder components, often the input parameters get updated upon
271 // parsing the header of elementary stream. Client needs to collect this
272 // information and reconfigure
getInputChannelInfo(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2AudioDecHidlTest::standardComp compName,int32_t * bitStreamInfo)273 void getInputChannelInfo(const std::shared_ptr<android::Codec2Client::Component>& component,
274                          Codec2AudioDecHidlTest::standardComp compName, int32_t* bitStreamInfo) {
275     // query nSampleRate and nChannels
276     std::initializer_list<C2Param::Index> indices{
277             C2StreamSampleRateInfo::output::PARAM_TYPE,
278             C2StreamChannelCountInfo::output::PARAM_TYPE,
279     };
280     std::vector<std::unique_ptr<C2Param>> inParams;
281     c2_status_t status = component->query({}, indices, C2_DONT_BLOCK, &inParams);
282     if (status != C2_OK && inParams.size() == 0) {
283         ALOGE("Query media type failed => %d", status);
284         ASSERT_TRUE(false);
285     } else {
286         size_t offset = sizeof(C2Param);
287         for (size_t i = 0; i < inParams.size(); ++i) {
288             C2Param* param = inParams[i].get();
289             bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
290         }
291         switch (compName) {
292             case Codec2AudioDecHidlTest::amrnb: {
293                 ASSERT_EQ(bitStreamInfo[0], 8000);
294                 ASSERT_EQ(bitStreamInfo[1], 1);
295                 break;
296             }
297             case Codec2AudioDecHidlTest::amrwb: {
298                 ASSERT_EQ(bitStreamInfo[0], 16000);
299                 ASSERT_EQ(bitStreamInfo[1], 1);
300                 break;
301             }
302             case Codec2AudioDecHidlTest::gsm: {
303                 ASSERT_EQ(bitStreamInfo[0], 8000);
304                 break;
305             }
306             default:
307                 break;
308         }
309     }
310 }
311 
312 // number of elementary streams per component
313 #define STREAM_COUNT 2
314 
315 // LookUpTable of clips and metadata for component testing
GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp,char * mURL,char * info,size_t streamIndex=0)316 void GetURLForComponent(Codec2AudioDecHidlTest::standardComp comp, char* mURL, char* info,
317                         size_t streamIndex = 0) {
318     struct CompToURL {
319         Codec2AudioDecHidlTest::standardComp comp;
320         const char mURL[STREAM_COUNT][512];
321         const char info[STREAM_COUNT][512];
322     };
323     ASSERT_TRUE(streamIndex < STREAM_COUNT);
324 
325     static const CompToURL kCompToURL[] = {
326             {Codec2AudioDecHidlTest::standardComp::xaac,
327              {"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.aac"},
328              {"bbb_aac_stereo_128kbps_48000hz.info",
329               "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
330             {Codec2AudioDecHidlTest::standardComp::mp3,
331              {"bbb_mp3_stereo_192kbps_48000hz.mp3", "bbb_mp3_stereo_192kbps_48000hz.mp3"},
332              {"bbb_mp3_stereo_192kbps_48000hz.info",
333               "bbb_mp3_stereo_192kbps_48000hz_multi_frame.info"}},
334             {Codec2AudioDecHidlTest::standardComp::aac,
335              {"bbb_aac_stereo_128kbps_48000hz.aac", "bbb_aac_stereo_128kbps_48000hz.aac"},
336              {"bbb_aac_stereo_128kbps_48000hz.info",
337               "bbb_aac_stereo_128kbps_48000hz_multi_frame.info"}},
338             {Codec2AudioDecHidlTest::standardComp::amrnb,
339              {"sine_amrnb_1ch_12kbps_8000hz.amrnb", "sine_amrnb_1ch_12kbps_8000hz.amrnb"},
340              {"sine_amrnb_1ch_12kbps_8000hz.info",
341               "sine_amrnb_1ch_12kbps_8000hz_multi_frame.info"}},
342             {Codec2AudioDecHidlTest::standardComp::amrwb,
343              {"bbb_amrwb_1ch_14kbps_16000hz.amrwb", "bbb_amrwb_1ch_14kbps_16000hz.amrwb"},
344              {"bbb_amrwb_1ch_14kbps_16000hz.info",
345               "bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info"}},
346             {Codec2AudioDecHidlTest::standardComp::vorbis,
347              {"bbb_vorbis_stereo_128kbps_48000hz.vorbis", ""},
348              {"bbb_vorbis_stereo_128kbps_48000hz.info", ""}},
349             {Codec2AudioDecHidlTest::standardComp::opus,
350              {"bbb_opus_stereo_128kbps_48000hz.opus", ""},
351              {"bbb_opus_stereo_128kbps_48000hz.info", ""}},
352             {Codec2AudioDecHidlTest::standardComp::g711alaw,
353              {"bbb_g711alaw_1ch_8khz.raw", ""},
354              {"bbb_g711alaw_1ch_8khz.info", ""}},
355             {Codec2AudioDecHidlTest::standardComp::g711mlaw,
356              {"bbb_g711mulaw_1ch_8khz.raw", ""},
357              {"bbb_g711mulaw_1ch_8khz.info", ""}},
358             {Codec2AudioDecHidlTest::standardComp::gsm,
359              {"bbb_gsm_1ch_8khz_13kbps.raw", ""},
360              {"bbb_gsm_1ch_8khz_13kbps.info", ""}},
361             {Codec2AudioDecHidlTest::standardComp::raw,
362              {"bbb_raw_1ch_8khz_s32le.raw", ""},
363              {"bbb_raw_1ch_8khz_s32le.info", ""}},
364             {Codec2AudioDecHidlTest::standardComp::flac,
365              {"bbb_flac_stereo_680kbps_48000hz.flac", ""},
366              {"bbb_flac_stereo_680kbps_48000hz.info", ""}},
367     };
368 
369     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
370         if (kCompToURL[i].comp == comp) {
371             strcat(mURL, kCompToURL[i].mURL[streamIndex]);
372             strcat(info, kCompToURL[i].info[streamIndex]);
373             return;
374         }
375     }
376 }
377 
decodeNFrames(const std::shared_ptr<android::Codec2Client::Component> & component,std::mutex & queueLock,std::condition_variable & queueCondition,std::list<std::unique_ptr<C2Work>> & workQueue,std::list<uint64_t> & flushedIndices,std::shared_ptr<C2BlockPool> & linearPool,std::ifstream & eleStream,android::Vector<FrameInfo> * Info,int offset,int range,bool signalEOS=true)378 void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
379                    std::mutex& queueLock, std::condition_variable& queueCondition,
380                    std::list<std::unique_ptr<C2Work>>& workQueue,
381                    std::list<uint64_t>& flushedIndices, std::shared_ptr<C2BlockPool>& linearPool,
382                    std::ifstream& eleStream, android::Vector<FrameInfo>* Info, int offset,
383                    int range, bool signalEOS = true) {
384     typedef std::unique_lock<std::mutex> ULock;
385     int frameID = offset;
386     int maxRetry = 0;
387     while (1) {
388         if (frameID == (int)Info->size() || frameID == (offset + range)) break;
389         uint32_t flags = 0;
390         std::unique_ptr<C2Work> work;
391         // Prepare C2Work
392         while (!work && (maxRetry < MAX_RETRY)) {
393             ULock l(queueLock);
394             if (!workQueue.empty()) {
395                 work.swap(workQueue.front());
396                 workQueue.pop_front();
397             } else {
398                 queueCondition.wait_for(l, TIME_OUT);
399                 maxRetry++;
400             }
401         }
402         if (!work && (maxRetry >= MAX_RETRY)) {
403             ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
404         }
405         int64_t timestamp = (*Info)[frameID].timestamp;
406         if ((*Info)[frameID].flags) flags = 1u << ((*Info)[frameID].flags - 1);
407         if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1))))
408             flags |= C2FrameData::FLAG_END_OF_STREAM;
409 
410         work->input.flags = (C2FrameData::flags_t)flags;
411         work->input.ordinal.timestamp = timestamp;
412         work->input.ordinal.frameIndex = frameID;
413         {
414             ULock l(queueLock);
415             flushedIndices.emplace_back(frameID);
416         }
417         int size = (*Info)[frameID].bytesCount;
418         char* data = (char*)malloc(size);
419         ASSERT_NE(data, nullptr);
420 
421         eleStream.read(data, size);
422         ASSERT_EQ(eleStream.gcount(), size);
423 
424         work->input.buffers.clear();
425         if (size) {
426             std::shared_ptr<C2LinearBlock> block;
427             ASSERT_EQ(C2_OK,
428                       linearPool->fetchLinearBlock(
429                               size, {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE}, &block));
430             ASSERT_TRUE(block);
431 
432             // Write View
433             C2WriteView view = block->map().get();
434             if (view.error() != C2_OK) {
435                 fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
436                 break;
437             }
438             ASSERT_EQ((size_t)size, view.capacity());
439             ASSERT_EQ(0u, view.offset());
440             ASSERT_EQ((size_t)size, view.size());
441 
442             memcpy(view.base(), data, size);
443 
444             work->input.buffers.emplace_back(new LinearBuffer(block));
445             free(data);
446         }
447         work->worklets.clear();
448         work->worklets.emplace_back(new C2Worklet);
449 
450         std::list<std::unique_ptr<C2Work>> items;
451         items.push_back(std::move(work));
452 
453         // DO THE DECODING
454         ASSERT_EQ(component->queue(&items), C2_OK);
455         ALOGV("Frame #%d size = %d queued", frameID, size);
456         frameID++;
457         maxRetry = 0;
458     }
459 }
460 
validateTimestampList(int32_t * bitStreamInfo)461 void Codec2AudioDecHidlTestBase::validateTimestampList(int32_t* bitStreamInfo) {
462     uint32_t samplesReceived = 0;
463     // Update SampleRate and ChannelCount
464     ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
465     int32_t nSampleRate = bitStreamInfo[0];
466     int32_t nChannels = bitStreamInfo[1];
467     std::list<uint64_t>::iterator itIn = mTimestampUslist.begin();
468     auto itOut = oBufferMetaData.begin();
469     EXPECT_EQ(*itIn, itOut->timestampUs);
470     uint64_t expectedTimeStamp = *itIn;
471     while (itOut != oBufferMetaData.end()) {
472         EXPECT_EQ(expectedTimeStamp, itOut->timestampUs);
473         if (expectedTimeStamp != itOut->timestampUs) break;
474         // buffer samples = ((total bytes) / (ac * (bits per sample / 8))
475         samplesReceived += ((itOut->rangeLength) / (nChannels * 2));
476         expectedTimeStamp = samplesReceived * 1000000ll / nSampleRate;
477         itOut++;
478     }
479     itIn = mTimestampUslist.end();
480     --itIn;
481     EXPECT_GT(expectedTimeStamp, *itIn);
482     oBufferMetaData.clear();
483     mTimestampUslist.clear();
484 }
485 
TEST_P(Codec2AudioDecHidlTest,validateCompName)486 TEST_P(Codec2AudioDecHidlTest, validateCompName) {
487     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
488     ALOGV("Checks if the given component is a valid audio component");
489     validateComponent(mComponent, mCompName, mDisableTest);
490     ASSERT_EQ(mDisableTest, false);
491 }
492 
TEST_P(Codec2AudioDecHidlTest,configComp)493 TEST_P(Codec2AudioDecHidlTest, configComp) {
494     description("Tests component specific configuration");
495     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
496     ASSERT_EQ(mComponent->start(), C2_OK);
497     int32_t bitStreamInfo[2] = {0};
498     ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
499     setupConfigParam(mComponent, bitStreamInfo);
500     ASSERT_EQ(mComponent->stop(), C2_OK);
501 }
502 
503 class Codec2AudioDecDecodeTest
504     : public Codec2AudioDecHidlTestBase,
505       public ::testing::WithParamInterface<
506               std::tuple<std::string, std::string, std::string, std::string>> {
getParams()507     void getParams() {
508         mInstanceName = std::get<0>(GetParam());
509         mComponentName = std::get<1>(GetParam());
510     }
511 };
512 
TEST_P(Codec2AudioDecDecodeTest,DecodeTest)513 TEST_P(Codec2AudioDecDecodeTest, DecodeTest) {
514     description("Decodes input file");
515     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
516 
517     uint32_t streamIndex = std::stoi(std::get<2>(GetParam()));
518     ;
519     bool signalEOS = !std::get<3>(GetParam()).compare("true");
520     mTimestampDevTest = true;
521     char mURL[512], info[512];
522     android::Vector<FrameInfo> Info;
523 
524     strcpy(mURL, sResourceDir.c_str());
525     strcpy(info, sResourceDir.c_str());
526     GetURLForComponent(mCompName, mURL, info, streamIndex);
527     if (!strcmp(mURL, sResourceDir.c_str())) {
528         ALOGV("EMPTY INPUT sResourceDir.c_str() %s mURL  %s ", sResourceDir.c_str(), mURL);
529         return;
530     }
531 
532     int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
533     ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
534 
535     // Reset total no of frames received
536     mFramesReceived = 0;
537     mTimestampUs = 0;
538     int32_t bitStreamInfo[2] = {0};
539     if (mCompName == raw) {
540         bitStreamInfo[0] = 8000;
541         bitStreamInfo[1] = 1;
542     } else {
543         ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
544     }
545     if (!setupConfigParam(mComponent, bitStreamInfo)) {
546         std::cout << "[   WARN   ] Test Skipped \n";
547         return;
548     }
549     ASSERT_EQ(mComponent->start(), C2_OK);
550     ALOGV("mURL : %s", mURL);
551     std::ifstream eleStream;
552     eleStream.open(mURL, std::ifstream::binary);
553     ASSERT_EQ(eleStream.is_open(), true);
554     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
555                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
556                                           (int)Info.size(), signalEOS));
557 
558     // If EOS is not sent, sending empty input with EOS flag
559     size_t infoSize = Info.size();
560     if (!signalEOS) {
561         ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
562         ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
563                                                 C2FrameData::FLAG_END_OF_STREAM, false));
564         infoSize += 1;
565     }
566     // blocking call to ensures application to Wait till all the inputs are
567     // consumed
568     waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
569     eleStream.close();
570     if (mFramesReceived != infoSize) {
571         ALOGE("Input buffer count and Output buffer count mismatch");
572         ALOGE("framesReceived : %d inputFrames : %zu", mFramesReceived, infoSize);
573         ASSERT_TRUE(false);
574     }
575     ASSERT_EQ(mEos, true);
576 
577     if (mTimestampDevTest) {
578         validateTimestampList(bitStreamInfo);
579     }
580     ASSERT_EQ(mComponent->stop(), C2_OK);
581     ASSERT_EQ(mWorkResult, C2_OK);
582 }
583 
584 // thumbnail test
TEST_P(Codec2AudioDecHidlTest,ThumbnailTest)585 TEST_P(Codec2AudioDecHidlTest, ThumbnailTest) {
586     description("Test Request for thumbnail");
587     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
588 
589     char mURL[512], info[512];
590     android::Vector<FrameInfo> Info;
591 
592     strcpy(mURL, sResourceDir.c_str());
593     strcpy(info, sResourceDir.c_str());
594     GetURLForComponent(mCompName, mURL, info);
595 
596     int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
597     ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
598 
599     int32_t bitStreamInfo[2] = {0};
600     if (mCompName == raw) {
601         bitStreamInfo[0] = 8000;
602         bitStreamInfo[1] = 1;
603     } else {
604         ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
605     }
606     if (!setupConfigParam(mComponent, bitStreamInfo)) {
607         std::cout << "[   WARN   ] Test Skipped \n";
608         return;
609     }
610     ASSERT_EQ(mComponent->start(), C2_OK);
611     ALOGV("mURL : %s", mURL);
612 
613     // request EOS for thumbnail
614     // signal EOS flag with last frame
615     size_t i = -1;
616     uint32_t flags;
617     do {
618         i++;
619         flags = 0;
620         if (Info[i].flags) flags = 1u << (Info[i].flags - 1);
621 
622     } while (!(flags & SYNC_FRAME));
623     std::ifstream eleStream;
624     eleStream.open(mURL, std::ifstream::binary);
625     ASSERT_EQ(eleStream.is_open(), true);
626     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
627                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
628                                           i + 1));
629     waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
630     eleStream.close();
631     EXPECT_GE(mFramesReceived, 1U);
632     ASSERT_EQ(mEos, true);
633     ASSERT_EQ(mComponent->stop(), C2_OK);
634     ASSERT_EQ(mWorkResult, C2_OK);
635 }
636 
TEST_P(Codec2AudioDecHidlTest,EOSTest)637 TEST_P(Codec2AudioDecHidlTest, EOSTest) {
638     description("Test empty input buffer with EOS flag");
639     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
640     typedef std::unique_lock<std::mutex> ULock;
641     ASSERT_EQ(mComponent->start(), C2_OK);
642     std::unique_ptr<C2Work> work;
643     // Prepare C2Work
644     {
645         ULock l(mQueueLock);
646         if (!mWorkQueue.empty()) {
647             work.swap(mWorkQueue.front());
648             mWorkQueue.pop_front();
649         } else {
650             ASSERT_TRUE(false) << "mWorkQueue Empty at the start of test";
651         }
652     }
653     ASSERT_NE(work, nullptr);
654 
655     work->input.flags = (C2FrameData::flags_t)C2FrameData::FLAG_END_OF_STREAM;
656     work->input.ordinal.timestamp = 0;
657     work->input.ordinal.frameIndex = 0;
658     work->input.buffers.clear();
659     work->worklets.clear();
660     work->worklets.emplace_back(new C2Worklet);
661 
662     std::list<std::unique_ptr<C2Work>> items;
663     items.push_back(std::move(work));
664     ASSERT_EQ(mComponent->queue(&items), C2_OK);
665 
666     {
667         ULock l(mQueueLock);
668         if (mWorkQueue.size() != MAX_INPUT_BUFFERS) {
669             mQueueCondition.wait_for(l, TIME_OUT);
670         }
671     }
672     ASSERT_EQ(mEos, true);
673     ASSERT_EQ(mWorkQueue.size(), (size_t)MAX_INPUT_BUFFERS);
674     ASSERT_EQ(mComponent->stop(), C2_OK);
675     ASSERT_EQ(mWorkResult, C2_OK);
676 }
677 
TEST_P(Codec2AudioDecHidlTest,FlushTest)678 TEST_P(Codec2AudioDecHidlTest, FlushTest) {
679     description("Tests Flush calls");
680     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
681     char mURL[512], info[512];
682     android::Vector<FrameInfo> Info;
683 
684     strcpy(mURL, sResourceDir.c_str());
685     strcpy(info, sResourceDir.c_str());
686     GetURLForComponent(mCompName, mURL, info);
687 
688     int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
689     ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << info;
690 
691     int32_t bitStreamInfo[2] = {0};
692     if (mCompName == raw) {
693         bitStreamInfo[0] = 8000;
694         bitStreamInfo[1] = 1;
695     } else {
696         ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
697     }
698     if (!setupConfigParam(mComponent, bitStreamInfo)) {
699         std::cout << "[   WARN   ] Test Skipped \n";
700         return;
701     }
702     ASSERT_EQ(mComponent->start(), C2_OK);
703     // flush
704     std::list<std::unique_ptr<C2Work>> flushedWork;
705     c2_status_t err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
706     ASSERT_EQ(err, C2_OK);
707     ASSERT_NO_FATAL_FAILURE(
708             verifyFlushOutput(flushedWork, mWorkQueue, mFlushedIndices, mQueueLock));
709     ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
710 
711     ALOGV("mURL : %s", mURL);
712     std::ifstream eleStream;
713     eleStream.open(mURL, std::ifstream::binary);
714     ASSERT_EQ(eleStream.is_open(), true);
715     // Decode 30 frames and flush.
716     uint32_t numFramesFlushed = FLUSH_INTERVAL;
717     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
718                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
719                                           numFramesFlushed, false));
720     // flush
721     err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
722     ASSERT_EQ(err, C2_OK);
723     waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
724                            (size_t)MAX_INPUT_BUFFERS - flushedWork.size());
725     ASSERT_NO_FATAL_FAILURE(
726             verifyFlushOutput(flushedWork, mWorkQueue, mFlushedIndices, mQueueLock));
727     ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
728 
729     // Seek to next key frame and start decoding till the end
730     mFlushedIndices.clear();
731     int index = numFramesFlushed;
732     bool keyFrame = false;
733     uint32_t flags = 0;
734     while (index < (int)Info.size()) {
735         if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
736         if ((flags & SYNC_FRAME) == SYNC_FRAME) {
737             keyFrame = true;
738             break;
739         }
740         flags = 0;
741         eleStream.ignore(Info[index].bytesCount);
742         index++;
743     }
744     if (keyFrame) {
745         ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
746                                               mFlushedIndices, mLinearPool, eleStream, &Info, index,
747                                               (int)Info.size() - index));
748     }
749     eleStream.close();
750     err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
751     ASSERT_EQ(err, C2_OK);
752     waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
753                            (size_t)MAX_INPUT_BUFFERS - flushedWork.size());
754     ASSERT_NO_FATAL_FAILURE(
755             verifyFlushOutput(flushedWork, mWorkQueue, mFlushedIndices, mQueueLock));
756     ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
757     // TODO: (b/154671521)
758     // Add assert for mWorkResult
759     ASSERT_EQ(mComponent->stop(), C2_OK);
760 }
761 
TEST_P(Codec2AudioDecHidlTest,DecodeTestEmptyBuffersInserted)762 TEST_P(Codec2AudioDecHidlTest, DecodeTestEmptyBuffersInserted) {
763     description("Decode with multiple empty input frames");
764     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
765 
766     char mURL[512], info[512];
767     std::ifstream eleStream, eleInfo;
768 
769     strcpy(mURL, sResourceDir.c_str());
770     strcpy(info, sResourceDir.c_str());
771     GetURLForComponent(mCompName, mURL, info);
772 
773     eleInfo.open(info);
774     ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
775     android::Vector<FrameInfo> Info;
776     int bytesCount = 0;
777     uint32_t frameId = 0;
778     uint32_t flags = 0;
779     uint32_t timestamp = 0;
780     bool codecConfig = false;
781     // This test introduces empty CSD after every 20th frame
782     // and empty input frames at an interval of 5 frames.
783     while (1) {
784         if (!(frameId % 5)) {
785             if (!(frameId % 20))
786                 flags = 32;
787             else
788                 flags = 0;
789             bytesCount = 0;
790         } else {
791             if (!(eleInfo >> bytesCount)) break;
792             eleInfo >> flags;
793             eleInfo >> timestamp;
794             codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
795         }
796         Info.push_back({bytesCount, flags, timestamp});
797         frameId++;
798     }
799     eleInfo.close();
800     int32_t bitStreamInfo[2] = {0};
801     if (mCompName == raw) {
802         bitStreamInfo[0] = 8000;
803         bitStreamInfo[1] = 1;
804     } else {
805         ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
806     }
807     if (!setupConfigParam(mComponent, bitStreamInfo)) {
808         std::cout << "[   WARN   ] Test Skipped \n";
809         return;
810     }
811     ASSERT_EQ(mComponent->start(), C2_OK);
812     ALOGV("mURL : %s", mURL);
813     eleStream.open(mURL, std::ifstream::binary);
814     ASSERT_EQ(eleStream.is_open(), true);
815     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
816                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
817                                           (int)Info.size()));
818 
819     // blocking call to ensures application to Wait till all the inputs are
820     // consumed
821     if (!mEos) {
822         ALOGV("Waiting for input consumption");
823         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
824     }
825 
826     eleStream.close();
827     if (mFramesReceived != Info.size()) {
828         ALOGE("Input buffer count and Output buffer count mismatch");
829         ALOGV("framesReceived : %d inputFrames : %zu", mFramesReceived, Info.size());
830         ASSERT_TRUE(false);
831     }
832 
833     ASSERT_EQ(mComponent->stop(), C2_OK);
834 }
835 
836 class Codec2AudioDecCsdInputTests
837     : public Codec2AudioDecHidlTestBase,
838       public ::testing::WithParamInterface<std::tuple<std::string, std::string, std::string>> {
getParams()839     void getParams() {
840         mInstanceName = std::get<0>(GetParam());
841         mComponentName = std::get<1>(GetParam());
842     }
843 };
844 
845 // Test the codecs for the following
846 // start - csd - data… - (with/without)flush - data… - flush - data…
TEST_P(Codec2AudioDecCsdInputTests,CSDFlushTest)847 TEST_P(Codec2AudioDecCsdInputTests, CSDFlushTest) {
848     description("Tests codecs for flush at different states");
849     if (mDisableTest) GTEST_SKIP() << "Test is disabled";
850 
851     char mURL[512], info[512];
852     android::Vector<FrameInfo> Info;
853 
854     strcpy(mURL, sResourceDir.c_str());
855     strcpy(info, sResourceDir.c_str());
856     GetURLForComponent(mCompName, mURL, info);
857     if (!strcmp(mURL, sResourceDir.c_str())) {
858         ALOGV("EMPTY INPUT sResourceDir.c_str() %s mURL  %s ", sResourceDir.c_str(), mURL);
859         return;
860     }
861     ALOGV("mURL : %s", mURL);
862 
863     int32_t numCsds = populateInfoVector(info, &Info, mTimestampDevTest, &mTimestampUslist);
864     ASSERT_GE(numCsds, 0) << "Error in parsing input info file";
865 
866     int32_t bitStreamInfo[2] = {0};
867     if (mCompName == raw) {
868         bitStreamInfo[0] = 8000;
869         bitStreamInfo[1] = 1;
870     } else {
871         ASSERT_NO_FATAL_FAILURE(getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
872     }
873     if (!setupConfigParam(mComponent, bitStreamInfo)) {
874         std::cout << "[   WARN   ] Test Skipped \n";
875         return;
876     }
877 
878     ASSERT_EQ(mComponent->start(), C2_OK);
879     std::ifstream eleStream;
880     eleStream.open(mURL, std::ifstream::binary);
881     ASSERT_EQ(eleStream.is_open(), true);
882 
883     bool signalEOS = false;
884     bool flushCsd = !std::get<2>(GetParam()).compare("true");
885     ALOGV("sending %d csd data ", numCsds);
886     int framesToDecode = numCsds;
887     ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
888                                           mFlushedIndices, mLinearPool, eleStream, &Info, 0,
889                                           framesToDecode, false));
890 
891     c2_status_t err = C2_OK;
892     std::list<std::unique_ptr<C2Work>> flushedWork;
893     if (numCsds && flushCsd) {
894         // We wait for all the CSD buffers to get consumed.
895         // Once we have received all CSD work back, we call flush
896         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
897 
898         err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
899         ASSERT_EQ(err, C2_OK);
900         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
901                                MAX_INPUT_BUFFERS - flushedWork.size());
902         ASSERT_NO_FATAL_FAILURE(
903                 verifyFlushOutput(flushedWork, mWorkQueue, mFlushedIndices, mQueueLock));
904         ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
905         oBufferMetaData.clear();
906     }
907 
908     int offset = framesToDecode;
909     while (1) {
910         framesToDecode = c2_min(FLUSH_INTERVAL, (int)Info.size() - offset);
911         if (framesToDecode < FLUSH_INTERVAL) signalEOS = true;
912         ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
913                                               mFlushedIndices, mLinearPool, eleStream, &Info,
914                                               offset, framesToDecode, signalEOS));
915         offset += framesToDecode;
916         err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
917         ASSERT_EQ(err, C2_OK);
918         // blocking call to ensures application to Wait till remaining
919         // 'non-flushed' inputs are consumed
920         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
921                                MAX_INPUT_BUFFERS - flushedWork.size());
922         ASSERT_NO_FATAL_FAILURE(
923                 verifyFlushOutput(flushedWork, mWorkQueue, mFlushedIndices, mQueueLock));
924         ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
925         if (signalEOS || offset >= (int)Info.size()) {
926             break;
927         }
928     }
929     if (!signalEOS) {
930         ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
931                                                 C2FrameData::FLAG_END_OF_STREAM, false));
932         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
933     }
934     eleStream.close();
935     ASSERT_EQ(mWorkQueue.size(), MAX_INPUT_BUFFERS);
936     ASSERT_EQ(mComponent->stop(), C2_OK);
937 }
938 
939 INSTANTIATE_TEST_SUITE_P(PerInstance, Codec2AudioDecHidlTest, testing::ValuesIn(kTestParameters),
940                          android::hardware::PrintInstanceTupleNameToString<>);
941 
942 // DecodeTest with StreamIndex and EOS / No EOS
943 INSTANTIATE_TEST_SUITE_P(StreamIndexAndEOS, Codec2AudioDecDecodeTest,
944                          testing::ValuesIn(kDecodeTestParameters),
945                          android::hardware::PrintInstanceTupleNameToString<>);
946 
947 INSTANTIATE_TEST_SUITE_P(CsdInputs, Codec2AudioDecCsdInputTests,
948                          testing::ValuesIn(kCsdFlushTestParameters),
949                          android::hardware::PrintInstanceTupleNameToString<>);
950 
951 }  // anonymous namespace
952 
main(int argc,char ** argv)953 int main(int argc, char** argv) {
954     kTestParameters = getTestParameters(C2Component::DOMAIN_AUDIO, C2Component::KIND_DECODER);
955     for (auto params : kTestParameters) {
956         kDecodeTestParameters.push_back(
957                 std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "false"));
958         kDecodeTestParameters.push_back(
959                 std::make_tuple(std::get<0>(params), std::get<1>(params), "0", "true"));
960         kDecodeTestParameters.push_back(
961                 std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "false"));
962         kDecodeTestParameters.push_back(
963                 std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "true"));
964 
965         kCsdFlushTestParameters.push_back(
966                 std::make_tuple(std::get<0>(params), std::get<1>(params), "true"));
967         kCsdFlushTestParameters.push_back(
968                 std::make_tuple(std::get<0>(params), std::get<1>(params), "false"));
969     }
970 
971     // Set the resource directory based on command line args.
972     // Test will fail to set up if the argument is not set.
973     for (int i = 1; i < argc; i++) {
974         if (strcmp(argv[i], "-P") == 0 && i < argc - 1) {
975             sResourceDir = argv[i + 1];
976             break;
977         }
978     }
979 
980     ::testing::InitGoogleTest(&argc, argv);
981     return RUN_ALL_TESTS();
982 }
983