From b3fb40bd0549d49bd38dcfde365eaa2eabb3e6ba Mon Sep 17 00:00:00 2001 From: Amy Zhang Date: Thu, 2 Apr 2020 13:48:43 -0700 Subject: [PATCH] Make VtsHalTvTunerV1_0FrontendTest an independent test. Note that this refactoring extracts two header files for VtsHalTvTunerV1_0FrontendTest and VtsHalTvTunerV1_0TargetTest. Test: atest VtsHalTvTunerV1_0FrontendTest/VtsHalTvTunerV1_0TargetTest Bug: 150953857 Change-Id: Ie5f0dc4a9180ecc779004cb451a45ae54a6ea47c --- tv/tuner/1.0/vts/functional/Android.bp | 5 +- tv/tuner/1.0/vts/functional/FrontendTests.cpp | 310 ++++++++ tv/tuner/1.0/vts/functional/FrontendTests.h | 127 +++ .../VtsHalTvTunerV1_0TargetTest.cpp | 752 +----------------- .../functional/VtsHalTvTunerV1_0TargetTest.h | 333 ++++++++ 5 files changed, 796 insertions(+), 731 deletions(-) create mode 100644 tv/tuner/1.0/vts/functional/FrontendTests.cpp create mode 100644 tv/tuner/1.0/vts/functional/FrontendTests.h create mode 100644 tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h diff --git a/tv/tuner/1.0/vts/functional/Android.bp b/tv/tuner/1.0/vts/functional/Android.bp index 641e16a937..b4dbda7896 100644 --- a/tv/tuner/1.0/vts/functional/Android.bp +++ b/tv/tuner/1.0/vts/functional/Android.bp @@ -17,7 +17,10 @@ cc_test { name: "VtsHalTvTunerV1_0TargetTest", defaults: ["VtsHalTargetTestDefaults"], - srcs: ["VtsHalTvTunerV1_0TargetTest.cpp"], + srcs: [ + "VtsHalTvTunerV1_0TargetTest.cpp", + "FrontendTests.cpp", + ], static_libs: [ "android.hardware.tv.tuner@1.0", "android.hidl.allocator@1.0", 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..5bc3705fcd --- /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 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 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& 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& 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& 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& 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& 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()); +} \ No newline at end of file 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..5aa6e159f1 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/FrontendTests.h @@ -0,0 +1,127 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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_handle; +using android::hardware::hidl_string; +using android::hardware::hidl_vec; +using android::hardware::HidlMemory; +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; + +#define INVALID_ID -1 +#define WAIT_TIMEOUT 3000000000 + +class FrontendCallback : public IFrontendCallback { + public: + virtual Return onEvent(FrontendEventType frontendEventType) override; + virtual Return onScanMessage(FrontendScanMessageType type, + const FrontendScanMessage& message) override; + + void tuneTestOnEventReceive(sp& frontend, FrontendSettings settings); + void tuneTestOnLock(sp& frontend, FrontendSettings settings); + void scanTest(sp& 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 mEventMessage; + android::Mutex mMsgLock; + android::Condition mMsgCondition; + android::Condition mLockMsgCondition; +}; + +class FrontendTests { + public: + sp mService; + + void setService(sp 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 mFrontend; + FrontendInfo mFrontendInfo; + sp mFrontendCallback; + hidl_vec 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..59c94793ec 100644 --- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp @@ -14,433 +14,10 @@ * limitations under the License. */ -#define LOG_TAG "Tuner_hidl_hal_test" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -using MQDesc = MQDescriptorSync; - -const std::vector 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 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 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& frontend, FrontendSettings settings); - void tuneTestOnLock(sp& frontend, FrontendSettings settings); - void scanTest(sp& 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 mEventMessage; - android::Mutex mMsgLock; - android::Condition mMsgCondition; - android::Condition mLockMsgCondition; -}; - -void FrontendCallback::tuneTestOnEventReceive(sp& 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& 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& 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 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 onFilterStatus(const DemuxFilterStatus /*status*/) override { - return Void(); - } - - void setFilterId(uint32_t filterId) { mFilterId = filterId; } - void setFilterInterface(sp 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 mDataOutputBuffer; - - string mFilterIdToGoldenOutput; - - uint32_t mFilterId; - sp mFilter; - FilterEventType mFilterEventType; - std::unique_ptr 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)); @@ -555,89 +132,6 @@ bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) { /******************************** End FilterCallback **********************************/ /******************************** Start DvrCallback **********************************/ -class DvrCallback : public IDvrCallback { - public: - virtual Return 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 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 mDataOutputBuffer; - - std::map> mFilterMQ; - std::unique_ptr mPlaybackMQ; - std::unique_ptr mRecordMQ; - std::map 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(playbackMQDescriptor, true /* resetPointers */); @@ -809,176 +303,6 @@ void DvrCallback::stopRecordThread() { } /********************************** End DvrCallback ************************************/ -/***************************** Start Test Implementation ******************************/ -class TunerHidlTest : public testing::TestWithParam { - public: - virtual void SetUp() override { - mService = ITuner::getService(GetParam()); - ASSERT_NE(mService, nullptr); - initFrontendConfig(); - initFrontendScanConfig(); - initFilterConfig(); - } - - sp 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 mFrontend; - FrontendInfo mFrontendInfo; - sp mFrontendCallback; - sp mDescrambler; - sp mDemux; - sp mDvr; - sp mFilter; - std::map> mFilters; - std::map> mFilterCallbacks; - - sp mFilterCallback; - sp mDvrCallback; - MQDesc mFilterMQDescriptor; - MQDesc mDvrMQDescriptor; - MQDesc mRecordMQDescriptor; - vector mUsedFilterIds; - hidl_vec 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 filterConf, PlaybackConf playbackConf, - vector goldenOutputFiles); - AssertionResult recordDataFlowTest(vector filterConf, - RecordSettings recordSetting, - vector goldenOutputFiles); - AssertionResult broadcastDataFlowTest(vector 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& 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& 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; @@ -992,7 +316,6 @@ AssertionResult TunerHidlTest::openDemux() { 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()); } @@ -1176,7 +499,6 @@ AssertionResult TunerHidlTest::getDvrMQDescriptor() { /*========================== Start Data Flow Tests Implementation ==========================*/ AssertionResult TunerHidlTest::broadcastDataFlowTest(vector /*goldenOutputFiles*/) { - EXPECT_TRUE(mFrontend) << "Test with openFilterInDemux first."; EXPECT_TRUE(mDemux) << "Test with openDemux first."; EXPECT_TRUE(mFilterCallback) << "Test with getFilterMQDescriptor first."; @@ -1334,32 +656,18 @@ AssertionResult TunerHidlTest::recordDataFlowTest(vector 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(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); ASSERT_TRUE(openDemux()); ASSERT_TRUE(setDemuxFrontendDataSource(feId)); ASSERT_TRUE(openFilterInDemux(filterConf.type)); @@ -1369,25 +677,14 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf, ASSERT_TRUE(getFilterMQDescriptor(filterId)); ASSERT_TRUE(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(mFrontendTests.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.closeFrontend()); } /*================================== End Test Module ==================================*/ @@ -1442,38 +739,29 @@ FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) { /***************************** 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) { 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(mFrontendTests.openFrontendById(feId)); + ASSERT_TRUE(mFrontendTests.setFrontendCallback()); ASSERT_TRUE(openDemux()); ASSERT_TRUE(setDemuxFrontendDataSource(feId)); ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type)); @@ -1485,7 +773,7 @@ TEST_P(TunerHidlTest, StartFilterInDemux) { ASSERT_TRUE(stopFilter(filterId)); ASSERT_TRUE(closeFilter(filterId)); ASSERT_TRUE(closeDemux()); - ASSERT_TRUE(closeFrontend()); + ASSERT_TRUE(mFrontendTests.closeFrontend()); } /*============================ End Demux/Filter Tests ============================*/ @@ -1614,9 +902,13 @@ 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); +} // 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..4d6715eeb7 --- /dev/null +++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h @@ -0,0 +1,333 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "FrontendTests.h" + +using android::hardware::EventFlag; +using android::hardware::kSynchronizedReadWrite; +using android::hardware::MessageQueue; +using android::hardware::MQDescriptorSync; +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::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::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 FilterMQ = MessageQueue; +using MQDesc = MQDescriptorSync; + +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; +}; + +static AssertionResult failure() { + return ::testing::AssertionFailure(); +} + +static AssertionResult success() { + return ::testing::AssertionSuccess(); +} + +namespace { + +class FilterCallback : public IFilterCallback { + public: + virtual Return 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 onFilterStatus(const DemuxFilterStatus /*status*/) override { + return Void(); + } + + void setFilterId(uint32_t filterId) { mFilterId = filterId; } + void setFilterInterface(sp 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 mDataOutputBuffer; + + string mFilterIdToGoldenOutput; + + uint32_t mFilterId; + sp mFilter; + FilterEventType mFilterEventType; + std::unique_ptr mFilterMQ; + EventFlag* mFilterMQEventFlag; + DemuxFilterEvent mFilterEvent; + + android::Mutex mMsgLock; + android::Mutex mFilterOutputLock; + android::Condition mMsgCondition; + android::Condition mFilterOutputCondition; + + pthread_t mFilterThread; + + int mPidFilterOutputCount = 0; +}; + +class DvrCallback : public IDvrCallback { + public: + virtual Return 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 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 mDataOutputBuffer; + + std::map> mFilterMQ; + std::unique_ptr mPlaybackMQ; + std::unique_ptr mRecordMQ; + std::map 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 { + public: + sp mService; + FrontendTests mFrontendTests; + + 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); + } +}; + +class TunerHidlTest : public testing::TestWithParam { + public: + sp mService; + FrontendTests mFrontendTests; + + virtual void SetUp() override { + mService = ITuner::getService(GetParam()); + ASSERT_NE(mService, nullptr); + initFrontendConfig(); + initFrontendScanConfig(); + initFilterConfig(); + + mFrontendTests.setService(mService); + } + + protected: + static void description(const std::string& description) { + RecordProperty("description", description); + } + + sp mDescrambler; + + sp mDemux; + sp mDvr; + sp mFilter; + std::map> mFilters; + std::map> mFilterCallbacks; + + sp mFilterCallback; + sp mDvrCallback; + MQDesc mFilterMQDescriptor; + MQDesc mDvrMQDescriptor; + MQDesc mRecordMQDescriptor; + vector mUsedFilterIds; + hidl_vec mFeIds; + + uint32_t mDemuxId; + uint32_t mFilterId = -1; + + pthread_t mPlaybackshread; + bool mPlaybackThreadRunning; + + 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 filterConf, PlaybackConf playbackConf, + vector goldenOutputFiles); + AssertionResult recordDataFlowTest(vector filterConf, + RecordSettings recordSetting, + vector goldenOutputFiles); + AssertionResult broadcastDataFlowTest(vector goldenOutputFiles); + + void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf); + + FilterEventType getFilterEventType(DemuxFilterType type); +}; +} // namespace \ No newline at end of file