diff --git a/tv/tuner/aidl/vts/functional/FilterTests.cpp b/tv/tuner/aidl/vts/functional/FilterTests.cpp index c53adb26b9..a5acdc171d 100644 --- a/tv/tuner/aidl/vts/functional/FilterTests.cpp +++ b/tv/tuner/aidl/vts/functional/FilterTests.cpp @@ -23,6 +23,33 @@ using ::aidl::android::hardware::common::NativeHandle; +::ndk::ScopedAStatus FilterCallback::onFilterEvent(const vector& events) { + android::Mutex::Autolock autoLock(mMsgLock); + // Temprarily we treat the first coming back filter data on the matching pid a success + // once all of the MQ are cleared, means we got all the expected output + readFilterEventsData(events); + mPidFilterOutputCount++; + mMsgCondition.signal(); + + // HACK: we need to cast the const away as DemuxFilterEvent contains a ScopedFileDescriptor + // that cannot be copied. + for (auto&& e : const_cast&>(events)) { + auto it = mFilterEventPromises.find(e.getTag()); + if (it != mFilterEventPromises.cend()) { + it->second.set_value(std::move(e)); + mFilterEventPromises.erase(it); + } + } + + return ::ndk::ScopedAStatus::ok(); +} + +std::future FilterCallback::getNextFilterEventWithTag(DemuxFilterEvent::Tag tag) { + // Note: this currently only supports one future per DemuxFilterEvent::Tag. + mFilterEventPromises[tag] = std::promise(); + return mFilterEventPromises[tag].get_future(); +} + void FilterCallback::testFilterDataOutput() { android::Mutex::Autolock autoLock(mMsgLock); while (mPidFilterOutputCount < 1) { diff --git a/tv/tuner/aidl/vts/functional/FilterTests.h b/tv/tuner/aidl/vts/functional/FilterTests.h index c965d953c2..6258bacb47 100644 --- a/tv/tuner/aidl/vts/functional/FilterTests.h +++ b/tv/tuner/aidl/vts/functional/FilterTests.h @@ -24,7 +24,9 @@ #include #include #include +#include #include +#include #include @@ -58,15 +60,9 @@ using MQDesc = MQDescriptor; class FilterCallback : public BnFilterCallback { public: - virtual ::ndk::ScopedAStatus onFilterEvent(const vector& events) override { - android::Mutex::Autolock autoLock(mMsgLock); - // Temprarily we treat the first coming back filter data on the matching pid a success - // once all of the MQ are cleared, means we got all the expected output - readFilterEventsData(events); - mPidFilterOutputCount++; - mMsgCondition.signal(); - return ::ndk::ScopedAStatus::ok(); - } + virtual ::ndk::ScopedAStatus onFilterEvent(const vector& events) override; + + std::future getNextFilterEventWithTag(DemuxFilterEvent::Tag tag); virtual ::ndk::ScopedAStatus onFilterStatus(const DemuxFilterStatus /*status*/) override { return ::ndk::ScopedAStatus::ok(); @@ -89,6 +85,7 @@ class FilterCallback : public BnFilterCallback { int32_t mFilterId; std::shared_ptr mFilter; + std::unordered_map> mFilterEventPromises; native_handle_t* mAvSharedHandle = nullptr; uint64_t mAvSharedMemSize = -1; diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp index 85e5c68b6a..88890e45a6 100644 --- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp +++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp @@ -640,6 +640,57 @@ TEST_P(TunerFilterAidlTest, testTimeFilter) { testTimeFilter(timeFilterMap[timeFilter.timeFilterId]); } +// TODO: move boilerplate into text fixture +TEST_P(TunerFilterAidlTest, FilterTimeDelayHintTest) { + description("Test filter delay hint."); + + int32_t feId; + int32_t demuxId; + std::shared_ptr demux; + int64_t filterId; + + mFrontendTests.getFrontendIdByType(frontendMap[live.frontendId].type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId)); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + mFilterTests.setDemux(demux); + + const auto& filterConf = filterMap[live.ipFilterId]; + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize)); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); + ASSERT_TRUE(mFilterTests.configIpFilterCid(filterConf.ipCid, filterId)); + + auto filter = mFilterTests.getFilterById(filterId); + + auto delayValue = std::chrono::milliseconds(5000); + FilterDelayHint delayHint; + delayHint.hintType = FilterDelayHintType::TIME_DELAY_IN_MS; + delayHint.hintValue = delayValue.count(); + + auto status = filter->setDelayHint(delayHint); + ASSERT_TRUE(status.isOk()); + + auto startTime = std::chrono::steady_clock::now(); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + + auto cb = mFilterTests.getFilterCallbacks().at(filterId); + auto future = cb->getNextFilterEventWithTag(DemuxFilterEvent::Tag::ipPayload); + + // block and wait for callback to be received. + ASSERT_EQ(future.wait_for(std::chrono::seconds(10)), std::future_status::ready); + auto duration = std::chrono::steady_clock::now() - startTime; + ASSERT_GE(duration, delayValue); + + // cleanup + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); +} + TEST_P(TunerPlaybackAidlTest, PlaybackDataFlowWithTsSectionFilterTest) { description("Feed ts data from playback and configure Ts section filter to get output"); if (!playback.support || playback.sectionFilterId.compare(emptyHardwareId) == 0) {