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