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 "FrontendTests.h"
18 
onEvent(FrontendEventType frontendEventType)19 Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) {
20     android::Mutex::Autolock autoLock(mMsgLock);
21     ALOGD("[vts] frontend event received. Type: %d", frontendEventType);
22     mEventReceived = true;
23     mMsgCondition.signal();
24     switch (frontendEventType) {
25         case FrontendEventType::LOCKED:
26             mLockMsgReceived = true;
27             mLockMsgCondition.signal();
28             return Void();
29         default:
30             // do nothing
31             return Void();
32     }
33 }
34 
onScanMessage(FrontendScanMessageType type,const FrontendScanMessage & message)35 Return<void> FrontendCallback::onScanMessage(FrontendScanMessageType type,
36                                              const FrontendScanMessage& message) {
37     android::Mutex::Autolock autoLock(mMsgLock);
38     while (!mScanMsgProcessed) {
39         mMsgCondition.wait(mMsgLock);
40     }
41     ALOGD("[vts] frontend scan message. Type: %d", type);
42     mScanMessageReceived = true;
43     mScanMsgProcessed = false;
44     mScanMessageType = type;
45     mScanMessage = message;
46     mMsgCondition.signal();
47     return Void();
48 }
49 
onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,const FrontendScanMessageExt1_1 & message)50 Return<void> FrontendCallback::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type,
51                                                    const FrontendScanMessageExt1_1& message) {
52     android::Mutex::Autolock autoLock(mMsgLock);
53     ALOGD("[vts] frontend ext1_1 scan message. Type: %d", type);
54     switch (message.getDiscriminator()) {
55         case FrontendScanMessageExt1_1::hidl_discriminator::modulation:
56             readFrontendScanMessageExt1_1Modulation(message.modulation());
57             break;
58         case FrontendScanMessageExt1_1::hidl_discriminator::isHighPriority:
59             ALOGD("[vts] frontend ext1_1 scan message high priority: %d", message.isHighPriority());
60             break;
61         case FrontendScanMessageExt1_1::hidl_discriminator::annex:
62             ALOGD("[vts] frontend ext1_1 scan message dvbc annex: %hhu", message.annex());
63             break;
64         default:
65             break;
66     }
67     return Void();
68 }
69 
readFrontendScanMessageExt1_1Modulation(FrontendModulation modulation)70 void FrontendCallback::readFrontendScanMessageExt1_1Modulation(FrontendModulation modulation) {
71     switch (modulation.getDiscriminator()) {
72         case FrontendModulation::hidl_discriminator::dvbc:
73             ALOGD("[vts] frontend ext1_1 scan message modulation dvbc: %d", modulation.dvbc());
74             break;
75         case FrontendModulation::hidl_discriminator::dvbs:
76             ALOGD("[vts] frontend ext1_1 scan message modulation dvbs: %d", modulation.dvbs());
77             break;
78         case FrontendModulation::hidl_discriminator::isdbs:
79             ALOGD("[vts] frontend ext1_1 scan message modulation isdbs: %d", modulation.isdbs());
80             break;
81         case FrontendModulation::hidl_discriminator::isdbs3:
82             ALOGD("[vts] frontend ext1_1 scan message modulation isdbs3: %d", modulation.isdbs3());
83             break;
84         case FrontendModulation::hidl_discriminator::isdbt:
85             ALOGD("[vts] frontend ext1_1 scan message modulation isdbt: %d", modulation.isdbt());
86             break;
87         case FrontendModulation::hidl_discriminator::atsc:
88             ALOGD("[vts] frontend ext1_1 scan message modulation atsc: %d", modulation.atsc());
89             break;
90         case FrontendModulation::hidl_discriminator::atsc3:
91             ALOGD("[vts] frontend ext1_1 scan message modulation atsc3: %d", modulation.atsc3());
92             break;
93         case FrontendModulation::hidl_discriminator::dvbt:
94             ALOGD("[vts] frontend ext1_1 scan message modulation dvbt: %d", modulation.dvbt());
95             break;
96         default:
97             break;
98     }
99 }
100 
tuneTestOnLock(sp<IFrontend> & frontend,FrontendSettings settings,FrontendSettingsExt1_1 settingsExt1_1)101 void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings,
102                                       FrontendSettingsExt1_1 settingsExt1_1) {
103     sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
104     frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(frontend);
105     if (frontend_1_1 == nullptr) {
106         EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
107         return;
108     }
109 
110     Result result = frontend_1_1->tune_1_1(settings, settingsExt1_1);
111     EXPECT_TRUE(result == Result::SUCCESS);
112 
113     android::Mutex::Autolock autoLock(mMsgLock);
114     while (!mLockMsgReceived) {
115         if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
116             EXPECT_TRUE(false) << "Event LOCKED not received within timeout";
117             mLockMsgReceived = false;
118             return;
119         }
120     }
121     mLockMsgReceived = false;
122 }
123 
scanTest(sp<IFrontend> & frontend,FrontendConfig1_1 config,FrontendScanType type)124 void FrontendCallback::scanTest(sp<IFrontend>& frontend, FrontendConfig1_1 config,
125                                 FrontendScanType type) {
126     sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
127     frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(frontend);
128     if (frontend_1_1 == nullptr) {
129         EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
130         return;
131     }
132 
133     uint32_t targetFrequency = getTargetFrequency(config.config1_0.settings);
134     if (type == FrontendScanType::SCAN_BLIND) {
135         // reset the frequency in the scan configuration to test blind scan. The settings param of
136         // passed in means the real input config on the transponder connected to the DUT.
137         // We want the blind the test to start from lower frequency than this to check the blind
138         // scan implementation.
139         resetBlindScanStartingFrequency(config, targetFrequency - 100);
140     }
141 
142     Result result = frontend_1_1->scan_1_1(config.config1_0.settings, type, config.settingsExt1_1);
143     EXPECT_TRUE(result == Result::SUCCESS);
144 
145     bool scanMsgLockedReceived = false;
146     bool targetFrequencyReceived = false;
147 
148     android::Mutex::Autolock autoLock(mMsgLock);
149 wait:
150     while (!mScanMessageReceived) {
151         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
152             EXPECT_TRUE(false) << "Scan message not received within timeout";
153             mScanMessageReceived = false;
154             mScanMsgProcessed = true;
155             return;
156         }
157     }
158 
159     if (mScanMessageType != FrontendScanMessageType::END) {
160         if (mScanMessageType == FrontendScanMessageType::LOCKED) {
161             scanMsgLockedReceived = true;
162             Result result =
163                     frontend_1_1->scan_1_1(config.config1_0.settings, type, config.settingsExt1_1);
164             EXPECT_TRUE(result == Result::SUCCESS);
165         }
166 
167         if (mScanMessageType == FrontendScanMessageType::FREQUENCY) {
168             targetFrequencyReceived = mScanMessage.frequencies().size() > 0 &&
169                                       mScanMessage.frequencies()[0] == targetFrequency;
170         }
171 
172         if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) {
173             ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent());
174         }
175 
176         mScanMessageReceived = false;
177         mScanMsgProcessed = true;
178         mMsgCondition.signal();
179         goto wait;
180     }
181 
182     EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END";
183     EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
184     mScanMessageReceived = false;
185     mScanMsgProcessed = true;
186 }
187 
getTargetFrequency(FrontendSettings settings)188 uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings) {
189     switch (settings.getDiscriminator()) {
190         case FrontendSettings::hidl_discriminator::analog:
191             return settings.analog().frequency;
192         case FrontendSettings::hidl_discriminator::atsc:
193             return settings.atsc().frequency;
194         case FrontendSettings::hidl_discriminator::atsc3:
195             return settings.atsc3().frequency;
196         case FrontendSettings::hidl_discriminator::dvbc:
197             return settings.dvbc().frequency;
198         case FrontendSettings::hidl_discriminator::dvbs:
199             return settings.dvbs().frequency;
200         case FrontendSettings::hidl_discriminator::dvbt:
201             return settings.dvbt().frequency;
202         case FrontendSettings::hidl_discriminator::isdbs:
203             return settings.isdbs().frequency;
204         case FrontendSettings::hidl_discriminator::isdbs3:
205             return settings.isdbs3().frequency;
206         case FrontendSettings::hidl_discriminator::isdbt:
207             return settings.isdbt().frequency;
208     }
209 }
210 
resetBlindScanStartingFrequency(FrontendConfig1_1 & config,uint32_t resetingFreq)211 void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig1_1& config,
212                                                        uint32_t resetingFreq) {
213     switch (config.config1_0.settings.getDiscriminator()) {
214         case FrontendSettings::hidl_discriminator::analog:
215             config.config1_0.settings.analog().frequency = resetingFreq;
216             break;
217         case FrontendSettings::hidl_discriminator::atsc:
218             config.config1_0.settings.atsc().frequency = resetingFreq;
219             break;
220         case FrontendSettings::hidl_discriminator::atsc3:
221             config.config1_0.settings.atsc3().frequency = resetingFreq;
222             break;
223         case FrontendSettings::hidl_discriminator::dvbc:
224             config.config1_0.settings.dvbc().frequency = resetingFreq;
225             break;
226         case FrontendSettings::hidl_discriminator::dvbs:
227             config.config1_0.settings.dvbs().frequency = resetingFreq;
228             break;
229         case FrontendSettings::hidl_discriminator::dvbt:
230             config.config1_0.settings.dvbt().frequency = resetingFreq;
231             break;
232         case FrontendSettings::hidl_discriminator::isdbs:
233             config.config1_0.settings.isdbs().frequency = resetingFreq;
234             break;
235         case FrontendSettings::hidl_discriminator::isdbs3:
236             config.config1_0.settings.isdbs3().frequency = resetingFreq;
237             break;
238         case FrontendSettings::hidl_discriminator::isdbt:
239             config.config1_0.settings.isdbt().frequency = resetingFreq;
240             break;
241     }
242 }
243 
getFrontendIds()244 AssertionResult FrontendTests::getFrontendIds() {
245     Result status;
246     mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
247         status = result;
248         mFeIds = frontendIds;
249     });
250     return AssertionResult(status == Result::SUCCESS);
251 }
252 
getFrontendInfo(uint32_t frontendId)253 AssertionResult FrontendTests::getFrontendInfo(uint32_t frontendId) {
254     Result status;
255     mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) {
256         mFrontendInfo = frontendInfo;
257         status = result;
258     });
259     return AssertionResult(status == Result::SUCCESS);
260 }
261 
openFrontendById(uint32_t frontendId)262 AssertionResult FrontendTests::openFrontendById(uint32_t frontendId) {
263     Result status;
264     mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) {
265         mFrontend = frontend;
266         status = result;
267     });
268     return AssertionResult(status == Result::SUCCESS);
269 }
270 
setFrontendCallback()271 AssertionResult FrontendTests::setFrontendCallback() {
272     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
273     mFrontendCallback = new FrontendCallback();
274     auto callbackStatus = mFrontend->setCallback(mFrontendCallback);
275     return AssertionResult(callbackStatus.isOk());
276 }
277 
scanFrontend(FrontendConfig1_1 config,FrontendScanType type)278 AssertionResult FrontendTests::scanFrontend(FrontendConfig1_1 config, FrontendScanType type) {
279     EXPECT_TRUE(mFrontendCallback)
280             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
281 
282     EXPECT_TRUE(mFrontendInfo.type == config.config1_0.type)
283             << "FrontendConfig does not match the frontend info of the given id.";
284 
285     mFrontendCallback->scanTest(mFrontend, config, type);
286     return AssertionResult(true);
287 }
288 
stopScanFrontend()289 AssertionResult FrontendTests::stopScanFrontend() {
290     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
291     Result status;
292     status = mFrontend->stopScan();
293 
294     return AssertionResult(status == Result::SUCCESS);
295 }
296 
getFrontendDtmbCaps(uint32_t id)297 AssertionResult FrontendTests::getFrontendDtmbCaps(uint32_t id) {
298     Result status;
299     mService->getFrontendDtmbCapabilities(
300             id, [&](Result result, const FrontendDtmbCapabilities& /*caps*/) { status = result; });
301     return AssertionResult(status == Result::SUCCESS);
302 }
303 
linkCiCam(uint32_t ciCamId)304 AssertionResult FrontendTests::linkCiCam(uint32_t ciCamId) {
305     sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
306     frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFrontend);
307     if (frontend_1_1 == nullptr) {
308         EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
309         return failure();
310     }
311 
312     Result status;
313     uint32_t ltsId;
314     frontend_1_1->linkCiCam(ciCamId, [&](Result r, uint32_t id) {
315         status = r;
316         ltsId = id;
317     });
318 
319     return AssertionResult(status == Result::SUCCESS);
320 }
321 
unlinkCiCam(uint32_t ciCamId)322 AssertionResult FrontendTests::unlinkCiCam(uint32_t ciCamId) {
323     sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
324     frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFrontend);
325     if (frontend_1_1 == nullptr) {
326         EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
327         return failure();
328     }
329 
330     Result status = frontend_1_1->unlinkCiCam(ciCamId);
331     return AssertionResult(status == Result::SUCCESS);
332 }
333 
verifyFrontendStatusExt1_1(vector<FrontendStatusTypeExt1_1> statusTypes,vector<FrontendStatusExt1_1> expectStatuses)334 void FrontendTests::verifyFrontendStatusExt1_1(vector<FrontendStatusTypeExt1_1> statusTypes,
335                                                vector<FrontendStatusExt1_1> expectStatuses) {
336     ASSERT_TRUE(mFrontend) << "Frontend is not opened yet.";
337     Result status;
338     vector<FrontendStatusExt1_1> realStatuses;
339 
340     sp<android::hardware::tv::tuner::V1_1::IFrontend> frontend_1_1;
341     frontend_1_1 = android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFrontend);
342     if (frontend_1_1 == nullptr) {
343         EXPECT_TRUE(false) << "Couldn't get 1.1 IFrontend from the Hal implementation.";
344         return;
345     }
346 
347     frontend_1_1->getStatusExt1_1(
348             statusTypes, [&](Result result, const hidl_vec<FrontendStatusExt1_1>& statuses) {
349                 status = result;
350                 realStatuses = statuses;
351             });
352 
353     ASSERT_TRUE(realStatuses.size() == statusTypes.size());
354     for (int i = 0; i < statusTypes.size(); i++) {
355         FrontendStatusTypeExt1_1 type = statusTypes[i];
356         switch (type) {
357             case FrontendStatusTypeExt1_1::MODULATIONS: {
358                 // TODO: verify modulations
359                 break;
360             }
361             case FrontendStatusTypeExt1_1::BERS: {
362                 ASSERT_TRUE(std::equal(realStatuses[i].bers().begin(), realStatuses[i].bers().end(),
363                                        expectStatuses[i].bers().begin()));
364                 break;
365             }
366             case FrontendStatusTypeExt1_1::CODERATES: {
367                 ASSERT_TRUE(std::equal(realStatuses[i].codeRates().begin(),
368                                        realStatuses[i].codeRates().end(),
369                                        expectStatuses[i].codeRates().begin()));
370                 break;
371             }
372             case FrontendStatusTypeExt1_1::GUARD_INTERVAL: {
373                 // TODO: verify interval
374                 break;
375             }
376             case FrontendStatusTypeExt1_1::TRANSMISSION_MODE: {
377                 // TODO: verify tranmission mode
378                 break;
379             }
380             case FrontendStatusTypeExt1_1::UEC: {
381                 ASSERT_TRUE(realStatuses[i].uec() == expectStatuses[i].uec());
382                 break;
383             }
384             case FrontendStatusTypeExt1_1::T2_SYSTEM_ID: {
385                 ASSERT_TRUE(realStatuses[i].systemId() == expectStatuses[i].systemId());
386                 break;
387             }
388             case FrontendStatusTypeExt1_1::INTERLEAVINGS: {
389                 ASSERT_TRUE(std::equal(realStatuses[i].interleaving().begin(),
390                                        realStatuses[i].interleaving().end(),
391                                        expectStatuses[i].interleaving().begin()));
392                 break;
393             }
394             case FrontendStatusTypeExt1_1::ISDBT_SEGMENTS: {
395                 ASSERT_TRUE(std::equal(realStatuses[i].isdbtSegment().begin(),
396                                        realStatuses[i].isdbtSegment().end(),
397                                        expectStatuses[i].isdbtSegment().begin()));
398                 break;
399             }
400             case FrontendStatusTypeExt1_1::TS_DATA_RATES: {
401                 ASSERT_TRUE(std::equal(realStatuses[i].tsDataRate().begin(),
402                                        realStatuses[i].tsDataRate().end(),
403                                        expectStatuses[i].tsDataRate().begin()));
404                 break;
405             }
406             case FrontendStatusTypeExt1_1::ROLL_OFF: {
407                 // TODO: verify roll off
408                 break;
409             }
410             case FrontendStatusTypeExt1_1::IS_MISO: {
411                 ASSERT_TRUE(realStatuses[i].isMiso() == expectStatuses[i].isMiso());
412                 break;
413             }
414             case FrontendStatusTypeExt1_1::IS_LINEAR: {
415                 ASSERT_TRUE(realStatuses[i].isLinear() == expectStatuses[i].isLinear());
416                 break;
417             }
418             case FrontendStatusTypeExt1_1::IS_SHORT_FRAMES: {
419                 ASSERT_TRUE(realStatuses[i].isShortFrames() == expectStatuses[i].isShortFrames());
420                 break;
421             }
422             default: {
423                 continue;
424             }
425         }
426     }
427     ASSERT_TRUE(status == Result::SUCCESS);
428 }
429 
tuneFrontend(FrontendConfig1_1 config,bool testWithDemux)430 AssertionResult FrontendTests::tuneFrontend(FrontendConfig1_1 config, bool testWithDemux) {
431     EXPECT_TRUE(mFrontendCallback)
432             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
433 
434     EXPECT_TRUE(mFrontendInfo.type == config.config1_0.type)
435             << "FrontendConfig does not match the frontend info of the given id.";
436 
437     mIsSoftwareFe = config.config1_0.isSoftwareFe;
438     bool result = true;
439     if (mIsSoftwareFe && testWithDemux) {
440         result &= mDvrTests.openDvrInDemux(mDvrConfig.type, mDvrConfig.bufferSize) == success();
441         result &= mDvrTests.configDvrPlayback(mDvrConfig.settings) == success();
442         result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
443         mDvrTests.startPlaybackInputThread(mDvrConfig.playbackInputFile,
444                                            mDvrConfig.settings.playback());
445         if (!result) {
446             ALOGW("[vts] Software frontend dvr configure failed.");
447             return failure();
448         }
449     }
450     mFrontendCallback->tuneTestOnLock(mFrontend, config.config1_0.settings, config.settingsExt1_1);
451     return AssertionResult(true);
452 }
453 
stopTuneFrontend(bool testWithDemux)454 AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
455     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
456     Result status;
457     status = mFrontend->stopTune();
458     if (mIsSoftwareFe && testWithDemux) {
459         mDvrTests.stopPlaybackThread();
460         mDvrTests.closeDvrPlayback();
461     }
462     return AssertionResult(status == Result::SUCCESS);
463 }
464 
closeFrontend()465 AssertionResult FrontendTests::closeFrontend() {
466     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
467     Result status;
468     status = mFrontend->close();
469     mFrontend = nullptr;
470     mFrontendCallback = nullptr;
471     return AssertionResult(status == Result::SUCCESS);
472 }
473 
getFrontendIdByType(FrontendType feType,uint32_t & feId)474 void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) {
475     ASSERT_TRUE(getFrontendIds());
476     ASSERT_TRUE(mFeIds.size() > 0);
477     for (size_t i = 0; i < mFeIds.size(); i++) {
478         ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
479         if (mFrontendInfo.type != feType) {
480             continue;
481         }
482         feId = mFeIds[i];
483         return;
484     }
485     feId = INVALID_ID;
486 }
487 
tuneTest(FrontendConfig1_1 frontendConf)488 void FrontendTests::tuneTest(FrontendConfig1_1 frontendConf) {
489     uint32_t feId;
490     getFrontendIdByType(frontendConf.config1_0.type, feId);
491     ASSERT_TRUE(feId != INVALID_ID);
492     ASSERT_TRUE(openFrontendById(feId));
493     ASSERT_TRUE(setFrontendCallback());
494     if (frontendConf.canConnectToCiCam) {
495         ASSERT_TRUE(linkCiCam(frontendConf.ciCamId));
496         ASSERT_TRUE(unlinkCiCam(frontendConf.ciCamId));
497     }
498     ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
499     verifyFrontendStatusExt1_1(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
500     ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
501     ASSERT_TRUE(closeFrontend());
502 }
503 
scanTest(FrontendConfig1_1 frontendConf,FrontendScanType scanType)504 void FrontendTests::scanTest(FrontendConfig1_1 frontendConf, FrontendScanType scanType) {
505     uint32_t feId;
506     getFrontendIdByType(frontendConf.config1_0.type, feId);
507     ASSERT_TRUE(feId != INVALID_ID);
508     ASSERT_TRUE(openFrontendById(feId));
509     ASSERT_TRUE(setFrontendCallback());
510     ASSERT_TRUE(scanFrontend(frontendConf, scanType));
511     ASSERT_TRUE(stopScanFrontend());
512     ASSERT_TRUE(closeFrontend());
513 }
514 
getFrontendDtmbCapsTest()515 void FrontendTests::getFrontendDtmbCapsTest() {
516     uint32_t feId;
517     getFrontendIdByType(
518             static_cast<FrontendType>(android::hardware::tv::tuner::V1_1::FrontendType::DTMB),
519             feId);
520     if (feId != INVALID_ID) {
521         ALOGD("[vts] Found DTMB Frontend");
522         ASSERT_TRUE(getFrontendDtmbCaps(feId));
523     }
524 }
525