mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
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
This commit is contained in:
@@ -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",
|
||||
|
||||
310
tv/tuner/1.0/vts/functional/FrontendTests.cpp
Normal file
310
tv/tuner/1.0/vts/functional/FrontendTests.cpp
Normal file
@@ -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());
|
||||
}
|
||||
127
tv/tuner/1.0/vts/functional/FrontendTests.h
Normal file
127
tv/tuner/1.0/vts/functional/FrontendTests.h
Normal file
@@ -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 <VtsHalHidlTargetTestBase.h>
|
||||
#include <VtsHalHidlTargetTestEnvBase.h>
|
||||
#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_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<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;
|
||||
};
|
||||
@@ -14,433 +14,10 @@
|
||||
* 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));
|
||||
@@ -555,89 +132,6 @@ bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
|
||||
/******************************** 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,176 +303,6 @@ 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;
|
||||
@@ -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<string> /*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> 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
|
||||
|
||||
333
tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
Normal file
333
tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
Normal file
@@ -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 <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/types.h>
|
||||
#include <binder/MemoryDealer.h>
|
||||
#include <fmq/MessageQueue.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#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<uint8_t, kSynchronizedReadWrite>;
|
||||
using MQDesc = MQDescriptorSync<uint8_t>;
|
||||
|
||||
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<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 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:
|
||||
sp<ITuner> 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<std::string> {
|
||||
public:
|
||||
sp<ITuner> 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<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 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);
|
||||
|
||||
FilterEventType getFilterEventType(DemuxFilterType type);
|
||||
};
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user