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 "FrontendTests.h"
18 
19 #include <aidl/android/hardware/tv/tuner/Result.h>
20 
onEvent(FrontendEventType frontendEventType)21 ndk::ScopedAStatus FrontendCallback::onEvent(FrontendEventType frontendEventType) {
22     android::Mutex::Autolock autoLock(mMsgLock);
23     ALOGD("[vts] frontend event received. Type: %d", frontendEventType);
24     mEventReceived = true;
25     mMsgCondition.signal();
26     switch (frontendEventType) {
27         case FrontendEventType::LOCKED:
28             mLockMsgReceived = true;
29             mLockMsgCondition.signal();
30             break;
31         default:
32             // do nothing
33             break;
34     }
35     return ndk::ScopedAStatus::ok();
36 }
37 
onScanMessage(FrontendScanMessageType type,const FrontendScanMessage & message)38 ndk::ScopedAStatus FrontendCallback::onScanMessage(FrontendScanMessageType type,
39                                                    const FrontendScanMessage& message) {
40     android::Mutex::Autolock autoLock(mMsgLock);
41     while (!mScanMsgProcessed) {
42         mMsgCondition.wait(mMsgLock);
43     }
44     ALOGD("[vts] frontend scan message. Type: %d", type);
45     switch (message.getTag()) {
46         case FrontendScanMessage::modulation:
47             readFrontendScanMessage_Modulation(message.get<FrontendScanMessage::Tag::modulation>());
48             break;
49         case FrontendScanMessage::Tag::isHighPriority:
50             ALOGD("[vts] frontend scan message high priority: %d",
51                   message.get<FrontendScanMessage::Tag::isHighPriority>());
52             break;
53         case FrontendScanMessage::Tag::annex:
54             ALOGD("[vts] frontend scan message dvbc annex: %hhu",
55                   message.get<FrontendScanMessage::Tag::annex>());
56             break;
57         default:
58             break;
59     }
60     mScanMessageReceived = true;
61     mScanMsgProcessed = false;
62     mScanMessageType = type;
63     mScanMessage = message;
64     mMsgCondition.signal();
65     return ndk::ScopedAStatus::ok();
66 }
67 
readFrontendScanMessage_Modulation(FrontendModulation modulation)68 void FrontendCallback::readFrontendScanMessage_Modulation(FrontendModulation modulation) {
69     switch (modulation.getTag()) {
70         case FrontendModulation::Tag::dvbc:
71             ALOGD("[vts] frontend scan message modulation dvbc: %d",
72                   modulation.get<FrontendModulation::Tag::dvbc>());
73             break;
74         case FrontendModulation::Tag::dvbs:
75             ALOGD("[vts] frontend scan message modulation dvbs: %d",
76                   modulation.get<FrontendModulation::Tag::dvbs>());
77             break;
78         case FrontendModulation::Tag::isdbs:
79             ALOGD("[vts] frontend scan message modulation isdbs: %d",
80                   modulation.get<FrontendModulation::Tag::isdbs>());
81             break;
82         case FrontendModulation::Tag::isdbs3:
83             ALOGD("[vts] frontend scan message modulation isdbs3: %d",
84                   modulation.get<FrontendModulation::Tag::isdbs3>());
85             break;
86         case FrontendModulation::Tag::isdbt:
87             ALOGD("[vts] frontend scan message modulation isdbt: %d",
88                   modulation.get<FrontendModulation::Tag::isdbt>());
89             break;
90         case FrontendModulation::Tag::atsc:
91             ALOGD("[vts] frontend scan message modulation atsc: %d",
92                   modulation.get<FrontendModulation::Tag::atsc>());
93             break;
94         case FrontendModulation::Tag::atsc3:
95             ALOGD("[vts] frontend scan message modulation atsc3: %d",
96                   modulation.get<FrontendModulation::Tag::atsc3>());
97             break;
98         case FrontendModulation::Tag::dvbt:
99             ALOGD("[vts] frontend scan message modulation dvbt: %d",
100                   modulation.get<FrontendModulation::Tag::dvbt>());
101             break;
102         default:
103             break;
104     }
105 }
106 
tuneTestOnLock(std::shared_ptr<IFrontend> & frontend,FrontendSettings settings)107 void FrontendCallback::tuneTestOnLock(std::shared_ptr<IFrontend>& frontend,
108                                       FrontendSettings settings) {
109     ndk::ScopedAStatus result = frontend->tune(settings);
110     EXPECT_TRUE(result.isOk());
111 
112     android::Mutex::Autolock autoLock(mMsgLock);
113     while (!mLockMsgReceived) {
114         if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
115             EXPECT_TRUE(false) << "Event LOCKED not received within timeout";
116             mLockMsgReceived = false;
117             return;
118         }
119     }
120     mLockMsgReceived = false;
121 }
122 
scanTest(std::shared_ptr<IFrontend> & frontend,FrontendConfig config,FrontendScanType type)123 void FrontendCallback::scanTest(std::shared_ptr<IFrontend>& frontend, FrontendConfig config,
124                                 FrontendScanType type) {
125     int64_t targetFrequency = getTargetFrequency(config.settings);
126     if (type == FrontendScanType::SCAN_BLIND) {
127         // reset the frequency in the scan configuration to test blind scan. The settings param of
128         // passed in means the real input config on the transponder connected to the DUT.
129         // We want the blind the test to start from lower frequency than this to check the blind
130         // scan implementation.
131         resetBlindScanStartingFrequency(config, targetFrequency - 100 * 1000);
132     }
133 
134     ndk::ScopedAStatus result = frontend->scan(config.settings, type);
135     EXPECT_TRUE(result.isOk());
136 
137     bool scanMsgLockedReceived = false;
138     bool targetFrequencyReceived = false;
139 
140     android::Mutex::Autolock autoLock(mMsgLock);
141 wait:
142     while (!mScanMessageReceived) {
143         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
144             EXPECT_TRUE(false) << "Scan message not received within timeout";
145             mScanMessageReceived = false;
146             mScanMsgProcessed = true;
147             return;
148         }
149     }
150 
151     if (mScanMessageType != FrontendScanMessageType::END) {
152         if (mScanMessageType == FrontendScanMessageType::LOCKED) {
153             scanMsgLockedReceived = true;
154             result = frontend->scan(config.settings, type);
155             EXPECT_TRUE(result.isOk());
156         }
157 
158         if (mScanMessageType == FrontendScanMessageType::FREQUENCY) {
159             targetFrequencyReceived =
160                     mScanMessage.get<FrontendScanMessage::Tag::frequencies>().size() > 0 &&
161                     mScanMessage.get<FrontendScanMessage::Tag::frequencies>()[0] == targetFrequency;
162         }
163 
164         if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) {
165             ALOGD("[vts] Scan in progress...[%d%%]",
166                   mScanMessage.get<FrontendScanMessage::Tag::progressPercent>());
167         }
168 
169         mScanMessageReceived = false;
170         mScanMsgProcessed = true;
171         mMsgCondition.signal();
172         goto wait;
173     }
174 
175     EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END";
176     if (type == FrontendScanType::SCAN_BLIND)
177         EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
178     mScanMessageReceived = false;
179     mScanMsgProcessed = true;
180 }
181 
getTargetFrequency(FrontendSettings & settings)182 int64_t FrontendCallback::getTargetFrequency(FrontendSettings& settings) {
183     switch (settings.getTag()) {
184         case FrontendSettings::Tag::analog:
185             return settings.get<FrontendSettings::Tag::analog>().frequency;
186         case FrontendSettings::Tag::atsc:
187             return settings.get<FrontendSettings::Tag::atsc>().frequency;
188         case FrontendSettings::Tag::atsc3:
189             return settings.get<FrontendSettings::Tag::atsc3>().frequency;
190         case FrontendSettings::Tag::dvbc:
191             return settings.get<FrontendSettings::Tag::dvbc>().frequency;
192         case FrontendSettings::Tag::dvbs:
193             return settings.get<FrontendSettings::Tag::dvbs>().frequency;
194         case FrontendSettings::Tag::dvbt:
195             return settings.get<FrontendSettings::Tag::dvbt>().frequency;
196         case FrontendSettings::Tag::isdbs:
197             return settings.get<FrontendSettings::Tag::isdbs>().frequency;
198         case FrontendSettings::Tag::isdbs3:
199             return settings.get<FrontendSettings::Tag::isdbs3>().frequency;
200         case FrontendSettings::Tag::isdbt:
201             return settings.get<FrontendSettings::Tag::isdbt>().frequency;
202         default:
203             return 0;
204     }
205 }
206 
resetBlindScanStartingFrequency(FrontendConfig & config,int64_t resetingFreq)207 void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config,
208                                                        int64_t resetingFreq) {
209     switch (config.settings.getTag()) {
210         case FrontendSettings::Tag::analog:
211             config.settings.get<FrontendSettings::Tag::analog>().frequency = resetingFreq;
212             break;
213         case FrontendSettings::Tag::atsc:
214             config.settings.get<FrontendSettings::Tag::atsc>().frequency = resetingFreq;
215             break;
216         case FrontendSettings::Tag::atsc3:
217             config.settings.get<FrontendSettings::Tag::atsc3>().frequency = resetingFreq;
218             break;
219         case FrontendSettings::Tag::dvbc:
220             config.settings.get<FrontendSettings::Tag::dvbc>().frequency = resetingFreq;
221             break;
222         case FrontendSettings::Tag::dvbs:
223             config.settings.get<FrontendSettings::Tag::dvbs>().frequency = resetingFreq;
224             break;
225         case FrontendSettings::Tag::dvbt:
226             config.settings.get<FrontendSettings::Tag::dvbt>().frequency = resetingFreq;
227             break;
228         case FrontendSettings::Tag::isdbs:
229             config.settings.get<FrontendSettings::Tag::isdbs>().frequency = resetingFreq;
230             break;
231         case FrontendSettings::Tag::isdbs3:
232             config.settings.get<FrontendSettings::Tag::isdbs3>().frequency = resetingFreq;
233             break;
234         case FrontendSettings::Tag::isdbt:
235             config.settings.get<FrontendSettings::Tag::isdbt>().frequency = resetingFreq;
236             break;
237         default:
238             break;
239     }
240 }
241 
getFrontendIds()242 AssertionResult FrontendTests::getFrontendIds() {
243     ndk::ScopedAStatus status;
244     status = mService->getFrontendIds(&mFeIds);
245     return AssertionResult(status.isOk());
246 }
247 
getFrontendInfo(int32_t frontendId)248 AssertionResult FrontendTests::getFrontendInfo(int32_t frontendId) {
249     ndk::ScopedAStatus status;
250     status = mService->getFrontendInfo(frontendId, &mFrontendInfo);
251     return AssertionResult(status.isOk());
252 }
253 
openFrontendById(int32_t frontendId)254 AssertionResult FrontendTests::openFrontendById(int32_t frontendId) {
255     ndk::ScopedAStatus status;
256     status = mService->openFrontendById(frontendId, &mFrontend);
257     return AssertionResult(status.isOk());
258 }
259 
setFrontendCallback()260 AssertionResult FrontendTests::setFrontendCallback() {
261     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
262     mFrontendCallback = ndk::SharedRefBase::make<FrontendCallback>();
263     auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
264     return AssertionResult(callbackStatus.isOk());
265 }
266 
scanFrontend(FrontendConfig config,FrontendScanType type)267 AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) {
268     EXPECT_TRUE(mFrontendCallback)
269             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
270 
271     EXPECT_TRUE(mFrontendInfo.type == config.type)
272             << "FrontendConfig does not match the frontend info of the given id.";
273 
274     mFrontendCallback->scanTest(mFrontend, config, type);
275     return AssertionResult(true);
276 }
277 
stopScanFrontend()278 AssertionResult FrontendTests::stopScanFrontend() {
279     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
280     ndk::ScopedAStatus status;
281     status = mFrontend->stopScan();
282 
283     return AssertionResult(status.isOk());
284 }
285 
setLnb(int32_t lnbId)286 AssertionResult FrontendTests::setLnb(int32_t lnbId) {
287     if (!mFrontendCallback) {
288         ALOGW("[vts] open and set frontend callback first.");
289         return failure();
290     }
291     return AssertionResult(mFrontend->setLnb(lnbId).isOk());
292 }
293 
linkCiCam(int32_t ciCamId)294 AssertionResult FrontendTests::linkCiCam(int32_t ciCamId) {
295     ndk::ScopedAStatus status;
296     int32_t ltsId;
297     status = mFrontend->linkCiCam(ciCamId, &ltsId);
298     return AssertionResult(status.isOk());
299 }
300 
removeOutputPid(int32_t removePid)301 AssertionResult FrontendTests::removeOutputPid(int32_t removePid) {
302     ndk::ScopedAStatus status;
303     status = mFrontend->removeOutputPid(removePid);
304     return AssertionResult(status.isOk() || status.getServiceSpecificError() ==
305                                                     static_cast<int32_t>(Result::UNAVAILABLE));
306 }
307 
unlinkCiCam(int32_t ciCamId)308 AssertionResult FrontendTests::unlinkCiCam(int32_t ciCamId) {
309     ndk::ScopedAStatus status = mFrontend->unlinkCiCam(ciCamId);
310     return AssertionResult(status.isOk());
311 }
312 
verifyFrontendStatus(vector<FrontendStatusType> statusTypes,vector<FrontendStatus> expectStatuses)313 void FrontendTests::verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
314                                          vector<FrontendStatus> expectStatuses) {
315     ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
316     ndk::ScopedAStatus status;
317     vector<FrontendStatus> realStatuses;
318 
319     status = mFrontend->getStatus(statusTypes, &realStatuses);
320     ASSERT_TRUE(status.isOk() && realStatuses.size() == statusTypes.size());
321 
322     for (int i = 0; i < statusTypes.size(); i++) {
323         FrontendStatusType type = statusTypes[i];
324         switch (type) {
325             case FrontendStatusType::MODULATIONS: {
326                 ASSERT_TRUE(std::equal(
327                         realStatuses[i].get<FrontendStatus::Tag::modulations>().begin(),
328                         realStatuses[i].get<FrontendStatus::Tag::modulations>().end(),
329                         expectStatuses[i].get<FrontendStatus::Tag::modulations>().begin()));
330                 break;
331             }
332             case FrontendStatusType::BERS: {
333                 ASSERT_TRUE(std::equal(realStatuses[i].get<FrontendStatus::Tag::bers>().begin(),
334                                        realStatuses[i].get<FrontendStatus::Tag::bers>().end(),
335                                        expectStatuses[i].get<FrontendStatus::Tag::bers>().begin()));
336                 break;
337             }
338             case FrontendStatusType::CODERATES: {
339                 ASSERT_TRUE(std::equal(
340                         realStatuses[i].get<FrontendStatus::Tag::codeRates>().begin(),
341                         realStatuses[i].get<FrontendStatus::Tag::codeRates>().end(),
342                         expectStatuses[i].get<FrontendStatus::Tag::codeRates>().begin()));
343                 break;
344             }
345             case FrontendStatusType::GUARD_INTERVAL: {
346                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::interval>() ==
347                             expectStatuses[i].get<FrontendStatus::Tag::interval>());
348                 break;
349             }
350             case FrontendStatusType::TRANSMISSION_MODE: {
351                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::transmissionMode>() ==
352                             expectStatuses[i].get<FrontendStatus::Tag::transmissionMode>());
353                 break;
354             }
355             case FrontendStatusType::UEC: {
356                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::uec>() >= 0);
357                 break;
358             }
359             case FrontendStatusType::T2_SYSTEM_ID: {
360                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::systemId>() ==
361                             expectStatuses[i].get<FrontendStatus::Tag::systemId>());
362                 break;
363             }
364             case FrontendStatusType::INTERLEAVINGS: {
365                 ASSERT_TRUE(std::equal(
366                         realStatuses[i].get<FrontendStatus::Tag::interleaving>().begin(),
367                         realStatuses[i].get<FrontendStatus::Tag::interleaving>().end(),
368                         expectStatuses[i].get<FrontendStatus::Tag::interleaving>().begin()));
369                 break;
370             }
371             case FrontendStatusType::ISDBT_SEGMENTS: {
372                 ASSERT_TRUE(std::equal(
373                         realStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().begin(),
374                         realStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().end(),
375                         expectStatuses[i].get<FrontendStatus::Tag::isdbtSegment>().begin()));
376                 break;
377             }
378             case FrontendStatusType::TS_DATA_RATES: {
379                 ASSERT_TRUE(std::equal(
380                         realStatuses[i].get<FrontendStatus::Tag::tsDataRate>().begin(),
381                         realStatuses[i].get<FrontendStatus::Tag::tsDataRate>().end(),
382                         expectStatuses[i].get<FrontendStatus::Tag::tsDataRate>().begin()));
383                 break;
384             }
385             case FrontendStatusType::ROLL_OFF: {
386                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::rollOff>() ==
387                             expectStatuses[i].get<FrontendStatus::Tag::rollOff>());
388                 break;
389             }
390             case FrontendStatusType::IS_MISO: {
391                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isMiso>() ==
392                             expectStatuses[i].get<FrontendStatus::Tag::isMiso>());
393                 break;
394             }
395             case FrontendStatusType::IS_LINEAR: {
396                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isLinear>() ==
397                             expectStatuses[i].get<FrontendStatus::Tag::isLinear>());
398                 break;
399             }
400             case FrontendStatusType::IS_SHORT_FRAMES: {
401                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isShortFrames>() ==
402                             expectStatuses[i].get<FrontendStatus::Tag::isShortFrames>());
403                 break;
404             }
405             case FrontendStatusType::ISDBT_MODE: {
406                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::isdbtMode>() ==
407                             expectStatuses[i].get<FrontendStatus::Tag::isdbtMode>());
408                 break;
409             }
410             case FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG: {
411                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::partialReceptionFlag>() ==
412                             expectStatuses[i].get<FrontendStatus::Tag::partialReceptionFlag>());
413                 break;
414             }
415             case FrontendStatusType::STREAM_ID_LIST: {
416                 ASSERT_TRUE(std::equal(
417                         realStatuses[i].get<FrontendStatus::Tag::streamIdList>().begin(),
418                         realStatuses[i].get<FrontendStatus::Tag::streamIdList>().end(),
419                         expectStatuses[i].get<FrontendStatus::Tag::streamIdList>().begin()));
420                 break;
421             }
422             case FrontendStatusType::DVBT_CELL_IDS: {
423                 ASSERT_TRUE(std::equal(
424                         realStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().begin(),
425                         realStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().end(),
426                         expectStatuses[i].get<FrontendStatus::Tag::dvbtCellIds>().begin()));
427                 break;
428             }
429             case FrontendStatusType::ATSC3_ALL_PLP_INFO: {
430                 ASSERT_TRUE(std::equal(
431                         realStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().begin(),
432                         realStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().end(),
433                         expectStatuses[i].get<FrontendStatus::Tag::allPlpInfo>().begin()));
434                 break;
435             }
436             case FrontendStatusType::IPTV_CONTENT_URL: {
437                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::iptvContentUrl>() ==
438                             expectStatuses[i].get<FrontendStatus::Tag::iptvContentUrl>());
439                 break;
440             }
441             case FrontendStatusType::IPTV_PACKETS_LOST: {
442                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::iptvPacketsLost>() ==
443                             expectStatuses[i].get<FrontendStatus::Tag::iptvPacketsLost>());
444                 break;
445             }
446             case FrontendStatusType::IPTV_PACKETS_RECEIVED: {
447                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::iptvPacketsReceived>() ==
448                             expectStatuses[i].get<FrontendStatus::Tag::iptvPacketsReceived>());
449                 break;
450             }
451             case FrontendStatusType::IPTV_WORST_JITTER_MS: {
452                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::iptvWorstJitterMs>() ==
453                             expectStatuses[i].get<FrontendStatus::Tag::iptvWorstJitterMs>());
454                 break;
455             }
456             case FrontendStatusType::IPTV_AVERAGE_JITTER_MS: {
457                 ASSERT_TRUE(realStatuses[i].get<FrontendStatus::Tag::iptvAverageJitterMs>() ==
458                             expectStatuses[i].get<FrontendStatus::Tag::iptvAverageJitterMs>());
459                 break;
460             }
461             default: {
462                 continue;
463             }
464         }
465     }
466     ASSERT_TRUE(status.isOk());
467 }
468 
tuneFrontend(FrontendConfig config,bool testWithDemux)469 AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
470     EXPECT_TRUE(mFrontendCallback)
471             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
472 
473     EXPECT_TRUE(mFrontendInfo.type == config.type)
474             << "FrontendConfig does not match the frontend info of the given id.";
475 
476     mIsSoftwareFe = config.isSoftwareFe;
477     std::unique_ptr<IpStreamer> ipThread = std::make_unique<IpStreamer>();
478     if (config.type == FrontendType::IPTV) {
479         ipThread->startIpStream();
480     }
481     if (mIsSoftwareFe && testWithDemux) {
482         if (getDvrTests()->openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) != success()) {
483             ALOGW("[vts] Software frontend dvr configure openDvr failed.");
484             return failure();
485         }
486         if (getDvrTests()->configDvrPlayback(mDvrConfig.settings) != success()) {
487             ALOGW("[vts] Software frontend dvr configure Dvr playback failed.");
488             return failure();
489         }
490         if (getDvrTests()->getDvrPlaybackMQDescriptor() != success()) {
491             ALOGW("[vts] Software frontend dvr configure get MQDesc failed.");
492             return failure();
493         }
494         getDvrTests()->startPlaybackInputThread(
495                 mDvrConfig.playbackInputFile,
496                 mDvrConfig.settings.get<DvrSettings::Tag::playback>());
497         getDvrTests()->startDvrPlayback();
498     }
499     mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
500     if (config.type == FrontendType::IPTV) {
501         ipThread->stopIpStream();
502     }
503     return AssertionResult(true);
504 }
505 
stopTuneFrontend(bool testWithDemux)506 AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
507     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
508     ndk::ScopedAStatus status;
509     status = mFrontend->stopTune();
510     if (mIsSoftwareFe && testWithDemux) {
511         getDvrTests()->stopPlaybackThread();
512         getDvrTests()->stopDvrPlayback();
513         getDvrTests()->closeDvrPlayback();
514     }
515     return AssertionResult(status.isOk());
516 }
517 
closeFrontend()518 AssertionResult FrontendTests::closeFrontend() {
519     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
520     ndk::ScopedAStatus status;
521     status = mFrontend->close();
522     mFrontend = nullptr;
523     mFrontendCallback = nullptr;
524     return AssertionResult(status.isOk());
525 }
526 
getFrontendIdByType(FrontendType feType,int32_t & feId)527 void FrontendTests::getFrontendIdByType(FrontendType feType, int32_t& feId) {
528     ASSERT_TRUE(getFrontendIds());
529     for (size_t i = 0; i < mFeIds.size(); i++) {
530         ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
531         if (mFrontendInfo.type != feType) {
532             continue;
533         }
534         feId = mFeIds[i];
535         return;
536     }
537     feId = INVALID_ID;
538 }
539 
verifyHardwareInfo()540 AssertionResult FrontendTests::verifyHardwareInfo() {
541     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
542     std::string info;
543     ndk::ScopedAStatus status = mFrontend->getHardwareInfo(&info);
544     return AssertionResult(status.isOk() && !info.empty());
545 }
546 
tuneTest(FrontendConfig frontendConf)547 void FrontendTests::tuneTest(FrontendConfig frontendConf) {
548     int32_t feId;
549     getFrontendIdByType(frontendConf.type, feId);
550     ASSERT_TRUE(feId != INVALID_ID);
551     ASSERT_TRUE(openFrontendById(feId));
552     ASSERT_TRUE(setFrontendCallback());
553     if (frontendConf.canConnectToCiCam) {
554         ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
555         ASSERT_TRUE(removeOutputPid(frontendConf.removePid));
556         ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
557     }
558     ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
559     verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
560     ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
561     ASSERT_TRUE(closeFrontend());
562 }
563 
debugInfoTest(FrontendConfig frontendConf)564 void FrontendTests::debugInfoTest(FrontendConfig frontendConf) {
565     int32_t feId;
566     getFrontendIdByType(frontendConf.type, feId);
567     ASSERT_TRUE(feId != INVALID_ID);
568     ASSERT_TRUE(openFrontendById(feId));
569     ASSERT_TRUE(setFrontendCallback());
570     ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
571     ASSERT_TRUE(verifyHardwareInfo());
572     ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
573     ASSERT_TRUE(closeFrontend());
574 }
575 
maxNumberOfFrontendsTest()576 void FrontendTests::maxNumberOfFrontendsTest() {
577     ASSERT_TRUE(getFrontendIds());
578     for (size_t i = 0; i < mFeIds.size(); i++) {
579         ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
580         int32_t defaultMax = -1;
581         ndk::ScopedAStatus status;
582         // Check default value
583         status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &defaultMax);
584         ASSERT_TRUE(status.isOk());
585         ASSERT_TRUE(defaultMax > 0);
586         // Set to -1
587         status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, -1);
588         ASSERT_TRUE(status.getServiceSpecificError() ==
589                     static_cast<int32_t>(Result::INVALID_ARGUMENT));
590         // Set to defaultMax + 1
591         status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, defaultMax + 1);
592         ASSERT_TRUE(status.getServiceSpecificError() ==
593                     static_cast<int32_t>(Result::INVALID_ARGUMENT));
594         // Set to 0
595         status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, 0);
596         ASSERT_TRUE(status.isOk());
597         // Check after set
598         int32_t currentMax = -1;
599         status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &currentMax);
600         ASSERT_TRUE(status.isOk());
601         ASSERT_TRUE(currentMax == 0);
602         // Reset to default
603         status = mService->setMaxNumberOfFrontends(mFrontendInfo.type, defaultMax);
604         ASSERT_TRUE(status.isOk());
605         status = mService->getMaxNumberOfFrontends(mFrontendInfo.type, &currentMax);
606         ASSERT_TRUE(status.isOk());
607         ASSERT_TRUE(defaultMax == currentMax);
608     }
609 }
610 
scanTest(FrontendConfig frontendConf,FrontendScanType scanType)611 void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) {
612     int32_t feId;
613     getFrontendIdByType(frontendConf.type, feId);
614     ASSERT_TRUE(feId != INVALID_ID);
615     ASSERT_TRUE(openFrontendById(feId));
616     ASSERT_TRUE(setFrontendCallback());
617     ASSERT_TRUE(scanFrontend(frontendConf, scanType));
618     ASSERT_TRUE(stopScanFrontend());
619     ASSERT_TRUE(closeFrontend());
620 }
621 
statusReadinessTest(FrontendConfig frontendConf)622 void FrontendTests::statusReadinessTest(FrontendConfig frontendConf) {
623     int32_t feId;
624     vector<FrontendStatusType> allTypes;
625     vector<FrontendStatusReadiness> readiness;
626     getFrontendIdByType(frontendConf.type, feId);
627     ASSERT_TRUE(feId != INVALID_ID);
628     ASSERT_TRUE(openFrontendById(feId));
629     ASSERT_TRUE(setFrontendCallback());
630     if (frontendConf.canConnectToCiCam) {
631         ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
632         ASSERT_TRUE(removeOutputPid(frontendConf.removePid));
633         ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
634     }
635     ASSERT_TRUE(getFrontendInfo(feId));
636     ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
637 
638     // TODO: find a better way to push all frontend status types
639     for (int32_t i = 0; i <= static_cast<int32_t>(FrontendStatusType::ATSC3_ALL_PLP_INFO); i++) {
640         allTypes.push_back(static_cast<FrontendStatusType>(i));
641     }
642 
643     ndk::ScopedAStatus status = mFrontend->getFrontendStatusReadiness(allTypes, &readiness);
644     ASSERT_TRUE(status.isOk());
645     ASSERT_TRUE(readiness.size() == allTypes.size());
646     for (int32_t i = 0; i < readiness.size(); i++) {
647         int32_t j = 0;
648         while (j < mFrontendInfo.statusCaps.size()) {
649             if (allTypes[i] == mFrontendInfo.statusCaps[j]) {
650                 ASSERT_TRUE(readiness[i] == FrontendStatusReadiness::UNAVAILABLE ||
651                             readiness[i] == FrontendStatusReadiness::UNSTABLE ||
652                             readiness[i] == FrontendStatusReadiness::STABLE);
653                 break;
654             }
655             j++;
656         }
657 
658         if (j >= mFrontendInfo.statusCaps.size()) {
659             ASSERT_TRUE(readiness[i] == FrontendStatusReadiness::UNSUPPORTED);
660         }
661     }
662 
663     ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
664     ASSERT_TRUE(closeFrontend());
665 }
666