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_component_test"
19
20 #include <android-base/logging.h>
21 #include <gtest/gtest.h>
22
23 #include <C2Config.h>
24 #include <codec2/hidl/client.h>
25
26 #include <VtsHalHidlTargetTestBase.h>
27 #include "media_c2_hidl_test_common.h"
28
29 static ComponentTestEnvironment* gEnv = nullptr;
30
31 namespace {
32
33 // google.codec2 Component test setup
34 class Codec2ComponentHidlTest : public ::testing::VtsHalHidlTargetTestBase {
35 private:
36 typedef ::testing::VtsHalHidlTargetTestBase Super;
37
38 public:
SetUp()39 virtual void SetUp() override {
40 Super::SetUp();
41 mEos = false;
42 mClient = android::Codec2Client::CreateFromService(
43 gEnv->getInstance().c_str());
44 ASSERT_NE(mClient, nullptr);
45 mListener.reset(new CodecListener(
46 [this](std::list<std::unique_ptr<C2Work>>& workItems) {
47 handleWorkDone(workItems);
48 }));
49 ASSERT_NE(mListener, nullptr);
50 mClient->createComponent(gEnv->getComponent().c_str(), mListener,
51 &mComponent);
52 ASSERT_NE(mComponent, nullptr);
53 for (int i = 0; i < MAX_INPUT_BUFFERS; ++i) {
54 mWorkQueue.emplace_back(new C2Work);
55 }
56 }
57
TearDown()58 virtual void TearDown() override {
59 if (mComponent != nullptr) {
60 // If you have encountered a fatal failure, it is possible that
61 // freeNode() will not go through. Instead of hanging the app.
62 // let it pass through and report errors
63 if (::testing::Test::HasFatalFailure()) return;
64 mComponent->release();
65 mComponent = nullptr;
66 }
67 Super::TearDown();
68 }
69 // callback function to process onWorkDone received by Listener
handleWorkDone(std::list<std::unique_ptr<C2Work>> & workItems)70 void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
71 for (std::unique_ptr<C2Work>& work : workItems) {
72 if (!work->worklets.empty()) {
73 bool mCsd = false;
74 uint32_t mFramesReceived = 0;
75 std::list<uint64_t> mFlushedIndices;
76 workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition,
77 mWorkQueue, mEos, mCsd, mFramesReceived);
78 }
79 }
80 }
81
82 bool mEos;
83 std::mutex mQueueLock;
84 std::condition_variable mQueueCondition;
85 std::list<std::unique_ptr<C2Work>> mWorkQueue;
86
87 std::shared_ptr<android::Codec2Client> mClient;
88 std::shared_ptr<android::Codec2Client::Listener> mListener;
89 std::shared_ptr<android::Codec2Client::Component> mComponent;
90
91 protected:
description(const std::string & description)92 static void description(const std::string& description) {
93 RecordProperty("description", description);
94 }
95 };
96
97 // Test Empty Flush
TEST_F(Codec2ComponentHidlTest,EmptyFlush)98 TEST_F(Codec2ComponentHidlTest, EmptyFlush) {
99 ALOGV("Empty Flush Test");
100 c2_status_t err = mComponent->start();
101 ASSERT_EQ(err, C2_OK);
102
103 std::list<std::unique_ptr<C2Work>> flushedWork;
104 err = mComponent->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
105 ASSERT_EQ(err, C2_OK);
106
107 err = mComponent->stop();
108 ASSERT_EQ(err, C2_OK);
109 // Empty Flush should not return any work
110 ASSERT_EQ(flushedWork.size(), 0u);
111 }
112
113 // Test Queue Empty Work
TEST_F(Codec2ComponentHidlTest,QueueEmptyWork)114 TEST_F(Codec2ComponentHidlTest, QueueEmptyWork) {
115 ALOGV("Queue Empty Work Test");
116 c2_status_t err = mComponent->start();
117 ASSERT_EQ(err, C2_OK);
118
119 // Queueing an empty WorkBundle
120 std::list<std::unique_ptr<C2Work>> workList;
121 err = mComponent->queue(&workList);
122 ASSERT_EQ(err, C2_OK);
123
124 err = mComponent->reset();
125 ASSERT_EQ(err, C2_OK);
126 }
127
128 // Test Component Configuration
TEST_F(Codec2ComponentHidlTest,Config)129 TEST_F(Codec2ComponentHidlTest, Config) {
130 ALOGV("Configuration Test");
131
132 C2String name = mComponent->getName();
133 EXPECT_NE(name.empty(), true) << "Invalid Component Name";
134
135 c2_status_t err = C2_OK;
136 std::vector<std::unique_ptr<C2Param>> queried;
137 std::vector<std::unique_ptr<C2SettingResult>> failures;
138
139 // Query supported params by the component
140 std::vector<std::shared_ptr<C2ParamDescriptor>> params;
141 err = mComponent->querySupportedParams(¶ms);
142 ASSERT_EQ(err, C2_OK);
143 ALOGV("Number of total params - %zu", params.size());
144
145 // Query and config all the supported params
146 for (std::shared_ptr<C2ParamDescriptor> p : params) {
147 ALOGD("Querying index %d", (int)p->index());
148 err = mComponent->query({}, {p->index()}, C2_DONT_BLOCK, &queried);
149 EXPECT_NE(queried.size(), 0u);
150 EXPECT_EQ(err, C2_OK);
151 err = mComponent->config({queried[0].get()}, C2_DONT_BLOCK, &failures);
152 ASSERT_EQ(err, C2_OK);
153 ASSERT_EQ(failures.size(), 0u);
154 }
155 }
156
157 // Test Multiple Start Stop Reset Test
TEST_F(Codec2ComponentHidlTest,MultipleStartStopReset)158 TEST_F(Codec2ComponentHidlTest, MultipleStartStopReset) {
159 ALOGV("Multiple Start Stop and Reset Test");
160 c2_status_t err = C2_OK;
161
162 for (size_t i = 0; i < MAX_RETRY; i++) {
163 err = mComponent->start();
164 ASSERT_EQ(err, C2_OK);
165
166 err = mComponent->stop();
167 ASSERT_EQ(err, C2_OK);
168 }
169
170 err = mComponent->start();
171 ASSERT_EQ(err, C2_OK);
172
173 for (size_t i = 0; i < MAX_RETRY; i++) {
174 err = mComponent->reset();
175 ASSERT_EQ(err, C2_OK);
176 }
177
178 err = mComponent->start();
179 ASSERT_EQ(err, C2_OK);
180
181 err = mComponent->stop();
182 ASSERT_EQ(err, C2_OK);
183
184 // Second stop should return error
185 err = mComponent->stop();
186 ASSERT_NE(err, C2_OK);
187 }
188
189 // Test Component Release API
TEST_F(Codec2ComponentHidlTest,MultipleRelease)190 TEST_F(Codec2ComponentHidlTest, MultipleRelease) {
191 ALOGV("Multiple Release Test");
192 c2_status_t err = mComponent->start();
193 ASSERT_EQ(err, C2_OK);
194
195 // Query Component Domain Type
196 std::vector<std::unique_ptr<C2Param>> queried;
197 err = mComponent->query({}, {C2PortMediaTypeSetting::input::PARAM_TYPE},
198 C2_DONT_BLOCK, &queried);
199 EXPECT_NE(queried.size(), 0u);
200
201 // Configure Component Domain
202 std::vector<std::unique_ptr<C2SettingResult>> failures;
203 C2PortMediaTypeSetting::input* portMediaType =
204 C2PortMediaTypeSetting::input::From(queried[0].get());
205 err = mComponent->config({portMediaType}, C2_DONT_BLOCK, &failures);
206 ASSERT_EQ(err, C2_OK);
207 ASSERT_EQ(failures.size(), 0u);
208
209 for (size_t i = 0; i < MAX_RETRY; i++) {
210 err = mComponent->release();
211 ASSERT_EQ(err, C2_OK);
212 }
213 }
214
215 class Codec2ComponentInputTests : public Codec2ComponentHidlTest,
216 public ::testing::WithParamInterface<std::pair<uint32_t, bool> > {
217 };
218
TEST_P(Codec2ComponentInputTests,InputBufferTest)219 TEST_P(Codec2ComponentInputTests, InputBufferTest) {
220 description("Tests for different inputs");
221
222 uint32_t flags = GetParam().first;
223 bool isNullBuffer = GetParam().second;
224 if (isNullBuffer) ALOGD("Testing for null input buffer with flag : %u", flags);
225 else ALOGD("Testing for empty input buffer with flag : %u", flags);
226 mEos = false;
227 ASSERT_EQ(mComponent->start(), C2_OK);
228 ASSERT_NO_FATAL_FAILURE(testInputBuffer(
229 mComponent, mQueueLock, mWorkQueue, flags, isNullBuffer));
230
231 ALOGD("Waiting for input consumption");
232 ASSERT_NO_FATAL_FAILURE(
233 waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue));
234
235 if (flags == C2FrameData::FLAG_END_OF_STREAM) ASSERT_EQ(mEos, true);
236 ASSERT_EQ(mComponent->stop(), C2_OK);
237 ASSERT_EQ(mComponent->reset(), C2_OK);
238 }
239
240 INSTANTIATE_TEST_CASE_P(NonStdInputs, Codec2ComponentInputTests, ::testing::Values(
241 std::make_pair(0, true),
242 std::make_pair(C2FrameData::FLAG_END_OF_STREAM, true),
243 std::make_pair(0, false),
244 std::make_pair(C2FrameData::FLAG_CODEC_CONFIG, false),
245 std::make_pair(C2FrameData::FLAG_END_OF_STREAM, false)));
246
247 } // anonymous namespace
248
249 // TODO: Add test for Invalid work,
250 // TODO: Add test for Invalid states
main(int argc,char ** argv)251 int main(int argc, char** argv) {
252 gEnv = new ComponentTestEnvironment();
253 ::testing::AddGlobalTestEnvironment(gEnv);
254 ::testing::InitGoogleTest(&argc, argv);
255 gEnv->init(&argc, argv);
256 int status = gEnv->initFromOptions(argc, argv);
257 if (status == 0) {
258 status = RUN_ALL_TESTS();
259 LOG(INFO) << "C2 Test result = " << status;
260 }
261 return status;
262 }
263