Merge "Separate Demux and Filter fixture classes from the Tuner HAL VTS target test" into rvc-dev
This commit is contained in:
commit
62bc360c11
9 changed files with 663 additions and 456 deletions
|
@ -20,6 +20,8 @@ cc_test {
|
|||
srcs: [
|
||||
"VtsHalTvTunerV1_0TargetTest.cpp",
|
||||
"FrontendTests.cpp",
|
||||
"DemuxTests.cpp",
|
||||
"FilterTests.cpp",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.tv.tuner@1.0",
|
||||
|
|
41
tv/tuner/1.0/vts/functional/DemuxTests.cpp
Normal file
41
tv/tuner/1.0/vts/functional/DemuxTests.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "DemuxTests.h"
|
||||
|
||||
AssertionResult DemuxTests::openDemux(sp<IDemux>& demux, uint32_t& demuxId) {
|
||||
Result status;
|
||||
mService->openDemux([&](Result result, uint32_t id, const sp<IDemux>& demuxSp) {
|
||||
mDemux = demuxSp;
|
||||
demux = demuxSp;
|
||||
demuxId = id;
|
||||
status = result;
|
||||
});
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult DemuxTests::setDemuxFrontendDataSource(uint32_t frontendId) {
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
auto status = mDemux->setFrontendDataSource(frontendId);
|
||||
return AssertionResult(status.isOk());
|
||||
}
|
||||
|
||||
AssertionResult DemuxTests::closeDemux() {
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
auto status = mDemux->close();
|
||||
mDemux = nullptr;
|
||||
return AssertionResult(status.isOk());
|
||||
}
|
57
tv/tuner/1.0/vts/functional/DemuxTests.h
Normal file
57
tv/tuner/1.0/vts/functional/DemuxTests.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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/IDemux.h>
|
||||
#include <android/hardware/tv/tuner/1.0/ITuner.h>
|
||||
#include <android/hardware/tv/tuner/1.0/types.h>
|
||||
#include <binder/MemoryDealer.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <hidl/ServiceManagement.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <hidlmemory/FrameworkUtils.h>
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <map>
|
||||
|
||||
using android::sp;
|
||||
using android::hardware::Return;
|
||||
using android::hardware::Void;
|
||||
using android::hardware::tv::tuner::V1_0::IDemux;
|
||||
using android::hardware::tv::tuner::V1_0::ITuner;
|
||||
using android::hardware::tv::tuner::V1_0::Result;
|
||||
|
||||
using ::testing::AssertionResult;
|
||||
|
||||
class DemuxTests {
|
||||
public:
|
||||
sp<ITuner> mService;
|
||||
|
||||
void setService(sp<ITuner> tuner) { mService = tuner; }
|
||||
|
||||
AssertionResult openDemux(sp<IDemux>& demux, uint32_t& demuxId);
|
||||
AssertionResult setDemuxFrontendDataSource(uint32_t frontendId);
|
||||
AssertionResult closeDemux();
|
||||
|
||||
protected:
|
||||
static AssertionResult failure() { return ::testing::AssertionFailure(); }
|
||||
|
||||
static AssertionResult success() { return ::testing::AssertionSuccess(); }
|
||||
|
||||
sp<IDemux> mDemux;
|
||||
};
|
226
tv/tuner/1.0/vts/functional/FilterTests.cpp
Normal file
226
tv/tuner/1.0/vts/functional/FilterTests.cpp
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "FilterTests.h"
|
||||
|
||||
void FilterCallback::startFilterEventThread(DemuxFilterEvent event) {
|
||||
struct FilterThreadArgs* threadArgs =
|
||||
(struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
|
||||
threadArgs->user = this;
|
||||
threadArgs->event = event;
|
||||
|
||||
pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
|
||||
pthread_setname_np(mFilterThread, "test_playback_input_loop");
|
||||
}
|
||||
|
||||
void FilterCallback::testFilterDataOutput() {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
while (mPidFilterOutputCount < 1) {
|
||||
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
|
||||
EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
|
||||
return;
|
||||
}
|
||||
}
|
||||
mPidFilterOutputCount = 0;
|
||||
ALOGW("[vts] pass and stop");
|
||||
}
|
||||
|
||||
void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) {
|
||||
mFilterMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
|
||||
EXPECT_TRUE(mFilterMQ);
|
||||
EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) ==
|
||||
android::OK);
|
||||
}
|
||||
|
||||
void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) {
|
||||
mFilterIdToGoldenOutput = goldenOutputFile;
|
||||
}
|
||||
|
||||
void* FilterCallback::__threadLoopFilter(void* threadArgs) {
|
||||
FilterCallback* const self =
|
||||
static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
|
||||
self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
|
||||
android::Mutex::Autolock autoLock(mFilterOutputLock);
|
||||
// Read from mFilterMQ[event.filterId] per event and filter type
|
||||
|
||||
// Assemble to filterOutput[filterId]
|
||||
|
||||
// check if filterOutput[filterId] matches goldenOutput[filterId]
|
||||
|
||||
// If match, remove filterId entry from MQ map
|
||||
|
||||
// end thread
|
||||
}
|
||||
|
||||
bool FilterCallback::readFilterEventData() {
|
||||
bool result = false;
|
||||
DemuxFilterEvent filterEvent = mFilterEvent;
|
||||
ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
|
||||
// todo separate filter handlers
|
||||
for (int i = 0; i < filterEvent.events.size(); i++) {
|
||||
switch (mFilterEventType) {
|
||||
case FilterEventType::SECTION:
|
||||
mDataLength = filterEvent.events[i].section().dataLength;
|
||||
break;
|
||||
case FilterEventType::PES:
|
||||
mDataLength = filterEvent.events[i].pes().dataLength;
|
||||
break;
|
||||
case FilterEventType::MEDIA:
|
||||
return dumpAvData(filterEvent.events[i].media());
|
||||
case FilterEventType::RECORD:
|
||||
break;
|
||||
case FilterEventType::MMTPRECORD:
|
||||
break;
|
||||
case FilterEventType::DOWNLOAD:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
|
||||
// match";
|
||||
|
||||
mDataOutputBuffer.resize(mDataLength);
|
||||
result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength);
|
||||
EXPECT_TRUE(result) << "can't read from Filter MQ";
|
||||
|
||||
/*for (int i = 0; i < mDataLength; i++) {
|
||||
EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
|
||||
}*/
|
||||
}
|
||||
mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
|
||||
uint32_t length = event.dataLength;
|
||||
uint64_t dataId = event.avDataId;
|
||||
// read data from buffer pointed by a handle
|
||||
hidl_handle handle = event.avMemory;
|
||||
|
||||
int av_fd = handle.getNativeHandle()->data[0];
|
||||
uint8_t* buffer = static_cast<uint8_t*>(
|
||||
mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/));
|
||||
if (buffer == MAP_FAILED) {
|
||||
ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
|
||||
return false;
|
||||
}
|
||||
uint8_t output[length + 1];
|
||||
memcpy(output, buffer, length);
|
||||
// print buffer and check with golden output.
|
||||
EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS);
|
||||
return true;
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
|
||||
// Create demux callback
|
||||
mFilterCallback = new FilterCallback();
|
||||
|
||||
// Add filter to the local demux
|
||||
mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback,
|
||||
[&](Result result, const sp<IFilter>& filter) {
|
||||
mFilter = filter;
|
||||
status = result;
|
||||
});
|
||||
|
||||
if (status == Result::SUCCESS) {
|
||||
mFilterCallback->setFilterEventType(getFilterEventType(type));
|
||||
}
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::getNewlyOpenedFilterId(uint32_t& filterId) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first.";
|
||||
EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first.";
|
||||
|
||||
mFilter->getId([&](Result result, uint32_t filterId) {
|
||||
mFilterId = filterId;
|
||||
status = result;
|
||||
});
|
||||
|
||||
if (status == Result::SUCCESS) {
|
||||
mFilterCallback->setFilterId(mFilterId);
|
||||
mFilterCallback->setFilterInterface(mFilter);
|
||||
mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
|
||||
mFilters[mFilterId] = mFilter;
|
||||
mFilterCallbacks[mFilterId] = mFilterCallback;
|
||||
filterId = mFilterId;
|
||||
}
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint32_t filterId) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
status = mFilters[filterId]->configure(setting);
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::getFilterMQDescriptor(uint32_t filterId) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
|
||||
mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
|
||||
mFilterMQDescriptor = filterMQDesc;
|
||||
status = result;
|
||||
});
|
||||
|
||||
if (status == Result::SUCCESS) {
|
||||
mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor);
|
||||
}
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::startFilter(uint32_t filterId) {
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
Result status = mFilters[filterId]->start();
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::stopFilter(uint32_t filterId) {
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
Result status = mFilters[filterId]->stop();
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult FilterTests::closeFilter(uint32_t filterId) {
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
Result status = mFilters[filterId]->close();
|
||||
if (status == Result::SUCCESS) {
|
||||
for (int i = 0; i < mUsedFilterIds.size(); i++) {
|
||||
if (mUsedFilterIds[i] == filterId) {
|
||||
mUsedFilterIds.erase(mUsedFilterIds.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mFilterCallbacks.erase(filterId);
|
||||
mFilters.erase(filterId);
|
||||
}
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
226
tv/tuner/1.0/vts/functional/FilterTests.h
Normal file
226
tv/tuner/1.0/vts/functional/FilterTests.h
Normal file
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <VtsHalHidlTargetTestBase.h>
|
||||
#include <VtsHalHidlTargetTestEnvBase.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android/hardware/tv/tuner/1.0/IFilter.h>
|
||||
#include <android/hardware/tv/tuner/1.0/IFilterCallback.h>
|
||||
#include <android/hardware/tv/tuner/1.0/ITuner.h>
|
||||
#include <android/hardware/tv/tuner/1.0/types.h>
|
||||
#include <fmq/MessageQueue.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <hidl/HidlSupport.h>
|
||||
#include <hidl/HidlTransportSupport.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <map>
|
||||
|
||||
using android::Condition;
|
||||
using android::Mutex;
|
||||
using android::sp;
|
||||
using android::hardware::EventFlag;
|
||||
using android::hardware::hidl_handle;
|
||||
using android::hardware::hidl_string;
|
||||
using android::hardware::hidl_vec;
|
||||
using android::hardware::kSynchronizedReadWrite;
|
||||
using android::hardware::MessageQueue;
|
||||
using android::hardware::MQDescriptorSync;
|
||||
using android::hardware::Return;
|
||||
using android::hardware::Void;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterType;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
|
||||
using android::hardware::tv::tuner::V1_0::IDemux;
|
||||
using android::hardware::tv::tuner::V1_0::IFilter;
|
||||
using android::hardware::tv::tuner::V1_0::IFilterCallback;
|
||||
using android::hardware::tv::tuner::V1_0::ITuner;
|
||||
using android::hardware::tv::tuner::V1_0::Result;
|
||||
|
||||
using ::testing::AssertionResult;
|
||||
|
||||
enum FilterEventType : uint8_t {
|
||||
UNDEFINED,
|
||||
SECTION,
|
||||
MEDIA,
|
||||
PES,
|
||||
RECORD,
|
||||
MMTPRECORD,
|
||||
DOWNLOAD,
|
||||
TEMI,
|
||||
};
|
||||
|
||||
using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
|
||||
using MQDesc = MQDescriptorSync<uint8_t>;
|
||||
|
||||
const uint32_t FMQ_SIZE_1M = 0x100000;
|
||||
const uint32_t FMQ_SIZE_16M = 0x1000000;
|
||||
|
||||
#define WAIT_TIMEOUT 3000000000
|
||||
|
||||
class FilterCallback : public IFilterCallback {
|
||||
public:
|
||||
virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent) override {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
// Temprarily we treat the first coming back filter data on the matching pid a success
|
||||
// once all of the MQ are cleared, means we got all the expected output
|
||||
mFilterEvent = filterEvent;
|
||||
readFilterEventData();
|
||||
mPidFilterOutputCount++;
|
||||
// mFilterIdToMQ.erase(filterEvent.filterId);
|
||||
|
||||
// startFilterEventThread(filterEvent);
|
||||
mMsgCondition.signal();
|
||||
return Void();
|
||||
}
|
||||
|
||||
virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override {
|
||||
return Void();
|
||||
}
|
||||
|
||||
void setFilterId(uint32_t filterId) { mFilterId = filterId; }
|
||||
void setFilterInterface(sp<IFilter> filter) { mFilter = filter; }
|
||||
void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
|
||||
|
||||
void testFilterDataOutput();
|
||||
|
||||
void startFilterEventThread(DemuxFilterEvent event);
|
||||
static void* __threadLoopFilter(void* threadArgs);
|
||||
void filterThreadLoop(DemuxFilterEvent& event);
|
||||
|
||||
void updateFilterMQ(MQDesc& filterMQDescriptor);
|
||||
void updateGoldenOutputMap(string goldenOutputFile);
|
||||
bool readFilterEventData();
|
||||
bool dumpAvData(DemuxFilterMediaEvent event);
|
||||
|
||||
private:
|
||||
struct FilterThreadArgs {
|
||||
FilterCallback* user;
|
||||
DemuxFilterEvent event;
|
||||
};
|
||||
uint16_t mDataLength = 0;
|
||||
std::vector<uint8_t> mDataOutputBuffer;
|
||||
|
||||
string mFilterIdToGoldenOutput;
|
||||
|
||||
uint32_t mFilterId;
|
||||
sp<IFilter> mFilter;
|
||||
FilterEventType mFilterEventType;
|
||||
std::unique_ptr<FilterMQ> mFilterMQ;
|
||||
EventFlag* mFilterMQEventFlag;
|
||||
DemuxFilterEvent mFilterEvent;
|
||||
|
||||
android::Mutex mMsgLock;
|
||||
android::Mutex mFilterOutputLock;
|
||||
android::Condition mMsgCondition;
|
||||
android::Condition mFilterOutputCondition;
|
||||
|
||||
pthread_t mFilterThread;
|
||||
|
||||
int mPidFilterOutputCount = 0;
|
||||
};
|
||||
|
||||
class FilterTests {
|
||||
public:
|
||||
void setService(sp<ITuner> tuner) { mService = tuner; }
|
||||
void setDemux(sp<IDemux> demux) { mDemux = demux; }
|
||||
|
||||
std::map<uint32_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
|
||||
|
||||
AssertionResult openFilterInDemux(DemuxFilterType type);
|
||||
AssertionResult getNewlyOpenedFilterId(uint32_t& filterId);
|
||||
AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId);
|
||||
AssertionResult getFilterMQDescriptor(uint32_t filterId);
|
||||
AssertionResult startFilter(uint32_t filterId);
|
||||
AssertionResult stopFilter(uint32_t filterId);
|
||||
AssertionResult closeFilter(uint32_t filterId);
|
||||
|
||||
FilterEventType getFilterEventType(DemuxFilterType type) {
|
||||
FilterEventType eventType = FilterEventType::UNDEFINED;
|
||||
switch (type.mainType) {
|
||||
case DemuxFilterMainType::TS:
|
||||
switch (type.subType.tsFilterType()) {
|
||||
case DemuxTsFilterType::UNDEFINED:
|
||||
break;
|
||||
case DemuxTsFilterType::SECTION:
|
||||
eventType = FilterEventType::SECTION;
|
||||
break;
|
||||
case DemuxTsFilterType::PES:
|
||||
eventType = FilterEventType::PES;
|
||||
break;
|
||||
case DemuxTsFilterType::TS:
|
||||
break;
|
||||
case DemuxTsFilterType::AUDIO:
|
||||
case DemuxTsFilterType::VIDEO:
|
||||
eventType = FilterEventType::MEDIA;
|
||||
break;
|
||||
case DemuxTsFilterType::PCR:
|
||||
break;
|
||||
case DemuxTsFilterType::RECORD:
|
||||
eventType = FilterEventType::RECORD;
|
||||
break;
|
||||
case DemuxTsFilterType::TEMI:
|
||||
eventType = FilterEventType::TEMI;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DemuxFilterMainType::MMTP:
|
||||
/*mmtpSettings*/
|
||||
break;
|
||||
case DemuxFilterMainType::IP:
|
||||
/*ipSettings*/
|
||||
break;
|
||||
case DemuxFilterMainType::TLV:
|
||||
/*tlvSettings*/
|
||||
break;
|
||||
case DemuxFilterMainType::ALP:
|
||||
/*alpSettings*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return eventType;
|
||||
}
|
||||
|
||||
protected:
|
||||
static AssertionResult failure() { return ::testing::AssertionFailure(); }
|
||||
|
||||
static AssertionResult success() { return ::testing::AssertionSuccess(); }
|
||||
|
||||
sp<ITuner> mService;
|
||||
sp<IFilter> mFilter;
|
||||
sp<IDemux> mDemux;
|
||||
std::map<uint32_t, sp<IFilter>> mFilters;
|
||||
std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks;
|
||||
|
||||
sp<FilterCallback> mFilterCallback;
|
||||
MQDesc mFilterMQDescriptor;
|
||||
vector<uint32_t> mUsedFilterIds;
|
||||
|
||||
uint32_t mFilterId = -1;
|
||||
};
|
|
@ -307,4 +307,4 @@ void FrontendTests::scanTest(FrontendConfig frontendConf, FrontendScanType scanT
|
|||
ASSERT_TRUE(scanFrontend(frontendConf, scanType));
|
||||
ASSERT_TRUE(stopScanFrontend());
|
||||
ASSERT_TRUE(closeFrontend());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,10 +45,7 @@ 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;
|
||||
|
|
|
@ -17,119 +17,6 @@
|
|||
#include "VtsHalTvTunerV1_0TargetTest.h"
|
||||
|
||||
namespace {
|
||||
/******************************** Start FilterCallback **********************************/
|
||||
void FilterCallback::startFilterEventThread(DemuxFilterEvent event) {
|
||||
struct FilterThreadArgs* threadArgs =
|
||||
(struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
|
||||
threadArgs->user = this;
|
||||
threadArgs->event = event;
|
||||
|
||||
pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
|
||||
pthread_setname_np(mFilterThread, "test_playback_input_loop");
|
||||
}
|
||||
|
||||
void FilterCallback::testFilterDataOutput() {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
while (mPidFilterOutputCount < 1) {
|
||||
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
|
||||
EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
|
||||
return;
|
||||
}
|
||||
}
|
||||
mPidFilterOutputCount = 0;
|
||||
ALOGW("[vts] pass and stop");
|
||||
}
|
||||
|
||||
void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) {
|
||||
mFilterMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
|
||||
EXPECT_TRUE(mFilterMQ);
|
||||
EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) ==
|
||||
android::OK);
|
||||
}
|
||||
|
||||
void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) {
|
||||
mFilterIdToGoldenOutput = goldenOutputFile;
|
||||
}
|
||||
|
||||
void* FilterCallback::__threadLoopFilter(void* threadArgs) {
|
||||
FilterCallback* const self =
|
||||
static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
|
||||
self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
|
||||
android::Mutex::Autolock autoLock(mFilterOutputLock);
|
||||
// Read from mFilterMQ[event.filterId] per event and filter type
|
||||
|
||||
// Assemble to filterOutput[filterId]
|
||||
|
||||
// check if filterOutput[filterId] matches goldenOutput[filterId]
|
||||
|
||||
// If match, remove filterId entry from MQ map
|
||||
|
||||
// end thread
|
||||
}
|
||||
|
||||
bool FilterCallback::readFilterEventData() {
|
||||
bool result = false;
|
||||
DemuxFilterEvent filterEvent = mFilterEvent;
|
||||
ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
|
||||
// todo separate filter handlers
|
||||
for (int i = 0; i < filterEvent.events.size(); i++) {
|
||||
switch (mFilterEventType) {
|
||||
case FilterEventType::SECTION:
|
||||
mDataLength = filterEvent.events[i].section().dataLength;
|
||||
break;
|
||||
case FilterEventType::PES:
|
||||
mDataLength = filterEvent.events[i].pes().dataLength;
|
||||
break;
|
||||
case FilterEventType::MEDIA:
|
||||
return dumpAvData(filterEvent.events[i].media());
|
||||
case FilterEventType::RECORD:
|
||||
break;
|
||||
case FilterEventType::MMTPRECORD:
|
||||
break;
|
||||
case FilterEventType::DOWNLOAD:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
|
||||
// match";
|
||||
|
||||
mDataOutputBuffer.resize(mDataLength);
|
||||
result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength);
|
||||
EXPECT_TRUE(result) << "can't read from Filter MQ";
|
||||
|
||||
/*for (int i = 0; i < mDataLength; i++) {
|
||||
EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
|
||||
}*/
|
||||
}
|
||||
mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
|
||||
uint32_t length = event.dataLength;
|
||||
uint64_t dataId = event.avDataId;
|
||||
// read data from buffer pointed by a handle
|
||||
hidl_handle handle = event.avMemory;
|
||||
|
||||
int av_fd = handle.getNativeHandle()->data[0];
|
||||
uint8_t* buffer = static_cast<uint8_t*>(
|
||||
mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/));
|
||||
if (buffer == MAP_FAILED) {
|
||||
ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
|
||||
return false;
|
||||
}
|
||||
uint8_t output[length + 1];
|
||||
memcpy(output, buffer, length);
|
||||
// print buffer and check with golden output.
|
||||
EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS);
|
||||
return true;
|
||||
}
|
||||
/******************************** End FilterCallback **********************************/
|
||||
|
||||
/******************************** Start DvrCallback **********************************/
|
||||
void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf,
|
||||
|
@ -303,134 +190,9 @@ void DvrCallback::stopRecordThread() {
|
|||
}
|
||||
/********************************** End DvrCallback ************************************/
|
||||
|
||||
/*============================ Start Demux APIs Tests Implementation ============================*/
|
||||
AssertionResult TunerHidlTest::openDemux() {
|
||||
Result status;
|
||||
mService->openDemux([&](Result result, uint32_t demuxId, const sp<IDemux>& demux) {
|
||||
mDemux = demux;
|
||||
mDemuxId = demuxId;
|
||||
status = result;
|
||||
});
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::setDemuxFrontendDataSource(uint32_t frontendId) {
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
auto status = mDemux->setFrontendDataSource(frontendId);
|
||||
return AssertionResult(status.isOk());
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::closeDemux() {
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
auto status = mDemux->close();
|
||||
mDemux = nullptr;
|
||||
return AssertionResult(status.isOk());
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::openFilterInDemux(DemuxFilterType type) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
|
||||
// Create demux callback
|
||||
mFilterCallback = new FilterCallback();
|
||||
|
||||
// Add filter to the local demux
|
||||
mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback,
|
||||
[&](Result result, const sp<IFilter>& filter) {
|
||||
mFilter = filter;
|
||||
status = result;
|
||||
});
|
||||
|
||||
if (status == Result::SUCCESS) {
|
||||
mFilterCallback->setFilterEventType(getFilterEventType(type));
|
||||
}
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
/*============================ End Demux APIs Tests Implementation ============================*/
|
||||
|
||||
/*=========================== Start Filter APIs Tests Implementation ===========================*/
|
||||
AssertionResult TunerHidlTest::getNewlyOpenedFilterId(uint32_t& filterId) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mFilter) << "Test with openFilterInDemux first.";
|
||||
EXPECT_TRUE(mFilterCallback) << "Test with openFilterInDemux first.";
|
||||
|
||||
mFilter->getId([&](Result result, uint32_t filterId) {
|
||||
mFilterId = filterId;
|
||||
status = result;
|
||||
});
|
||||
|
||||
if (status == Result::SUCCESS) {
|
||||
mFilterCallback->setFilterId(mFilterId);
|
||||
mFilterCallback->setFilterInterface(mFilter);
|
||||
mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
|
||||
mFilters[mFilterId] = mFilter;
|
||||
mFilterCallbacks[mFilterId] = mFilterCallback;
|
||||
filterId = mFilterId;
|
||||
}
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::configFilter(DemuxFilterSettings setting, uint32_t filterId) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
status = mFilters[filterId]->configure(setting);
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::getFilterMQDescriptor(uint32_t filterId) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
|
||||
mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
|
||||
mFilterMQDescriptor = filterMQDesc;
|
||||
status = result;
|
||||
});
|
||||
|
||||
if (status == Result::SUCCESS) {
|
||||
mFilterCallbacks[filterId]->updateFilterMQ(mFilterMQDescriptor);
|
||||
}
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::startFilter(uint32_t filterId) {
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
Result status = mFilters[filterId]->start();
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::stopFilter(uint32_t filterId) {
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
Result status = mFilters[filterId]->stop();
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::closeFilter(uint32_t filterId) {
|
||||
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
|
||||
Result status = mFilters[filterId]->close();
|
||||
if (status == Result::SUCCESS) {
|
||||
for (int i = 0; i < mUsedFilterIds.size(); i++) {
|
||||
if (mUsedFilterIds[i] == filterId) {
|
||||
mUsedFilterIds.erase(mUsedFilterIds.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mFilterCallbacks.erase(filterId);
|
||||
mFilters.erase(filterId);
|
||||
}
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
/*=========================== End Filter APIs Tests Implementation ===========================*/
|
||||
|
||||
/*======================== Start Descrambler APIs Tests Implementation ========================*/
|
||||
AssertionResult TunerHidlTest::createDescrambler() {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
|
||||
mDescrambler = descrambler;
|
||||
status = result;
|
||||
|
@ -464,7 +226,6 @@ AssertionResult TunerHidlTest::closeDescrambler() {
|
|||
/*============================ Start Dvr APIs Tests Implementation ============================*/
|
||||
AssertionResult TunerHidlTest::openDvrInDemux(DvrType type) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
|
||||
// Create dvr callback
|
||||
mDvrCallback = new DvrCallback();
|
||||
|
@ -485,7 +246,6 @@ AssertionResult TunerHidlTest::configDvr(DvrSettings setting) {
|
|||
|
||||
AssertionResult TunerHidlTest::getDvrMQDescriptor() {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mDvr) << "Test with openDvr first.";
|
||||
|
||||
mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
|
||||
|
@ -499,12 +259,10 @@ AssertionResult TunerHidlTest::getDvrMQDescriptor() {
|
|||
|
||||
/*========================== Start Data Flow Tests Implementation ==========================*/
|
||||
AssertionResult TunerHidlTest::broadcastDataFlowTest(vector<string> /*goldenOutputFiles*/) {
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mFilterCallback) << "Test with getFilterMQDescriptor first.";
|
||||
|
||||
// Data Verify Module
|
||||
std::map<uint32_t, sp<FilterCallback>>::iterator it;
|
||||
for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
|
||||
std::map<uint32_t, sp<FilterCallback>> filterCallbacks = mFilterTests.getFilterCallbacks();
|
||||
for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
|
||||
it->second->testFilterDataOutput();
|
||||
}
|
||||
return success();
|
||||
|
@ -668,74 +426,26 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf,
|
|||
}
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(openDemux());
|
||||
ASSERT_TRUE(setDemuxFrontendDataSource(feId));
|
||||
ASSERT_TRUE(openFilterInDemux(filterConf.type));
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId));
|
||||
mFilterTests.setDemux(mDemux);
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type));
|
||||
uint32_t filterId;
|
||||
ASSERT_TRUE(getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(configFilter(filterConf.setting, filterId));
|
||||
ASSERT_TRUE(getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(startFilter(filterId));
|
||||
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterConf.setting, filterId));
|
||||
ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(mFilterTests.startFilter(filterId));
|
||||
// tune test
|
||||
ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf));
|
||||
// broadcast data flow test
|
||||
ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles));
|
||||
ASSERT_TRUE(mFrontendTests.stopTuneFrontend());
|
||||
ASSERT_TRUE(stopFilter(filterId));
|
||||
ASSERT_TRUE(closeFilter(filterId));
|
||||
ASSERT_TRUE(closeDemux());
|
||||
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
|
||||
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
|
||||
ASSERT_TRUE(mDemuxTests.closeDemux());
|
||||
ASSERT_TRUE(mFrontendTests.closeFrontend());
|
||||
}
|
||||
/*================================== End Test Module ==================================*/
|
||||
|
||||
/*=============================== Start Helper Functions ===============================*/
|
||||
FilterEventType TunerHidlTest::getFilterEventType(DemuxFilterType type) {
|
||||
FilterEventType eventType = FilterEventType::UNDEFINED;
|
||||
switch (type.mainType) {
|
||||
case DemuxFilterMainType::TS:
|
||||
switch (type.subType.tsFilterType()) {
|
||||
case DemuxTsFilterType::UNDEFINED:
|
||||
break;
|
||||
case DemuxTsFilterType::SECTION:
|
||||
eventType = FilterEventType::SECTION;
|
||||
break;
|
||||
case DemuxTsFilterType::PES:
|
||||
eventType = FilterEventType::PES;
|
||||
break;
|
||||
case DemuxTsFilterType::TS:
|
||||
break;
|
||||
case DemuxTsFilterType::AUDIO:
|
||||
case DemuxTsFilterType::VIDEO:
|
||||
eventType = FilterEventType::MEDIA;
|
||||
break;
|
||||
case DemuxTsFilterType::PCR:
|
||||
break;
|
||||
case DemuxTsFilterType::RECORD:
|
||||
eventType = FilterEventType::RECORD;
|
||||
break;
|
||||
case DemuxTsFilterType::TEMI:
|
||||
eventType = FilterEventType::TEMI;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case DemuxFilterMainType::MMTP:
|
||||
/*mmtpSettings*/
|
||||
break;
|
||||
case DemuxFilterMainType::IP:
|
||||
/*ipSettings*/
|
||||
break;
|
||||
case DemuxFilterMainType::TLV:
|
||||
/*tlvSettings*/
|
||||
break;
|
||||
case DemuxFilterMainType::ALP:
|
||||
/*alpSettings*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return eventType;
|
||||
}
|
||||
/*============================== End Helper Functions ==============================*/
|
||||
/***************************** End Test Implementation *****************************/
|
||||
|
||||
/******************************** Start Test Entry **********************************/
|
||||
|
@ -754,28 +464,39 @@ TEST_P(TunerFrontendHidlTest, BlindScanFrontend) {
|
|||
mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND);
|
||||
}
|
||||
|
||||
/*============================ Start Demux/Filter Tests ============================*/
|
||||
TEST_P(TunerHidlTest, StartFilterInDemux) {
|
||||
TEST_P(TunerDemuxHidlTest, openDemux) {
|
||||
description("Open and close a Demux.");
|
||||
uint32_t feId;
|
||||
mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
|
||||
ASSERT_TRUE(feId != INVALID_ID);
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId));
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
ASSERT_TRUE(mDemuxTests.closeDemux());
|
||||
}
|
||||
|
||||
TEST_P(TunerFilterHidlTest, StartFilterInDemux) {
|
||||
description("Open and start a filter in Demux.");
|
||||
uint32_t feId;
|
||||
mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
|
||||
ASSERT_TRUE(feId != INVALID_ID);
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(openDemux());
|
||||
ASSERT_TRUE(setDemuxFrontendDataSource(feId));
|
||||
ASSERT_TRUE(openFilterInDemux(filterArray[TS_VIDEO0].type));
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId));
|
||||
mFilterTests.setDemux(mDemux);
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterArray[TS_VIDEO0].type));
|
||||
uint32_t filterId;
|
||||
ASSERT_TRUE(getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(configFilter(filterArray[TS_VIDEO0].setting, filterId));
|
||||
ASSERT_TRUE(getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(startFilter(filterId));
|
||||
ASSERT_TRUE(stopFilter(filterId));
|
||||
ASSERT_TRUE(closeFilter(filterId));
|
||||
ASSERT_TRUE(closeDemux());
|
||||
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterArray[TS_VIDEO0].setting, filterId));
|
||||
ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(mFilterTests.startFilter(filterId));
|
||||
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
|
||||
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
|
||||
ASSERT_TRUE(mDemuxTests.closeDemux());
|
||||
ASSERT_TRUE(mFrontendTests.closeFrontend());
|
||||
}
|
||||
/*============================ End Demux/Filter Tests ============================*/
|
||||
|
||||
/*============================ Start Descrambler Tests ============================*/
|
||||
/*
|
||||
|
@ -911,4 +632,14 @@ INSTANTIATE_TEST_SUITE_P(
|
|||
PerInstance, TunerHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
|
||||
android::hardware::PrintInstanceNameToString);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PerInstance, TunerDemuxHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
|
||||
android::hardware::PrintInstanceNameToString);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PerInstance, TunerFilterHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
|
||||
android::hardware::PrintInstanceNameToString);
|
||||
} // namespace
|
||||
|
|
|
@ -14,70 +14,27 @@
|
|||
* 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 "DemuxTests.h"
|
||||
#include "FilterTests.h"
|
||||
#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;
|
||||
|
@ -93,68 +50,6 @@ static AssertionResult success() {
|
|||
|
||||
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 {
|
||||
|
@ -240,9 +135,6 @@ class DvrCallback : public IDvrCallback {
|
|||
|
||||
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);
|
||||
|
@ -256,12 +148,69 @@ class TunerFrontendHidlTest : public testing::TestWithParam<std::string> {
|
|||
static void description(const std::string& description) {
|
||||
RecordProperty("description", description);
|
||||
}
|
||||
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
};
|
||||
|
||||
class TunerDemuxHidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
mService = ITuner::getService(GetParam());
|
||||
ASSERT_NE(mService, nullptr);
|
||||
initFrontendConfig();
|
||||
initFrontendScanConfig();
|
||||
initFilterConfig();
|
||||
|
||||
mFrontendTests.setService(mService);
|
||||
mDemuxTests.setService(mService);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void description(const std::string& description) {
|
||||
RecordProperty("description", description);
|
||||
}
|
||||
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
sp<IDemux> mDemux;
|
||||
uint32_t mDemuxId;
|
||||
};
|
||||
|
||||
class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
mService = ITuner::getService(GetParam());
|
||||
ASSERT_NE(mService, nullptr);
|
||||
initFrontendConfig();
|
||||
initFrontendScanConfig();
|
||||
initFilterConfig();
|
||||
|
||||
mFrontendTests.setService(mService);
|
||||
mDemuxTests.setService(mService);
|
||||
mFilterTests.setService(mService);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void description(const std::string& description) {
|
||||
RecordProperty("description", description);
|
||||
}
|
||||
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
FilterTests mFilterTests;
|
||||
sp<IDemux> mDemux;
|
||||
uint32_t mDemuxId;
|
||||
};
|
||||
|
||||
class TunerHidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
FilterTests mFilterTests;
|
||||
|
||||
virtual void SetUp() override {
|
||||
mService = ITuner::getService(GetParam());
|
||||
|
@ -271,6 +220,8 @@ class TunerHidlTest : public testing::TestWithParam<std::string> {
|
|||
initFilterConfig();
|
||||
|
||||
mFrontendTests.setService(mService);
|
||||
mDemuxTests.setService(mService);
|
||||
mFilterTests.setService(mService);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -279,43 +230,21 @@ class TunerHidlTest : public testing::TestWithParam<std::string> {
|
|||
}
|
||||
|
||||
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<IDemux> mDemux;
|
||||
uint32_t mDemuxId;
|
||||
|
||||
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();
|
||||
|
||||
|
@ -327,7 +256,5 @@ class TunerHidlTest : public testing::TestWithParam<std::string> {
|
|||
AssertionResult broadcastDataFlowTest(vector<string> goldenOutputFiles);
|
||||
|
||||
void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf);
|
||||
|
||||
FilterEventType getFilterEventType(DemuxFilterType type);
|
||||
};
|
||||
} // namespace
|
Loading…
Reference in a new issue