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 <binder/MemoryDealer.h>
18
19 #include "../../../config/TunerTestingConfigAidlReaderV1_0.h"
20
21 #include <aidl/android/hardware/tv/tuner/DataFormat.h>
22 #include <aidl/android/hardware/tv/tuner/DemuxAlpFilterType.h>
23 #include <aidl/android/hardware/tv/tuner/DemuxFilterMainType.h>
24 #include <aidl/android/hardware/tv/tuner/DemuxFilterMonitorEventType.h>
25 #include <aidl/android/hardware/tv/tuner/DemuxFilterSettings.h>
26 #include <aidl/android/hardware/tv/tuner/DemuxFilterType.h>
27 #include <aidl/android/hardware/tv/tuner/DemuxIpAddress.h>
28 #include <aidl/android/hardware/tv/tuner/DemuxIpFilterSettings.h>
29 #include <aidl/android/hardware/tv/tuner/DemuxIpFilterType.h>
30 #include <aidl/android/hardware/tv/tuner/DemuxMmtpFilterType.h>
31 #include <aidl/android/hardware/tv/tuner/DemuxRecordScIndexType.h>
32 #include <aidl/android/hardware/tv/tuner/DemuxTsFilterType.h>
33 #include <aidl/android/hardware/tv/tuner/DvrSettings.h>
34 #include <aidl/android/hardware/tv/tuner/DvrType.h>
35 #include <aidl/android/hardware/tv/tuner/FrontendDvbtBandwidth.h>
36 #include <aidl/android/hardware/tv/tuner/FrontendDvbtCoderate.h>
37 #include <aidl/android/hardware/tv/tuner/FrontendDvbtConstellation.h>
38 #include <aidl/android/hardware/tv/tuner/FrontendDvbtGuardInterval.h>
39 #include <aidl/android/hardware/tv/tuner/FrontendDvbtHierarchy.h>
40 #include <aidl/android/hardware/tv/tuner/FrontendDvbtSettings.h>
41 #include <aidl/android/hardware/tv/tuner/FrontendDvbtStandard.h>
42 #include <aidl/android/hardware/tv/tuner/FrontendDvbtTransmissionMode.h>
43 #include <aidl/android/hardware/tv/tuner/FrontendSettings.h>
44 #include <aidl/android/hardware/tv/tuner/FrontendType.h>
45 #include <aidl/android/hardware/tv/tuner/PlaybackSettings.h>
46 #include <aidl/android/hardware/tv/tuner/RecordSettings.h>
47
48 using namespace std;
49 using namespace aidl::android::hardware::tv::tuner;
50 using namespace android::media::tuner::testing::configuration::V1_0;
51
52 const int32_t FMQ_SIZE_4M = 0x400000;
53 const int32_t FMQ_SIZE_16M = 0x1000000;
54
55 #define FILTER_MAIN_TYPE_BIT_COUNT 5
56 #define STATUS_CHECK_INTERVAL_MS 100L
57
58 // Hardware configs
59 static map<string, FrontendConfig> frontendMap;
60 static map<string, FilterConfig> filterMap;
61 static map<string, DvrConfig> dvrMap;
62 static map<string, LnbConfig> lnbMap;
63 static map<string, TimeFilterConfig> timeFilterMap;
64 static map<string, vector<uint8_t>> diseqcMsgMap;
65 static map<string, DescramblerConfig> descramblerMap;
66
67 // Hardware and test cases connections
68 static LiveBroadcastHardwareConnections live;
69 static ScanHardwareConnections scan;
70 static DvrPlaybackHardwareConnections playback;
71 static DvrRecordHardwareConnections record;
72 static DescramblingHardwareConnections descrambling;
73 static LnbLiveHardwareConnections lnbLive;
74 static LnbRecordHardwareConnections lnbRecord;
75 static TimeFilterHardwareConnections timeFilter;
76 static LnbDescramblingHardwareConnections lnbDescrambling;
77
78 /*
79 * This function takes in a 2d vector of device Id's
80 * The n vectors correlate to the ids for n different devices (eg frontends, filters)
81 * The resultant 2d vector is every combination of id's with 1 id from each vector
82 */
generateIdCombinations(vector<vector<string>> & ids)83 inline vector<vector<string>> generateIdCombinations(vector<vector<string>>& ids) {
84 vector<vector<string>> combinations;
85
86 // The index of each vector in ids that will be used in the next combination
87 // EG {0, 2} means combo {ids[0][0] ids[1][2]} will be next
88 const int size = static_cast<int>(ids.size());
89 vector<int> indexes_used_in_combination(size, 0);
90
91 // The vector number from ids whose elements we will cycle through to make combinations.
92 // First, start at the right most vector
93 int cycled_vector = size - 1;
94
95 while (cycled_vector >= 0) {
96 // Make a combination (one at a time)
97 vector<string> combo;
98 for (size_t i = 0; i < indexes_used_in_combination.size(); ++i) {
99 const int combo_index = indexes_used_in_combination[i];
100 combo.push_back(ids[i][combo_index]);
101 }
102 combinations.push_back(combo);
103
104 // Find the right most vector that still has space [elements left] to cycle through and
105 // create a combination
106 while (cycled_vector >= 0 &&
107 indexes_used_in_combination[cycled_vector] == ids[cycled_vector].size() - 1) {
108 cycled_vector--;
109 }
110
111 // Use this check to avoid segmentation faults
112 if (cycled_vector >= 0) {
113 // Once found, we have a vector we can cycle through, so increase to its next element
114 indexes_used_in_combination[cycled_vector]++;
115
116 // Reset the other vectors to the right to their first element so we can cycle through
117 // them again with the new element from cycled vector
118 for (size_t i = cycled_vector + 1; i < indexes_used_in_combination.size(); ++i) {
119 indexes_used_in_combination[i] = 0;
120 }
121
122 // all the vectors to the right were reset, so we can cycle through them again
123 // Start at the furthest right vector
124 cycled_vector = size - 1;
125 }
126 }
127
128 return combinations;
129 }
130
131 /*
132 * index 0 - playback dvr
133 * index 1 - audio filters
134 * index 2 - optional section filters
135 */
generatePlaybackCombinations()136 static inline vector<DvrPlaybackHardwareConnections> generatePlaybackCombinations() {
137 vector<DvrPlaybackHardwareConnections> combinations;
138 vector<string> sectionFilterIds_optional = sectionFilterIds;
139 sectionFilterIds_optional.push_back(emptyHardwareId);
140 vector<vector<string>> deviceIds{playbackDvrIds, audioFilterIds, sectionFilterIds_optional};
141
142 const int dvrIndex = 0;
143 const int audioFilterIndex = 1;
144 const int sectionFilterIndex = 2;
145
146 auto idCombinations = generateIdCombinations(deviceIds);
147 for (auto& combo : idCombinations) {
148 DvrPlaybackHardwareConnections mPlayback;
149 mPlayback.dvrId = combo[dvrIndex];
150 mPlayback.audioFilterId = combo[audioFilterIndex];
151 mPlayback.sectionFilterId = combo[sectionFilterIndex];
152 const int videoFilterIndex =
153 find(audioFilterIds.begin(), audioFilterIds.end(), mPlayback.audioFilterId) -
154 audioFilterIds.begin();
155 mPlayback.videoFilterId = videoFilterIds[videoFilterIndex];
156 combinations.push_back(mPlayback);
157 }
158
159 return combinations;
160 }
161
generatePlaybackConfigs()162 static inline vector<DvrPlaybackHardwareConnections> generatePlaybackConfigs() {
163 vector<DvrPlaybackHardwareConnections> playback_configs;
164 if (configuredPlayback) {
165 ALOGD("Using DVR playback configuration provided.");
166 playback_configs = {playback};
167 } else {
168 ALOGD("Dvr playback not provided. Generating possible combinations. Consider adding it to "
169 "the configuration file.");
170 playback_configs = generatePlaybackCombinations();
171 }
172
173 return playback_configs;
174 }
175
176 /*
177 * index 0 - frontends
178 * index 1 - audio filters
179 * index 2 - lnbs
180 */
generateLnbLiveCombinations()181 static inline vector<LnbLiveHardwareConnections> generateLnbLiveCombinations() {
182 vector<LnbLiveHardwareConnections> combinations;
183 vector<vector<string>> deviceIds{frontendIds, audioFilterIds, lnbIds};
184
185 const int frontendIndex = 0;
186 const int audioFilterIndex = 1;
187 const int lnbIndex = 2;
188
189 // TODO: Find a better way to vary diseqcMsgs, if at all
190 auto idCombinations = generateIdCombinations(deviceIds);
191 for (auto& combo : idCombinations) {
192 const string feId = combo[frontendIndex];
193 auto type = frontendMap[feId].type;
194 if (type == FrontendType::DVBS || type == FrontendType::ISDBS ||
195 type == FrontendType::ISDBS3) {
196 LnbLiveHardwareConnections mLnbLive;
197 mLnbLive.frontendId = feId;
198 mLnbLive.audioFilterId = combo[audioFilterIndex];
199 const int videoFilterIndex =
200 find(audioFilterIds.begin(), audioFilterIds.end(), mLnbLive.audioFilterId) -
201 audioFilterIds.begin();
202 mLnbLive.videoFilterId = videoFilterIds[videoFilterIndex];
203 mLnbLive.lnbId = combo[lnbIndex];
204 mLnbLive.diseqcMsgs = diseqcMsgs;
205 combinations.push_back(mLnbLive);
206 }
207 }
208
209 return combinations;
210 }
211
generateLnbLiveConfigurations()212 static inline vector<LnbLiveHardwareConnections> generateLnbLiveConfigurations() {
213 vector<LnbLiveHardwareConnections> lnbLive_configs;
214 if (configuredLnbLive) {
215 ALOGD("Using LnbLive configuration provided.");
216 lnbLive_configs = {lnbLive};
217 } else {
218 ALOGD("LnbLive not provided. Generating possible combinations. Consider adding it to the "
219 "configuration file.");
220 lnbLive_configs = generateLnbLiveCombinations();
221 }
222
223 return lnbLive_configs;
224 }
225
generateScanCombinations()226 static inline vector<ScanHardwareConnections> generateScanCombinations() {
227 vector<ScanHardwareConnections> combinations;
228
229 for (auto& id : frontendIds) {
230 ScanHardwareConnections mScan;
231 mScan.frontendId = id;
232 combinations.push_back(mScan);
233 }
234
235 return combinations;
236 }
237
generateScanConfigurations()238 static inline vector<ScanHardwareConnections> generateScanConfigurations() {
239 vector<ScanHardwareConnections> scan_configs;
240 if (configuredScan) {
241 ALOGD("Using scan configuration provided.");
242 scan_configs = {scan};
243 } else {
244 ALOGD("Scan not provided. Generating possible combinations. Consider adding it to "
245 "the configuration file.");
246 scan_configs = generateScanCombinations();
247 }
248
249 return scan_configs;
250 }
251
252 /*
253 * index 0 - frontends
254 * index 1 - record filter
255 * index 2 - Record Dvr
256 * index 3 - Lnb
257 */
generateLnbRecordCombinations()258 static inline vector<LnbRecordHardwareConnections> generateLnbRecordCombinations() {
259 vector<LnbRecordHardwareConnections> combinations;
260 vector<vector<string>> deviceIds{frontendIds, recordFilterIds, recordDvrIds, lnbIds};
261
262 const int frontendIndex = 0;
263 const int recordFilterIndex = 1;
264 const int dvrIndex = 2;
265 const int lnbIndex = 3;
266
267 auto idCombinations = generateIdCombinations(deviceIds);
268 // TODO : Find a better way to vary diseqcMsgs, if at all
269 for (auto& combo : idCombinations) {
270 const string feId = combo[frontendIndex];
271 auto type = frontendMap[feId].type;
272 if (type == FrontendType::DVBS || type == FrontendType::ISDBS ||
273 type == FrontendType::ISDBS3) {
274 LnbRecordHardwareConnections mLnbRecord;
275 mLnbRecord.frontendId = feId;
276 mLnbRecord.recordFilterId = combo[recordFilterIndex];
277 mLnbRecord.dvrRecordId = combo[dvrIndex];
278 mLnbRecord.lnbId = combo[lnbIndex];
279 mLnbRecord.diseqcMsgs = diseqcMsgs;
280 combinations.push_back(mLnbRecord);
281 }
282 }
283
284 return combinations;
285 }
286
generateLnbRecordConfigurations()287 static inline vector<LnbRecordHardwareConnections> generateLnbRecordConfigurations() {
288 vector<LnbRecordHardwareConnections> lnbRecord_configs;
289 if (configuredLnbRecord) {
290 ALOGD("Using LnbRecord configuration provided.");
291 lnbRecord_configs = {lnbRecord};
292 } else {
293 ALOGD("LnbRecord not provided. Generating possible combinations. Consider adding it to "
294 "the configuration file.");
295 lnbRecord_configs = generateLnbRecordCombinations();
296 }
297
298 return lnbRecord_configs;
299 }
300
301 /*
302 * index 0 - decramblers
303 * index 1 - frontends
304 * index 2 - audio filters
305 * index 3 - Dvr SW Fe Connections
306 * index 4 - DVR Source Connections
307 */
generateDescramblingCombinations()308 static inline vector<DescramblingHardwareConnections> generateDescramblingCombinations() {
309 vector<DescramblingHardwareConnections> combinations;
310 vector<string> mfrontendIds = frontendIds;
311 vector<string> mDvrFeConnectionIds = playbackDvrIds;
312 vector<string> mDvrSourceConnectionIds = playbackDvrIds;
313
314 // Add the empty hardware id to each vector to include combinations where these 3 fields might
315 // be optional
316 mfrontendIds.push_back(emptyHardwareId);
317 mDvrFeConnectionIds.push_back(emptyHardwareId);
318 mDvrSourceConnectionIds.push_back(emptyHardwareId);
319
320 const int descramblerIndex = 0;
321 const int frontendIndex = 1;
322 const int audioFilterIndex = 2;
323 const int dvrFeIdIndex = 3;
324 const int dvrSourceIdIndex = 4;
325
326 vector<vector<string>> deviceIds{descramblerIds, mfrontendIds, audioFilterIds,
327 mDvrFeConnectionIds, mDvrSourceConnectionIds};
328 auto idCombinations = generateIdCombinations(deviceIds);
329 for (auto& combo : idCombinations) {
330 DescramblingHardwareConnections mDescrambling;
331 const string feId = combo[frontendIndex];
332 const string dvrSwFeId = combo[dvrFeIdIndex];
333 const string dvrSourceId = combo[dvrSourceIdIndex];
334 mDescrambling.hasFrontendConnection = feId.compare(emptyHardwareId) == 0 ? false : true;
335 if (!mDescrambling.hasFrontendConnection) {
336 if (dvrSourceId.compare(emptyHardwareId) == 0) {
337 // If combination does not have a frontend or dvr source connection, do not include
338 // it
339 continue;
340 }
341 } else {
342 if (frontendMap[feId].isSoftwareFe && dvrSwFeId.compare(emptyHardwareId) == 0) {
343 // If combination has a software frontend and no dvr->software frontend connection,
344 // do not include it
345 continue;
346 }
347 }
348 if (dvrSwFeId.compare(dvrSourceId) == 0) {
349 // If dvr->software frontend connection is the same as dvr source input to tuner, do not
350 // include it.
351 continue;
352 }
353 mDescrambling.frontendId = feId;
354 mDescrambling.audioFilterId = combo[audioFilterIndex];
355 const int videoFilterIndex =
356 find(audioFilterIds.begin(), audioFilterIds.end(), mDescrambling.audioFilterId) -
357 audioFilterIds.begin();
358 mDescrambling.videoFilterId = videoFilterIds[videoFilterIndex];
359 mDescrambling.dvrSoftwareFeId = dvrSwFeId;
360 mDescrambling.dvrSourceId = dvrSourceId;
361 mDescrambling.descramblerId = combo[descramblerIndex];
362 combinations.push_back(mDescrambling);
363 }
364
365 return combinations;
366 }
367
generateDescramblingConfigurations()368 static inline vector<DescramblingHardwareConnections> generateDescramblingConfigurations() {
369 vector<DescramblingHardwareConnections> descrambling_configs;
370 if (configuredDescrambling) {
371 ALOGD("Using Descrambling configuration provided.");
372 descrambling_configs = {descrambling};
373 } else {
374 ALOGD("Descrambling not provided. Generating possible combinations. Consider adding it to "
375 "the "
376 "configuration file.");
377 descrambling_configs = generateDescramblingCombinations();
378 }
379
380 return descrambling_configs;
381 }
382
generateTimeFilterCombinations()383 static inline vector<TimeFilterHardwareConnections> generateTimeFilterCombinations() {
384 vector<TimeFilterHardwareConnections> combinations;
385
386 for (auto& id : timeFilterIds) {
387 TimeFilterHardwareConnections mTimeFilter;
388 mTimeFilter.timeFilterId = id;
389 combinations.push_back(mTimeFilter);
390 }
391
392 return combinations;
393 }
394
generateTimeFilterConfigurations()395 static inline vector<TimeFilterHardwareConnections> generateTimeFilterConfigurations() {
396 vector<TimeFilterHardwareConnections> timeFilter_configs;
397 if (configuredTimeFilter) {
398 ALOGD("Using TimeFilter configuration provided.");
399 timeFilter_configs = {timeFilter};
400 } else {
401 ALOGD("TimeFilter not provided. Generating possible combinations. Consider adding it to "
402 "the "
403 "configuration file.");
404 timeFilter_configs = generateTimeFilterCombinations();
405 }
406
407 return timeFilter_configs;
408 }
409
410 /*
411 * index 0 - frontends
412 * index 1 - record dvrs
413 * index 2 - record filters
414 */
generateRecordCombinations()415 static inline vector<DvrRecordHardwareConnections> generateRecordCombinations() {
416 vector<DvrRecordHardwareConnections> combinations;
417
418 const int frontendIdIndex = 0;
419 const int recordDvrIndex = 1;
420 const int recordFilterIndex = 2;
421
422 vector<vector<string>> deviceIds{frontendIds, recordDvrIds, recordFilterIds};
423
424 auto idCombinations = generateIdCombinations(deviceIds);
425 for (auto& combo : idCombinations) {
426 DvrRecordHardwareConnections mRecord;
427 const string feId = combo[frontendIdIndex];
428 mRecord.hasFrontendConnection = true;
429 if (frontendMap[feId].isSoftwareFe) {
430 // If we have a software frontend, do not include configuration for testing.
431 continue;
432 }
433 mRecord.frontendId = feId;
434 mRecord.support = true;
435 mRecord.dvrSourceId = emptyHardwareId;
436 mRecord.dvrSoftwareFeId = emptyHardwareId;
437 mRecord.recordFilterId = combo[recordFilterIndex];
438 mRecord.dvrRecordId = combo[recordDvrIndex];
439 combinations.push_back(mRecord);
440 }
441
442 return combinations;
443 }
444
generateRecordConfigurations()445 static inline vector<DvrRecordHardwareConnections> generateRecordConfigurations() {
446 vector<DvrRecordHardwareConnections> record_configs;
447 if (configuredRecord) {
448 ALOGD("Using Record configuration provided.");
449 record_configs = {record};
450 } else {
451 ALOGD("Record not provided. Generating possible combinations. Consider adding it to "
452 "the "
453 "configuration file.");
454 record_configs = generateRecordCombinations();
455 }
456
457 return record_configs;
458 }
459
460 /*
461 * index 0 - frontends
462 * index 1 - audio filters
463 * index 2 - playback dvrs
464 * index 3 - section Filters
465 */
generateLiveCombinations()466 static inline vector<LiveBroadcastHardwareConnections> generateLiveCombinations() {
467 vector<LiveBroadcastHardwareConnections> combinations;
468 vector<string> mSectionFilterIds = sectionFilterIds;
469 vector<string> mDvrSwConnectionIds = playbackDvrIds;
470
471 // Adding the empty hardware id to cover cases where fields are optional
472 mSectionFilterIds.push_back(emptyHardwareId);
473 mDvrSwConnectionIds.push_back(emptyHardwareId);
474
475 const int frontendIdIndex = 0;
476 const int audioFilterIdIndex = 1;
477 const int dvrSwConnectionIdIndex = 2;
478 const int sectionFilterIdIndex = 3;
479
480 vector<vector<string>> deviceIds{frontendIds, audioFilterIds, mDvrSwConnectionIds,
481 mSectionFilterIds};
482
483 auto idCombinations = generateIdCombinations(deviceIds);
484 for (auto& combo : idCombinations) {
485 LiveBroadcastHardwareConnections mLive;
486 const string feId = combo[frontendIdIndex];
487 const string dvrSwConnectionId = combo[dvrSwConnectionIdIndex];
488 mLive.hasFrontendConnection = true;
489
490 if (frontendMap[feId].isSoftwareFe && dvrSwConnectionId.compare(emptyHardwareId) == 0) {
491 // If the frontend is a software frontend and there is no dvr playback connected, do not
492 // include configuration
493 continue;
494 }
495 mLive.frontendId = feId;
496 mLive.dvrSoftwareFeId = dvrSwConnectionId;
497 mLive.audioFilterId = combo[audioFilterIdIndex];
498 const int videoFilterIdIndex =
499 find(audioFilterIds.begin(), audioFilterIds.end(), mLive.audioFilterId) -
500 audioFilterIds.begin();
501 mLive.videoFilterId = videoFilterIds[videoFilterIdIndex];
502 mLive.sectionFilterId = combo[sectionFilterIdIndex];
503
504 if (pcrFilterIds.empty()) {
505 // If pcr Filters have not been provided, set it to empty hardware id
506 mLive.pcrFilterId = emptyHardwareId;
507 } else {
508 // If pcr Filters have been provided, use the first index if there is only 1, or choose
509 // the filter that corresponds to the correct audio and video filter pair
510 const int pcrFilterIdIndex = pcrFilterIds.size() == 1 ? 0 : videoFilterIdIndex;
511 mLive.pcrFilterId = pcrFilterIds[pcrFilterIdIndex];
512 }
513
514 combinations.push_back(mLive);
515 }
516
517 return combinations;
518 }
519
generateLiveConfigurations()520 static inline vector<LiveBroadcastHardwareConnections> generateLiveConfigurations() {
521 vector<LiveBroadcastHardwareConnections> live_configs;
522 if (configuredLive) {
523 ALOGD("Using Live configuration provided.");
524 live_configs = {live};
525 } else {
526 ALOGD("Live not provided. Generating possible combinations. Consider adding it to "
527 "the "
528 "configuration file.");
529 live_configs = generateLiveCombinations();
530 }
531
532 return live_configs;
533 }
534
generateLnbDescramblingCombinations()535 static inline vector<LnbDescramblingHardwareConnections> generateLnbDescramblingCombinations() {
536 vector<LnbDescramblingHardwareConnections> combinations;
537 vector<vector<string>> deviceIds{frontendIds, audioFilterIds, lnbIds, descramblerIds};
538
539 const int frontendIdIndex = 0;
540 const int audioFilterIdIndex = 1;
541 const int lnbIdIndex = 2;
542 const int descramblerIdIndex = 3;
543
544 auto idCombinations = generateIdCombinations(deviceIds);
545 // TODO : Find a better way to vary diseqcMsgs, if at all
546 for (auto& combo : idCombinations) {
547 const string feId = combo[frontendIdIndex];
548 auto type = frontendMap[feId].type;
549 if (type == FrontendType::DVBS || type == FrontendType::ISDBS ||
550 type == FrontendType::ISDBS3) {
551 LnbDescramblingHardwareConnections mLnbDescrambling;
552 mLnbDescrambling.support = true;
553 mLnbDescrambling.frontendId = feId;
554 mLnbDescrambling.audioFilterId = combo[audioFilterIdIndex];
555 const int videoFilterIdIndex = find(audioFilterIds.begin(), audioFilterIds.end(),
556 mLnbDescrambling.audioFilterId) -
557 audioFilterIds.begin();
558 mLnbDescrambling.videoFilterId = videoFilterIds[videoFilterIdIndex];
559 mLnbDescrambling.lnbId = combo[lnbIdIndex];
560 mLnbDescrambling.descramblerId = combo[descramblerIdIndex];
561 mLnbDescrambling.diseqcMsgs = diseqcMsgs;
562 combinations.push_back(mLnbDescrambling);
563 }
564 }
565
566 return combinations;
567 }
568
generateLnbDescramblingConfigurations()569 static inline vector<LnbDescramblingHardwareConnections> generateLnbDescramblingConfigurations() {
570 vector<LnbDescramblingHardwareConnections> lnbDescrambling_configs;
571 if (configuredLnbDescrambling) {
572 ALOGD("Using LnbDescrambling configuration provided");
573 lnbDescrambling_configs = {lnbDescrambling};
574 } else {
575 ALOGD("LnbDescrambling not provided. Generating possible combinations. Consider adding it "
576 "to the configuration file.");
577 lnbDescrambling_configs = generateLnbDescramblingCombinations();
578 }
579
580 return lnbDescrambling_configs;
581 }
582
583 /** Config all the frontends that would be used in the tests */
initFrontendConfig()584 inline void initFrontendConfig() {
585 // The test will use the internal default fe when default fe is connected to any data flow
586 // without overriding in the xml config.
587 string defaultFeId = "FE_DEFAULT";
588 FrontendDvbtSettings dvbtSettings{
589 .frequency = 578000000,
590 .transmissionMode = FrontendDvbtTransmissionMode::AUTO,
591 .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
592 .isHighPriority = true,
593 };
594 frontendMap[defaultFeId].type = FrontendType::DVBT;
595 frontendMap[defaultFeId].settings.set<FrontendSettings::Tag::dvbt>(dvbtSettings);
596
597 vector<FrontendStatusType> types;
598 types.push_back(FrontendStatusType::UEC);
599 types.push_back(FrontendStatusType::IS_MISO);
600
601 vector<FrontendStatus> statuses;
602 FrontendStatus status;
603 status.set<FrontendStatus::Tag::uec>(4);
604 statuses.push_back(status);
605 status.set<FrontendStatus::Tag::isMiso>(true);
606 statuses.push_back(status);
607
608 frontendMap[defaultFeId].tuneStatusTypes = types;
609 frontendMap[defaultFeId].expectTuneStatuses = statuses;
610 frontendMap[defaultFeId].isSoftwareFe = true;
611 frontendMap[defaultFeId].canConnectToCiCam = true;
612 frontendMap[defaultFeId].ciCamId = 0;
613 frontendMap[defaultFeId].supportBlindScan = true;
614 FrontendDvbtSettings dvbt;
615 dvbt.transmissionMode = FrontendDvbtTransmissionMode::MODE_8K_E;
616 frontendMap[defaultFeId].settings.set<FrontendSettings::Tag::dvbt>(dvbt);
617 // Read customized config
618 TunerTestingConfigAidlReader1_0::readFrontendConfig1_0(frontendMap);
619 };
620
initFilterConfig()621 inline void initFilterConfig() {
622 // The test will use the internal default filter when default filter is connected to any
623 // data flow without overriding in the xml config.
624 string defaultAudioFilterId = "FILTER_AUDIO_DEFAULT";
625 string defaultVideoFilterId = "FILTER_VIDEO_DEFAULT";
626
627 filterMap[defaultVideoFilterId].type.mainType = DemuxFilterMainType::TS;
628 filterMap[defaultVideoFilterId].type.subType.set<DemuxFilterSubType::Tag::tsFilterType>(
629 DemuxTsFilterType::VIDEO);
630 filterMap[defaultVideoFilterId].bufferSize = FMQ_SIZE_16M;
631 filterMap[defaultVideoFilterId].settings =
632 DemuxFilterSettings::make<DemuxFilterSettings::Tag::ts>();
633 filterMap[defaultVideoFilterId].settings.get<DemuxFilterSettings::Tag::ts>().tpid = 256;
634 DemuxFilterAvSettings video;
635 video.isPassthrough = false;
636 filterMap[defaultVideoFilterId]
637 .settings.get<DemuxFilterSettings::Tag::ts>()
638 .filterSettings.set<DemuxTsFilterSettingsFilterSettings::Tag::av>(video);
639 filterMap[defaultVideoFilterId].monitorEventTypes =
640 static_cast<int32_t>(DemuxFilterMonitorEventType::SCRAMBLING_STATUS) |
641 static_cast<int32_t>(DemuxFilterMonitorEventType::IP_CID_CHANGE);
642 filterMap[defaultVideoFilterId].streamType.set<AvStreamType::Tag::video>(
643 VideoStreamType::MPEG1);
644
645 filterMap[defaultAudioFilterId].type.mainType = DemuxFilterMainType::TS;
646 filterMap[defaultAudioFilterId].type.subType.set<DemuxFilterSubType::Tag::tsFilterType>(
647 DemuxTsFilterType::AUDIO);
648 filterMap[defaultAudioFilterId].bufferSize = FMQ_SIZE_16M;
649 filterMap[defaultAudioFilterId].settings =
650 DemuxFilterSettings::make<DemuxFilterSettings::Tag::ts>();
651 filterMap[defaultAudioFilterId].settings.get<DemuxFilterSettings::Tag::ts>().tpid = 256;
652 DemuxFilterAvSettings audio;
653 audio.isPassthrough = false;
654 filterMap[defaultAudioFilterId]
655 .settings.get<DemuxFilterSettings::Tag::ts>()
656 .filterSettings.set<DemuxTsFilterSettingsFilterSettings::Tag::av>(audio);
657 filterMap[defaultAudioFilterId].monitorEventTypes =
658 static_cast<int32_t>(DemuxFilterMonitorEventType::SCRAMBLING_STATUS) |
659 static_cast<int32_t>(DemuxFilterMonitorEventType::IP_CID_CHANGE);
660 filterMap[defaultAudioFilterId].streamType.set<AvStreamType::Tag::audio>(AudioStreamType::MP3);
661 // Read customized config
662 TunerTestingConfigAidlReader1_0::readFilterConfig1_0(filterMap);
663 };
664
665 /** Config all the dvrs that would be used in the tests */
initDvrConfig()666 inline void initDvrConfig() {
667 // Read customized config
668 TunerTestingConfigAidlReader1_0::readDvrConfig1_0(dvrMap);
669 };
670
initTimeFilterConfig()671 inline void initTimeFilterConfig() {
672 // Read customized config
673 TunerTestingConfigAidlReader1_0::readTimeFilterConfig1_0(timeFilterMap);
674 };
675
initDescramblerConfig()676 inline void initDescramblerConfig() {
677 // Read customized config
678 TunerTestingConfigAidlReader1_0::readDescramblerConfig1_0(descramblerMap);
679 }
680
initLnbConfig()681 inline void initLnbConfig() {
682 // Read customized config
683 TunerTestingConfigAidlReader1_0::readLnbConfig1_0(lnbMap);
684 };
685
initDiseqcMsgsConfig()686 inline void initDiseqcMsgsConfig() {
687 // Read customized config
688 TunerTestingConfigAidlReader1_0::readDiseqcMessages(diseqcMsgMap);
689 };
690
determineScan()691 inline void determineScan() {
692 if (!frontendMap.empty()) {
693 scan.hasFrontendConnection = true;
694 ALOGD("Can support scan");
695 }
696 }
697
determineTimeFilter()698 inline void determineTimeFilter() {
699 if (!timeFilterMap.empty()) {
700 timeFilter.support = true;
701 ALOGD("Can support time filter");
702 }
703 }
704
determineDvrPlayback()705 inline void determineDvrPlayback() {
706 if (!playbackDvrIds.empty() && !audioFilterIds.empty() && !videoFilterIds.empty()) {
707 playback.support = true;
708 ALOGD("Can support dvr playback");
709 }
710 }
711
determineLnbLive()712 inline void determineLnbLive() {
713 if (!audioFilterIds.empty() && !videoFilterIds.empty() && !frontendMap.empty() &&
714 !lnbMap.empty()) {
715 lnbLive.support = true;
716 ALOGD("Can support lnb live");
717 }
718 }
719
determineLnbRecord()720 inline void determineLnbRecord() {
721 if (!frontendMap.empty() && !recordFilterIds.empty() && !recordDvrIds.empty() &&
722 !lnbMap.empty()) {
723 lnbRecord.support = true;
724 ALOGD("Can support lnb record");
725 }
726 }
727
determineLive()728 inline void determineLive() {
729 if (videoFilterIds.empty() || audioFilterIds.empty() || frontendMap.empty()) {
730 return;
731 }
732 if (!hasHwFe) {
733 if (hasSwFe) {
734 if (dvrMap.empty()) {
735 ALOGD("Cannot configure Live. Only software frontends and no dvr connections.");
736 return;
737 }
738 // Live is available if there is SW FE and some DVR is attached.
739 } else {
740 // We will arrive here because frontendMap won't be empty since
741 // there will be at least a default frontend declared. But the
742 // default frontend doesn't count as "hasSwFe".
743 ALOGD("Cannot configure Live. No frontend declared at all.");
744 return;
745 }
746 }
747 ALOGD("Can support live");
748 live.hasFrontendConnection = true;
749 }
750
determineDescrambling()751 inline void determineDescrambling() {
752 if (descramblerMap.empty() || audioFilterIds.empty() || videoFilterIds.empty()) {
753 return;
754 }
755 if (frontendMap.empty() && playbackDvrIds.empty()) {
756 ALOGD("Cannot configure descrambling. No frontends or playback dvr's");
757 return;
758 }
759 if (hasSwFe && !hasHwFe && playbackDvrIds.empty()) {
760 ALOGD("cannot configure descrambling. Only SW frontends and no playback dvr's");
761 return;
762 }
763 ALOGD("Can support descrambling");
764 descrambling.support = true;
765 }
766
determineDvrRecord()767 inline void determineDvrRecord() {
768 if (recordDvrIds.empty() || recordFilterIds.empty()) {
769 return;
770 }
771 if (frontendMap.empty() && playbackDvrIds.empty()) {
772 ALOGD("Cannot support dvr record. No frontends and no playback dvr's");
773 return;
774 }
775 if (hasSwFe && !hasHwFe && playbackDvrIds.empty()) {
776 ALOGD("Cannot support dvr record. Only SW frontends and no playback dvr's");
777 return;
778 }
779 ALOGD("Can support dvr record.");
780 record.support = true;
781 }
782
determineLnbDescrambling()783 inline void determineLnbDescrambling() {
784 if (frontendIds.empty() || audioFilterIds.empty() || videoFilterIds.empty() || lnbIds.empty() ||
785 descramblerIds.empty()) {
786 return;
787 }
788 ALOGD("Can support LnbDescrambling.");
789 lnbDescrambling.support = true;
790 }
791
792 /** Read the vendor configurations of which hardware to use for each test cases/data flows */
connectHardwaresToTestCases()793 inline void connectHardwaresToTestCases() {
794 TunerTestingConfigAidlReader1_0::connectLiveBroadcast(live);
795 TunerTestingConfigAidlReader1_0::connectScan(scan);
796 TunerTestingConfigAidlReader1_0::connectDvrRecord(record);
797 TunerTestingConfigAidlReader1_0::connectTimeFilter(timeFilter);
798 TunerTestingConfigAidlReader1_0::connectDescrambling(descrambling);
799 TunerTestingConfigAidlReader1_0::connectLnbLive(lnbLive);
800 TunerTestingConfigAidlReader1_0::connectLnbRecord(lnbRecord);
801 TunerTestingConfigAidlReader1_0::connectDvrPlayback(playback);
802 TunerTestingConfigAidlReader1_0::connectLnbDescrambling(lnbDescrambling);
803 };
804
determineDataFlows()805 inline void determineDataFlows() {
806 determineScan();
807 determineTimeFilter();
808 determineDvrPlayback();
809 determineLnbLive();
810 determineLnbRecord();
811 determineLive();
812 determineDescrambling();
813 determineDvrRecord();
814 determineLnbDescrambling();
815 }
816
validateConnections()817 inline bool validateConnections() {
818 if (record.support && !record.hasFrontendConnection &&
819 record.dvrSourceId.compare(emptyHardwareId) == 0) {
820 ALOGW("[vts config] Record must support either a DVR source or a Frontend source.");
821 return false;
822 }
823 bool feIsValid = live.hasFrontendConnection
824 ? frontendMap.find(live.frontendId) != frontendMap.end()
825 : true;
826 feIsValid &= scan.hasFrontendConnection ? frontendMap.find(scan.frontendId) != frontendMap.end()
827 : true;
828 feIsValid &= record.support && record.hasFrontendConnection
829 ? frontendMap.find(record.frontendId) != frontendMap.end()
830 : true;
831 feIsValid &= descrambling.support && descrambling.hasFrontendConnection
832 ? frontendMap.find(descrambling.frontendId) != frontendMap.end()
833 : true;
834
835 feIsValid &= lnbLive.support ? frontendMap.find(lnbLive.frontendId) != frontendMap.end() : true;
836
837 feIsValid &=
838 lnbRecord.support ? frontendMap.find(lnbRecord.frontendId) != frontendMap.end() : true;
839
840 feIsValid &= lnbDescrambling.support
841 ? frontendMap.find(lnbDescrambling.frontendId) != frontendMap.end()
842 : true;
843
844 if (!feIsValid) {
845 ALOGW("[vts config] dynamic config fe connection is invalid.");
846 return false;
847 }
848
849 bool dvrIsValid = frontendMap[live.frontendId].isSoftwareFe
850 ? dvrMap.find(live.dvrSoftwareFeId) != dvrMap.end()
851 : true;
852
853 if (record.support) {
854 if (record.hasFrontendConnection) {
855 if (frontendMap[record.frontendId].isSoftwareFe) {
856 dvrIsValid &= dvrMap.find(record.dvrSoftwareFeId) != dvrMap.end();
857 }
858 } else {
859 dvrIsValid &= dvrMap.find(record.dvrSourceId) != dvrMap.end();
860 }
861 dvrIsValid &= dvrMap.find(record.dvrRecordId) != dvrMap.end();
862 }
863
864 if (descrambling.support) {
865 if (descrambling.hasFrontendConnection) {
866 if (frontendMap[descrambling.frontendId].isSoftwareFe) {
867 dvrIsValid &= dvrMap.find(descrambling.dvrSoftwareFeId) != dvrMap.end();
868 }
869 } else {
870 dvrIsValid &= dvrMap.find(descrambling.dvrSourceId) != dvrMap.end();
871 }
872 }
873
874 dvrIsValid &= lnbRecord.support ? dvrMap.find(lnbRecord.dvrRecordId) != dvrMap.end() : true;
875
876 dvrIsValid &= playback.support ? dvrMap.find(playback.dvrId) != dvrMap.end() : true;
877
878 if (!dvrIsValid) {
879 ALOGW("[vts config] dynamic config dvr connection is invalid.");
880 return false;
881 }
882
883 bool filterIsValid = (live.hasFrontendConnection)
884 ? filterMap.find(live.audioFilterId) != filterMap.end() &&
885 filterMap.find(live.videoFilterId) != filterMap.end()
886 : true;
887 filterIsValid &=
888 record.support ? filterMap.find(record.recordFilterId) != filterMap.end() : true;
889
890 filterIsValid &= descrambling.support
891 ? filterMap.find(descrambling.videoFilterId) != filterMap.end() &&
892 filterMap.find(descrambling.audioFilterId) != filterMap.end()
893 : true;
894
895 for (auto& filterId : descrambling.extraFilters) {
896 filterIsValid &= filterMap.find(filterId) != filterMap.end();
897 }
898
899 filterIsValid &= lnbLive.support
900 ? filterMap.find(lnbLive.audioFilterId) != filterMap.end() &&
901 filterMap.find(lnbLive.videoFilterId) != filterMap.end()
902 : true;
903
904 filterIsValid &=
905 lnbRecord.support ? filterMap.find(lnbRecord.recordFilterId) != filterMap.end() : true;
906
907 for (auto& filterId : lnbRecord.extraFilters) {
908 filterIsValid &= filterMap.find(filterId) != filterMap.end();
909 }
910
911 for (auto& filterId : lnbLive.extraFilters) {
912 filterIsValid &= filterMap.find(filterId) != filterMap.end();
913 }
914
915 filterIsValid &= playback.support
916 ? filterMap.find(playback.audioFilterId) != filterMap.end() &&
917 filterMap.find(playback.videoFilterId) != filterMap.end()
918 : true;
919 filterIsValid &= playback.sectionFilterId.compare(emptyHardwareId) == 0
920 ? true
921 : filterMap.find(playback.sectionFilterId) != filterMap.end();
922
923 for (auto& filterId : playback.extraFilters) {
924 filterIsValid &=
925 playback.hasExtraFilters ? filterMap.find(filterId) != filterMap.end() : true;
926 }
927
928 filterIsValid &=
929 lnbDescrambling.support
930 ? filterMap.find(lnbDescrambling.audioFilterId) != filterMap.end() &&
931 filterMap.find(lnbDescrambling.videoFilterId) != filterMap.end()
932 : true;
933
934 if (!filterIsValid) {
935 ALOGW("[vts config] dynamic config filter connection is invalid.");
936 return false;
937 }
938
939 if (audioFilterIds.size() != videoFilterIds.size()) {
940 ALOGW("[vts config] the number of audio and video filters should be equal");
941 return false;
942 }
943
944 if (!pcrFilterIds.empty() && pcrFilterIds.size() != 1 &&
945 pcrFilterIds.size() != audioFilterIds.size()) {
946 ALOGW("[vts config] When more than 1 pcr filter is configured, the number of pcr filters "
947 "must equal the number of audio and video filters.");
948 return false;
949 }
950
951 bool timeFilterIsValid =
952 timeFilter.support ? timeFilterMap.find(timeFilter.timeFilterId) != timeFilterMap.end()
953 : true;
954
955 if (!timeFilterIsValid) {
956 ALOGW("[vts config] dynamic config time filter connection is invalid.");
957 }
958
959 bool descramblerIsValid =
960 descrambling.support
961 ? descramblerMap.find(descrambling.descramblerId) != descramblerMap.end()
962 : true;
963
964 descramblerIsValid &=
965 lnbDescrambling.support
966 ? descramblerMap.find(lnbDescrambling.descramblerId) != descramblerMap.end()
967 : true;
968
969 if (!descramblerIsValid) {
970 ALOGW("[vts config] dynamic config descrambler connection is invalid.");
971 return false;
972 }
973
974 bool lnbIsValid = lnbLive.support ? lnbMap.find(lnbLive.lnbId) != lnbMap.end() : true;
975
976 lnbIsValid &= lnbRecord.support ? lnbMap.find(lnbRecord.lnbId) != lnbMap.end() : true;
977
978 lnbIsValid &=
979 lnbDescrambling.support ? lnbMap.find(lnbDescrambling.lnbId) != lnbMap.end() : true;
980
981 if (!lnbIsValid) {
982 ALOGW("[vts config] dynamic config lnb connection is invalid.");
983 return false;
984 }
985
986 bool diseqcMsgsIsValid = true;
987
988 for (auto& msg : lnbRecord.diseqcMsgs) {
989 diseqcMsgsIsValid &= diseqcMsgMap.find(msg) != diseqcMsgMap.end();
990 }
991
992 for (auto& msg : lnbLive.diseqcMsgs) {
993 diseqcMsgsIsValid &= diseqcMsgMap.find(msg) != diseqcMsgMap.end();
994 }
995
996 for (auto& msg : lnbDescrambling.diseqcMsgs) {
997 diseqcMsgsIsValid &= diseqcMsgMap.find(msg) != diseqcMsgMap.end();
998 }
999
1000 if (!diseqcMsgsIsValid) {
1001 ALOGW("[vts config] dynamic config diseqcMsg is invalid.");
1002 return false;
1003 }
1004
1005 return true;
1006 }
1007