diff --git a/tv/tuner/1.1/IFilter.hal b/tv/tuner/1.1/IFilter.hal index b362e32c22..2ba9bb761d 100644 --- a/tv/tuner/1.1/IFilter.hal +++ b/tv/tuner/1.1/IFilter.hal @@ -51,4 +51,23 @@ interface IFilter extends @1.0::IFilter { * UNKNOWN_ERROR if failed for other reasons. */ configureIpCid(uint32_t ipCid) generates (Result result); + + /** + * Get the shared AV memory handle. Use IFilter.releaseAvHandle to release the handle. + * + * When media filters are opened, call this API to initialize the share memory handle if it's + * needed. + * + * If DemuxFilterMediaEvent.avMemory contains file descriptor, share memory should be ignored. + * + * @return avMemory A handle associated to the shared memory for audio or video. + * avMemory.data[0] is normally an fd for ION memory. When the avMemory->numFd is 0, the + * share memory is not initialized and does not contain valid fd. + * avMemory.data[avMemory.numFds] is an index used as a parameter of + * C2DataIdInfo to build C2 buffer in Codec. No C2 buffer would be created if the index + * does not exist. + * @return avMemSize the size of the shared av memory. It should be ignored when the share + * memory is not initialized. + */ + getAvSharedHandle() generates (Result result, handle avMemory, uint64_t avMemSize); }; diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp index 3db8b9e70d..c69beca12b 100644 --- a/tv/tuner/1.1/default/Filter.cpp +++ b/tv/tuner/1.1/default/Filter.cpp @@ -163,8 +163,17 @@ Return Filter::flush() { return Result::SUCCESS; } -Return Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t avDataId) { +Return Filter::releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) { ALOGV("%s", __FUNCTION__); + + if ((avMemory.getNativeHandle()->numFds > 0) && + (mSharedAvMemHandle.getNativeHandle()->numFds > 0) && + (sameFile(avMemory.getNativeHandle()->data[0], + mSharedAvMemHandle.getNativeHandle()->data[0]))) { + freeSharedAvHandle(); + return Result::SUCCESS; + } + if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) { return Result::INVALID_ARGUMENT; } @@ -190,6 +199,35 @@ Return Filter::configureIpCid(uint32_t ipCid) { return Result::SUCCESS; } +Return Filter::getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + if (!mIsMediaFilter) { + _hidl_cb(Result::INVALID_STATE, NULL, BUFFER_SIZE_16M); + return Void(); + } + + if (mSharedAvMemHandle.getNativeHandle() != nullptr) { + _hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M); + return Void(); + } + + int av_fd = createAvIonFd(BUFFER_SIZE_16M); + if (av_fd == -1) { + _hidl_cb(Result::UNKNOWN_ERROR, NULL, 0); + } + + native_handle_t* nativeHandle = createNativeHandle(av_fd); + if (nativeHandle == NULL) { + _hidl_cb(Result::UNKNOWN_ERROR, NULL, 0); + } + mSharedAvMemHandle.setTo(nativeHandle, /*shouldOwn=*/true); + ::close(av_fd); + + _hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M); + return Void(); +} + bool Filter::createFilterMQ() { ALOGV("%s", __FUNCTION__); @@ -313,10 +351,19 @@ void Filter::freeAvHandle() { } for (int i = 0; i < mFilterEvent.events.size(); i++) { ::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]); - native_handle_close(mFilterEvent.events[i].media().avMemory.getNativeHandle()); + native_handle_delete(const_cast( + mFilterEvent.events[i].media().avMemory.getNativeHandle())); } } +void Filter::freeSharedAvHandle() { + if (!mIsMediaFilter) { + return; + } + ::close(mSharedAvMemHandle.getNativeHandle()->data[0]); + native_handle_delete(const_cast(mSharedAvMemHandle.getNativeHandle())); +} + void Filter::maySendFilterStatusCallback() { if (!mIsUsingFMQ) { return; @@ -509,8 +556,8 @@ Result Filter::startMediaFilterHandler() { return Result::SUCCESS; } + Result result; if (mPts) { - Result result; result = createMediaFilterEventWithIon(mFilterOutput); if (result == Result::SUCCESS) { mFilterOutput.clear(); @@ -551,7 +598,10 @@ Result Filter::startMediaFilterHandler() { continue; } - createMediaFilterEventWithIon(mPesOutput); + result = createMediaFilterEventWithIon(mPesOutput); + if (result != Result::SUCCESS) { + return result; + } } mFilterOutput.clear(); @@ -560,51 +610,14 @@ Result Filter::startMediaFilterHandler() { } Result Filter::createMediaFilterEventWithIon(vector output) { - int av_fd = createAvIonFd(output.size()); - if (av_fd == -1) { - return Result::UNKNOWN_ERROR; + if (mUsingSharedAvMem) { + if (mSharedAvMemHandle.getNativeHandle() == nullptr) { + return Result::UNKNOWN_ERROR; + } + return createShareMemMediaEvents(output); } - // copy the filtered data to the buffer - uint8_t* avBuffer = getIonBuffer(av_fd, output.size()); - if (avBuffer == NULL) { - return Result::UNKNOWN_ERROR; - } - memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t)); - native_handle_t* nativeHandle = createNativeHandle(av_fd); - if (nativeHandle == NULL) { - return Result::UNKNOWN_ERROR; - } - hidl_handle handle; - handle.setTo(nativeHandle, /*shouldOwn=*/true); - - // Create a dataId and add a pair into the dataId2Avfd map - uint64_t dataId = mLastUsedDataId++ /*createdUID*/; - mDataId2Avfd[dataId] = dup(av_fd); - - // Create mediaEvent and send callback - DemuxFilterMediaEvent mediaEvent; - mediaEvent = { - .avMemory = std::move(handle), - .dataLength = static_cast(output.size()), - .avDataId = dataId, - }; - if (mPts) { - mediaEvent.pts = mPts; - mPts = 0; - } - int size = mFilterEvent.events.size(); - mFilterEvent.events.resize(size + 1); - mFilterEvent.events[size].media(mediaEvent); - - // Clear and log - output.clear(); - mAvBufferCopyCount = 0; - ::close(av_fd); - if (DEBUG_FILTER) { - ALOGD("[Filter] av data length %d", mediaEvent.dataLength); - } - return Result::SUCCESS; + return createIndependentMediaEvents(output); } Result Filter::startRecordFilterHandler() { @@ -713,15 +726,119 @@ uint8_t* Filter::getIonBuffer(int fd, int size) { } native_handle_t* Filter::createNativeHandle(int fd) { - // Create a native handle to pass the av fd via the callback event. - native_handle_t* nativeHandle = native_handle_create(/*numFd*/ 1, 0); + native_handle_t* nativeHandle; + if (fd < 0) { + nativeHandle = native_handle_create(/*numFd*/ 0, 0); + } else { + // Create a native handle to pass the av fd via the callback event. + nativeHandle = native_handle_create(/*numFd*/ 1, 0); + } if (nativeHandle == NULL) { ALOGE("[Filter] Failed to create native_handle %d", errno); return NULL; } - nativeHandle->data[0] = dup(fd); + if (nativeHandle->numFds > 0) { + nativeHandle->data[0] = dup(fd); + } return nativeHandle; } + +Result Filter::createIndependentMediaEvents(vector output) { + int av_fd = createAvIonFd(output.size()); + if (av_fd == -1) { + return Result::UNKNOWN_ERROR; + } + // copy the filtered data to the buffer + uint8_t* avBuffer = getIonBuffer(av_fd, output.size()); + if (avBuffer == NULL) { + return Result::UNKNOWN_ERROR; + } + memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t)); + + native_handle_t* nativeHandle = createNativeHandle(av_fd); + if (nativeHandle == NULL) { + return Result::UNKNOWN_ERROR; + } + hidl_handle handle; + handle.setTo(nativeHandle, /*shouldOwn=*/true); + + // Create a dataId and add a pair into the dataId2Avfd map + uint64_t dataId = mLastUsedDataId++ /*createdUID*/; + mDataId2Avfd[dataId] = dup(av_fd); + + // Create mediaEvent and send callback + DemuxFilterMediaEvent mediaEvent; + mediaEvent = { + .avMemory = std::move(handle), + .dataLength = static_cast(output.size()), + .avDataId = dataId, + }; + if (mPts) { + mediaEvent.pts = mPts; + mPts = 0; + } + int size = mFilterEvent.events.size(); + mFilterEvent.events.resize(size + 1); + mFilterEvent.events[size].media(mediaEvent); + + // Clear and log + output.clear(); + mAvBufferCopyCount = 0; + ::close(av_fd); + if (DEBUG_FILTER) { + ALOGD("[Filter] av data length %d", mediaEvent.dataLength); + } + return Result::SUCCESS; +} + +Result Filter::createShareMemMediaEvents(vector output) { + // copy the filtered data to the shared buffer + uint8_t* sharedAvBuffer = getIonBuffer(mSharedAvMemHandle.getNativeHandle()->data[0], + output.size() + mSharedAvMemOffset); + if (sharedAvBuffer == NULL) { + return Result::UNKNOWN_ERROR; + } + memcpy(sharedAvBuffer + mSharedAvMemOffset, output.data(), output.size() * sizeof(uint8_t)); + + // Create a memory handle with numFds == 0 + native_handle_t* nativeHandle = createNativeHandle(-1); + if (nativeHandle == NULL) { + return Result::UNKNOWN_ERROR; + } + hidl_handle handle; + handle.setTo(nativeHandle, /*shouldOwn=*/true); + + // Create mediaEvent and send callback + DemuxFilterMediaEvent mediaEvent; + mediaEvent = { + .offset = static_cast(mSharedAvMemOffset), + .dataLength = static_cast(output.size()), + .avMemory = handle, + }; + mSharedAvMemOffset += output.size(); + if (mPts) { + mediaEvent.pts = mPts; + mPts = 0; + } + int size = mFilterEvent.events.size(); + mFilterEvent.events.resize(size + 1); + mFilterEvent.events[size].media(mediaEvent); + + // Clear and log + output.clear(); + if (DEBUG_FILTER) { + ALOGD("[Filter] shared av data length %d", mediaEvent.dataLength); + } + return Result::SUCCESS; +} + +bool Filter::sameFile(int fd1, int fd2) { + struct stat stat1, stat2; + if (fstat(fd1, &stat1) < 0 || fstat(fd2, &stat2) < 0) { + return false; + } + return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino); +} } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.1/default/Filter.h b/tv/tuner/1.1/default/Filter.h index 23bc25c0d3..f6776661d3 100644 --- a/tv/tuner/1.1/default/Filter.h +++ b/tv/tuner/1.1/default/Filter.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "Demux.h" #include "Dvr.h" @@ -43,6 +44,7 @@ using ::android::hardware::MessageQueue; using ::android::hardware::MQDescriptorSync; using FilterMQ = MessageQueue; +const uint32_t BUFFER_SIZE_16M = 0x1000000; class Demux; class Dvr; @@ -78,6 +80,8 @@ class Filter : public V1_1::IFilter { virtual Return configureIpCid(uint32_t ipCid) override; + virtual Return getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) override; + /** * To create a FilterMQ and its Event Flag. * @@ -93,6 +97,7 @@ class Filter : public V1_1::IFilter { void attachFilterToRecord(const sp dvr); void detachFilterFromRecord(); void freeAvHandle(); + void freeSharedAvHandle(); bool isMediaFilter() { return mIsMediaFilter; }; bool isPcrFilter() { return mIsPcrFilter; }; bool isRecordFilter() { return mIsRecordFilter; }; @@ -185,6 +190,9 @@ class Filter : public V1_1::IFilter { uint8_t* getIonBuffer(int fd, int size); native_handle_t* createNativeHandle(int fd); Result createMediaFilterEventWithIon(vector output); + Result createIndependentMediaEvents(vector output); + Result createShareMemMediaEvents(vector output); + bool sameFile(int fd1, int fd2); /** * Lock to protect writes to the FMQs @@ -212,6 +220,11 @@ class Filter : public V1_1::IFilter { std::map mDataId2Avfd; uint64_t mLastUsedDataId = 1; int mAvBufferCopyCount = 0; + + // Shared A/V memory handle + hidl_handle mSharedAvMemHandle; + bool mUsingSharedAvMem = true; + uint32_t mSharedAvMemOffset = 0; }; } // namespace implementation diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp index 7e5b5498e0..5a8985dc2a 100644 --- a/tv/tuner/1.1/vts/functional/FilterTests.cpp +++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp @@ -16,22 +16,70 @@ #include "FilterTests.h" -bool FilterCallback::readFilterEventData() { - bool result = false; - ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId); +void FilterCallback::testFilterDataOutput() { + android::Mutex::Autolock autoLock(mMsgLock); + while (mPidFilterOutputCount < 1) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "filter output matching pid does not output within timeout"; + return; + } + } + mPidFilterOutputCount = 0; + ALOGW("[vts] pass and stop"); +} + +void FilterCallback::readFilterEventData() { + ALOGW("[vts] reading filter event"); // todo separate filter handlers + for (int i = 0; i < mFilterEvent.events.size(); i++) { + auto event = mFilterEvent.events[i]; + switch (event.getDiscriminator()) { + case DemuxFilterEvent::Event::hidl_discriminator::media: + ALOGD("[vts] Media filter event, avMemHandle numFds=%d.", + event.media().avMemory.getNativeHandle()->numFds); + dumpAvData(event.media()); + break; + default: + break; + } + } for (int i = 0; i < mFilterEventExt.events.size(); i++) { auto eventExt = mFilterEventExt.events[i]; switch (eventExt.getDiscriminator()) { case DemuxFilterEventExt::Event::hidl_discriminator::tsRecord: - ALOGW("[vts] Extended TS record filter event, pts=%" PRIu64 ".", + ALOGD("[vts] Extended TS record filter event, pts=%" PRIu64 ".", eventExt.tsRecord().pts); break; default: break; } } - return result; +} + +bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { + uint32_t length = event.dataLength; + uint32_t offset = event.offset; + // read data from buffer pointed by a handle + hidl_handle handle = event.avMemory; + if (handle.getNativeHandle()->numFds == 0) { + if (mAvSharedHandle == NULL) { + return false; + } + handle = mAvSharedHandle; + } + + int av_fd = handle.getNativeHandle()->data[0]; + uint8_t* buffer = + static_cast(mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0)); + if (buffer == MAP_FAILED) { + ALOGE("[vts] fail to allocate av buffer, errno=%d", errno); + return false; + } + uint8_t output[length + 1]; + memcpy(output, buffer + offset, length); + // print buffer and check with golden output. + ::close(av_fd); + return true; } AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) { @@ -81,6 +129,33 @@ AssertionResult FilterTests::getNewlyOpenedFilterId_64bit(uint64_t& filterId) { return AssertionResult(status == Result::SUCCESS); } +AssertionResult FilterTests::getSharedAvMemoryHandle(uint64_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Open media filter first."; + Result status = Result::UNKNOWN_ERROR; + sp filter_v1_1 = + android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilters[filterId]); + if (filter_v1_1 != NULL) { + filter_v1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) { + status = r; + if (status == Result::SUCCESS) { + mFilterCallbacks[mFilterId]->setSharedHandle(avMemory); + mFilterCallbacks[mFilterId]->setMemSize(avMemSize); + mAvSharedHandle = avMemory; + } + }); + } + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::releaseShareAvHandle(uint64_t filterId) { + Result status; + EXPECT_TRUE(mFilters[filterId]) << "Open media filter first."; + EXPECT_TRUE(mAvSharedHandle) << "No shared av handle to release."; + status = mFilters[filterId]->releaseAvHandle(mAvSharedHandle, 0 /*dataId*/); + + return AssertionResult(status == Result::SUCCESS); +} + AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint64_t filterId) { Result status; EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h index a47f631868..bc6db86f9c 100644 --- a/tv/tuner/1.1/vts/functional/FilterTests.h +++ b/tv/tuner/1.1/vts/functional/FilterTests.h @@ -46,6 +46,7 @@ using android::hardware::Return; using android::hardware::Void; using android::hardware::tv::tuner::V1_0::DemuxFilterEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterMainType; +using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent; using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; using android::hardware::tv::tuner::V1_0::DemuxFilterType; @@ -93,7 +94,14 @@ class FilterCallback : public IFilterCallback { } virtual Return onFilterEvent( - const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& /*filterEvent*/) override { + const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& filterEvent) 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 + mFilterEvent = filterEvent; + readFilterEventData(); + mPidFilterOutputCount++; + mMsgCondition.signal(); return Void(); } @@ -104,8 +112,13 @@ class FilterCallback : public IFilterCallback { void setFilterId(uint32_t filterId) { mFilterId = filterId; } void setFilterInterface(sp filter) { mFilter = filter; } void setFilterEventType(FilterEventType type) { mFilterEventType = type; } + void setSharedHandle(hidl_handle sharedHandle) { mAvSharedHandle = sharedHandle; } + void setMemSize(uint64_t size) { mAvSharedMemSize = size; } - bool readFilterEventData(); + void testFilterDataOutput(); + + void readFilterEventData(); + bool dumpAvData(DemuxFilterMediaEvent event); private: uint32_t mFilterId; @@ -114,6 +127,9 @@ class FilterCallback : public IFilterCallback { DemuxFilterEvent mFilterEvent; DemuxFilterEventExt mFilterEventExt; + hidl_handle mAvSharedHandle = NULL; + uint64_t mAvSharedMemSize = -1; + android::Mutex mMsgLock; android::Mutex mFilterOutputLock; android::Condition mMsgCondition; @@ -127,10 +143,12 @@ class FilterTests { void setDemux(sp demux) { mDemux = demux; } sp getFilterById(uint64_t filterId) { return mFilters[filterId]; } - std::map> getFilterCallbacks() { return mFilterCallbacks; } + map> getFilterCallbacks() { return mFilterCallbacks; } AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize); AssertionResult getNewlyOpenedFilterId_64bit(uint64_t& filterId); + AssertionResult getSharedAvMemoryHandle(uint64_t filterId); + AssertionResult releaseShareAvHandle(uint64_t filterId); AssertionResult configFilter(DemuxFilterSettings setting, uint64_t filterId); AssertionResult configIpFilterCid(uint32_t ipCid, uint64_t filterId); AssertionResult getFilterMQDescriptor(uint64_t filterId); @@ -193,12 +211,14 @@ class FilterTests { sp mService; sp mFilter; sp mDemux; - std::map> mFilters; - std::map> mFilterCallbacks; + map> mFilters; + map> mFilterCallbacks; sp mFilterCallback; MQDesc mFilterMQDescriptor; vector mUsedFilterIds; + hidl_handle mAvSharedHandle = NULL; + uint64_t mFilterId = -1; }; diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp index e06de5394c..f87fa3c0d6 100644 --- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp +++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp @@ -18,6 +18,10 @@ namespace { +AssertionResult TunerBroadcastHidlTest::filterDataOutputTest() { + return filterDataOutputTestBase(mFilterTests); +} + void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf) { uint32_t feId; @@ -46,6 +50,38 @@ void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf, ASSERT_TRUE(mFrontendTests.closeFrontend()); } +void TunerBroadcastHidlTest::mediaFilterUsingSharedMemoryTest(FilterConfig filterConf, + FrontendConfig frontendConf) { + uint32_t feId; + uint32_t demuxId; + sp demux; + uint64_t filterId; + + mFrontendTests.getFrontendIdByType(frontendConf.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)); + mFrontendTests.setDemux(demux); + mFilterTests.setDemux(demux); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize)); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId)); + ASSERT_TRUE(mFilterTests.getSharedAvMemoryHandle(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + // tune test + ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/)); + ASSERT_TRUE(filterDataOutputTest()); + ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/)); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.releaseShareAvHandle(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); +} + void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf, DvrConfig dvrConf) { uint32_t feId; @@ -116,6 +152,16 @@ TEST_P(TunerFrontendHidlTest, BlindScanFrontendWithEndFrequency) { mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND); } +TEST_P(TunerBroadcastHidlTest, MediaFilterWithSharedMemoryHandle) { + description("Test the Media Filter with shared memory handle"); + mediaFilterUsingSharedMemoryTest(filterArray[TS_VIDEO0], frontendArray[DVBT]); +} + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerBroadcastHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); + INSTANTIATE_TEST_SUITE_P( PerInstance, TunerFrontendHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h index 47004f62f0..f77a740136 100644 --- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h +++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h @@ -26,6 +26,20 @@ void initConfiguration() { initDvrConfig(); } +static AssertionResult success() { + return ::testing::AssertionSuccess(); +} + +AssertionResult filterDataOutputTestBase(FilterTests tests) { + // Data Verify Module + std::map>::iterator it; + std::map> filterCallbacks = tests.getFilterCallbacks(); + for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) { + it->second->testFilterDataOutput(); + } + return success(); +} + class TunerFilterHidlTest : public testing::TestWithParam { public: virtual void SetUp() override { @@ -103,4 +117,34 @@ class TunerFrontendHidlTest : public testing::TestWithParam { }; GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFrontendHidlTest); + +class TunerBroadcastHidlTest : public testing::TestWithParam { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initConfiguration(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + mFilterTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; + + AssertionResult filterDataOutputTest(); + + void mediaFilterUsingSharedMemoryTest(FilterConfig filterConf, FrontendConfig frontendConf); +}; + +// TODO remove from the allow list once the cf tv target is enabled for testing +GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerBroadcastHidlTest); } // namespace \ No newline at end of file