Merge "Make VtsHalTvTunerV1_0FrontendTest an independent test." into rvc-dev

This commit is contained in:
Amy Zhang
2020-04-14 05:47:46 +00:00
committed by Android (Google) Code Review
5 changed files with 796 additions and 731 deletions

View File

@@ -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",

View 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());
}

View 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;
};

View File

@@ -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

View 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