1 /*
2 * Copyright 2020 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 #include "FilterTests.h"
18
startFilterEventThread(DemuxFilterEvent event)19 void FilterCallback::startFilterEventThread(DemuxFilterEvent event) {
20 struct FilterThreadArgs* threadArgs =
21 (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
22 threadArgs->user = this;
23 threadArgs->event = event;
24
25 pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
26 pthread_setname_np(mFilterThread, "test_playback_input_loop");
27 }
28
testFilterDataOutput()29 void FilterCallback::testFilterDataOutput() {
30 android::Mutex::Autolock autoLock(mMsgLock);
31 while (mPidFilterOutputCount < 1) {
32 if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
33 EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
34 return;
35 }
36 }
37 mPidFilterOutputCount = 0;
38 ALOGW("[vts] pass and stop");
39 }
40
updateFilterMQ(MQDesc & filterMQDescriptor)41 void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) {
42 mFilterMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
43 EXPECT_TRUE(mFilterMQ);
44 EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) ==
45 android::OK);
46 }
47
updateGoldenOutputMap(string goldenOutputFile)48 void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) {
49 mFilterIdToGoldenOutput = goldenOutputFile;
50 }
51
__threadLoopFilter(void * threadArgs)52 void* FilterCallback::__threadLoopFilter(void* threadArgs) {
53 FilterCallback* const self =
54 static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
55 self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
56 return 0;
57 }
58
filterThreadLoop(DemuxFilterEvent &)59 void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
60 android::Mutex::Autolock autoLock(mFilterOutputLock);
61 // Read from mFilterMQ[event.filterId] per event and filter type
62
63 // Assemble to filterOutput[filterId]
64
65 // check if filterOutput[filterId] matches goldenOutput[filterId]
66
67 // If match, remove filterId entry from MQ map
68
69 // end thread
70 }
71
readFilterEventData()72 bool FilterCallback::readFilterEventData() {
73 bool result = false;
74 DemuxFilterEvent filterEvent = mFilterEvent;
75 ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
76 // todo separate filter handlers
77 for (auto event : filterEvent.events) {
78 switch (event.getDiscriminator()) {
79 case DemuxFilterEvent::Event::hidl_discriminator::section:
80 mDataLength = event.section().dataLength;
81 break;
82 case DemuxFilterEvent::Event::hidl_discriminator::pes:
83 mDataLength = event.pes().dataLength;
84 break;
85 case DemuxFilterEvent::Event::hidl_discriminator::media:
86 return dumpAvData(event.media());
87 case DemuxFilterEvent::Event::hidl_discriminator::tsRecord:
88 return readRecordData(event.tsRecord());
89 default:
90 continue;
91 }
92 // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
93 // match";
94 if (mFilterMQ != NULL) {
95 mDataOutputBuffer.resize(mDataLength);
96 result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength);
97 EXPECT_TRUE(result) << "can't read from Filter MQ";
98 }
99
100 /*for (int i = 0; i < mDataLength; i++) {
101 EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
102 }*/
103 }
104 if (mFilterMQ != NULL) {
105 mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
106 }
107 return result;
108 }
109
dumpAvData(DemuxFilterMediaEvent event)110 bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
111 uint32_t length = event.dataLength;
112 uint64_t dataId = event.avDataId;
113 // read data from buffer pointed by a handle
114 hidl_handle handle = event.avMemory;
115
116 int av_fd = handle.getNativeHandle()->data[0];
117 uint8_t* buffer = static_cast<uint8_t*>(
118 mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/));
119 if (buffer == MAP_FAILED) {
120 ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
121 return false;
122 }
123 uint8_t output[length + 1];
124 memcpy(output, buffer, length);
125 // print buffer and check with golden output.
126 EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS);
127 return true;
128 }
129
readRecordData(DemuxFilterTsRecordEvent event)130 bool FilterCallback::readRecordData(DemuxFilterTsRecordEvent event) {
131 ALOGD("[vts] got DemuxFilterTsRecordEvent with pid=%d.", event.pid.tPid());
132 return true;
133 }
134
openFilterInDemux(DemuxFilterType type,uint32_t bufferSize)135 AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
136 Result status;
137 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
138
139 // Create demux callback
140 mFilterCallback = new FilterCallback();
141
142 // Add filter to the local demux
143 mDemux->openFilter(type, bufferSize, mFilterCallback,
144 [&](Result result, const sp<IFilter>& filter) {
145 mFilter = filter;
146 status = result;
147 });
148 return AssertionResult(status == Result::SUCCESS);
149 }
150
openTimeFilterInDemux()151 AssertionResult FilterTests::openTimeFilterInDemux() {
152 if (!mDemux) {
153 ALOGW("[vts] Test with openDemux first.");
154 return failure();
155 }
156
157 // Add time filter to the local demux
158 Result status;
159 mDemux->openTimeFilter([&](Result result, const sp<ITimeFilter>& filter) {
160 mTimeFilter = filter;
161 status = result;
162 });
163
164 return AssertionResult(status == Result::SUCCESS);
165 }
166
setTimeStamp(uint64_t timeStamp)167 AssertionResult FilterTests::setTimeStamp(uint64_t timeStamp) {
168 if (!mTimeFilter) {
169 ALOGW("[vts] Test with openTimeFilterInDemux first.");
170 return failure();
171 }
172
173 mBeginTimeStamp = timeStamp;
174 return AssertionResult(mTimeFilter->setTimeStamp(timeStamp) == Result::SUCCESS);
175 }
176
getTimeStamp()177 AssertionResult FilterTests::getTimeStamp() {
178 if (!mTimeFilter) {
179 ALOGW("[vts] Test with openTimeFilterInDemux first.");
180 return failure();
181 }
182
183 Result status;
184 mTimeFilter->getTimeStamp([&](Result result, uint64_t /*timeStamp*/) { status = result; });
185
186 return AssertionResult(status == Result::SUCCESS);
187 }
188
getNewlyOpenedFilterId(uint32_t & filterId)189 AssertionResult FilterTests::getNewlyOpenedFilterId(uint32_t& filterId) {
190 Result status;
191 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
192 EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first.";
193 EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first.";
194
195 mFilter->getId([&](Result result, uint32_t filterId) {
196 mFilterId = filterId;
197 status = result;
198 });
199
200 if (status == Result::SUCCESS) {
201 mFilterCallback->setFilterId(mFilterId);
202 mFilterCallback->setFilterInterface(mFilter);
203 mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
204 mFilters[mFilterId] = mFilter;
205 mFilterCallbacks[mFilterId] = mFilterCallback;
206 filterId = mFilterId;
207 }
208
209 return AssertionResult(status == Result::SUCCESS);
210 }
211
configFilter(DemuxFilterSettings setting,uint32_t filterId)212 AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint32_t filterId) {
213 Result status;
214 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
215 status = mFilters[filterId]->configure(setting);
216
217 return AssertionResult(status == Result::SUCCESS);
218 }
219
getFilterMQDescriptor(uint32_t filterId,bool getMqDesc)220 AssertionResult FilterTests::getFilterMQDescriptor(uint32_t filterId, bool getMqDesc) {
221 if (!getMqDesc) {
222 ALOGE("[vts] Filter does not need FMQ.");
223 return success();
224 }
225 Result status;
226 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
227 EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
228
229 mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
230 mFilterMQDescriptor = filterMQDesc;
231 status = result;
232 });
233
234 if (status == Result::SUCCESS) {
235 mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor);
236 }
237
238 return AssertionResult(status == Result::SUCCESS);
239 }
240
setFilterDataSource(uint32_t sourceFilterId,uint32_t sinkFilterId)241 AssertionResult FilterTests::setFilterDataSource(uint32_t sourceFilterId, uint32_t sinkFilterId) {
242 if (!mFilters[sourceFilterId] || !mFilters[sinkFilterId]) {
243 ALOGE("[vts] setFilterDataSource filter not opened.");
244 return failure();
245 }
246
247 auto status = mFilters[sinkFilterId]->setDataSource(mFilters[sourceFilterId]);
248 return AssertionResult(status == Result::SUCCESS);
249 }
250
setFilterDataSourceToDemux(uint32_t filterId)251 AssertionResult FilterTests::setFilterDataSourceToDemux(uint32_t filterId) {
252 if (!mFilters[filterId]) {
253 ALOGE("[vts] setFilterDataSourceToDemux filter not opened.");
254 return failure();
255 }
256
257 auto status = mFilters[filterId]->setDataSource(NULL);
258 return AssertionResult(status == Result::SUCCESS);
259 }
260
startFilter(uint32_t filterId)261 AssertionResult FilterTests::startFilter(uint32_t filterId) {
262 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
263 Result status = mFilters[filterId]->start();
264 return AssertionResult(status == Result::SUCCESS);
265 }
266
stopFilter(uint32_t filterId)267 AssertionResult FilterTests::stopFilter(uint32_t filterId) {
268 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
269 Result status = mFilters[filterId]->stop();
270 return AssertionResult(status == Result::SUCCESS);
271 }
272
clearTimeStamp()273 AssertionResult FilterTests::clearTimeStamp() {
274 if (!mTimeFilter) {
275 ALOGW("[vts] Test with openTimeFilterInDemux first.");
276 return failure();
277 }
278
279 return AssertionResult(mTimeFilter->clearTimeStamp() == Result::SUCCESS);
280 }
281
closeFilter(uint32_t filterId)282 AssertionResult FilterTests::closeFilter(uint32_t filterId) {
283 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
284 Result status = mFilters[filterId]->close();
285 for (int i = 0; i < mUsedFilterIds.size(); i++) {
286 if (mUsedFilterIds[i] == filterId) {
287 mUsedFilterIds.erase(mUsedFilterIds.begin() + i);
288 break;
289 }
290 }
291 mFilterCallbacks.erase(filterId);
292 mFilters.erase(filterId);
293 return AssertionResult(status == Result::SUCCESS);
294 }
295
closeTimeFilter()296 AssertionResult FilterTests::closeTimeFilter() {
297 if (!mTimeFilter) {
298 ALOGW("[vts] Test with openTimeFilterInDemux first.");
299 return failure();
300 }
301
302 return AssertionResult(mTimeFilter->close() == Result::SUCCESS);
303 }
304