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 ALOGD("[vts] Media filter event, avMemHandle numFds=%zu.",
110 events[i].get<DemuxFilterEvent::Tag::media>().avMemory.fds.size());
111 dumpAvData(events[i].get<DemuxFilterEvent::Tag::media>());
112 break;
113 case DemuxFilterEvent::Tag::tsRecord:
114 ALOGD("[vts] TS record filter event, pts=%" PRIu64 ", firstMbInSlice=%d",
115 events[i].get<DemuxFilterEvent::Tag::tsRecord>().pts,
116 events[i].get<DemuxFilterEvent::Tag::tsRecord>().firstMbInSlice);
117 break;
118 case DemuxFilterEvent::Tag::mmtpRecord:
119 ALOGD("[vts] MMTP record filter event, pts=%" PRIu64
120 ", firstMbInSlice=%d, mpuSequenceNumber=%d, tsIndexMask=%d",
121 events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().pts,
122 events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().firstMbInSlice,
123 events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().mpuSequenceNumber,
124 events[i].get<DemuxFilterEvent::Tag::mmtpRecord>().tsIndexMask);
125 break;
126 case DemuxFilterEvent::Tag::monitorEvent:
127 switch (events[i].get<DemuxFilterEvent::Tag::monitorEvent>().getTag()) {
128 case DemuxFilterMonitorEvent::Tag::scramblingStatus:
129 mScramblingStatusEvent++;
130 break;
131 case DemuxFilterMonitorEvent::Tag::cid:
132 mIpCidEvent++;
133 break;
134 default:
135 break;
136 }
137 break;
138 case DemuxFilterEvent::Tag::startId:
139 ALOGD("[vts] Restart filter event, startId=%d",
140 events[i].get<DemuxFilterEvent::Tag::startId>());
141 mStartIdReceived = true;
142 break;
143 default:
144 break;
145 }
146 }
147 }
148
dumpAvData(const DemuxFilterMediaEvent & event)149 bool FilterCallback::dumpAvData(const DemuxFilterMediaEvent& event) {
150 int64_t length = event.dataLength;
151 int64_t offset = event.offset;
152 int av_fd;
153 // read data from buffer pointed by a handle
154 if (event.avMemory.fds.size() == 0) {
155 if (mAvSharedHandle == nullptr) {
156 return false;
157 }
158 av_fd = mAvSharedHandle->data[0];
159 } else {
160 av_fd = event.avMemory.fds[0].get();
161 }
162 uint8_t* buffer = static_cast<uint8_t*>(
163 mmap(NULL, length + offset, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0));
164 if (buffer == MAP_FAILED) {
165 ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
166 return false;
167 }
168 uint8_t output[length + 1];
169 memcpy(output, buffer + offset, length);
170 // print buffer and check with golden output.
171 return true;
172 }
173
openFilterInDemux(DemuxFilterType type,int32_t bufferSize)174 AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, int32_t bufferSize) {
175 ndk::ScopedAStatus status;
176 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
177
178 // Create demux callback
179 mFilterCallback = ndk::SharedRefBase::make<FilterCallback>();
180
181 // Add filter to the local demux
182 status = mDemux->openFilter(type, bufferSize, mFilterCallback, &mFilter);
183
184 return AssertionResult(status.isOk());
185 }
186
getNewlyOpenedFilterId_64bit(int64_t & filterId)187 AssertionResult FilterTests::getNewlyOpenedFilterId_64bit(int64_t& filterId) {
188 ndk::ScopedAStatus status;
189 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
190 EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first.";
191 EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first.";
192
193 status = mFilter->getId64Bit(&mFilterId);
194 if (status.isOk()) {
195 mFilterCallback->setFilterId(mFilterId);
196 mFilterCallback->setFilterInterface(mFilter);
197 mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
198 mFilters[mFilterId] = mFilter;
199 mFilterCallbacks[mFilterId] = mFilterCallback;
200 filterId = mFilterId;
201
202 // Check getId() too.
203 int32_t filterId32Bit;
204 status = mFilter->getId(&filterId32Bit);
205 }
206
207 return AssertionResult(status.isOk());
208 }
209
getSharedAvMemoryHandle(int64_t filterId)210 AssertionResult FilterTests::getSharedAvMemoryHandle(int64_t filterId) {
211 EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
212 NativeHandle avMemory;
213 int64_t avMemSize;
214 ndk::ScopedAStatus status = mFilters[filterId]->getAvSharedHandle(&avMemory, &avMemSize);
215 if (status.isOk()) {
216 mAvSharedHandle = android::dupFromAidl(avMemory);
217 mFilterCallbacks[mFilterId]->setSharedHandle(mAvSharedHandle);
218 mFilterCallbacks[mFilterId]->setMemSize(avMemSize);
219 }
220 return AssertionResult(status.isOk());
221 }
222
releaseShareAvHandle(int64_t filterId)223 AssertionResult FilterTests::releaseShareAvHandle(int64_t filterId) {
224 ndk::ScopedAStatus status;
225 EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
226 EXPECT_TRUE(mAvSharedHandle) << "No shared av handle to release.";
227 status = mFilters[filterId]->releaseAvHandle(::android::makeToAidl(mAvSharedHandle),
228 0 /*dataId*/);
229 native_handle_close(mAvSharedHandle);
230 native_handle_delete(mAvSharedHandle);
231 mAvSharedHandle = nullptr;
232
233 return AssertionResult(status.isOk());
234 }
235
configFilter(DemuxFilterSettings setting,int64_t filterId)236 AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, int64_t filterId) {
237 ndk::ScopedAStatus status;
238 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
239 status = mFilters[filterId]->configure(setting);
240
241 return AssertionResult(status.isOk());
242 }
243
configAvFilterStreamType(AvStreamType type,int64_t filterId)244 AssertionResult FilterTests::configAvFilterStreamType(AvStreamType type, int64_t filterId) {
245 ndk::ScopedAStatus status;
246 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
247
248 status = mFilters[filterId]->configureAvStreamType(type);
249 return AssertionResult(status.isOk());
250 }
251
configIpFilterCid(int32_t ipCid,int64_t filterId)252 AssertionResult FilterTests::configIpFilterCid(int32_t ipCid, int64_t filterId) {
253 ndk::ScopedAStatus status;
254 EXPECT_TRUE(mFilters[filterId]) << "Open Ip filter first.";
255
256 status = mFilters[filterId]->configureIpCid(ipCid);
257 return AssertionResult(status.isOk());
258 }
259
getFilterMQDescriptor(int64_t filterId,bool getMqDesc)260 AssertionResult FilterTests::getFilterMQDescriptor(int64_t filterId, bool getMqDesc) {
261 if (!getMqDesc) {
262 ALOGE("[vts] Filter does not need FMQ.");
263 return success();
264 }
265 ndk::ScopedAStatus status;
266 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
267 EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
268
269 status = mFilters[filterId]->getQueueDesc(&mFilterMQDescriptor);
270 return AssertionResult(status.isOk());
271 }
272
startFilter(int64_t filterId)273 AssertionResult FilterTests::startFilter(int64_t filterId) {
274 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
275
276 ndk::ScopedAStatus status = mFilters[filterId]->start();
277 return AssertionResult(status.isOk());
278 }
279
stopFilter(int64_t filterId)280 AssertionResult FilterTests::stopFilter(int64_t filterId) {
281 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
282
283 ndk::ScopedAStatus status = mFilters[filterId]->stop();
284 return AssertionResult(status.isOk());
285 }
286
closeFilter(int64_t filterId)287 AssertionResult FilterTests::closeFilter(int64_t filterId) {
288 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
289 ndk::ScopedAStatus status = mFilters[filterId]->close();
290 if (status.isOk()) {
291 for (int i = 0; i < mUsedFilterIds.size(); i++) {
292 if (mUsedFilterIds[i] == filterId) {
293 mUsedFilterIds.erase(mUsedFilterIds.begin() + i);
294 break;
295 }
296 }
297 mFilterCallbacks.erase(filterId);
298 mFilters.erase(filterId);
299 }
300 return AssertionResult(status.isOk());
301 }
302
configureMonitorEvent(int64_t filterId,int32_t monitorEventTypes)303 AssertionResult FilterTests::configureMonitorEvent(int64_t filterId, int32_t monitorEventTypes) {
304 EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
305 ndk::ScopedAStatus status;
306
307 status = mFilters[filterId]->configureMonitorEvent(monitorEventTypes);
308 if (monitorEventTypes & static_cast<int32_t>(DemuxFilterMonitorEventType::SCRAMBLING_STATUS)) {
309 mFilterCallbacks[filterId]->testFilterScramblingEvent();
310 }
311 if (monitorEventTypes & static_cast<int32_t>(DemuxFilterMonitorEventType::IP_CID_CHANGE)) {
312 mFilterCallbacks[filterId]->testFilterIpCidEvent();
313 }
314 return AssertionResult(status.isOk());
315 }
316
startIdTest(int64_t filterId)317 AssertionResult FilterTests::startIdTest(int64_t filterId) {
318 EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
319 mFilterCallbacks[filterId]->testStartIdAfterReconfigure();
320 return AssertionResult(true);
321 }
322
openTimeFilterInDemux()323 AssertionResult FilterTests::openTimeFilterInDemux() {
324 if (!mDemux) {
325 ALOGW("[vts] Test with openDemux first.");
326 return failure();
327 }
328
329 // Add time filter to the local demux
330 auto status = mDemux->openTimeFilter(&mTimeFilter);
331 return AssertionResult(status.isOk());
332 }
333
setTimeStamp(int64_t timeStamp)334 AssertionResult FilterTests::setTimeStamp(int64_t timeStamp) {
335 if (!mTimeFilter) {
336 ALOGW("[vts] Test with openTimeFilterInDemux first.");
337 return failure();
338 }
339
340 mBeginTimeStamp = timeStamp;
341 return AssertionResult(mTimeFilter->setTimeStamp(timeStamp).isOk());
342 }
343
getTimeStamp()344 AssertionResult FilterTests::getTimeStamp() {
345 if (!mTimeFilter) {
346 ALOGW("[vts] Test with openTimeFilterInDemux first.");
347 return failure();
348 }
349
350 int64_t timeStamp;
351 auto status = mTimeFilter->getTimeStamp(&timeStamp);
352 return AssertionResult(status.isOk());
353 }
354
setFilterDataSource(int64_t sourceFilterId,int64_t sinkFilterId)355 AssertionResult FilterTests::setFilterDataSource(int64_t sourceFilterId, int64_t sinkFilterId) {
356 if (!mFilters[sourceFilterId] || !mFilters[sinkFilterId]) {
357 ALOGE("[vts] setFilterDataSource filter not opened.");
358 return failure();
359 }
360
361 auto status = mFilters[sinkFilterId]->setDataSource(mFilters[sourceFilterId]);
362 return AssertionResult(status.isOk());
363 }
364
setFilterDataSourceToDemux(int64_t filterId)365 AssertionResult FilterTests::setFilterDataSourceToDemux(int64_t filterId) {
366 if (!mFilters[filterId]) {
367 ALOGE("[vts] setFilterDataSourceToDemux filter not opened.");
368 return failure();
369 }
370
371 auto status = mFilters[filterId]->setDataSource(nullptr);
372 return AssertionResult(status.isOk());
373 }
374
clearTimeStamp()375 AssertionResult FilterTests::clearTimeStamp() {
376 if (!mTimeFilter) {
377 ALOGW("[vts] Test with openTimeFilterInDemux first.");
378 return failure();
379 }
380
381 return AssertionResult(mTimeFilter->clearTimeStamp().isOk());
382 }
383
closeTimeFilter()384 AssertionResult FilterTests::closeTimeFilter() {
385 if (!mTimeFilter) {
386 ALOGW("[vts] Test with openTimeFilterInDemux first.");
387 return failure();
388 }
389
390 return AssertionResult(mTimeFilter->close().isOk());
391 }
392