xref: /aosp_15_r20/hardware/interfaces/tv/tuner/aidl/vts/functional/FilterTests.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
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