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