From 976c640464b1d6ed82f68522ab4f7b692ca69dbb Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Tue, 8 Sep 2020 17:08:29 -0700 Subject: [PATCH] Add API to get the shared memory Audio/Video handle In the MediaEvent of AV filters, the AV memory handle is mapped/unmapped on each event. If the vendor allocates a persistent memory block, and use MediaEvent.offset to access the data, the mapping change is unnecessary. To improve this, a new API to get shared AV Memory is introduced. To pass additional information to Codec2 for AV memory, the index for Codec2 to setup additional information can be carried in the handle. Test: atest VtsHalTvTunerV1_1TargetTest Bug: 162013047 Bug: 157143515 Bug: 156664393 Change-Id: Ibd4471ff8e19b0a99b8bcbc982dc08dbcc92efcf --- tv/tuner/1.1/IFilter.hal | 19 ++ tv/tuner/1.1/default/Filter.cpp | 217 ++++++++++++++---- tv/tuner/1.1/default/Filter.h | 13 ++ tv/tuner/1.1/vts/functional/FilterTests.cpp | 85 ++++++- tv/tuner/1.1/vts/functional/FilterTests.h | 30 ++- .../VtsHalTvTunerV1_1TargetTest.cpp | 46 ++++ .../functional/VtsHalTvTunerV1_1TargetTest.h | 44 ++++ 7 files changed, 394 insertions(+), 60 deletions(-) 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