diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 5fbdd2df0c..491318e5c1 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -394,6 +394,9 @@ TEST_P(TunerDemuxHidlTest, openDemux) { TEST_P(TunerDemuxHidlTest, getAvSyncTime) { description("Get the A/V sync time from a PCR filter."); + if (live.pcrFilterId.compare(emptyHardwareId) == 0) { + return; + } uint32_t feId; uint32_t demuxId; sp demux; @@ -409,15 +412,15 @@ TEST_P(TunerDemuxHidlTest, getAvSyncTime) { ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); mFilterTests.setDemux(demux); - ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO1].type, - filterArray[TS_VIDEO1].bufferSize)); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterMap[live.videoFilterId].type, + filterMap[live.videoFilterId].bufferSize)); ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(mediaFilterId)); - ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO1].settings, mediaFilterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterMap[live.videoFilterId].settings, mediaFilterId)); mediaFilter = mFilterTests.getFilterById(mediaFilterId); - ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_PCR0].type, - filterArray[TS_PCR0].bufferSize)); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterMap[live.pcrFilterId].type, + filterMap[live.pcrFilterId].bufferSize)); ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(pcrFilterId)); - ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_PCR0].settings, pcrFilterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterMap[live.pcrFilterId].settings, pcrFilterId)); ASSERT_TRUE(mDemuxTests.getAvSyncId(mediaFilter, avSyncHwId)); ASSERT_TRUE(pcrFilterId == avSyncHwId); ASSERT_TRUE(mDemuxTests.getAvSyncTime(pcrFilterId)); @@ -430,7 +433,7 @@ TEST_P(TunerDemuxHidlTest, getAvSyncTime) { TEST_P(TunerFilterHidlTest, StartFilterInDemux) { description("Open and start a filter in Demux."); // TODO use paramterized tests - configSingleFilterInDemuxTest(filterArray[TS_VIDEO0], frontendMap[live.frontendId]); + configSingleFilterInDemuxTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]); } TEST_P(TunerFilterHidlTest, SetFilterLinkage) { @@ -471,35 +474,42 @@ TEST_P(TunerFilterHidlTest, testTimeFilter) { TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowVideoFilterTest) { description("Test Video Filter functionality in Broadcast use case."); - broadcastSingleFilterTest(filterArray[TS_VIDEO1], frontendMap[live.frontendId]); + broadcastSingleFilterTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]); } TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowAudioFilterTest) { description("Test Audio Filter functionality in Broadcast use case."); - broadcastSingleFilterTest(filterArray[TS_AUDIO0], frontendMap[live.frontendId]); + broadcastSingleFilterTest(filterMap[live.audioFilterId], frontendMap[live.frontendId]); } TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowSectionFilterTest) { description("Test Section Filter functionality in Broadcast use case."); - broadcastSingleFilterTest(filterArray[TS_SECTION0], frontendMap[live.frontendId]); + if (live.sectionFilterId.compare(emptyHardwareId) == 0) { + return; + } + broadcastSingleFilterTest(filterMap[live.sectionFilterId], frontendMap[live.frontendId]); } TEST_P(TunerBroadcastHidlTest, IonBufferTest) { description("Test the av filter data bufferring."); - broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendMap[live.frontendId]); + broadcastSingleFilterTest(filterMap[live.videoFilterId], frontendMap[live.frontendId]); } TEST_P(TunerBroadcastHidlTest, LnbBroadcastDataFlowVideoFilterTest) { description("Test Video Filter functionality in Broadcast with Lnb use case."); - broadcastSingleFilterTest(filterArray[TS_VIDEO0], frontendMap[live.frontendId]); + if (!lnbLive.support) { + return; + } + broadcastSingleFilterTestWithLnb(filterMap[lnbLive.videoFilterId], + frontendMap[lnbLive.frontendId], lnbArray[LNB0]); } TEST_P(TunerPlaybackHidlTest, PlaybackDataFlowWithTsSectionFilterTest) { description("Feed ts data from playback and configure Ts section filter to get output"); - if (!playback.support) { + if (!playback.support || playback.sectionFilterId.compare(emptyHardwareId) == 0) { return; } - playbackSingleFilterTest(filterArray[TS_SECTION0], dvrMap[playback.dvrId]); + playbackSingleFilterTest(filterMap[playback.sectionFilterId], dvrMap[playback.dvrId]); } TEST_P(TunerRecordHidlTest, AttachFiltersToRecordTest) { @@ -508,8 +518,8 @@ TEST_P(TunerRecordHidlTest, AttachFiltersToRecordTest) { if (!record.support) { return; } - attachSingleFilterToRecordDvrTest(filterArray[TS_RECORD0], frontendMap[record.frontendId], - dvrMap[record.dvrRecordId]); + attachSingleFilterToRecordDvrTest(filterMap[record.recordFilterId], + frontendMap[record.frontendId], dvrMap[record.dvrRecordId]); } TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) { @@ -517,17 +527,18 @@ TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) { if (!record.support) { return; } - recordSingleFilterTest(filterArray[TS_RECORD0], frontendMap[record.frontendId], + recordSingleFilterTest(filterMap[record.recordFilterId], frontendMap[record.frontendId], dvrMap[record.dvrRecordId]); } TEST_P(TunerRecordHidlTest, LnbRecordDataFlowWithTsRecordFilterTest) { description("Feed ts data from Fe with Lnb to recording and test with ts record filter"); - if (record.support) { + if (lnbRecord.support) { return; } - recordSingleFilterTestWithLnb(filterArray[TS_RECORD0], frontendMap[lnbRecord.frontendId], - dvrMap[record.dvrRecordId], lnbArray[LNB0]); + recordSingleFilterTestWithLnb(filterMap[lnbRecord.recordFilterId], + frontendMap[lnbRecord.frontendId], dvrMap[lnbRecord.dvrRecordId], + lnbArray[LNB0]); } TEST_P(TunerDescramblerHidlTest, CreateDescrambler) { @@ -556,8 +567,8 @@ TEST_P(TunerDescramblerHidlTest, ScrambledBroadcastDataFlowMediaFiltersTest) { return; } set filterConfs; - filterConfs.insert(filterArray[TS_AUDIO0]); - filterConfs.insert(filterArray[TS_VIDEO1]); + filterConfs.insert(static_cast(filterMap[descrambling.audioFilterId])); + filterConfs.insert(static_cast(filterMap[descrambling.videoFilterId])); scrambledBroadcastTest(filterConfs, frontendMap[descrambling.frontendId], descramblerArray[DESC_0]); } diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h index 9723c2d645..07ce201746 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h @@ -33,6 +33,7 @@ bool initConfiguration() { return false; } initFrontendConfig(); + initFilterConfig(); initDvrConfig(); connectHardwaresToTestCases(); if (!validateConnections()) { @@ -41,7 +42,6 @@ bool initConfiguration() { } initLnbConfig(); - initFilterConfig(); initTimeFilterConfig(); initDescramblerConfig(); diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index a1c5cd9aa2..8537fe8410 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -79,19 +79,6 @@ const uint32_t FMQ_SIZE_16M = 0x1000000; " \"track_types\": [ ] " \ "} " -typedef enum { - TS_VIDEO0, - TS_VIDEO1, - TS_AUDIO0, - TS_AUDIO1, - TS_PES0, - TS_PCR0, - TS_SECTION0, - TS_TS0, - TS_RECORD0, - FILTER_MAX, -} Filter; - typedef enum { TIMER0, TIMER_MAX, @@ -119,15 +106,6 @@ typedef enum { DESC_MAX, } Descrambler; -struct FilterConfig { - uint32_t bufferSize; - DemuxFilterType type; - DemuxFilterSettings settings; - bool getMqDesc; - - bool operator<(const FilterConfig& /*c*/) const { return false; } -}; - struct TimeFilterConfig { bool supportTimeFilter; uint64_t timeStamp; @@ -150,13 +128,13 @@ struct DescramblerConfig { // TODO: remove all the manual config array after the dynamic config refactoring is done. static LnbConfig lnbArray[LNB_MAX]; static vector diseqcMsgArray[DISEQC_MAX]; -static FilterConfig filterArray[FILTER_MAX]; static TimeFilterConfig timeFilterArray[TIMER_MAX]; static DemuxFilterType filterLinkageTypes[LINKAGE_DIR][FILTER_MAIN_TYPE_BIT_COUNT]; static DescramblerConfig descramblerArray[DESC_MAX]; // Hardware configs static map frontendMap; +static map filterMap; static map dvrMap; // Hardware and test cases connections @@ -196,6 +174,28 @@ inline void initFrontendConfig() { TunerTestingConfigReader::readFrontendConfig1_0(frontendMap); }; +inline void initFilterConfig() { + // The test will use the internal default filter when default filter is connected to any + // data flow without overriding in the xml config. + string defaultAudioFilterId = "FILTER_AUDIO_DEFAULT"; + string defaultVideoFilterId = "FILTER_VIDEO_DEFAULT"; + + filterMap[defaultVideoFilterId].type.mainType = DemuxFilterMainType::TS; + filterMap[defaultVideoFilterId].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); + filterMap[defaultVideoFilterId].bufferSize = FMQ_SIZE_16M; + filterMap[defaultVideoFilterId].settings.ts().tpid = 256; + filterMap[defaultVideoFilterId].settings.ts().filterSettings.av({.isPassthrough = false}); + + filterMap[defaultAudioFilterId].type.mainType = DemuxFilterMainType::TS; + filterMap[defaultAudioFilterId].type.subType.tsFilterType(DemuxTsFilterType::AUDIO); + filterMap[defaultAudioFilterId].bufferSize = FMQ_SIZE_16M; + filterMap[defaultAudioFilterId].settings.ts().tpid = 256; + filterMap[defaultAudioFilterId].settings.ts().filterSettings.av({.isPassthrough = false}); + + // Read customized config + TunerTestingConfigReader::readFilterConfig1_0(filterMap); +}; + /** Config all the dvrs that would be used in the tests */ inline void initDvrConfig() { // Read customized config @@ -250,6 +250,34 @@ inline bool validateConnections() { return false; } + bool filterIsValid = filterMap.find(live.audioFilterId) != filterMap.end() && + filterMap.find(live.videoFilterId) != filterMap.end(); + + filterIsValid &= playback.support + ? (filterMap.find(playback.audioFilterId) != filterMap.end() && + filterMap.find(playback.videoFilterId) != filterMap.end()) + : true; + + filterIsValid &= + record.support ? filterMap.find(record.recordFilterId) != filterMap.end() : true; + + filterIsValid &= descrambling.support + ? (filterMap.find(descrambling.audioFilterId) != filterMap.end() && + filterMap.find(descrambling.videoFilterId) != filterMap.end()) + : true; + + filterIsValid &= lnbLive.support ? (filterMap.find(lnbLive.audioFilterId) != filterMap.end() && + filterMap.find(lnbLive.videoFilterId) != filterMap.end()) + : true; + + filterIsValid &= + lnbRecord.support ? filterMap.find(lnbRecord.recordFilterId) != filterMap.end() : true; + + if (!filterIsValid) { + ALOGW("[vts config] dynamic config filter connection is invalid."); + return false; + } + return true; } @@ -272,91 +300,6 @@ inline void initDiseqcMsg() { diseqcMsgArray[DISEQC_POWER_ON] = {0xE, 0x0, 0x0, 0x0, 0x0, 0x3}; }; -/** Configuration array for the filter test */ -inline void initFilterConfig() { - // TS VIDEO filter setting for default implementation testing - filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); - filterArray[TS_VIDEO0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_VIDEO0].settings.ts().tpid = 256; - filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false}); - filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO); - filterArray[TS_VIDEO1].bufferSize = FMQ_SIZE_16M; - filterArray[TS_VIDEO1].settings.ts().tpid = 256; - filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false}); - // TS AUDIO filter setting - filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO); - filterArray[TS_AUDIO0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_AUDIO0].settings.ts().tpid = 256; - filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false}); - filterArray[TS_AUDIO1].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_AUDIO1].type.subType.tsFilterType(DemuxTsFilterType::AUDIO); - filterArray[TS_AUDIO1].bufferSize = FMQ_SIZE_16M; - filterArray[TS_AUDIO1].settings.ts().tpid = 257; - filterArray[TS_AUDIO1].settings.ts().filterSettings.av({.isPassthrough = false}); - // TS PES filter setting - filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES); - filterArray[TS_PES0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_PES0].settings.ts().tpid = 256; - filterArray[TS_PES0].settings.ts().filterSettings.pesData({ - .isRaw = false, - .streamId = 0xbd, - }); - filterArray[TS_PES0].getMqDesc = true; - // TS PCR filter setting - filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR); - filterArray[TS_PCR0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_PCR0].settings.ts().tpid = 256; - filterArray[TS_PCR0].settings.ts().filterSettings.noinit(); - // TS filter setting - filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS); - filterArray[TS_TS0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_TS0].settings.ts().tpid = 256; - filterArray[TS_TS0].settings.ts().filterSettings.noinit(); - // TS SECTION filter setting - filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION); - filterArray[TS_SECTION0].bufferSize = FMQ_SIZE_16M; - filterArray[TS_SECTION0].settings.ts().tpid = 256; - filterArray[TS_SECTION0].settings.ts().filterSettings.section({ - .isRaw = false, - }); - filterArray[TS_SECTION0].getMqDesc = true; - // TS RECORD filter setting - filterArray[TS_RECORD0].type.mainType = DemuxFilterMainType::TS; - filterArray[TS_RECORD0].type.subType.tsFilterType(DemuxTsFilterType::RECORD); - filterArray[TS_RECORD0].settings.ts().tpid = 81; - filterArray[TS_RECORD0].settings.ts().filterSettings.record({ - .scIndexType = DemuxRecordScIndexType::NONE, - }); - - // TS Linkage filter setting - filterLinkageTypes[SOURCE][0].mainType = DemuxFilterMainType::TS; - filterLinkageTypes[SOURCE][0].subType.tsFilterType(DemuxTsFilterType::TS); - filterLinkageTypes[SINK][0] = filterLinkageTypes[SOURCE][0]; - // MMTP Linkage filter setting - filterLinkageTypes[SOURCE][1].mainType = DemuxFilterMainType::MMTP; - filterLinkageTypes[SOURCE][1].subType.mmtpFilterType(DemuxMmtpFilterType::AUDIO); - filterLinkageTypes[SINK][1] = filterLinkageTypes[SOURCE][1]; - // IP Linkage filter setting - filterLinkageTypes[SOURCE][2].mainType = DemuxFilterMainType::IP; - filterLinkageTypes[SOURCE][2].subType.ipFilterType(DemuxIpFilterType::IP); - filterLinkageTypes[SINK][2] = filterLinkageTypes[SOURCE][2]; - // TLV Linkage filter setting - filterLinkageTypes[SOURCE][3].mainType = DemuxFilterMainType::TLV; - filterLinkageTypes[SOURCE][3].subType.tlvFilterType(DemuxTlvFilterType::TLV); - filterLinkageTypes[SINK][3] = filterLinkageTypes[SOURCE][3]; - // ALP Linkage PTP filter setting - filterLinkageTypes[SOURCE][4].mainType = DemuxFilterMainType::ALP; - filterLinkageTypes[SOURCE][4].subType.alpFilterType(DemuxAlpFilterType::PTP); - filterLinkageTypes[SINK][4] = filterLinkageTypes[SOURCE][4]; -}; - /** Configuration array for the timer filter test */ inline void initTimeFilterConfig() { timeFilterArray[TIMER0].supportTimeFilter = true; diff --git a/tv/tuner/config/TunerTestingConfigReader.h b/tv/tuner/config/TunerTestingConfigReader.h index aa2b75c1de..9ee509c6c1 100644 --- a/tv/tuner/config/TunerTestingConfigReader.h +++ b/tv/tuner/config/TunerTestingConfigReader.h @@ -29,8 +29,11 @@ using namespace android::media::tuner::testing::configuration::V1_0; using android::hardware::tv::tuner::V1_0::DataFormat; using android::hardware::tv::tuner::V1_0::DemuxAlpFilterType; +using android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterType; using android::hardware::tv::tuner::V1_0::DemuxIpFilterType; @@ -61,6 +64,7 @@ using android::hardware::tv::tuner::V1_0::PlaybackSettings; using android::hardware::tv::tuner::V1_0::RecordSettings; const string configFilePath = "/vendor/etc/tuner_vts_config.xml"; +const string emptyHardwareId = ""; struct FrontendConfig { bool isSoftwareFe; @@ -70,6 +74,15 @@ struct FrontendConfig { vector expectTuneStatuses; }; +struct FilterConfig { + uint32_t bufferSize; + DemuxFilterType type; + DemuxFilterSettings settings; + bool getMqDesc; + + bool operator<(const FilterConfig& /*c*/) const { return false; } +}; + struct DvrConfig { DvrType type; uint32_t bufferSize; @@ -80,9 +93,11 @@ struct DvrConfig { struct LiveBroadcastHardwareConnections { string frontendId; string dvrSoftwareFeId; - /* string audioFilterId; + string audioFilterId; string videoFilterId; - list string of extra filters; */ + string sectionFilterId; + string pcrFilterId; + /* list string of extra filters; */ }; struct ScanHardwareConnections { @@ -93,9 +108,10 @@ struct DvrPlaybackHardwareConnections { bool support; string frontendId; string dvrId; - /* string audioFilterId; + string audioFilterId; string videoFilterId; - list string of extra filters; */ + string sectionFilterId; + /* list string of extra filters; */ }; struct DvrRecordHardwareConnections { @@ -103,34 +119,34 @@ struct DvrRecordHardwareConnections { string frontendId; string dvrRecordId; string dvrSoftwareFeId; - /* string recordFilterId; - string dvrId; */ + string recordFilterId; }; struct DescramblingHardwareConnections { bool support; string frontendId; string dvrSoftwareFeId; - /* string descramblerId; string audioFilterId; string videoFilterId; + /* string descramblerId; list string of extra filters; */ }; struct LnbLiveHardwareConnections { bool support; string frontendId; - /* string audioFilterId; + string audioFilterId; string videoFilterId; - list string of extra filters; + /* list string of extra filters; string lnbId; */ }; struct LnbRecordHardwareConnections { bool support; string frontendId; - /* string recordFilterId; - list string of extra filters; + string dvrRecordId; + string recordFilterId; + /* list string of extra filters; string lnbId; */ }; @@ -149,7 +165,7 @@ struct TunerTestingConfigReader { static void readFrontendConfig1_0(map& frontendMap) { auto hardwareConfig = getHardwareConfig(); if (hardwareConfig.hasFrontends()) { - // TODO: complete the tune status config + // TODO: b/182519645 complete the tune status config vector types; types.push_back(FrontendStatusType::DEMOD_LOCK); FrontendStatus status; @@ -169,7 +185,7 @@ struct TunerTestingConfigReader { case FrontendTypeEnum::UNDEFINED: type = FrontendType::UNDEFINED; break; - // TODO: finish all other frontend settings + // TODO: b/182519645 finish all other frontend settings case FrontendTypeEnum::ANALOG: type = FrontendType::ANALOG; break; @@ -209,13 +225,42 @@ struct TunerTestingConfigReader { } frontendMap[id].type = type; frontendMap[id].isSoftwareFe = feConfig.getIsSoftwareFrontend(); - // TODO: complete the tune status config + // TODO: b/182519645 complete the tune status config frontendMap[id].tuneStatusTypes = types; frontendMap[id].expectTuneStatuses = statuses; } } } + static void readFilterConfig1_0(map& filterMap) { + auto hardwareConfig = getHardwareConfig(); + if (hardwareConfig.hasFilters()) { + auto filters = *hardwareConfig.getFirstFilters(); + for (auto filterConfig : filters.getFilter()) { + string id = filterConfig.getId(); + if (id.compare(string("FILTER_AUDIO_DEFAULT")) == 0) { + // overrid default + filterMap.erase(string("FILTER_AUDIO_DEFAULT")); + } + if (id.compare(string("FILTER_VIDEO_DEFAULT")) == 0) { + // overrid default + filterMap.erase(string("FILTER_VIDEO_DEFAULT")); + } + + DemuxFilterType type; + DemuxFilterSettings settings; + if (!readFilterTypeAndSettings(filterConfig, type, settings)) { + ALOGW("[ConfigReader] invalid filter type"); + return; + } + filterMap[id].type = type; + filterMap[id].bufferSize = filterConfig.getBufferSize(); + filterMap[id].getMqDesc = filterConfig.getUseFMQ(); + filterMap[id].settings = settings; + } + } + } + static void readDvrConfig1_0(map& dvrMap) { auto hardwareConfig = getHardwareConfig(); if (hardwareConfig.hasDvrs()) { @@ -246,10 +291,23 @@ struct TunerTestingConfigReader { } static void connectLiveBroadcast(LiveBroadcastHardwareConnections& live) { - auto liveConfig = getDataFlowConfiguration().getFirstClearLiveBroadcast(); - live.frontendId = liveConfig->getFrontendConnection(); - if (liveConfig->hasDvrSoftwareFeConnection()) { - live.dvrSoftwareFeId = liveConfig->getDvrSoftwareFeConnection(); + auto liveConfig = *getDataFlowConfiguration().getFirstClearLiveBroadcast(); + live.frontendId = liveConfig.getFrontendConnection(); + + live.audioFilterId = liveConfig.getAudioFilterConnection(); + live.videoFilterId = liveConfig.getVideoFilterConnection(); + if (liveConfig.hasPcrFilterConnection()) { + live.pcrFilterId = liveConfig.getPcrFilterConnection(); + } else { + live.pcrFilterId = emptyHardwareId; + } + if (liveConfig.hasSectionFilterConnection()) { + live.sectionFilterId = liveConfig.getSectionFilterConnection(); + } else { + live.sectionFilterId = emptyHardwareId; + } + if (liveConfig.hasDvrSoftwareFeConnection()) { + live.dvrSoftwareFeId = liveConfig.getDvrSoftwareFeConnection(); } } @@ -260,59 +318,78 @@ struct TunerTestingConfigReader { static void connectDvrPlayback(DvrPlaybackHardwareConnections& playback) { auto dataFlow = getDataFlowConfiguration(); - if (!dataFlow.hasDvrPlayback()) { - playback.support = false; + if (dataFlow.hasDvrPlayback()) { + playback.support = true; + } else { return; } - auto playbackConfig = dataFlow.getFirstDvrPlayback(); - playback.dvrId = playbackConfig->getDvrConnection(); + auto playbackConfig = *dataFlow.getFirstDvrPlayback(); + playback.dvrId = playbackConfig.getDvrConnection(); + playback.audioFilterId = playbackConfig.getAudioFilterConnection(); + playback.videoFilterId = playbackConfig.getVideoFilterConnection(); + if (playbackConfig.hasSectionFilterConnection()) { + playback.sectionFilterId = playbackConfig.getSectionFilterConnection(); + } else { + playback.sectionFilterId = emptyHardwareId; + } } static void connectDvrRecord(DvrRecordHardwareConnections& record) { auto dataFlow = getDataFlowConfiguration(); - if (!dataFlow.hasDvrRecord()) { - record.support = false; + if (dataFlow.hasDvrRecord()) { + record.support = true; + } else { return; } - auto recordConfig = dataFlow.getFirstDvrRecord(); - record.frontendId = recordConfig->getFrontendConnection(); - record.dvrRecordId = recordConfig->getDvrRecordConnection(); - if (recordConfig->hasDvrSoftwareFeConnection()) { - record.dvrSoftwareFeId = recordConfig->getDvrSoftwareFeConnection(); + auto recordConfig = *dataFlow.getFirstDvrRecord(); + record.frontendId = recordConfig.getFrontendConnection(); + record.recordFilterId = recordConfig.getRecordFilterConnection(); + record.dvrRecordId = recordConfig.getDvrRecordConnection(); + if (recordConfig.hasDvrSoftwareFeConnection()) { + record.dvrSoftwareFeId = recordConfig.getDvrSoftwareFeConnection(); } } static void connectDescrambling(DescramblingHardwareConnections& descrambling) { auto dataFlow = getDataFlowConfiguration(); - if (!dataFlow.hasDescrambling()) { - descrambling.support = false; + if (dataFlow.hasDescrambling()) { + descrambling.support = true; + } else { return; } - auto descConfig = dataFlow.getFirstDescrambling(); - descrambling.frontendId = descConfig->getFrontendConnection(); - if (descConfig->hasDvrSoftwareFeConnection()) { - descrambling.dvrSoftwareFeId = descConfig->getDvrSoftwareFeConnection(); + auto descConfig = *dataFlow.getFirstDescrambling(); + descrambling.frontendId = descConfig.getFrontendConnection(); + descrambling.audioFilterId = descConfig.getAudioFilterConnection(); + descrambling.videoFilterId = descConfig.getVideoFilterConnection(); + if (descConfig.hasDvrSoftwareFeConnection()) { + descrambling.dvrSoftwareFeId = descConfig.getDvrSoftwareFeConnection(); } } static void connectLnbLive(LnbLiveHardwareConnections& lnbLive) { auto dataFlow = getDataFlowConfiguration(); - if (!dataFlow.hasLnbLive()) { - lnbLive.support = false; + if (dataFlow.hasLnbLive()) { + lnbLive.support = true; + } else { return; } - auto lnbLiveConfig = dataFlow.getFirstLnbLive(); - lnbLive.frontendId = lnbLiveConfig->getFrontendConnection(); + auto lnbLiveConfig = *dataFlow.getFirstLnbLive(); + lnbLive.frontendId = lnbLiveConfig.getFrontendConnection(); + lnbLive.audioFilterId = lnbLiveConfig.getAudioFilterConnection(); + lnbLive.videoFilterId = lnbLiveConfig.getVideoFilterConnection(); } static void connectLnbRecord(LnbRecordHardwareConnections& lnbRecord) { auto dataFlow = getDataFlowConfiguration(); - if (!dataFlow.hasLnbRecord()) { - lnbRecord.support = false; + if (dataFlow.hasLnbRecord()) { + lnbRecord.support = true; + } else { return; } - auto lnbRecordConfig = dataFlow.getFirstLnbRecord(); - lnbRecord.frontendId = lnbRecordConfig->getFrontendConnection(); + auto lnbRecordConfig = *dataFlow.getFirstLnbRecord(); + lnbRecord.frontendId = lnbRecordConfig.getFrontendConnection(); + lnbRecord.recordFilterId = lnbRecordConfig.getRecordFilterConnection(); + lnbRecord.dvrRecordId = lnbRecordConfig.getDvrRecordConnection(); } private: @@ -350,6 +427,147 @@ struct TunerTestingConfigReader { return dvbsSettings; } + static bool readFilterTypeAndSettings(Filter filterConfig, DemuxFilterType& type, + DemuxFilterSettings& settings) { + auto mainType = filterConfig.getMainType(); + auto subType = filterConfig.getSubType(); + uint32_t pid = static_cast(filterConfig.getPid()); + switch (mainType) { + case FilterMainTypeEnum::TS: { + ALOGW("[ConfigReader] filter main type is ts"); + type.mainType = DemuxFilterMainType::TS; + switch (subType) { + case FilterSubTypeEnum::UNDEFINED: + break; + case FilterSubTypeEnum::SECTION: + type.subType.tsFilterType(DemuxTsFilterType::SECTION); + settings.ts().filterSettings.section( + readSectionFilterSettings(filterConfig)); + break; + case FilterSubTypeEnum::PES: + // TODO: b/182519645 support all the filter settings + /*settings.ts().filterSettings.pesData( + getPesFilterSettings(filterConfig));*/ + type.subType.tsFilterType(DemuxTsFilterType::PES); + break; + case FilterSubTypeEnum::TS: + type.subType.tsFilterType(DemuxTsFilterType::TS); + settings.ts().filterSettings.noinit(); + break; + case FilterSubTypeEnum::PCR: + type.subType.tsFilterType(DemuxTsFilterType::PCR); + settings.ts().filterSettings.noinit(); + break; + case FilterSubTypeEnum::TEMI: + type.subType.tsFilterType(DemuxTsFilterType::TEMI); + settings.ts().filterSettings.noinit(); + break; + case FilterSubTypeEnum::AUDIO: + type.subType.tsFilterType(DemuxTsFilterType::AUDIO); + settings.ts().filterSettings.av(readAvFilterSettings(filterConfig)); + break; + case FilterSubTypeEnum::VIDEO: + type.subType.tsFilterType(DemuxTsFilterType::VIDEO); + settings.ts().filterSettings.av(readAvFilterSettings(filterConfig)); + break; + case FilterSubTypeEnum::RECORD: + type.subType.tsFilterType(DemuxTsFilterType::RECORD); + settings.ts().filterSettings.record(readRecordFilterSettings(filterConfig)); + break; + default: + ALOGW("[ConfigReader] ts subtype is not supported"); + return false; + } + settings.ts().tpid = pid; + break; + } + case FilterMainTypeEnum::MMTP: { + ALOGW("[ConfigReader] filter main type is mmtp"); + type.mainType = DemuxFilterMainType::MMTP; + switch (subType) { + case FilterSubTypeEnum::UNDEFINED: + break; + case FilterSubTypeEnum::SECTION: + type.subType.mmtpFilterType(DemuxMmtpFilterType::SECTION); + settings.mmtp().filterSettings.section( + readSectionFilterSettings(filterConfig)); + break; + case FilterSubTypeEnum::PES: + type.subType.mmtpFilterType(DemuxMmtpFilterType::PES); + // TODO: b/182519645 support all the filter settings + /*settings.mmtp().filterSettings.pesData( + getPesFilterSettings(filterConfig));*/ + break; + case FilterSubTypeEnum::MMTP: + type.subType.mmtpFilterType(DemuxMmtpFilterType::MMTP); + settings.mmtp().filterSettings.noinit(); + break; + case FilterSubTypeEnum::AUDIO: + type.subType.mmtpFilterType(DemuxMmtpFilterType::AUDIO); + settings.mmtp().filterSettings.av(readAvFilterSettings(filterConfig)); + break; + case FilterSubTypeEnum::VIDEO: + settings.mmtp().filterSettings.av(readAvFilterSettings(filterConfig)); + break; + case FilterSubTypeEnum::RECORD: + type.subType.mmtpFilterType(DemuxMmtpFilterType::RECORD); + settings.mmtp().filterSettings.record( + readRecordFilterSettings(filterConfig)); + break; + case FilterSubTypeEnum::DOWNLOAD: + type.subType.mmtpFilterType(DemuxMmtpFilterType::DOWNLOAD); + // TODO: b/182519645 support all the filter settings + /*settings.mmtp().filterSettings.download( + getDownloadFilterSettings(filterConfig));*/ + break; + default: + ALOGW("[ConfigReader] mmtp subtype is not supported"); + return false; + } + settings.mmtp().mmtpPid = pid; + break; + } + default: + // TODO: b/182519645 support all the filter configs + ALOGW("[ConfigReader] filter main type is not supported in dynamic config"); + return false; + } + return true; + } + + static DemuxFilterSectionSettings readSectionFilterSettings(Filter filterConfig) { + DemuxFilterSectionSettings settings; + if (!filterConfig.hasSectionFilterSettings_optional()) { + return settings; + } + auto section = filterConfig.getFirstSectionFilterSettings_optional(); + settings.isCheckCrc = section->getIsCheckCrc(); + settings.isRepeat = section->getIsRepeat(); + settings.isRaw = section->getIsRaw(); + return settings; + } + + static DemuxFilterAvSettings readAvFilterSettings(Filter filterConfig) { + DemuxFilterAvSettings settings; + if (!filterConfig.hasAvFilterSettings_optional()) { + return settings; + } + auto av = filterConfig.getFirstAvFilterSettings_optional(); + settings.isPassthrough = av->getIsPassthrough(); + return settings; + } + + static DemuxFilterRecordSettings readRecordFilterSettings(Filter filterConfig) { + DemuxFilterRecordSettings settings; + if (!filterConfig.hasRecordFilterSettings_optional()) { + return settings; + } + auto record = filterConfig.getFirstRecordFilterSettings_optional(); + settings.tsIndexMask = static_cast(record->getTsIndexMask()); + settings.scIndexType = static_cast(record->getScIndexType()); + return settings; + } + static PlaybackSettings readPlaybackSettings(Dvr dvrConfig) { ALOGW("[ConfigReader] dvr type is playback"); PlaybackSettings playbackSettings{ diff --git a/tv/tuner/config/api/current.txt b/tv/tuner/config/api/current.txt index 1ebd8e1494..a768acbb0d 100644 --- a/tv/tuner/config/api/current.txt +++ b/tv/tuner/config/api/current.txt @@ -1,6 +1,12 @@ // Signature format: 2.0 package android.media.tuner.testing.configuration.V1_0 { + public class AvFilterSettings { + ctor public AvFilterSettings(); + method @Nullable public boolean getIsPassthrough(); + method public void setIsPassthrough(@Nullable boolean); + } + public class DataFlowConfiguration { ctor public DataFlowConfiguration(); method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration.ClearLiveBroadcast getClearLiveBroadcast(); @@ -21,24 +27,42 @@ package android.media.tuner.testing.configuration.V1_0 { public static class DataFlowConfiguration.ClearLiveBroadcast { ctor public DataFlowConfiguration.ClearLiveBroadcast(); + method @Nullable public String getAudioFilterConnection(); method @Nullable public String getDvrSoftwareFeConnection(); method @Nullable public String getFrontendConnection(); + method @Nullable public String getPcrFilterConnection(); + method @Nullable public String getSectionFilterConnection(); + method @Nullable public String getVideoFilterConnection(); + method public void setAudioFilterConnection(@Nullable String); method public void setDvrSoftwareFeConnection(@Nullable String); method public void setFrontendConnection(@Nullable String); + method public void setPcrFilterConnection(@Nullable String); + method public void setSectionFilterConnection(@Nullable String); + method public void setVideoFilterConnection(@Nullable String); } public static class DataFlowConfiguration.Descrambling { ctor public DataFlowConfiguration.Descrambling(); + method @Nullable public String getAudioFilterConnection(); method @Nullable public String getDvrSoftwareFeConnection(); method @Nullable public String getFrontendConnection(); + method @Nullable public String getVideoFilterConnection(); + method public void setAudioFilterConnection(@Nullable String); method public void setDvrSoftwareFeConnection(@Nullable String); method public void setFrontendConnection(@Nullable String); + method public void setVideoFilterConnection(@Nullable String); } public static class DataFlowConfiguration.DvrPlayback { ctor public DataFlowConfiguration.DvrPlayback(); + method @Nullable public String getAudioFilterConnection(); method @Nullable public String getDvrConnection(); + method @Nullable public String getSectionFilterConnection(); + method @Nullable public String getVideoFilterConnection(); + method public void setAudioFilterConnection(@Nullable String); method public void setDvrConnection(@Nullable String); + method public void setSectionFilterConnection(@Nullable String); + method public void setVideoFilterConnection(@Nullable String); } public static class DataFlowConfiguration.DvrRecord { @@ -46,23 +70,31 @@ package android.media.tuner.testing.configuration.V1_0 { method @Nullable public String getDvrRecordConnection(); method @Nullable public String getDvrSoftwareFeConnection(); method @Nullable public String getFrontendConnection(); + method @Nullable public String getRecordFilterConnection(); method public void setDvrRecordConnection(@Nullable String); method public void setDvrSoftwareFeConnection(@Nullable String); method public void setFrontendConnection(@Nullable String); + method public void setRecordFilterConnection(@Nullable String); } public static class DataFlowConfiguration.LnbLive { ctor public DataFlowConfiguration.LnbLive(); + method @Nullable public String getAudioFilterConnection(); method @Nullable public String getFrontendConnection(); + method @Nullable public String getVideoFilterConnection(); + method public void setAudioFilterConnection(@Nullable String); method public void setFrontendConnection(@Nullable String); + method public void setVideoFilterConnection(@Nullable String); } public static class DataFlowConfiguration.LnbRecord { ctor public DataFlowConfiguration.LnbRecord(); method @Nullable public String getDvrRecordConnection(); method @Nullable public String getFrontendConnection(); + method @Nullable public String getRecordFilterConnection(); method public void setDvrRecordConnection(@Nullable String); method public void setFrontendConnection(@Nullable String); + method public void setRecordFilterConnection(@Nullable String); } public static class DataFlowConfiguration.Scan { @@ -133,6 +165,49 @@ package android.media.tuner.testing.configuration.V1_0 { enum_constant public static final android.media.tuner.testing.configuration.V1_0.DvrTypeEnum RECORD; } + public class Filter { + ctor public Filter(); + method @Nullable public android.media.tuner.testing.configuration.V1_0.AvFilterSettings getAvFilterSettings_optional(); + method @Nullable public java.math.BigInteger getBufferSize(); + method @Nullable public String getId(); + method @Nullable public android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum getMainType(); + method @Nullable public java.math.BigInteger getPid(); + method @Nullable public android.media.tuner.testing.configuration.V1_0.RecordFilterSettings getRecordFilterSettings_optional(); + method @Nullable public android.media.tuner.testing.configuration.V1_0.SectionFilterSettings getSectionFilterSettings_optional(); + method @Nullable public android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum getSubType(); + method @Nullable public boolean getUseFMQ(); + method public void setAvFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.AvFilterSettings); + method public void setBufferSize(@Nullable java.math.BigInteger); + method public void setId(@Nullable String); + method public void setMainType(@Nullable android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum); + method public void setPid(@Nullable java.math.BigInteger); + method public void setRecordFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.RecordFilterSettings); + method public void setSectionFilterSettings_optional(@Nullable android.media.tuner.testing.configuration.V1_0.SectionFilterSettings); + method public void setSubType(@Nullable android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum); + method public void setUseFMQ(@Nullable boolean); + } + + public enum FilterMainTypeEnum { + method @NonNull public String getRawName(); + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum MMTP; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterMainTypeEnum TS; + } + + public enum FilterSubTypeEnum { + method @NonNull public String getRawName(); + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum AUDIO; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum DOWNLOAD; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum MMTP; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum PCR; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum PES; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum RECORD; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum SECTION; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum TEMI; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum TS; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum UNDEFINED; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.FilterSubTypeEnum VIDEO; + } + public class Frontend { ctor public Frontend(); method @Nullable public java.math.BigInteger getConnectToCicamId(); @@ -171,8 +246,10 @@ package android.media.tuner.testing.configuration.V1_0 { public class HardwareConfiguration { ctor public HardwareConfiguration(); method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Dvrs getDvrs(); + method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Filters getFilters(); method @Nullable public android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Frontends getFrontends(); method public void setDvrs(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Dvrs); + method public void setFilters(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Filters); method public void setFrontends(@Nullable android.media.tuner.testing.configuration.V1_0.HardwareConfiguration.Frontends); } @@ -181,11 +258,41 @@ package android.media.tuner.testing.configuration.V1_0 { method @Nullable public java.util.List getDvr(); } + public static class HardwareConfiguration.Filters { + ctor public HardwareConfiguration.Filters(); + method @Nullable public java.util.List getFilter(); + } + public static class HardwareConfiguration.Frontends { ctor public HardwareConfiguration.Frontends(); method @Nullable public java.util.List getFrontend(); } + public class RecordFilterSettings { + ctor public RecordFilterSettings(); + method @Nullable public android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum getScIndexType(); + method @Nullable public java.math.BigInteger getTsIndexMask(); + method public void setScIndexType(@Nullable android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum); + method public void setTsIndexMask(@Nullable java.math.BigInteger); + } + + public enum ScIndexTypeEnum { + method @NonNull public String getRawName(); + enum_constant public static final android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum NONE; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum SC; + enum_constant public static final android.media.tuner.testing.configuration.V1_0.ScIndexTypeEnum SC_HEVC; + } + + public class SectionFilterSettings { + ctor public SectionFilterSettings(); + method @Nullable public boolean getIsCheckCrc(); + method @Nullable public boolean getIsRaw(); + method @Nullable public boolean getIsRepeat(); + method public void setIsCheckCrc(@Nullable boolean); + method public void setIsRaw(@Nullable boolean); + method public void setIsRepeat(@Nullable boolean); + } + public class TunerConfiguration { ctor public TunerConfiguration(); method @Nullable public android.media.tuner.testing.configuration.V1_0.DataFlowConfiguration getDataFlowConfiguration(); diff --git a/tv/tuner/config/sample_tuner_vts_config.xml b/tv/tuner/config/sample_tuner_vts_config.xml index 001e04574e..44120f7e66 100644 --- a/tv/tuner/config/sample_tuner_vts_config.xml +++ b/tv/tuner/config/sample_tuner_vts_config.xml @@ -60,6 +60,51 @@ connectToCicamId="0" frequency="578000" endFrequency="800000"> + + + + + + + + + + + + + + + + + + - - + + diff --git a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd index 45d25e5999..03482b3a29 100644 --- a/tv/tuner/config/tuner_testing_dynamic_configuration.xsd +++ b/tv/tuner/config/tuner_testing_dynamic_configuration.xsd @@ -85,7 +85,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Each filter element contain the following attributes: + "id": unique id of the filter that could be used to connect to the test the + "dataFlowConfiguration" + "mainType": the main filter type. The enums are defined in the xsd. + "subType": the sub filter type. The enums are defined in the xsd. + "bufferSize": the buffer size of the filter in hex. + "pid": the pid that would be used to configure the filter. + "useFMQ": if the filter uses FMQ. + + Each filter element also contains at most one type-related "filterSettings". + - The settings type should match the filter "subType" attribute. + - For example, when filter subType is audio or video, the avFilterSettings + can be configured. + - This is optional and skipping the settings would pass a setting with tpid + config only to the hal. + + + + + + + + + + + + + + + + + @@ -197,6 +303,27 @@ + + + + + This section contains configurations of all the filters that would be + used in the tests. + - This section is optional and can be skipped to use the default + filter settings. + - The default settings can be found in the + sample_tuner_vts_configurations.xml. + - The users can also override the default filter settings using + - id="FILTER_AUDIO_DEFAULT" or "FILTER_VIDEO_DEFAULT". + - The users can configure 1 or more filter elements in the filters + sections. + + + + + + + @@ -223,6 +350,11 @@ + + + + + @@ -235,6 +367,9 @@ + + + @@ -242,6 +377,10 @@ + + + + @@ -250,16 +389,21 @@ + + + + + @@ -279,5 +423,13 @@ + + + + + + + +