1 /*
2 * Copyright 2021 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
19 #include <inttypes.h>
20 #include <algorithm>
21
22 #include <aidl/android/hardware/tv/tuner/DemuxFilterMonitorEventType.h>
23 #include <aidlcommonsupport/NativeHandle.h>
24
25 using ::aidl::android::hardware::common::NativeHandle;
26
onFilterEvent(const vector<DemuxFilterEvent> & events)27 ::ndk::ScopedAStatus FilterCallback::onFilterEvent(const vector<DemuxFilterEvent>& events) {
28 android::Mutex::Autolock autoLock(mMsgLock);
29 // Temprarily we treat the first coming back filter data on the matching pid a success
30 // once all of the MQ are cleared, means we got all the expected output
31 readFilterEventsData(events);
32 mPidFilterOutputCount++;
33 mMsgCondition.signal();
34
35 for (auto it = mFilterCallbackVerifiers.begin(); it != mFilterCallbackVerifiers.end();) {
36 auto& [verifier, promise] = *it;
37 if (verifier(events)) {
38 promise.set_value();
39 it = mFilterCallbackVerifiers.erase(it);
40 } else {
41 ++it;
42 }
43 };
44
45 return ::ndk::ScopedAStatus::ok();
46 }
47
verifyFilterCallback(FilterCallbackVerifier && verifier)48 std::future<void> FilterCallback::verifyFilterCallback(FilterCallbackVerifier&& verifier) {
49 std::promise<void> promise;
50 auto future = promise.get_future();
51 mFilterCallbackVerifiers.emplace_back(std::move(verifier), std::move(promise));
52 return future;
53 }
54
testFilterDataOutput()55 void FilterCallback::testFilterDataOutput() {
56 android::Mutex::Autolock autoLock(mMsgLock);
57 while (mPidFilterOutputCount < 1) {
58 if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
59 EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
60 return;
61 }
62 }
63 mPidFilterOutputCount = 0;
64 ALOGW("[vts] pass and stop");
65 }
66
testFilterScramblingEvent()67 void FilterCallback::testFilterScramblingEvent() {
68 android::Mutex::Autolock autoLock(mMsgLock);
69 while (mScramblingStatusEvent < 1) {
70 if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
71 EXPECT_TRUE(false) << "scrambling event does not output within timeout";
72 return;
73 }
74 }
75 mScramblingStatusEvent = 0;
76 ALOGW("[vts] pass and stop");
77 }
78
testFilterIpCidEvent()79 void FilterCallback::testFilterIpCidEvent() {
80 android::Mutex::Autolock autoLock(mMsgLock);
81 while (mIpCidEvent < 1) {
82 if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
83 EXPECT_TRUE(false) << "ip cid change event does not output within timeout";
84 return;
85 }
86 }
87 mIpCidEvent = 0;
88 ALOGW("[vts] pass and stop");
89 }
90
testStartIdAfterReconfigure()91 void FilterCallback::testStartIdAfterReconfigure() {
92 android::Mutex::Autolock autoLock(mMsgLock);
93 while (!mStartIdReceived) {
94 if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
95 EXPECT_TRUE(false) << "does not receive start id within timeout";
96 return;
97 }
98 }
99 mStartIdReceived = false;
100 ALOGW("[vts] pass and stop");
101 }
102
readFilterEventsData(const vector<DemuxFilterEvent> & events)103 void FilterCallback::readFilterEventsData(const vector<DemuxFilterEvent>& events) {
104 ALOGW("[vts] reading filter event");
105 // todo separate filter handlers
106 for (int i = 0; i < events.size(); i++) {
107 switch (events[i].getTag()) {
108 case DemuxFilterEvent::Tag::media: {
109 int numDataPieces = events[i].get<DemuxFilterEvent::Tag::media>().numDataPieces;
110 int indexInDataGroup
111 = events[i].get<DemuxFilterEvent::Tag::media>().indexInDataGroup;
112 ALOGD("[vts] Media filter event, avMemHandle numFds=%zu, numDataPieces=%d,"
113 " indexInDataGroup=%d, dataGroupId=%d.",
114 events[i].get<DemuxFilterEvent::Tag::media>().avMemory.fds.size(),
115 numDataPieces,
116 indexInDataGroup,
117 events[i].get<DemuxFilterEvent::Tag::media>().dataGroupId);
118 if (numDataPieces > 1) {
119 EXPECT_TRUE(indexInDataGroup >= 0);
120 EXPECT_TRUE(indexInDataGroup < numDataPieces);
121 }
122 dumpAvData(events[i].get<DemuxFilterEvent::Tag::media>());
123 break;
124 }
125 case DemuxFilterEvent::Tag::tsRecord: {
126 ALOGD("[vts] TS record filter event, pts=%" PRIu64 ", firstMbInSlice=%d",
127 events[i].get<DemuxFilterEvent::Tag::tsRecord>().pts,
128 events[i].get<DemuxFilterEvent::Tag::tsRecord>().firstMbInSlice);
129 break;
130 }
131 case DemuxFilterEvent::Tag::mmtpRecord: {
132 ALOGD("[vts] MMTP record filter event, pts=%" PRIu64
133 ", firstMbInSlice=%d, mpuSequenceNumber=%d, tsIndexMask=%d",
134 events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().pts,
135 events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().firstMbInSlice,
136 events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().mpuSequenceNumber,
137 events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().tsIndexMask);
138 break;
139 }
140 case DemuxFilterEvent::Tag::monitorEvent: {
141 switch (events[i].get<DemuxFilterEvent::Tag::monitorEvent>().getTag()) {
142 case DemuxFilterMonitorEvent::Tag::scramblingStatus:
143 mScramblingStatusEvent++;
144 break;
145 case DemuxFilterMonitorEvent::Tag::cid:
146 mIpCidEvent++;
147 break;
148 default:
149 break;
150 }
151 break;
152 }
153 case DemuxFilterEvent::Tag::startId: {
154 ALOGD("[vts] Restart filter event, startId=%d",
155 events[i].get<DemuxFilterEvent::Tag::startId>());
156 mStartIdReceived = true;
157 break;
158 }
159 default: {
160 break;
161 }
162 }
163 }
164 }
165
dumpAvData(const DemuxFilterMediaEvent & event)166 bool FilterCallback::dumpAvData(const DemuxFilterMediaEvent& event) {
167 int64_t length = event.dataLength;
168 int64_t offset = event.offset;
169 int av_fd;
170 // read data from buffer pointed by a handle
171 if (event.avMemory.fds.size() == 0) {
172 if (mAvSharedHandle == nullptr) {
173 return false;
174 }
175 av_fd = mAvSharedHandle->data[0];
176 } else {
177 av_fd = event.avMemory.fds[0].get();
178 }
179 uint8_t* buffer = static_cast<uint8_t*>(
180 mmap(NULL, length + offset, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0));
181 if (buffer == MAP_FAILED) {
182 ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
183 return false;
184 }
185 uint8_t output[length + 1];
186 memcpy(output, buffer + offset, length);
187 // print buffer and check with golden output.
188 return true;
189 }
190
openFilterInDemux(DemuxFilterType type,int32_t bufferSize)191 AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, int32_t bufferSize) {
192 ndk::ScopedAStatus status;
193 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
194
195 // Create demux callback
196 mFilterCallback = ndk::SharedRefBase::make<FilterCallback>();
197
198 // Add filter to the local demux
199 status = mDemux->openFilter(type, bufferSize, mFilterCallback, &mFilter);
200
201 return AssertionResult(status.isOk());
202 }
203
getNewlyOpenedFilterId_64bit(int64_t & filterId)204 AssertionResult FilterTests::getNewlyOpenedFilterId_64bit(int64_t& filterId) {
205 ndk::ScopedAStatus status;
206 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
207 EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first.";
208 EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first.";
209
210 status = mFilter->getId64Bit(&mFilterId);
211 if (status.isOk()) {
212 mFilterCallback->setFilterId(mFilterId);
213 mFilterCallback->setFilterInterface(mFilter);
214 mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
215 mFilters[mFilterId] = mFilter;
216 mFilterCallbacks[mFilterId] = mFilterCallback;
217 filterId = mFilterId;
218
219 // Check getId() too.
220 int32_t filterId32Bit;
221 status = mFilter->getId(&filterId32Bit);
222 }
223
224 return AssertionResult(status.isOk());
225 }
226
getSharedAvMemoryHandle(int64_t filterId)227 AssertionResult FilterTests::getSharedAvMemoryHandle(int64_t filterId) {
228 EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
229 NativeHandle avMemory;
230 int64_t avMemSize;
231 ndk::ScopedAStatus status = mFilters[filterId]->getAvSharedHandle(&avMemory, &avMemSize);
232 if (status.isOk()) {
233 mAvSharedHandle = android::dupFromAidl(avMemory);
234 mFilterCallbacks[mFilterId]->setSharedHandle(mAvSharedHandle);
235 mFilterCallbacks[mFilterId]->setMemSize(avMemSize);
236 }
237 return AssertionResult(status.isOk());
238 }
239
releaseShareAvHandle(int64_t filterId)240 AssertionResult FilterTests::releaseShareAvHandle(int64_t filterId) {
241 ndk::ScopedAStatus status;
242 EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
243 EXPECT_TRUE(mAvSharedHandle) << "No shared av handle to release.";
244 status = mFilters[filterId]->releaseAvHandle(::android::makeToAidl(mAvSharedHandle),
245 0 /*dataId*/);
246 native_handle_close(mAvSharedHandle);
247 native_handle_delete(mAvSharedHandle);
248 mAvSharedHandle = nullptr;
249
250 return AssertionResult(status.isOk());
251 }
252
configFilter(DemuxFilterSettings setting,int64_t filterId)253 AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, int64_t filterId) {
254 ndk::ScopedAStatus status;
255 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
256 status = mFilters[filterId]->configure(setting);
257
258 return AssertionResult(status.isOk());
259 }
260
configAvFilterStreamType(AvStreamType type,int64_t filterId)261 AssertionResult FilterTests::configAvFilterStreamType(AvStreamType type, int64_t filterId) {
262 ndk::ScopedAStatus status;
263 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
264
265 status = mFilters[filterId]->configureAvStreamType(type);
266 return AssertionResult(status.isOk());
267 }
268
configIpFilterCid(int32_t ipCid,int64_t filterId)269 AssertionResult FilterTests::configIpFilterCid(int32_t ipCid, int64_t filterId) {
270 ndk::ScopedAStatus status;
271 EXPECT_TRUE(mFilters[filterId]) << "Open Ip filter first.";
272
273 status = mFilters[filterId]->configureIpCid(ipCid);
274 return AssertionResult(status.isOk());
275 }
276
getFilterMQDescriptor(int64_t filterId,bool getMqDesc)277 AssertionResult FilterTests::getFilterMQDescriptor(int64_t filterId, bool getMqDesc) {
278 if (!getMqDesc) {
279 ALOGE("[vts] Filter does not need FMQ.");
280 return success();
281 }
282 ndk::ScopedAStatus status;
283 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
284 EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
285
286 status = mFilters[filterId]->getQueueDesc(&mFilterMQDescriptor);
287 return AssertionResult(status.isOk());
288 }
289
startFilter(int64_t filterId)290 AssertionResult FilterTests::startFilter(int64_t filterId) {
291 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
292
293 ndk::ScopedAStatus status = mFilters[filterId]->start();
294 return AssertionResult(status.isOk());
295 }
296
stopFilter(int64_t filterId)297 AssertionResult FilterTests::stopFilter(int64_t filterId) {
298 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
299
300 ndk::ScopedAStatus status = mFilters[filterId]->stop();
301 return AssertionResult(status.isOk());
302 }
303
closeFilter(int64_t filterId)304 AssertionResult FilterTests::closeFilter(int64_t filterId) {
305 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
306 ndk::ScopedAStatus status = mFilters[filterId]->close();
307 if (status.isOk()) {
308 for (int i = 0; i < mUsedFilterIds.size(); i++) {
309 if (mUsedFilterIds[i] == filterId) {
310 mUsedFilterIds.erase(mUsedFilterIds.begin() + i);
311 break;
312 }
313 }
314 mFilterCallbacks.erase(filterId);
315 mFilters.erase(filterId);
316 }
317 return AssertionResult(status.isOk());
318 }
319
configureMonitorEvent(int64_t filterId,int32_t monitorEventTypes)320 AssertionResult FilterTests::configureMonitorEvent(int64_t filterId, int32_t monitorEventTypes) {
321 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
322 ndk::ScopedAStatus status;
323
324 status = mFilters[filterId]->configureMonitorEvent(monitorEventTypes);
325 return AssertionResult(status.isOk());
326 }
327
testMonitorEvent(uint64_t filterId,uint32_t monitorEventTypes)328 AssertionResult FilterTests::testMonitorEvent(uint64_t filterId, uint32_t monitorEventTypes) {
329 EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
330 if (monitorEventTypes & static_cast<int32_t>(DemuxFilterMonitorEventType::SCRAMBLING_STATUS)) {
331 mFilterCallbacks[filterId]->testFilterScramblingEvent();
332 }
333 if (monitorEventTypes & static_cast<int32_t>(DemuxFilterMonitorEventType::IP_CID_CHANGE)) {
334 mFilterCallbacks[filterId]->testFilterIpCidEvent();
335 }
336 return AssertionResult(true);
337 }
338
startIdTest(int64_t filterId)339 AssertionResult FilterTests::startIdTest(int64_t filterId) {
340 EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
341 mFilterCallbacks[filterId]->testStartIdAfterReconfigure();
342 return AssertionResult(true);
343 }
344
openTimeFilterInDemux()345 AssertionResult FilterTests::openTimeFilterInDemux() {
346 if (!mDemux) {
347 ALOGW("[vts] Test with openDemux first.");
348 return failure();
349 }
350
351 // Add time filter to the local demux
352 auto status = mDemux->openTimeFilter(&mTimeFilter);
353 return AssertionResult(status.isOk());
354 }
355
setTimeStamp(int64_t timeStamp)356 AssertionResult FilterTests::setTimeStamp(int64_t timeStamp) {
357 if (!mTimeFilter) {
358 ALOGW("[vts] Test with openTimeFilterInDemux first.");
359 return failure();
360 }
361
362 mBeginTimeStamp = timeStamp;
363 return AssertionResult(mTimeFilter->setTimeStamp(timeStamp).isOk());
364 }
365
getTimeStamp()366 AssertionResult FilterTests::getTimeStamp() {
367 if (!mTimeFilter) {
368 ALOGW("[vts] Test with openTimeFilterInDemux first.");
369 return failure();
370 }
371
372 int64_t timeStamp;
373 auto status = mTimeFilter->getTimeStamp(&timeStamp);
374 return AssertionResult(status.isOk());
375 }
376
setFilterDataSource(int64_t sourceFilterId,int64_t sinkFilterId)377 AssertionResult FilterTests::setFilterDataSource(int64_t sourceFilterId, int64_t sinkFilterId) {
378 if (!mFilters[sourceFilterId] || !mFilters[sinkFilterId]) {
379 ALOGE("[vts] setFilterDataSource filter not opened.");
380 return failure();
381 }
382
383 auto status = mFilters[sinkFilterId]->setDataSource(mFilters[sourceFilterId]);
384 return AssertionResult(status.isOk());
385 }
386
setFilterDataSourceToDemux(int64_t filterId)387 AssertionResult FilterTests::setFilterDataSourceToDemux(int64_t filterId) {
388 if (!mFilters[filterId]) {
389 ALOGE("[vts] setFilterDataSourceToDemux filter not opened.");
390 return failure();
391 }
392
393 auto status = mFilters[filterId]->setDataSource(nullptr);
394 return AssertionResult(status.isOk());
395 }
396
clearTimeStamp()397 AssertionResult FilterTests::clearTimeStamp() {
398 if (!mTimeFilter) {
399 ALOGW("[vts] Test with openTimeFilterInDemux first.");
400 return failure();
401 }
402
403 return AssertionResult(mTimeFilter->clearTimeStamp().isOk());
404 }
405
closeTimeFilter()406 AssertionResult FilterTests::closeTimeFilter() {
407 if (!mTimeFilter) {
408 ALOGW("[vts] Test with openTimeFilterInDemux first.");
409 return failure();
410 }
411
412 return AssertionResult(mTimeFilter->close().isOk());
413 }
414