diff options
Diffstat (limited to 'tv')
-rw-r--r-- | tv/tuner/1.0/vts/functional/Android.bp | 7 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/DemuxTests.cpp | 41 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/DemuxTests.h | 55 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/FilterTests.cpp | 226 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/FilterTests.h | 226 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/FrontendTests.cpp | 310 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/FrontendTests.h | 124 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp | 1115 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h | 260 | ||||
-rw-r--r-- | tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h | 2 |
10 files changed, 1319 insertions, 1047 deletions
diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp index 641e16a937..448575ea7a 100644 --- a/tv/tuner/1.0/vts/functional/Android.bp +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -17,7 +17,12 @@ cc_test { name: "VtsHalTvTunerV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], - srcs: ["VtsHalTvTunerV1_0TargetTest.cpp"], + srcs: [ + "VtsHalTvTunerV1_0TargetTest.cpp", + "FrontendTests.cpp", + "DemuxTests.cpp", + "FilterTests.cpp", + ], static_libs: [ "android.hardware.tv.tuner@1.0", "android.hidl.allocator@1.0", diff --git a/tv/tuner/1.0/vts/functional/DemuxTests.cpp b/tv/tuner/1.0/vts/functional/DemuxTests.cpp new file mode 100644 index 0000000000..b1d8a0a0b2 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/DemuxTests.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DemuxTests.h" + +AssertionResult DemuxTests::openDemux(sp<IDemux>& demux, uint32_t& demuxId) { + Result status; + mService->openDemux([&](Result result, uint32_t id, const sp<IDemux>& demuxSp) { + mDemux = demuxSp; + demux = demuxSp; + demuxId = id; + status = result; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult DemuxTests::setDemuxFrontendDataSource(uint32_t frontendId) { + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + auto status = mDemux->setFrontendDataSource(frontendId); + return AssertionResult(status.isOk()); +} + +AssertionResult DemuxTests::closeDemux() { + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + auto status = mDemux->close(); + mDemux = nullptr; + return AssertionResult(status.isOk()); +}
\ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/DemuxTests.h b/tv/tuner/1.0/vts/functional/DemuxTests.h new file mode 100644 index 0000000000..a72c09fd0c --- /dev/null +++ b/tv/tuner/1.0/vts/functional/DemuxTests.h @@ -0,0 +1,55 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/logging.h> +#include <android/hardware/tv/tuner/1.0/IDemux.h> +#include <android/hardware/tv/tuner/1.0/ITuner.h> +#include <android/hardware/tv/tuner/1.0/types.h> +#include <binder/MemoryDealer.h> +#include <gtest/gtest.h> +#include <hidl/ServiceManagement.h> +#include <hidl/Status.h> +#include <hidlmemory/FrameworkUtils.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <map> + +using android::sp; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::IDemux; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::Result; + +using ::testing::AssertionResult; + +class DemuxTests { + public: + sp<ITuner> mService; + + void setService(sp<ITuner> tuner) { mService = tuner; } + + AssertionResult openDemux(sp<IDemux>& demux, uint32_t& demuxId); + AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); + AssertionResult closeDemux(); + + protected: + static AssertionResult failure() { return ::testing::AssertionFailure(); } + + static AssertionResult success() { return ::testing::AssertionSuccess(); } + + sp<IDemux> mDemux; +}; diff --git a/tv/tuner/1.0/vts/functional/FilterTests.cpp b/tv/tuner/1.0/vts/functional/FilterTests.cpp new file mode 100644 index 0000000000..82e955d90e --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FilterTests.cpp @@ -0,0 +1,226 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FilterTests.h" + +void FilterCallback::startFilterEventThread(DemuxFilterEvent event) { + struct FilterThreadArgs* threadArgs = + (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs)); + threadArgs->user = this; + threadArgs->event = event; + + pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs); + pthread_setname_np(mFilterThread, "test_playback_input_loop"); +} + +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::updateFilterMQ(MQDesc& filterMQDescriptor) { + mFilterMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */); + EXPECT_TRUE(mFilterMQ); + EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == + android::OK); +} + +void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) { + mFilterIdToGoldenOutput = goldenOutputFile; +} + +void* FilterCallback::__threadLoopFilter(void* threadArgs) { + FilterCallback* const self = + static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user); + self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event); + return 0; +} + +void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { + android::Mutex::Autolock autoLock(mFilterOutputLock); + // Read from mFilterMQ[event.filterId] per event and filter type + + // Assemble to filterOutput[filterId] + + // check if filterOutput[filterId] matches goldenOutput[filterId] + + // If match, remove filterId entry from MQ map + + // end thread +} + +bool FilterCallback::readFilterEventData() { + bool result = false; + DemuxFilterEvent filterEvent = mFilterEvent; + ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId); + // todo separate filter handlers + for (int i = 0; i < filterEvent.events.size(); i++) { + switch (mFilterEventType) { + case FilterEventType::SECTION: + mDataLength = filterEvent.events[i].section().dataLength; + break; + case FilterEventType::PES: + mDataLength = filterEvent.events[i].pes().dataLength; + break; + case FilterEventType::MEDIA: + return dumpAvData(filterEvent.events[i].media()); + case FilterEventType::RECORD: + break; + case FilterEventType::MMTPRECORD: + break; + case FilterEventType::DOWNLOAD: + break; + default: + break; + } + // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not + // match"; + + mDataOutputBuffer.resize(mDataLength); + result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); + EXPECT_TRUE(result) << "can't read from Filter MQ"; + + /*for (int i = 0; i < mDataLength; i++) { + EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; + }*/ + } + mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); + return result; +} + +bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { + uint32_t length = event.dataLength; + uint64_t dataId = event.avDataId; + // read data from buffer pointed by a handle + hidl_handle handle = event.avMemory; + + int av_fd = handle.getNativeHandle()->data[0]; + uint8_t* buffer = static_cast<uint8_t*>( + mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/)); + if (buffer == MAP_FAILED) { + ALOGE("[vts] fail to allocate av buffer, errno=%d", errno); + return false; + } + uint8_t output[length + 1]; + memcpy(output, buffer, length); + // print buffer and check with golden output. + EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS); + return true; +} + +AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + + // Create demux callback + mFilterCallback = new FilterCallback(); + + // Add filter to the local demux + mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, + [&](Result result, const sp<IFilter>& filter) { + mFilter = filter; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallback->setFilterEventType(getFilterEventType(type)); + } + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::getNewlyOpenedFilterId(uint32_t& filterId) { + Result status; + EXPECT_TRUE(mDemux) << "Test with openDemux first."; + EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first."; + EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first."; + + mFilter->getId([&](Result result, uint32_t filterId) { + mFilterId = filterId; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallback->setFilterId(mFilterId); + mFilterCallback->setFilterInterface(mFilter); + mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId); + mFilters[mFilterId] = mFilter; + mFilterCallbacks[mFilterId] = mFilterCallback; + filterId = mFilterId; + } + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint32_t filterId) { + Result status; + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + status = mFilters[filterId]->configure(setting); + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::getFilterMQDescriptor(uint32_t filterId) { + Result status; + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first."; + + mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) { + mFilterMQDescriptor = filterMQDesc; + status = result; + }); + + if (status == Result::SUCCESS) { + mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor); + } + + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::startFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->start(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::stopFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->stop(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FilterTests::closeFilter(uint32_t filterId) { + EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; + Result status = mFilters[filterId]->close(); + if (status == Result::SUCCESS) { + for (int i = 0; i < mUsedFilterIds.size(); i++) { + if (mUsedFilterIds[i] == filterId) { + mUsedFilterIds.erase(mUsedFilterIds.begin() + i); + break; + } + } + mFilterCallbacks.erase(filterId); + mFilters.erase(filterId); + } + return AssertionResult(status == Result::SUCCESS); +}
\ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h new file mode 100644 index 0000000000..3cc06e578d --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FilterTests.h @@ -0,0 +1,226 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/logging.h> +#include <android/hardware/tv/tuner/1.0/IFilter.h> +#include <android/hardware/tv/tuner/1.0/IFilterCallback.h> +#include <android/hardware/tv/tuner/1.0/ITuner.h> +#include <android/hardware/tv/tuner/1.0/types.h> +#include <fmq/MessageQueue.h> +#include <gtest/gtest.h> +#include <hidl/HidlSupport.h> +#include <hidl/HidlTransportSupport.h> +#include <hidl/Status.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <map> + +using android::Condition; +using android::Mutex; +using android::sp; +using android::hardware::EventFlag; +using android::hardware::hidl_handle; +using android::hardware::hidl_string; +using android::hardware::hidl_vec; +using android::hardware::kSynchronizedReadWrite; +using android::hardware::MessageQueue; +using android::hardware::MQDescriptorSync; +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::DemuxFilterPesDataSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; +using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; +using android::hardware::tv::tuner::V1_0::DemuxFilterType; +using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; +using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; +using android::hardware::tv::tuner::V1_0::IDemux; +using android::hardware::tv::tuner::V1_0::IFilter; +using android::hardware::tv::tuner::V1_0::IFilterCallback; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::Result; + +using ::testing::AssertionResult; + +using namespace std; + +enum FilterEventType : uint8_t { + UNDEFINED, + SECTION, + MEDIA, + PES, + RECORD, + MMTPRECORD, + DOWNLOAD, + TEMI, +}; + +using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; +using MQDesc = MQDescriptorSync<uint8_t>; + +const uint32_t FMQ_SIZE_1M = 0x100000; +const uint32_t FMQ_SIZE_16M = 0x1000000; + +#define WAIT_TIMEOUT 3000000000 + +class FilterCallback : public IFilterCallback { + public: + virtual Return<void> onFilterEvent(const 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++; + // mFilterIdToMQ.erase(filterEvent.filterId); + + // startFilterEventThread(filterEvent); + mMsgCondition.signal(); + return Void(); + } + + virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override { + return Void(); + } + + void setFilterId(uint32_t filterId) { mFilterId = filterId; } + void setFilterInterface(sp<IFilter> filter) { mFilter = filter; } + void setFilterEventType(FilterEventType type) { mFilterEventType = type; } + + void testFilterDataOutput(); + + void startFilterEventThread(DemuxFilterEvent event); + static void* __threadLoopFilter(void* threadArgs); + void filterThreadLoop(DemuxFilterEvent& event); + + void updateFilterMQ(MQDesc& filterMQDescriptor); + void updateGoldenOutputMap(string goldenOutputFile); + bool readFilterEventData(); + bool dumpAvData(DemuxFilterMediaEvent event); + + private: + struct FilterThreadArgs { + FilterCallback* user; + DemuxFilterEvent event; + }; + uint16_t mDataLength = 0; + std::vector<uint8_t> mDataOutputBuffer; + + string mFilterIdToGoldenOutput; + + uint32_t mFilterId; + sp<IFilter> mFilter; + FilterEventType mFilterEventType; + std::unique_ptr<FilterMQ> mFilterMQ; + EventFlag* mFilterMQEventFlag; + DemuxFilterEvent mFilterEvent; + + android::Mutex mMsgLock; + android::Mutex mFilterOutputLock; + android::Condition mMsgCondition; + android::Condition mFilterOutputCondition; + + pthread_t mFilterThread; + + int mPidFilterOutputCount = 0; +}; + +class FilterTests { + public: + void setService(sp<ITuner> tuner) { mService = tuner; } + void setDemux(sp<IDemux> demux) { mDemux = demux; } + + std::map<uint32_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; } + + AssertionResult openFilterInDemux(DemuxFilterType type); + AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); + AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); + AssertionResult getFilterMQDescriptor(uint32_t filterId); + AssertionResult startFilter(uint32_t filterId); + AssertionResult stopFilter(uint32_t filterId); + AssertionResult closeFilter(uint32_t filterId); + + FilterEventType getFilterEventType(DemuxFilterType type) { + FilterEventType eventType = FilterEventType::UNDEFINED; + switch (type.mainType) { + case DemuxFilterMainType::TS: + switch (type.subType.tsFilterType()) { + case DemuxTsFilterType::UNDEFINED: + break; + case DemuxTsFilterType::SECTION: + eventType = FilterEventType::SECTION; + break; + case DemuxTsFilterType::PES: + eventType = FilterEventType::PES; + break; + case DemuxTsFilterType::TS: + break; + case DemuxTsFilterType::AUDIO: + case DemuxTsFilterType::VIDEO: + eventType = FilterEventType::MEDIA; + break; + case DemuxTsFilterType::PCR: + break; + case DemuxTsFilterType::RECORD: + eventType = FilterEventType::RECORD; + break; + case DemuxTsFilterType::TEMI: + eventType = FilterEventType::TEMI; + break; + } + break; + case DemuxFilterMainType::MMTP: + /*mmtpSettings*/ + break; + case DemuxFilterMainType::IP: + /*ipSettings*/ + break; + case DemuxFilterMainType::TLV: + /*tlvSettings*/ + break; + case DemuxFilterMainType::ALP: + /*alpSettings*/ + break; + default: + break; + } + return eventType; + } + + protected: + static AssertionResult failure() { return ::testing::AssertionFailure(); } + + static AssertionResult success() { return ::testing::AssertionSuccess(); } + + sp<ITuner> mService; + sp<IFilter> mFilter; + sp<IDemux> mDemux; + std::map<uint32_t, sp<IFilter>> mFilters; + std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks; + + sp<FilterCallback> mFilterCallback; + MQDesc mFilterMQDescriptor; + vector<uint32_t> mUsedFilterIds; + + uint32_t mFilterId = -1; +}; diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp new file mode 100644 index 0000000000..fc5071ceaa --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp @@ -0,0 +1,310 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FrontendTests.h" + +Return<void> FrontendCallback::onEvent(FrontendEventType frontendEventType) { + android::Mutex::Autolock autoLock(mMsgLock); + ALOGD("[vts] frontend event received. Type: %d", frontendEventType); + mEventReceived = true; + mMsgCondition.signal(); + switch (frontendEventType) { + case FrontendEventType::LOCKED: + mLockMsgReceived = true; + mLockMsgCondition.signal(); + return Void(); + default: + // do nothing + return Void(); + } +} + +Return<void> FrontendCallback::onScanMessage(FrontendScanMessageType type, + const FrontendScanMessage& message) { + android::Mutex::Autolock autoLock(mMsgLock); + while (!mScanMsgProcessed) { + mMsgCondition.wait(mMsgLock); + } + ALOGD("[vts] frontend scan message. Type: %d", type); + mScanMessageReceived = true; + mScanMsgProcessed = false; + mScanMessageType = type; + mScanMessage = message; + mMsgCondition.signal(); + return Void(); +} + +void FrontendCallback::tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings) { + Result result = frontend->tune(settings); + EXPECT_TRUE(result == Result::SUCCESS); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mEventReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "Event not received within timeout"; + mLockMsgReceived = false; + return; + } + } + mEventReceived = false; +} + +void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings) { + Result result = frontend->tune(settings); + EXPECT_TRUE(result == Result::SUCCESS); + + android::Mutex::Autolock autoLock(mMsgLock); + while (!mLockMsgReceived) { + if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "Event LOCKED not received within timeout"; + mLockMsgReceived = false; + return; + } + } + mLockMsgReceived = false; +} + +void FrontendCallback::scanTest(sp<IFrontend>& frontend, FrontendConfig config, + FrontendScanType type) { + uint32_t targetFrequency = getTargetFrequency(config.settings, config.type); + if (type == FrontendScanType::SCAN_BLIND) { + // reset the frequency in the scan configuration to test blind scan. The settings param of + // passed in means the real input config on the transponder connected to the DUT. + // We want the blind the test to start from lower frequency than this to check the blind + // scan implementation. + resetBlindScanStartingFrequency(config, targetFrequency - 100); + } + + Result result = frontend->scan(config.settings, type); + EXPECT_TRUE(result == Result::SUCCESS); + + bool scanMsgLockedReceived = false; + bool targetFrequencyReceived = false; + + android::Mutex::Autolock autoLock(mMsgLock); +wait: + while (!mScanMessageReceived) { + if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { + EXPECT_TRUE(false) << "Scan message not received within timeout"; + mScanMessageReceived = false; + mScanMsgProcessed = true; + return; + } + } + + if (mScanMessageType != FrontendScanMessageType::END) { + if (mScanMessageType == FrontendScanMessageType::LOCKED) { + scanMsgLockedReceived = true; + Result result = frontend->scan(config.settings, type); + EXPECT_TRUE(result == Result::SUCCESS); + } + + if (mScanMessageType == FrontendScanMessageType::FREQUENCY) { + targetFrequencyReceived = mScanMessage.frequencies().size() > 0 && + mScanMessage.frequencies()[0] == targetFrequency; + } + + if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) { + ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent()); + } + + mScanMessageReceived = false; + mScanMsgProcessed = true; + mMsgCondition.signal(); + goto wait; + } + + EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END"; + EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan"; + mScanMessageReceived = false; + mScanMsgProcessed = true; +} + +uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) { + switch (type) { + case FrontendType::ANALOG: + return settings.analog().frequency; + case FrontendType::ATSC: + return settings.atsc().frequency; + case FrontendType::ATSC3: + return settings.atsc3().frequency; + case FrontendType::DVBC: + return settings.dvbc().frequency; + case FrontendType::DVBS: + return settings.dvbs().frequency; + case FrontendType::DVBT: + return settings.dvbt().frequency; + case FrontendType::ISDBS: + return settings.isdbs().frequency; + case FrontendType::ISDBS3: + return settings.isdbs3().frequency; + case FrontendType::ISDBT: + return settings.isdbt().frequency; + default: + return 0; + } +} + +void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config, + uint32_t resetingFreq) { + switch (config.type) { + case FrontendType::ANALOG: + config.settings.analog().frequency = resetingFreq; + break; + case FrontendType::ATSC: + config.settings.atsc().frequency = resetingFreq; + break; + case FrontendType::ATSC3: + config.settings.atsc3().frequency = resetingFreq; + break; + case FrontendType::DVBC: + config.settings.dvbc().frequency = resetingFreq; + break; + case FrontendType::DVBS: + config.settings.dvbs().frequency = resetingFreq; + break; + case FrontendType::DVBT: + config.settings.dvbt().frequency = resetingFreq; + break; + case FrontendType::ISDBS: + config.settings.isdbs().frequency = resetingFreq; + break; + case FrontendType::ISDBS3: + config.settings.isdbs3().frequency = resetingFreq; + break; + case FrontendType::ISDBT: + config.settings.isdbt().frequency = resetingFreq; + break; + default: + // do nothing + return; + } +} + +AssertionResult FrontendTests::getFrontendIds() { + Result status; + mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) { + status = result; + mFeIds = frontendIds; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::getFrontendInfo(uint32_t frontendId) { + Result status; + mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) { + mFrontendInfo = frontendInfo; + status = result; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::openFrontendById(uint32_t frontendId) { + Result status; + mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) { + mFrontend = frontend; + status = result; + }); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::setFrontendCallback() { + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; + mFrontendCallback = new FrontendCallback(); + auto callbackStatus = mFrontend->setCallback(mFrontendCallback); + return AssertionResult(callbackStatus.isOk()); +} + +AssertionResult FrontendTests::scanFrontend(FrontendConfig config, FrontendScanType type) { + EXPECT_TRUE(mFrontendCallback) + << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; + + EXPECT_TRUE(mFrontendInfo.type == config.type) + << "FrontendConfig does not match the frontend info of the given id."; + + mFrontendCallback->scanTest(mFrontend, config, type); + return AssertionResult(true); +} + +AssertionResult FrontendTests::stopScanFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; + Result status; + status = mFrontend->stopScan(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::tuneFrontend(FrontendConfig config) { + EXPECT_TRUE(mFrontendCallback) + << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; + + EXPECT_TRUE(mFrontendInfo.type == config.type) + << "FrontendConfig does not match the frontend info of the given id."; + + mFrontendCallback->tuneTestOnLock(mFrontend, config.settings); + return AssertionResult(true); +} + +AssertionResult FrontendTests::stopTuneFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; + Result status; + status = mFrontend->stopTune(); + return AssertionResult(status == Result::SUCCESS); +} + +AssertionResult FrontendTests::closeFrontend() { + EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; + Result status; + status = mFrontend->close(); + mFrontend = nullptr; + mFrontendCallback = nullptr; + return AssertionResult(status == Result::SUCCESS); +} + +void FrontendTests::getFrontendIdByType(FrontendType feType, uint32_t& feId) { + ASSERT_TRUE(getFrontendIds()); + ASSERT_TRUE(mFeIds.size() > 0); + for (size_t i = 0; i < mFeIds.size(); i++) { + ASSERT_TRUE(getFrontendInfo(mFeIds[i])); + if (mFrontendInfo.type != feType) { + continue; + } + feId = mFeIds[i]; + return; + } + feId = INVALID_ID; +} + +void FrontendTests::tuneTest(FrontendConfig frontendConf) { + uint32_t feId; + getFrontendIdByType(frontendConf.type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(openFrontendById(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(tuneFrontend(frontendConf)); + ASSERT_TRUE(stopTuneFrontend()); + ASSERT_TRUE(closeFrontend()); +} + +void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) { + uint32_t feId; + getFrontendIdByType(frontendConf.type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(openFrontendById(feId)); + ASSERT_TRUE(setFrontendCallback()); + ASSERT_TRUE(scanFrontend(frontendConf, scanType)); + ASSERT_TRUE(stopScanFrontend()); + ASSERT_TRUE(closeFrontend()); +} diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h new file mode 100644 index 0000000000..1a9bec9627 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FrontendTests.h @@ -0,0 +1,124 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android-base/logging.h> +#include <android/hardware/tv/tuner/1.0/IFrontend.h> +#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h> +#include <android/hardware/tv/tuner/1.0/ITuner.h> +#include <android/hardware/tv/tuner/1.0/types.h> +#include <binder/MemoryDealer.h> +#include <gtest/gtest.h> +#include <hidl/GtestPrinter.h> +#include <hidl/HidlSupport.h> +#include <hidl/HidlTransportSupport.h> +#include <hidl/ServiceManagement.h> +#include <hidl/Status.h> +#include <hidlmemory/FrameworkUtils.h> +#include <utils/Condition.h> +#include <utils/Mutex.h> +#include <map> + +#include "VtsHalTvTunerV1_0TestConfigurations.h" + +#define WAIT_TIMEOUT 3000000000 +#define INVALID_ID -1 + +using android::Condition; +using android::IMemory; +using android::IMemoryHeap; +using android::MemoryDealer; +using android::Mutex; +using android::sp; +using android::hardware::fromHeap; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; +using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; +using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; +using android::hardware::tv::tuner::V1_0::FrontendEventType; +using android::hardware::tv::tuner::V1_0::FrontendId; +using android::hardware::tv::tuner::V1_0::FrontendInfo; +using android::hardware::tv::tuner::V1_0::FrontendInnerFec; +using android::hardware::tv::tuner::V1_0::FrontendScanMessage; +using android::hardware::tv::tuner::V1_0::FrontendScanMessageType; +using android::hardware::tv::tuner::V1_0::FrontendScanType; +using android::hardware::tv::tuner::V1_0::FrontendSettings; +using android::hardware::tv::tuner::V1_0::IFrontend; +using android::hardware::tv::tuner::V1_0::IFrontendCallback; +using android::hardware::tv::tuner::V1_0::ITuner; +using android::hardware::tv::tuner::V1_0::Result; + +using ::testing::AssertionResult; + +using namespace std; + +#define INVALID_ID -1 +#define WAIT_TIMEOUT 3000000000 + +class FrontendCallback : public IFrontendCallback { + public: + virtual Return<void> onEvent(FrontendEventType frontendEventType) override; + virtual Return<void> onScanMessage(FrontendScanMessageType type, + const FrontendScanMessage& message) override; + + void tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings); + void tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings); + void scanTest(sp<IFrontend>& frontend, FrontendConfig config, FrontendScanType type); + + // Helper methods + uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type); + void resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq); + + private: + bool mEventReceived = false; + bool mScanMessageReceived = false; + bool mLockMsgReceived = false; + bool mScanMsgProcessed = true; + FrontendScanMessageType mScanMessageType; + FrontendScanMessage mScanMessage; + hidl_vec<uint8_t> mEventMessage; + android::Mutex mMsgLock; + android::Condition mMsgCondition; + android::Condition mLockMsgCondition; +}; + +class FrontendTests { + public: + sp<ITuner> mService; + + void setService(sp<ITuner> tuner) { mService = tuner; } + + AssertionResult getFrontendIds(); + AssertionResult getFrontendInfo(uint32_t frontendId); + AssertionResult openFrontendById(uint32_t frontendId); + AssertionResult setFrontendCallback(); + AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type); + AssertionResult stopScanFrontend(); + AssertionResult tuneFrontend(FrontendConfig config); + AssertionResult stopTuneFrontend(); + AssertionResult closeFrontend(); + + void getFrontendIdByType(FrontendType feType, uint32_t& feId); + void tuneTest(FrontendConfig frontendConf); + void scanTest(FrontendConfig frontend, FrontendScanType type); + + protected: + sp<IFrontend> mFrontend; + FrontendInfo mFrontendInfo; + sp<FrontendCallback> mFrontendCallback; + hidl_vec<FrontendId> mFeIds; +}; diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp index 5e98367af6..d836c26f9f 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -14,630 +14,11 @@ * limitations under the License. */ -#define LOG_TAG "Tuner_hidl_hal_test" - -#include <VtsHalHidlTargetTestBase.h> -#include <VtsHalHidlTargetTestEnvBase.h> -#include <android-base/logging.h> -#include <android/hardware/tv/tuner/1.0/IDemux.h> -#include <android/hardware/tv/tuner/1.0/IDescrambler.h> -#include <android/hardware/tv/tuner/1.0/IDvr.h> -#include <android/hardware/tv/tuner/1.0/IDvrCallback.h> -#include <android/hardware/tv/tuner/1.0/IFilter.h> -#include <android/hardware/tv/tuner/1.0/IFilterCallback.h> -#include <android/hardware/tv/tuner/1.0/IFrontend.h> -#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h> -#include <android/hardware/tv/tuner/1.0/ITuner.h> -#include <android/hardware/tv/tuner/1.0/types.h> -#include <binder/MemoryDealer.h> -#include <fmq/MessageQueue.h> -#include <gtest/gtest.h> -#include <hidl/GtestPrinter.h> -#include <hidl/HidlSupport.h> -#include <hidl/HidlTransportSupport.h> -#include <hidl/ServiceManagement.h> -#include <hidl/Status.h> -#include <hidlmemory/FrameworkUtils.h> -#include <utils/Condition.h> -#include <utils/Mutex.h> -#include <fstream> -#include <iostream> -#include <map> - -#include "VtsHalTvTunerV1_0TestConfigurations.h" - -#define WAIT_TIMEOUT 3000000000 -#define INVALID_ID -1 - -using android::Condition; -using android::IMemory; -using android::IMemoryHeap; -using android::MemoryDealer; -using android::Mutex; -using android::sp; -using android::hardware::EventFlag; -using android::hardware::fromHeap; -using android::hardware::hidl_handle; -using android::hardware::hidl_string; -using android::hardware::hidl_vec; -using android::hardware::HidlMemory; -using android::hardware::kSynchronizedReadWrite; -using android::hardware::MessageQueue; -using android::hardware::MQDescriptorSync; -using android::hardware::Return; -using android::hardware::Void; -using android::hardware::tv::tuner::V1_0::DataFormat; -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::DemuxFilterPesDataSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; -using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterSettings; -using android::hardware::tv::tuner::V1_0::DemuxFilterStatus; -using android::hardware::tv::tuner::V1_0::DemuxFilterType; -using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; -using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; -using android::hardware::tv::tuner::V1_0::DemuxTsFilterType; -using android::hardware::tv::tuner::V1_0::DvrSettings; -using android::hardware::tv::tuner::V1_0::DvrType; -using android::hardware::tv::tuner::V1_0::FrontendAtscModulation; -using android::hardware::tv::tuner::V1_0::FrontendAtscSettings; -using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; -using android::hardware::tv::tuner::V1_0::FrontendEventType; -using android::hardware::tv::tuner::V1_0::FrontendId; -using android::hardware::tv::tuner::V1_0::FrontendInfo; -using android::hardware::tv::tuner::V1_0::FrontendInnerFec; -using android::hardware::tv::tuner::V1_0::FrontendScanMessage; -using android::hardware::tv::tuner::V1_0::FrontendScanMessageType; -using android::hardware::tv::tuner::V1_0::FrontendScanType; -using android::hardware::tv::tuner::V1_0::FrontendSettings; -using android::hardware::tv::tuner::V1_0::IDemux; -using android::hardware::tv::tuner::V1_0::IDescrambler; -using android::hardware::tv::tuner::V1_0::IDvr; -using android::hardware::tv::tuner::V1_0::IDvrCallback; -using android::hardware::tv::tuner::V1_0::IFilter; -using android::hardware::tv::tuner::V1_0::IFilterCallback; -using android::hardware::tv::tuner::V1_0::IFrontend; -using android::hardware::tv::tuner::V1_0::IFrontendCallback; -using android::hardware::tv::tuner::V1_0::ITuner; -using android::hardware::tv::tuner::V1_0::PlaybackSettings; -using android::hardware::tv::tuner::V1_0::PlaybackStatus; -using android::hardware::tv::tuner::V1_0::RecordSettings; -using android::hardware::tv::tuner::V1_0::RecordStatus; -using android::hardware::tv::tuner::V1_0::Result; - -using ::testing::AssertionResult; +#include "VtsHalTvTunerV1_0TargetTest.h" namespace { -using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; -using MQDesc = MQDescriptorSync<uint8_t>; - -const std::vector<uint8_t> goldenDataOutputBuffer{ - 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb, - 0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03, - 0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06, - 0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8, - 0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72, - 0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d, - 0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63, - 0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30, - 0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, - 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f, - 0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d, - 0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b, - 0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d, - 0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65, - 0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31, - 0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e, - 0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20, - 0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72, - 0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69, - 0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71, - 0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31, - 0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d, - 0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66, - 0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, - 0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68, - 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f, - 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20, - 0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79, - 0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, - 0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20, - 0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30, - 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20, - 0x73, 0x63, 0x65, 0x6e, 0x65, -}; - -// const uint16_t FMQ_SIZE_4K = 0x1000; -const uint32_t FMQ_SIZE_1M = 0x100000; -const uint32_t FMQ_SIZE_16M = 0x1000000; - -enum FilterEventType : uint8_t { - UNDEFINED, - SECTION, - MEDIA, - PES, - RECORD, - MMTPRECORD, - DOWNLOAD, - TEMI, -}; - -struct PlaybackConf { - string inputDataFile; - PlaybackSettings setting; -}; - -/******************************** Start FrontendCallback **********************************/ -class FrontendCallback : public IFrontendCallback { - public: - virtual Return<void> onEvent(FrontendEventType frontendEventType) override { - android::Mutex::Autolock autoLock(mMsgLock); - ALOGD("[vts] frontend event received. Type: %d", frontendEventType); - mEventReceived = true; - mMsgCondition.signal(); - switch (frontendEventType) { - case FrontendEventType::LOCKED: - mLockMsgReceived = true; - mLockMsgCondition.signal(); - return Void(); - default: - // do nothing - return Void(); - } - } - - virtual Return<void> onScanMessage(FrontendScanMessageType type, - const FrontendScanMessage& message) override { - android::Mutex::Autolock autoLock(mMsgLock); - while (!mScanMsgProcessed) { - mMsgCondition.wait(mMsgLock); - } - ALOGD("[vts] frontend scan message. Type: %d", type); - mScanMessageReceived = true; - mScanMsgProcessed = false; - mScanMessageType = type; - mScanMessage = message; - mMsgCondition.signal(); - return Void(); - } - - void tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings); - void tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings); - void scanTest(sp<IFrontend>& frontend, FrontendConfig config, FrontendScanType type); - - // Helper methods - uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type); - void resetBlindScanStartingFrequency(FrontendConfig& config, uint32_t resetingFreq); - - private: - bool mEventReceived = false; - bool mScanMessageReceived = false; - bool mLockMsgReceived = false; - bool mScanMsgProcessed = true; - FrontendScanMessageType mScanMessageType; - FrontendScanMessage mScanMessage; - hidl_vec<uint8_t> mEventMessage; - android::Mutex mMsgLock; - android::Condition mMsgCondition; - android::Condition mLockMsgCondition; -}; - -void FrontendCallback::tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings) { - Result result = frontend->tune(settings); - EXPECT_TRUE(result == Result::SUCCESS); - - android::Mutex::Autolock autoLock(mMsgLock); - while (!mEventReceived) { - if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "Event not received within timeout"; - mLockMsgReceived = false; - return; - } - } - mEventReceived = false; -} - -void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings) { - Result result = frontend->tune(settings); - EXPECT_TRUE(result == Result::SUCCESS); - - android::Mutex::Autolock autoLock(mMsgLock); - while (!mLockMsgReceived) { - if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "Event LOCKED not received within timeout"; - mLockMsgReceived = false; - return; - } - } - mLockMsgReceived = false; -} - -void FrontendCallback::scanTest(sp<IFrontend>& frontend, FrontendConfig config, - FrontendScanType type) { - uint32_t targetFrequency = getTargetFrequency(config.settings, config.type); - if (type == FrontendScanType::SCAN_BLIND) { - // reset the frequency in the scan configuration to test blind scan. The settings param of - // passed in means the real input config on the transponder connected to the DUT. - // We want the blind the test to start from lower frequency than this to check the blind - // scan implementation. - resetBlindScanStartingFrequency(config, targetFrequency - 100); - } - - Result result = frontend->scan(config.settings, type); - EXPECT_TRUE(result == Result::SUCCESS); - - bool scanMsgLockedReceived = false; - bool targetFrequencyReceived = false; - - android::Mutex::Autolock autoLock(mMsgLock); -wait: - while (!mScanMessageReceived) { - if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) { - EXPECT_TRUE(false) << "Scan message not received within timeout"; - mScanMessageReceived = false; - mScanMsgProcessed = true; - return; - } - } - - if (mScanMessageType != FrontendScanMessageType::END) { - if (mScanMessageType == FrontendScanMessageType::LOCKED) { - scanMsgLockedReceived = true; - Result result = frontend->scan(config.settings, type); - EXPECT_TRUE(result == Result::SUCCESS); - } - - if (mScanMessageType == FrontendScanMessageType::FREQUENCY) { - targetFrequencyReceived = mScanMessage.frequencies().size() > 0 && - mScanMessage.frequencies()[0] == targetFrequency; - } - - if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) { - ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent()); - } - - mScanMessageReceived = false; - mScanMsgProcessed = true; - mMsgCondition.signal(); - goto wait; - } - - EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END"; - EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan"; - mScanMessageReceived = false; - mScanMsgProcessed = true; -} - -uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) { - switch (type) { - case FrontendType::ANALOG: - return settings.analog().frequency; - case FrontendType::ATSC: - return settings.atsc().frequency; - case FrontendType::ATSC3: - return settings.atsc3().frequency; - case FrontendType::DVBC: - return settings.dvbc().frequency; - case FrontendType::DVBS: - return settings.dvbs().frequency; - case FrontendType::DVBT: - return settings.dvbt().frequency; - case FrontendType::ISDBS: - return settings.isdbs().frequency; - case FrontendType::ISDBS3: - return settings.isdbs3().frequency; - case FrontendType::ISDBT: - return settings.isdbt().frequency; - default: - return 0; - } -} - -void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig& config, - uint32_t resetingFreq) { - switch (config.type) { - case FrontendType::ANALOG: - config.settings.analog().frequency = resetingFreq; - break; - case FrontendType::ATSC: - config.settings.atsc().frequency = resetingFreq; - break; - case FrontendType::ATSC3: - config.settings.atsc3().frequency = resetingFreq; - break; - case FrontendType::DVBC: - config.settings.dvbc().frequency = resetingFreq; - break; - case FrontendType::DVBS: - config.settings.dvbs().frequency = resetingFreq; - break; - case FrontendType::DVBT: - config.settings.dvbt().frequency = resetingFreq; - break; - case FrontendType::ISDBS: - config.settings.isdbs().frequency = resetingFreq; - break; - case FrontendType::ISDBS3: - config.settings.isdbs3().frequency = resetingFreq; - break; - case FrontendType::ISDBT: - config.settings.isdbt().frequency = resetingFreq; - break; - default: - // do nothing - return; - } -} -/******************************** End FrontendCallback **********************************/ - -/******************************** Start FilterCallback **********************************/ -class FilterCallback : public IFilterCallback { - public: - virtual Return<void> onFilterEvent(const 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++; - // mFilterIdToMQ.erase(filterEvent.filterId); - - // startFilterEventThread(filterEvent); - mMsgCondition.signal(); - return Void(); - } - - virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override { - return Void(); - } - - void setFilterId(uint32_t filterId) { mFilterId = filterId; } - void setFilterInterface(sp<IFilter> filter) { mFilter = filter; } - void setFilterEventType(FilterEventType type) { mFilterEventType = type; } - - void testFilterDataOutput(); - - void startFilterEventThread(DemuxFilterEvent event); - static void* __threadLoopFilter(void* threadArgs); - void filterThreadLoop(DemuxFilterEvent& event); - - void updateFilterMQ(MQDesc& filterMQDescriptor); - void updateGoldenOutputMap(string goldenOutputFile); - bool readFilterEventData(); - bool dumpAvData(DemuxFilterMediaEvent event); - - private: - struct FilterThreadArgs { - FilterCallback* user; - DemuxFilterEvent event; - }; - uint16_t mDataLength = 0; - std::vector<uint8_t> mDataOutputBuffer; - - string mFilterIdToGoldenOutput; - - uint32_t mFilterId; - sp<IFilter> mFilter; - FilterEventType mFilterEventType; - std::unique_ptr<FilterMQ> mFilterMQ; - EventFlag* mFilterMQEventFlag; - DemuxFilterEvent mFilterEvent; - - android::Mutex mMsgLock; - android::Mutex mFilterOutputLock; - android::Condition mMsgCondition; - android::Condition mFilterOutputCondition; - - pthread_t mFilterThread; - - int mPidFilterOutputCount = 0; -}; - -void FilterCallback::startFilterEventThread(DemuxFilterEvent event) { - struct FilterThreadArgs* threadArgs = - (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs)); - threadArgs->user = this; - threadArgs->event = event; - - pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs); - pthread_setname_np(mFilterThread, "test_playback_input_loop"); -} - -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::updateFilterMQ(MQDesc& filterMQDescriptor) { - mFilterMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */); - EXPECT_TRUE(mFilterMQ); - EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) == - android::OK); -} - -void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) { - mFilterIdToGoldenOutput = goldenOutputFile; -} - -void* FilterCallback::__threadLoopFilter(void* threadArgs) { - FilterCallback* const self = - static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user); - self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event); - return 0; -} - -void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) { - android::Mutex::Autolock autoLock(mFilterOutputLock); - // Read from mFilterMQ[event.filterId] per event and filter type - - // Assemble to filterOutput[filterId] - - // check if filterOutput[filterId] matches goldenOutput[filterId] - - // If match, remove filterId entry from MQ map - - // end thread -} - -bool FilterCallback::readFilterEventData() { - bool result = false; - DemuxFilterEvent filterEvent = mFilterEvent; - ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId); - // todo separate filter handlers - for (int i = 0; i < filterEvent.events.size(); i++) { - switch (mFilterEventType) { - case FilterEventType::SECTION: - mDataLength = filterEvent.events[i].section().dataLength; - break; - case FilterEventType::PES: - mDataLength = filterEvent.events[i].pes().dataLength; - break; - case FilterEventType::MEDIA: - return dumpAvData(filterEvent.events[i].media()); - case FilterEventType::RECORD: - break; - case FilterEventType::MMTPRECORD: - break; - case FilterEventType::DOWNLOAD: - break; - default: - break; - } - // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not - // match"; - - mDataOutputBuffer.resize(mDataLength); - result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength); - EXPECT_TRUE(result) << "can't read from Filter MQ"; - - /*for (int i = 0; i < mDataLength; i++) { - EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match"; - }*/ - } - mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); - return result; -} - -bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { - uint32_t length = event.dataLength; - uint64_t dataId = event.avDataId; - // read data from buffer pointed by a handle - hidl_handle handle = event.avMemory; - - int av_fd = handle.getNativeHandle()->data[0]; - uint8_t* buffer = static_cast<uint8_t*>( - mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/)); - if (buffer == MAP_FAILED) { - ALOGE("[vts] fail to allocate av buffer, errno=%d", errno); - return false; - } - uint8_t output[length + 1]; - memcpy(output, buffer, length); - // print buffer and check with golden output. - EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS); - return true; -} -/******************************** End FilterCallback **********************************/ - /******************************** Start DvrCallback **********************************/ -class DvrCallback : public IDvrCallback { - public: - virtual Return<void> onRecordStatus(DemuxFilterStatus status) override { - ALOGW("[vts] record status %hhu", status); - switch (status) { - case DemuxFilterStatus::DATA_READY: - break; - case DemuxFilterStatus::LOW_WATER: - break; - case DemuxFilterStatus::HIGH_WATER: - case DemuxFilterStatus::OVERFLOW: - ALOGW("[vts] record overflow. Flushing"); - break; - } - return Void(); - } - - virtual Return<void> onPlaybackStatus(PlaybackStatus status) override { - // android::Mutex::Autolock autoLock(mMsgLock); - ALOGW("[vts] playback status %d", status); - switch (status) { - case PlaybackStatus::SPACE_EMPTY: - case PlaybackStatus::SPACE_ALMOST_EMPTY: - ALOGW("[vts] keep playback inputing %d", status); - mKeepWritingPlaybackFMQ = true; - break; - case PlaybackStatus::SPACE_ALMOST_FULL: - case PlaybackStatus::SPACE_FULL: - ALOGW("[vts] stop playback inputing %d", status); - mKeepWritingPlaybackFMQ = false; - break; - } - return Void(); - } - - void testFilterDataOutput(); - void stopPlaybackThread(); - void testRecordOutput(); - void stopRecordThread(); - - void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); - void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor); - static void* __threadLoopPlayback(void* threadArgs); - static void* __threadLoopRecord(void* threadArgs); - void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); - void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); - - bool readRecordFMQ(); - - private: - struct PlaybackThreadArgs { - DvrCallback* user; - PlaybackConf* playbackConf; - bool* keepWritingPlaybackFMQ; - }; - struct RecordThreadArgs { - DvrCallback* user; - RecordSettings* recordSetting; - bool* keepReadingRecordFMQ; - }; - uint16_t mDataLength = 0; - std::vector<uint8_t> mDataOutputBuffer; - - std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterMQ; - std::unique_ptr<FilterMQ> mPlaybackMQ; - std::unique_ptr<FilterMQ> mRecordMQ; - std::map<uint32_t, EventFlag*> mFilterMQEventFlag; - - android::Mutex mMsgLock; - android::Mutex mPlaybackThreadLock; - android::Mutex mRecordThreadLock; - android::Condition mMsgCondition; - - bool mKeepWritingPlaybackFMQ = true; - bool mKeepReadingRecordFMQ = true; - bool mPlaybackThreadRunning; - bool mRecordThreadRunning; - pthread_t mPlaybackThread; - pthread_t mRecordThread; - - int mPidFilterOutputCount = 0; -}; - void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor) { mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */); @@ -809,305 +190,9 @@ void DvrCallback::stopRecordThread() { } /********************************** End DvrCallback ************************************/ -/***************************** Start Test Implementation ******************************/ -class TunerHidlTest : public testing::TestWithParam<std::string> { - public: - virtual void SetUp() override { - mService = ITuner::getService(GetParam()); - ASSERT_NE(mService, nullptr); - initFrontendConfig(); - initFrontendScanConfig(); - initFilterConfig(); - } - - sp<ITuner> mService; - - protected: - static AssertionResult failure() { return ::testing::AssertionFailure(); } - - static AssertionResult success() { return ::testing::AssertionSuccess(); } - - static void description(const std::string& description) { - RecordProperty("description", description); - } - - sp<IFrontend> mFrontend; - FrontendInfo mFrontendInfo; - sp<FrontendCallback> mFrontendCallback; - sp<IDescrambler> mDescrambler; - sp<IDemux> mDemux; - sp<IDvr> mDvr; - sp<IFilter> mFilter; - std::map<uint32_t, sp<IFilter>> mFilters; - std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks; - - sp<FilterCallback> mFilterCallback; - sp<DvrCallback> mDvrCallback; - MQDesc mFilterMQDescriptor; - MQDesc mDvrMQDescriptor; - MQDesc mRecordMQDescriptor; - vector<uint32_t> mUsedFilterIds; - hidl_vec<FrontendId> mFeIds; - - uint32_t mDemuxId; - uint32_t mFilterId = -1; - - pthread_t mPlaybackshread; - bool mPlaybackThreadRunning; - - AssertionResult getFrontendIds(); - AssertionResult getFrontendInfo(uint32_t frontendId); - AssertionResult openFrontendById(uint32_t frontendId); - AssertionResult setFrontendCallback(); - AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type); - AssertionResult stopScanFrontend(); - AssertionResult tuneFrontend(FrontendConfig config); - AssertionResult stopTuneFrontend(); - AssertionResult closeFrontend(); - - AssertionResult openDemux(); - AssertionResult setDemuxFrontendDataSource(uint32_t frontendId); - AssertionResult closeDemux(); - - AssertionResult openDvrInDemux(DvrType type); - AssertionResult configDvr(DvrSettings setting); - AssertionResult getDvrMQDescriptor(); - - AssertionResult openFilterInDemux(DemuxFilterType type); - AssertionResult getNewlyOpenedFilterId(uint32_t& filterId); - AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId); - AssertionResult getFilterMQDescriptor(uint32_t filterId); - AssertionResult startFilter(uint32_t filterId); - AssertionResult stopFilter(uint32_t filterId); - AssertionResult closeFilter(uint32_t filterId); - - AssertionResult createDescrambler(); - AssertionResult closeDescrambler(); - - AssertionResult playbackDataFlowTest(vector<FilterConfig> filterConf, PlaybackConf playbackConf, - vector<string> goldenOutputFiles); - AssertionResult recordDataFlowTest(vector<FilterConfig> filterConf, - RecordSettings recordSetting, - vector<string> goldenOutputFiles); - AssertionResult broadcastDataFlowTest(vector<string> goldenOutputFiles); - - void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); - void getFrontendIdByType(FrontendType feType, uint32_t& feId); - void scanTest(FrontendConfig frontend, FrontendScanType type); - - FilterEventType getFilterEventType(DemuxFilterType type); -}; - -/*========================== Start Frontend APIs Tests Implementation ==========================*/ -AssertionResult TunerHidlTest::getFrontendIds() { - Result status; - mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) { - status = result; - mFeIds = frontendIds; - }); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::getFrontendInfo(uint32_t frontendId) { - Result status; - mService->getFrontendInfo(frontendId, [&](Result result, const FrontendInfo& frontendInfo) { - mFrontendInfo = frontendInfo; - status = result; - }); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::openFrontendById(uint32_t frontendId) { - Result status; - mService->openFrontendById(frontendId, [&](Result result, const sp<IFrontend>& frontend) { - mFrontend = frontend; - status = result; - }); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::setFrontendCallback() { - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - mFrontendCallback = new FrontendCallback(); - auto callbackStatus = mFrontend->setCallback(mFrontendCallback); - return AssertionResult(callbackStatus.isOk()); -} - -AssertionResult TunerHidlTest::scanFrontend(FrontendConfig config, FrontendScanType type) { - EXPECT_TRUE(mFrontendCallback) - << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; - - EXPECT_TRUE(mFrontendInfo.type == config.type) - << "FrontendConfig does not match the frontend info of the given id."; - - mFrontendCallback->scanTest(mFrontend, config, type); - return AssertionResult(true); -} - -AssertionResult TunerHidlTest::stopScanFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - Result status; - status = mFrontend->stopScan(); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::tuneFrontend(FrontendConfig config) { - EXPECT_TRUE(mFrontendCallback) - << "test with openFrontendById/setFrontendCallback/getFrontendInfo first."; - - EXPECT_TRUE(mFrontendInfo.type == config.type) - << "FrontendConfig does not match the frontend info of the given id."; - - mFrontendCallback->tuneTestOnLock(mFrontend, config.settings); - return AssertionResult(true); -} - -AssertionResult TunerHidlTest::stopTuneFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - Result status; - status = mFrontend->stopTune(); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::closeFrontend() { - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - Result status; - status = mFrontend->close(); - mFrontend = nullptr; - mFrontendCallback = nullptr; - return AssertionResult(status == Result::SUCCESS); -} -/*=========================== End Frontend APIs Tests Implementation ===========================*/ - -/*============================ Start Demux APIs Tests Implementation ============================*/ -AssertionResult TunerHidlTest::openDemux() { - Result status; - mService->openDemux([&](Result result, uint32_t demuxId, const sp<IDemux>& demux) { - mDemux = demux; - mDemuxId = demuxId; - status = result; - }); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::setDemuxFrontendDataSource(uint32_t frontendId) { - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - EXPECT_TRUE(mFrontend) << "Test with openFrontendById first."; - auto status = mDemux->setFrontendDataSource(frontendId); - return AssertionResult(status.isOk()); -} - -AssertionResult TunerHidlTest::closeDemux() { - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - auto status = mDemux->close(); - mDemux = nullptr; - return AssertionResult(status.isOk()); -} - -AssertionResult TunerHidlTest::openFilterInDemux(DemuxFilterType type) { - Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - - // Create demux callback - mFilterCallback = new FilterCallback(); - - // Add filter to the local demux - mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback, - [&](Result result, const sp<IFilter>& filter) { - mFilter = filter; - status = result; - }); - - if (status == Result::SUCCESS) { - mFilterCallback->setFilterEventType(getFilterEventType(type)); - } - - return AssertionResult(status == Result::SUCCESS); -} -/*============================ End Demux APIs Tests Implementation ============================*/ - -/*=========================== Start Filter APIs Tests Implementation ===========================*/ -AssertionResult TunerHidlTest::getNewlyOpenedFilterId(uint32_t& filterId) { - Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first."; - EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first."; - - mFilter->getId([&](Result result, uint32_t filterId) { - mFilterId = filterId; - status = result; - }); - - if (status == Result::SUCCESS) { - mFilterCallback->setFilterId(mFilterId); - mFilterCallback->setFilterInterface(mFilter); - mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId); - mFilters[mFilterId] = mFilter; - mFilterCallbacks[mFilterId] = mFilterCallback; - filterId = mFilterId; - } - - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::configFilter(DemuxFilterSettings setting, uint32_t filterId) { - Result status; - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - status = mFilters[filterId]->configure(setting); - - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::getFilterMQDescriptor(uint32_t filterId) { - Result status; - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first."; - - mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) { - mFilterMQDescriptor = filterMQDesc; - status = result; - }); - - if (status == Result::SUCCESS) { - mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor); - } - - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::startFilter(uint32_t filterId) { - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - Result status = mFilters[filterId]->start(); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::stopFilter(uint32_t filterId) { - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - Result status = mFilters[filterId]->stop(); - return AssertionResult(status == Result::SUCCESS); -} - -AssertionResult TunerHidlTest::closeFilter(uint32_t filterId) { - EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first."; - Result status = mFilters[filterId]->close(); - if (status == Result::SUCCESS) { - for (int i = 0; i < mUsedFilterIds.size(); i++) { - if (mUsedFilterIds[i] == filterId) { - mUsedFilterIds.erase(mUsedFilterIds.begin() + i); - break; - } - } - mFilterCallbacks.erase(filterId); - mFilters.erase(filterId); - } - return AssertionResult(status == Result::SUCCESS); -} -/*=========================== End Filter APIs Tests Implementation ===========================*/ - /*======================== Start Descrambler APIs Tests Implementation ========================*/ AssertionResult TunerHidlTest::createDescrambler() { Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) { mDescrambler = descrambler; status = result; @@ -1141,7 +226,6 @@ AssertionResult TunerHidlTest::closeDescrambler() { /*============================ Start Dvr APIs Tests Implementation ============================*/ AssertionResult TunerHidlTest::openDvrInDemux(DvrType type) { Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; // Create dvr callback mDvrCallback = new DvrCallback(); @@ -1162,7 +246,6 @@ AssertionResult TunerHidlTest::configDvr(DvrSettings setting) { AssertionResult TunerHidlTest::getDvrMQDescriptor() { Result status; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; EXPECT_TRUE(mDvr) << "Test with openDvr first."; mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) { @@ -1176,13 +259,10 @@ AssertionResult TunerHidlTest::getDvrMQDescriptor() { /*========================== Start Data Flow Tests Implementation ==========================*/ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector<string> /*goldenOutputFiles*/) { - EXPECT_TRUE(mFrontend) << "Test with openFilterInDemux first."; - EXPECT_TRUE(mDemux) << "Test with openDemux first."; - EXPECT_TRUE(mFilterCallback) << "Test with getFilterMQDescriptor first."; - // Data Verify Module std::map<uint32_t, sp<FilterCallback>>::iterator it; - for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) { + std::map<uint32_t, sp<FilterCallback>> filterCallbacks = mFilterTests.getFilterCallbacks(); + for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) { it->second->testFilterDataOutput(); } return success(); @@ -1334,160 +414,89 @@ AssertionResult TunerHidlTest::recordDataFlowTest(vector<FilterConf> filterConf, /*========================= End Data Flow Tests Implementation =========================*/ /*================================= Start Test Module =================================*/ -void TunerHidlTest::getFrontendIdByType(FrontendType feType, uint32_t& feId) { - ASSERT_TRUE(getFrontendIds()); - ASSERT_TRUE(mFeIds.size() > 0); - for (size_t i = 0; i < mFeIds.size(); i++) { - ASSERT_TRUE(getFrontendInfo(mFeIds[i])); - if (mFrontendInfo.type != feType) { - continue; - } - feId = mFeIds[i]; - return; - } - feId = INVALID_ID; -} - void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf) { uint32_t feId; - getFrontendIdByType(frontendConf.type, feId); + mFrontendTests.getFrontendIdByType(frontendConf.type, feId); if (feId == INVALID_ID) { // TODO broadcast test on Cuttlefish needs licensed ts input, // these tests are runnable on vendor device with real frontend module // or with manual ts installing and use DVBT frontend. return; } - ASSERT_TRUE(openFrontendById(feId)); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(feId)); - ASSERT_TRUE(openFilterInDemux(filterConf.type)); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); + mFilterTests.setDemux(mDemux); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type)); uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterConf.setting, filterId)); - ASSERT_TRUE(getFilterMQDescriptor(filterId)); - ASSERT_TRUE(startFilter(filterId)); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterConf.setting, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); // tune test - ASSERT_TRUE(tuneFrontend(frontendConf)); + ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf)); // broadcast data flow test ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles)); - ASSERT_TRUE(stopTuneFrontend()); - ASSERT_TRUE(stopFilter(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); -} - -void TunerHidlTest::scanTest(FrontendConfig frontendConf, FrontendScanType scanType) { - uint32_t feId; - getFrontendIdByType(frontendConf.type, feId); - ASSERT_TRUE(feId != INVALID_ID); - ASSERT_TRUE(openFrontendById(feId)); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(scanFrontend(frontendConf, scanType)); - ASSERT_TRUE(stopScanFrontend()); - ASSERT_TRUE(closeFrontend()); + ASSERT_TRUE(mFrontendTests.stopTuneFrontend()); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); } /*================================== End Test Module ==================================*/ - -/*=============================== Start Helper Functions ===============================*/ -FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { - FilterEventType eventType = FilterEventType::UNDEFINED; - switch (type.mainType) { - case DemuxFilterMainType::TS: - switch (type.subType.tsFilterType()) { - case DemuxTsFilterType::UNDEFINED: - break; - case DemuxTsFilterType::SECTION: - eventType = FilterEventType::SECTION; - break; - case DemuxTsFilterType::PES: - eventType = FilterEventType::PES; - break; - case DemuxTsFilterType::TS: - break; - case DemuxTsFilterType::AUDIO: - case DemuxTsFilterType::VIDEO: - eventType = FilterEventType::MEDIA; - break; - case DemuxTsFilterType::PCR: - break; - case DemuxTsFilterType::RECORD: - eventType = FilterEventType::RECORD; - break; - case DemuxTsFilterType::TEMI: - eventType = FilterEventType::TEMI; - break; - } - break; - case DemuxFilterMainType::MMTP: - /*mmtpSettings*/ - break; - case DemuxFilterMainType::IP: - /*ipSettings*/ - break; - case DemuxFilterMainType::TLV: - /*tlvSettings*/ - break; - case DemuxFilterMainType::ALP: - /*alpSettings*/ - break; - default: - break; - } - return eventType; -} -/*============================== End Helper Functions ==============================*/ /***************************** End Test Implementation *****************************/ /******************************** Start Test Entry **********************************/ -/*============================== Start Frontend Tests ==============================*/ -TEST_P(TunerHidlTest, TuneFrontend) { +TEST_P(TunerFrontendHidlTest, TuneFrontend) { description("Tune one Frontend with specific setting and check Lock event"); - uint32_t feId; - getFrontendIdByType(frontendArray[DVBT].type, feId); - ASSERT_TRUE(feId != INVALID_ID); - ASSERT_TRUE(openFrontendById(feId)); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(tuneFrontend(frontendArray[DVBT])); - ASSERT_TRUE(stopTuneFrontend()); - ASSERT_TRUE(closeFrontend()); + mFrontendTests.tuneTest(frontendArray[DVBT]); } -TEST_P(TunerHidlTest, AutoScanFrontend) { +TEST_P(TunerFrontendHidlTest, AutoScanFrontend) { description("Run an auto frontend scan with specific setting and check lock scanMessage"); - scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_AUTO); + mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_AUTO); } -TEST_P(TunerHidlTest, BlindScanFrontend) { +TEST_P(TunerFrontendHidlTest, BlindScanFrontend) { description("Run an blind frontend scan with specific setting and check lock scanMessage"); - scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND); + mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND); } -/*=============================== End Frontend Tests ===============================*/ -/*============================ Start Demux/Filter Tests ============================*/ -TEST_P(TunerHidlTest, StartFilterInDemux) { +TEST_P(TunerDemuxHidlTest, openDemux) { + description("Open and close a Demux."); + uint32_t feId; + mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId); + ASSERT_TRUE(feId != INVALID_ID); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); +} + +TEST_P(TunerFilterHidlTest, StartFilterInDemux) { description("Open and start a filter in Demux."); uint32_t feId; - getFrontendIdByType(frontendArray[DVBT].type, feId); + mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId); ASSERT_TRUE(feId != INVALID_ID); - ASSERT_TRUE(openFrontendById(feId)); - ASSERT_TRUE(setFrontendCallback()); - ASSERT_TRUE(openDemux()); - ASSERT_TRUE(setDemuxFrontendDataSource(feId)); - ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); + ASSERT_TRUE(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); + ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId)); + mFilterTests.setDemux(mDemux); + ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId)); + ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO0].type)); uint32_t filterId; - ASSERT_TRUE(getNewlyOpenedFilterId(filterId)); - ASSERT_TRUE(configFilter(filterArray[TS_VIDEO0].setting, filterId)); - ASSERT_TRUE(getFilterMQDescriptor(filterId)); - ASSERT_TRUE(startFilter(filterId)); - ASSERT_TRUE(stopFilter(filterId)); - ASSERT_TRUE(closeFilter(filterId)); - ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); + ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId)); + ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO0].setting, filterId)); + ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId)); + ASSERT_TRUE(mFilterTests.startFilter(filterId)); + ASSERT_TRUE(mFilterTests.stopFilter(filterId)); + ASSERT_TRUE(mFilterTests.closeFilter(filterId)); + ASSERT_TRUE(mDemuxTests.closeDemux()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); } -/*============================ End Demux/Filter Tests ============================*/ /*============================ Start Descrambler Tests ============================*/ /* @@ -1614,9 +623,23 @@ TEST_P(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) { }*/ /*============================== End Data Flow Tests ==============================*/ /******************************** End Test Entry **********************************/ -} // namespace +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerFrontendHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); INSTANTIATE_TEST_SUITE_P( PerInstance, TunerHidlTest, testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerDemuxHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); + +INSTANTIATE_TEST_SUITE_P( + PerInstance, TunerFilterHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)), + android::hardware::PrintInstanceNameToString); +} // namespace diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h new file mode 100644 index 0000000000..f17704774c --- /dev/null +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h @@ -0,0 +1,260 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/hardware/tv/tuner/1.0/IDescrambler.h> +#include <android/hardware/tv/tuner/1.0/IDvr.h> +#include <android/hardware/tv/tuner/1.0/IDvrCallback.h> +#include <fstream> +#include <iostream> + +#include "DemuxTests.h" +#include "FilterTests.h" +#include "FrontendTests.h" + +using android::hardware::tv::tuner::V1_0::DataFormat; +using android::hardware::tv::tuner::V1_0::DvrSettings; +using android::hardware::tv::tuner::V1_0::DvrType; +using android::hardware::tv::tuner::V1_0::IDescrambler; +using android::hardware::tv::tuner::V1_0::IDvr; +using android::hardware::tv::tuner::V1_0::IDvrCallback; +using android::hardware::tv::tuner::V1_0::PlaybackSettings; +using android::hardware::tv::tuner::V1_0::PlaybackStatus; +using android::hardware::tv::tuner::V1_0::RecordSettings; +using android::hardware::tv::tuner::V1_0::RecordStatus; + +struct PlaybackConf { + string inputDataFile; + PlaybackSettings setting; +}; + +static AssertionResult failure() { + return ::testing::AssertionFailure(); +} + +static AssertionResult success() { + return ::testing::AssertionSuccess(); +} + +namespace { + +class DvrCallback : public IDvrCallback { + public: + virtual Return<void> onRecordStatus(DemuxFilterStatus status) override { + ALOGW("[vts] record status %hhu", status); + switch (status) { + case DemuxFilterStatus::DATA_READY: + break; + case DemuxFilterStatus::LOW_WATER: + break; + case DemuxFilterStatus::HIGH_WATER: + case DemuxFilterStatus::OVERFLOW: + ALOGW("[vts] record overflow. Flushing"); + break; + } + return Void(); + } + + virtual Return<void> onPlaybackStatus(PlaybackStatus status) override { + // android::Mutex::Autolock autoLock(mMsgLock); + ALOGW("[vts] playback status %d", status); + switch (status) { + case PlaybackStatus::SPACE_EMPTY: + case PlaybackStatus::SPACE_ALMOST_EMPTY: + ALOGW("[vts] keep playback inputing %d", status); + mKeepWritingPlaybackFMQ = true; + break; + case PlaybackStatus::SPACE_ALMOST_FULL: + case PlaybackStatus::SPACE_FULL: + ALOGW("[vts] stop playback inputing %d", status); + mKeepWritingPlaybackFMQ = false; + break; + } + return Void(); + } + + void testFilterDataOutput(); + void stopPlaybackThread(); + void testRecordOutput(); + void stopRecordThread(); + + void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor); + void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor); + static void* __threadLoopPlayback(void* threadArgs); + static void* __threadLoopRecord(void* threadArgs); + void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ); + void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ); + + bool readRecordFMQ(); + + private: + struct PlaybackThreadArgs { + DvrCallback* user; + PlaybackConf* playbackConf; + bool* keepWritingPlaybackFMQ; + }; + struct RecordThreadArgs { + DvrCallback* user; + RecordSettings* recordSetting; + bool* keepReadingRecordFMQ; + }; + uint16_t mDataLength = 0; + std::vector<uint8_t> mDataOutputBuffer; + + std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterMQ; + std::unique_ptr<FilterMQ> mPlaybackMQ; + std::unique_ptr<FilterMQ> mRecordMQ; + std::map<uint32_t, EventFlag*> mFilterMQEventFlag; + + android::Mutex mMsgLock; + android::Mutex mPlaybackThreadLock; + android::Mutex mRecordThreadLock; + android::Condition mMsgCondition; + + bool mKeepWritingPlaybackFMQ = true; + bool mKeepReadingRecordFMQ = true; + bool mPlaybackThreadRunning; + bool mRecordThreadRunning; + pthread_t mPlaybackThread; + pthread_t mRecordThread; + + int mPidFilterOutputCount = 0; +}; + +class TunerFrontendHidlTest : public testing::TestWithParam<std::string> { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + + mFrontendTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp<ITuner> mService; + FrontendTests mFrontendTests; +}; + +class TunerDemuxHidlTest : public testing::TestWithParam<std::string> { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp<ITuner> mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + sp<IDemux> mDemux; + uint32_t mDemuxId; +}; + +class TunerFilterHidlTest : public testing::TestWithParam<std::string> { + public: + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + mFilterTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp<ITuner> mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; + sp<IDemux> mDemux; + uint32_t mDemuxId; +}; + +class TunerHidlTest : public testing::TestWithParam<std::string> { + public: + sp<ITuner> mService; + FrontendTests mFrontendTests; + DemuxTests mDemuxTests; + FilterTests mFilterTests; + + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + + mFrontendTests.setService(mService); + mDemuxTests.setService(mService); + mFilterTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp<IDescrambler> mDescrambler; + sp<IDvr> mDvr; + sp<IDemux> mDemux; + uint32_t mDemuxId; + + sp<DvrCallback> mDvrCallback; + MQDesc mDvrMQDescriptor; + MQDesc mRecordMQDescriptor; + + pthread_t mPlaybackshread; + bool mPlaybackThreadRunning; + + AssertionResult openDvrInDemux(DvrType type); + AssertionResult configDvr(DvrSettings setting); + AssertionResult getDvrMQDescriptor(); + + AssertionResult createDescrambler(); + AssertionResult closeDescrambler(); + + AssertionResult playbackDataFlowTest(vector<FilterConfig> filterConf, PlaybackConf playbackConf, + vector<string> goldenOutputFiles); + AssertionResult recordDataFlowTest(vector<FilterConfig> filterConf, + RecordSettings recordSetting, + vector<string> goldenOutputFiles); + AssertionResult broadcastDataFlowTest(vector<string> goldenOutputFiles); + + void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); +}; +} // namespace
\ No newline at end of file diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h index 10c60142ba..538773a209 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h @@ -38,6 +38,8 @@ using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode; using android::hardware::tv::tuner::V1_0::FrontendSettings; using android::hardware::tv::tuner::V1_0::FrontendType; +using namespace std; + typedef enum { TS_VIDEO0, TS_VIDEO1, |