• 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_enc_test"
19 
20 #include <android-base/logging.h>
21 #include <gtest/gtest.h>
22 #include <stdio.h>
23 #include <fstream>
24 #include <algorithm>
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 class LinearBuffer : public C2Buffer {
40    public:
LinearBuffer(const std::shared_ptr<C2LinearBlock> & block)41     explicit LinearBuffer(const std::shared_ptr<C2LinearBlock>& block)
42         : C2Buffer(
43               {block->share(block->offset(), block->size(), ::C2Fence())}) {}
44 };
45 
46 static ComponentTestEnvironment* gEnv = nullptr;
47 
48 namespace {
49 
50 class Codec2AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
51    private:
52     typedef ::testing::VtsHalHidlTargetTestBase Super;
53 
54    public:
getTestCaseInfo() const55     ::std::string getTestCaseInfo() const override {
56         return ::std::string() +
57                 "Component: " + gEnv->getComponent().c_str() + " | " +
58                 "Instance: " + gEnv->getInstance().c_str() + " | " +
59                 "Res: " + gEnv->getRes().c_str();
60     }
61 
62     // google.codec2 Audio test setup
SetUp()63     virtual void SetUp() override {
64         Super::SetUp();
65         mDisableTest = false;
66         ALOGV("Codec2AudioEncHidlTest SetUp");
67         mClient = android::Codec2Client::CreateFromService(
68             gEnv->getInstance().c_str());
69         ASSERT_NE(mClient, nullptr);
70         mListener.reset(new CodecListener(
71             [this](std::list<std::unique_ptr<C2Work>>& workItems) {
72                 handleWorkDone(workItems);
73             }));
74         ASSERT_NE(mListener, nullptr);
75         for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
76             mWorkQueue.emplace_back(new C2Work);
77         }
78         mClient->createComponent(gEnv->getComponent().c_str(), mListener,
79                                  &mComponent);
80         ASSERT_NE(mComponent, nullptr);
81 
82         std::shared_ptr<C2AllocatorStore> store =
83             android::GetCodec2PlatformAllocatorStore();
84         CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR,
85                                        &mLinearAllocator),
86                  C2_OK);
87         mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator,
88                                                           mBlockPoolId++);
89         ASSERT_NE(mLinearPool, nullptr);
90 
91         mCompName = unknown_comp;
92         struct StringToName {
93             const char* Name;
94             standardComp CompName;
95         };
96         const StringToName kStringToName[] = {
97             {"aac", aac},
98             {"flac", flac},
99             {"opus", opus},
100             {"amrnb", amrnb},
101             {"amrwb", amrwb},
102         };
103         const size_t kNumStringToName =
104             sizeof(kStringToName) / sizeof(kStringToName[0]);
105 
106         // Find the component type
107         std::string comp = std::string(gEnv->getComponent());
108         for (size_t i = 0; i < kNumStringToName; ++i) {
109             if (strcasestr(comp.c_str(), kStringToName[i].Name)) {
110                 mCompName = kStringToName[i].CompName;
111                 break;
112             }
113         }
114         mEos = false;
115         mCsd = false;
116         mFramesReceived = 0;
117         if (mCompName == unknown_comp) mDisableTest = true;
118         if (mDisableTest) std::cout << "[   WARN   ] Test Disabled \n";
119         getInputMaxBufSize();
120     }
121 
TearDown()122     virtual void TearDown() override {
123         if (mComponent != nullptr) {
124             if (::testing::Test::HasFatalFailure()) return;
125             mComponent->release();
126             mComponent = nullptr;
127         }
128         Super::TearDown();
129     }
130     // callback function to process onWorkDone received by Listener
handleWorkDone(std::list<std::unique_ptr<C2Work>> & workItems)131     void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
132         for (std::unique_ptr<C2Work>& work : workItems) {
133             if (!work->worklets.empty()) {
134                 workDone(mComponent, work, mFlushedIndices, mQueueLock,
135                          mQueueCondition, mWorkQueue, mEos, mCsd,
136                          mFramesReceived);
137             }
138         }
139     }
140     enum standardComp {
141         aac,
142         flac,
143         opus,
144         amrnb,
145         amrwb,
146         unknown_comp,
147     };
148 
149     bool mEos;
150     bool mCsd;
151     bool mDisableTest;
152     standardComp mCompName;
153     uint32_t mFramesReceived;
154     int32_t mInputMaxBufSize;
155     std::list<uint64_t> mFlushedIndices;
156 
157     C2BlockPool::local_id_t mBlockPoolId;
158     std::shared_ptr<C2BlockPool> mLinearPool;
159     std::shared_ptr<C2Allocator> mLinearAllocator;
160 
161     std::mutex mQueueLock;
162     std::condition_variable mQueueCondition;
163     std::list<std::unique_ptr<C2Work>> mWorkQueue;
164 
165     std::shared_ptr<android::Codec2Client> mClient;
166     std::shared_ptr<android::Codec2Client::Listener> mListener;
167     std::shared_ptr<android::Codec2Client::Component> mComponent;
168 
169    protected:
description(const std::string & description)170     static void description(const std::string& description) {
171         RecordProperty("description", description);
172     }
173 
174     // In encoder components, fetch the size of input buffer allocated
getInputMaxBufSize()175     void getInputMaxBufSize() {
176         int32_t bitStreamInfo[1] = {0};
177         std::vector<std::unique_ptr<C2Param>> inParams;
178         c2_status_t status = mComponent->query(
179             {}, {C2StreamMaxBufferSizeInfo::input::PARAM_TYPE}, C2_DONT_BLOCK,
180             &inParams);
181         if (status != C2_OK && inParams.size() == 0) {
182             ALOGE("Query MaxBufferSizeInfo failed => %d", status);
183             ASSERT_TRUE(false);
184         } else {
185             size_t offset = sizeof(C2Param);
186             for (size_t i = 0; i < inParams.size(); ++i) {
187                 C2Param* param = inParams[i].get();
188                 bitStreamInfo[i] = *(int32_t*)((uint8_t*)param + offset);
189             }
190         }
191         mInputMaxBufSize = bitStreamInfo[0];
192     }
193 
194 };
195 
validateComponent(const std::shared_ptr<android::Codec2Client::Component> & component,Codec2AudioEncHidlTest::standardComp compName,bool & disableTest)196 void validateComponent(
197     const std::shared_ptr<android::Codec2Client::Component>& component,
198     Codec2AudioEncHidlTest::standardComp compName, bool& disableTest) {
199     // Validate its a C2 Component
200     if (component->getName().find("c2") == std::string::npos) {
201         ALOGE("Not a c2 component");
202         disableTest = true;
203         return;
204     }
205 
206     // Validate its not an encoder and the component to be tested is audio
207     if (component->getName().find("decoder") != std::string::npos) {
208         ALOGE("Expected Encoder, given Decoder");
209         disableTest = true;
210         return;
211     }
212     std::vector<std::unique_ptr<C2Param>> queried;
213     c2_status_t c2err =
214         component->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
215                          C2_DONT_BLOCK, &queried);
216     if (c2err != C2_OK && queried.size() == 0) {
217         ALOGE("Query media type failed => %d", c2err);
218     } else {
219         std::string inputDomain =
220             ((C2StreamMediaTypeSetting::input*)queried[0].get())->m.value;
221         if (inputDomain.find("audio/") == std::string::npos) {
222             ALOGE("Expected Audio Component");
223             disableTest = true;
224             return;
225         }
226     }
227 
228     // Validates component name
229     if (compName == Codec2AudioEncHidlTest::unknown_comp) {
230         ALOGE("Component InValid");
231         disableTest = true;
232         return;
233     }
234     ALOGV("Component Valid");
235 }
236 
237 // Set Default config param.
setupConfigParam(const std::shared_ptr<android::Codec2Client::Component> & component,int32_t nChannels,int32_t nSampleRate)238 bool setupConfigParam(
239     const std::shared_ptr<android::Codec2Client::Component>& component,
240     int32_t nChannels, int32_t nSampleRate) {
241     std::vector<std::unique_ptr<C2SettingResult>> failures;
242     C2StreamSampleRateInfo::input sampleRateInfo(0u, nSampleRate);
243     C2StreamChannelCountInfo::input channelCountInfo(0u, nChannels);
244 
245     std::vector<C2Param*> configParam{&sampleRateInfo, &channelCountInfo};
246     c2_status_t status =
247         component->config(configParam, C2_DONT_BLOCK, &failures);
248     if (status == C2_OK && failures.size() == 0u) return true;
249     return false;
250 }
251 
252 // LookUpTable of clips and metadata for component testing
GetURLForComponent(Codec2AudioEncHidlTest::standardComp comp,char * mURL)253 void GetURLForComponent(Codec2AudioEncHidlTest::standardComp comp, char* mURL) {
254     struct CompToURL {
255         Codec2AudioEncHidlTest::standardComp comp;
256         const char* mURL;
257     };
258     static const CompToURL kCompToURL[] = {
259         {Codec2AudioEncHidlTest::standardComp::aac,
260          "bbb_raw_2ch_48khz_s16le.raw"},
261         {Codec2AudioEncHidlTest::standardComp::amrnb,
262          "bbb_raw_1ch_8khz_s16le.raw"},
263         {Codec2AudioEncHidlTest::standardComp::amrwb,
264          "bbb_raw_1ch_16khz_s16le.raw"},
265         {Codec2AudioEncHidlTest::standardComp::flac,
266          "bbb_raw_2ch_48khz_s16le.raw"},
267         {Codec2AudioEncHidlTest::standardComp::opus,
268          "bbb_raw_2ch_48khz_s16le.raw"},
269     };
270 
271     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
272         if (kCompToURL[i].comp == comp) {
273             strcat(mURL, kCompToURL[i].mURL);
274             return;
275         }
276     }
277 }
278 
encodeNFrames(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,uint32_t nFrames,int32_t samplesPerFrame,int32_t nChannels,int32_t nSampleRate,bool flushed=false,bool signalEOS=true)279 void encodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
280                    std::mutex &queueLock, std::condition_variable& queueCondition,
281                    std::list<std::unique_ptr<C2Work>>& workQueue,
282                    std::list<uint64_t>& flushedIndices,
283                    std::shared_ptr<C2BlockPool>& linearPool,
284                    std::ifstream& eleStream, uint32_t nFrames,
285                    int32_t samplesPerFrame, int32_t nChannels,
286                    int32_t nSampleRate, bool flushed = false,
287                    bool signalEOS = true) {
288     typedef std::unique_lock<std::mutex> ULock;
289 
290     uint32_t frameID = 0;
291     uint32_t maxRetry = 0;
292     int bytesCount = samplesPerFrame * nChannels * 2;
293     int32_t timestampIncr =
294         (int)(((float)samplesPerFrame / nSampleRate) * 1000000);
295     uint64_t timestamp = 0;
296     while (1) {
297         if (nFrames == 0) break;
298         uint32_t flags = 0;
299         std::unique_ptr<C2Work> work;
300         // Prepare C2Work
301         while (!work && (maxRetry < MAX_RETRY)) {
302             ULock l(queueLock);
303             if (!workQueue.empty()) {
304                 work.swap(workQueue.front());
305                 workQueue.pop_front();
306             } else {
307                 queueCondition.wait_for(l, TIME_OUT);
308                 maxRetry++;
309             }
310         }
311         if (!work && (maxRetry >= MAX_RETRY)) {
312             ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
313         }
314         if (signalEOS && (nFrames == 1))
315             flags |= C2FrameData::FLAG_END_OF_STREAM;
316         if (flushed) {
317             flags |= SYNC_FRAME;
318             flushed = false;
319         }
320         work->input.flags = (C2FrameData::flags_t)flags;
321         work->input.ordinal.timestamp = timestamp;
322         work->input.ordinal.frameIndex = frameID;
323         {
324             ULock l(queueLock);
325             flushedIndices.emplace_back(frameID);
326         }
327         char* data = (char*)malloc(bytesCount);
328         ASSERT_NE(data, nullptr);
329         eleStream.read(data, bytesCount);
330         ASSERT_EQ(eleStream.gcount(), bytesCount);
331         std::shared_ptr<C2LinearBlock> block;
332         ASSERT_EQ(C2_OK, linearPool->fetchLinearBlock(
333                              bytesCount, {C2MemoryUsage::CPU_READ,
334                                           C2MemoryUsage::CPU_WRITE},
335                              &block));
336         ASSERT_TRUE(block);
337         // Write View
338         C2WriteView view = block->map().get();
339         if (view.error() != C2_OK) {
340             fprintf(stderr, "C2LinearBlock::map() failed : %d", view.error());
341             break;
342         }
343         ASSERT_EQ((size_t)bytesCount, view.capacity());
344         ASSERT_EQ(0u, view.offset());
345         ASSERT_EQ((size_t)bytesCount, view.size());
346 
347         memcpy(view.base(), data, bytesCount);
348         work->input.buffers.clear();
349         work->input.buffers.emplace_back(new LinearBuffer(block));
350         work->worklets.clear();
351         work->worklets.emplace_back(new C2Worklet);
352         free(data);
353 
354         std::list<std::unique_ptr<C2Work>> items;
355         items.push_back(std::move(work));
356 
357         // DO THE DECODING
358         ASSERT_EQ(component->queue(&items), C2_OK);
359         ALOGV("Frame #%d size = %d queued", frameID, bytesCount);
360         nFrames--;
361         timestamp += timestampIncr;
362         frameID++;
363         maxRetry = 0;
364     }
365 }
366 
TEST_F(Codec2AudioEncHidlTest,validateCompName)367 TEST_F(Codec2AudioEncHidlTest, validateCompName) {
368     if (mDisableTest) return;
369     ALOGV("Checks if the given component is a valid audio component");
370     validateComponent(mComponent, mCompName, mDisableTest);
371     ASSERT_EQ(mDisableTest, false);
372 }
373 
374 class Codec2AudioEncEncodeTest
375     : public Codec2AudioEncHidlTest,
376       public ::testing::WithParamInterface<std::pair<bool, int32_t>> {
377 };
378 
TEST_P(Codec2AudioEncEncodeTest,EncodeTest)379 TEST_P(Codec2AudioEncEncodeTest, EncodeTest) {
380     ALOGV("EncodeTest");
381     if (mDisableTest) return;
382     char mURL[512];
383     strcpy(mURL, gEnv->getRes().c_str());
384     GetURLForComponent(mCompName, mURL);
385     bool signalEOS = GetParam().first;
386     // Ratio w.r.t to mInputMaxBufSize
387     int32_t inputMaxBufRatio = GetParam().second;
388 
389     // Setting default sampleRate
390     int32_t nChannels = 2;
391     int32_t nSampleRate = 44100;
392     switch (mCompName) {
393         case aac:
394             nChannels = 2;
395             nSampleRate = 48000;
396             break;
397         case flac:
398             nChannels = 2;
399             nSampleRate = 48000;
400             break;
401         case opus:
402             nChannels = 2;
403             nSampleRate = 48000;
404             break;
405         case amrnb:
406             nChannels = 1;
407             nSampleRate = 8000;
408             break;
409         case amrwb:
410             nChannels = 1;
411             nSampleRate = 16000;
412             break;
413         default:
414             ASSERT_TRUE(false);
415     }
416     int32_t samplesPerFrame =
417         ((mInputMaxBufSize / inputMaxBufRatio) / (nChannels * 2));
418     ALOGV("signalEOS %d mInputMaxBufSize %d samplesPerFrame %d", signalEOS,
419           mInputMaxBufSize, samplesPerFrame);
420 
421     if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
422         std::cout << "[   WARN   ] Test Skipped \n";
423         return;
424     }
425     ASSERT_EQ(mComponent->start(), C2_OK);
426     std::ifstream eleStream;
427     uint32_t numFrames = 16;
428     eleStream.open(mURL, std::ifstream::binary);
429     ASSERT_EQ(eleStream.is_open(), true);
430     ALOGV("mURL : %s", mURL);
431     ASSERT_NO_FATAL_FAILURE(
432         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
433                       mFlushedIndices, mLinearPool, eleStream, numFrames,
434                       samplesPerFrame, nChannels, nSampleRate, false,
435                       signalEOS));
436 
437     // If EOS is not sent, sending empty input with EOS flag
438     if (!signalEOS) {
439         ASSERT_NO_FATAL_FAILURE(
440             waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
441         ASSERT_NO_FATAL_FAILURE(
442             testInputBuffer(mComponent, mQueueLock, mWorkQueue,
443                             C2FrameData::FLAG_END_OF_STREAM, false));
444         numFrames += 1;
445     }
446 
447     // blocking call to ensures application to Wait till all the inputs are
448     // consumed
449     ASSERT_NO_FATAL_FAILURE(
450         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
451     eleStream.close();
452     if (mFramesReceived != numFrames) {
453         ALOGE("Input buffer count and Output buffer count mismatch");
454         ALOGE("framesReceived : %d inputFrames : %u", mFramesReceived, numFrames);
455         ASSERT_TRUE(false);
456     }
457     if ((mCompName == flac || mCompName == opus || mCompName == aac)) {
458         if (!mCsd) {
459             ALOGE("CSD buffer missing");
460             ASSERT_TRUE(false);
461         }
462     }
463     ASSERT_EQ(mEos, true);
464     ASSERT_EQ(mComponent->stop(), C2_OK);
465 }
466 
467 // EncodeTest with EOS / No EOS and inputMaxBufRatio
468 // inputMaxBufRatio is ratio w.r.t. to mInputMaxBufSize
469 INSTANTIATE_TEST_CASE_P(EncodeTest, Codec2AudioEncEncodeTest,
470                         ::testing::Values(std::make_pair(false, 1),
471                                           std::make_pair(false, 2),
472                                           std::make_pair(true, 1),
473                                           std::make_pair(true, 2)));
474 
475 
TEST_F(Codec2AudioEncHidlTest,EOSTest)476 TEST_F(Codec2AudioEncHidlTest, EOSTest) {
477     description("Test empty input buffer with EOS flag");
478     if (mDisableTest) return;
479     ASSERT_EQ(mComponent->start(), C2_OK);
480 
481     typedef std::unique_lock<std::mutex> ULock;
482     std::unique_ptr<C2Work> work;
483     {
484         ULock l(mQueueLock);
485         if (!mWorkQueue.empty()) {
486             work.swap(mWorkQueue.front());
487             mWorkQueue.pop_front();
488         } else {
489             ALOGE("mWorkQueue Empty is not expected at the start of the test");
490             ASSERT_TRUE(false);
491         }
492     }
493     ASSERT_NE(work, nullptr);
494     work->input.flags = (C2FrameData::flags_t)C2FrameData::FLAG_END_OF_STREAM;
495     work->input.ordinal.timestamp = 0;
496     work->input.ordinal.frameIndex = 0;
497     work->input.buffers.clear();
498     work->worklets.clear();
499     work->worklets.emplace_back(new C2Worklet);
500 
501     std::list<std::unique_ptr<C2Work>> items;
502     items.push_back(std::move(work));
503     ASSERT_EQ(mComponent->queue(&items), C2_OK);
504     uint32_t queueSize;
505     {
506         ULock l(mQueueLock);
507         queueSize = mWorkQueue.size();
508         if (queueSize < MAX_INPUT_BUFFERS) {
509             mQueueCondition.wait_for(l, TIME_OUT);
510         }
511     }
512     ASSERT_EQ(mEos, true);
513     ASSERT_EQ(mComponent->stop(), C2_OK);
514 }
515 
TEST_F(Codec2AudioEncHidlTest,FlushTest)516 TEST_F(Codec2AudioEncHidlTest, FlushTest) {
517     description("Test Request for flush");
518     if (mDisableTest) return;
519 
520     typedef std::unique_lock<std::mutex> ULock;
521     char mURL[512];
522     strcpy(mURL, gEnv->getRes().c_str());
523     GetURLForComponent(mCompName, mURL);
524 
525     // Setting default configuration
526     mFlushedIndices.clear();
527     int32_t nChannels = 2;
528     int32_t nSampleRate = 44100;
529     int32_t samplesPerFrame = 1024;
530     switch (mCompName) {
531         case aac:
532             nChannels = 2;
533             nSampleRate = 48000;
534             samplesPerFrame = 1024;
535             break;
536         case flac:
537             nChannels = 2;
538             nSampleRate = 48000;
539             samplesPerFrame = 1152;
540             break;
541         case opus:
542             nChannels = 2;
543             nSampleRate = 48000;
544             samplesPerFrame = 960;
545             break;
546         case amrnb:
547             nChannels = 1;
548             nSampleRate = 8000;
549             samplesPerFrame = 160;
550             break;
551         case amrwb:
552             nChannels = 1;
553             nSampleRate = 16000;
554             samplesPerFrame = 160;
555             break;
556         default:
557             ASSERT_TRUE(false);
558     }
559 
560     if (!setupConfigParam(mComponent, nChannels, nSampleRate)) {
561         std::cout << "[   WARN   ] Test Skipped \n";
562         return;
563     }
564     ASSERT_EQ(mComponent->start(), C2_OK);
565 
566     std::ifstream eleStream;
567     uint32_t numFramesFlushed = 30;
568     uint32_t numFrames = 128;
569     eleStream.open(mURL, std::ifstream::binary);
570     ASSERT_EQ(eleStream.is_open(), true);
571     ALOGV("mURL : %s", mURL);
572     ASSERT_NO_FATAL_FAILURE(
573         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
574                       mFlushedIndices, mLinearPool, eleStream, numFramesFlushed,
575                       samplesPerFrame, nChannels, nSampleRate));
576     std::list<std::unique_ptr<C2Work>> flushedWork;
577     c2_status_t err =
578         mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
579     ASSERT_EQ(err, C2_OK);
580     ASSERT_NO_FATAL_FAILURE(
581         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
582             (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
583     uint64_t frameIndex;
584     {
585         //Update mFlushedIndices based on the index received from flush()
586         ULock l(mQueueLock);
587         for (std::unique_ptr<C2Work>& work : flushedWork) {
588             ASSERT_NE(work, nullptr);
589             frameIndex = work->input.ordinal.frameIndex.peeku();
590             std::list<uint64_t>::iterator frameIndexIt =
591                 std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
592                           frameIndex);
593             if (!mFlushedIndices.empty() &&
594                 (frameIndexIt != mFlushedIndices.end())) {
595                 mFlushedIndices.erase(frameIndexIt);
596                 work->input.buffers.clear();
597                 work->worklets.clear();
598                 mWorkQueue.push_back(std::move(work));
599             }
600         }
601     }
602     mFlushedIndices.clear();
603     ASSERT_NO_FATAL_FAILURE(
604         encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
605                       mFlushedIndices, mLinearPool, eleStream,
606                       numFrames - numFramesFlushed, samplesPerFrame,
607                       nChannels, nSampleRate, true));
608     eleStream.close();
609     err =
610         mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
611     ASSERT_EQ(err, C2_OK);
612     ASSERT_NO_FATAL_FAILURE(
613         waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue,
614             (size_t)MAX_INPUT_BUFFERS - flushedWork.size()));
615     {
616         //Update mFlushedIndices based on the index received from flush()
617         ULock l(mQueueLock);
618         for (std::unique_ptr<C2Work>& work : flushedWork) {
619             ASSERT_NE(work, nullptr);
620             frameIndex = work->input.ordinal.frameIndex.peeku();
621             std::list<uint64_t>::iterator frameIndexIt =
622                 std::find(mFlushedIndices.begin(), mFlushedIndices.end(),
623                           frameIndex);
624             if (!mFlushedIndices.empty() &&
625                 (frameIndexIt != mFlushedIndices.end())) {
626                 mFlushedIndices.erase(frameIndexIt);
627                 work->input.buffers.clear();
628                 work->worklets.clear();
629                 mWorkQueue.push_back(std::move(work));
630             }
631         }
632     }
633     ASSERT_EQ(mFlushedIndices.empty(), true);
634     ASSERT_EQ(mComponent->stop(), C2_OK);
635 }
636 
637 }  // anonymous namespace
638 
main(int argc,char ** argv)639 int main(int argc, char** argv) {
640     gEnv = new ComponentTestEnvironment();
641     ::testing::AddGlobalTestEnvironment(gEnv);
642     ::testing::InitGoogleTest(&argc, argv);
643     gEnv->init(&argc, argv);
644     int status = gEnv->initFromOptions(argc, argv);
645     if (status == 0) {
646         int status = RUN_ALL_TESTS();
647         LOG(INFO) << "C2 Test result = " << status;
648     }
649     return status;
650 }
651