mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 15:58:43 +00:00
Merge "Make dvr tests a separate module" into rvc-dev am: d8040b86f7 am: 469196a204 am: 38f5760b30 am: f6d560ad52
Change-Id: Iaf7e76e422e9960e9ed934125594f8fc6df43856
This commit is contained in:
@@ -52,7 +52,7 @@ Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
|
||||
|
||||
mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
|
||||
|
||||
return startFrontendInputLoop();
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
|
||||
@@ -60,7 +60,6 @@ Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
|
||||
ALOGV("%s", __FUNCTION__);
|
||||
|
||||
uint32_t filterId;
|
||||
|
||||
if (!mUnusedFilterIds.empty()) {
|
||||
filterId = *mUnusedFilterIds.begin();
|
||||
|
||||
@@ -83,7 +82,6 @@ Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
|
||||
_hidl_cb(Result::UNKNOWN_ERROR, filter);
|
||||
return Void();
|
||||
}
|
||||
|
||||
mFilters[filterId] = filter;
|
||||
|
||||
_hidl_cb(Result::SUCCESS, filter);
|
||||
@@ -234,11 +232,9 @@ uint16_t Demux::getFilterTpid(uint32_t filterId) {
|
||||
return mFilters[filterId]->getTpid();
|
||||
}
|
||||
|
||||
Result Demux::startFrontendInputLoop() {
|
||||
void Demux::startFrontendInputLoop() {
|
||||
pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
|
||||
pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
|
||||
|
||||
return Result::SUCCESS;
|
||||
}
|
||||
|
||||
void* Demux::__threadLoopFrontend(void* user) {
|
||||
|
||||
@@ -89,6 +89,7 @@ class Demux : public IDemux {
|
||||
void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
|
||||
uint16_t getFilterTpid(uint32_t filterId);
|
||||
void setIsRecording(bool isRecording);
|
||||
void startFrontendInputLoop();
|
||||
|
||||
private:
|
||||
// Tuner service
|
||||
@@ -104,7 +105,6 @@ class Demux : public IDemux {
|
||||
uint32_t filterId;
|
||||
};
|
||||
|
||||
Result startFrontendInputLoop();
|
||||
static void* __threadLoopFrontend(void* user);
|
||||
void frontendInputThreadLoop();
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ Return<Result> Frontend::tune(const FrontendSettings& /* settings */) {
|
||||
return Result::INVALID_STATE;
|
||||
}
|
||||
|
||||
mTunerService->frontendStartTune(mId);
|
||||
mCallback->onEvent(FrontendEventType::LOCKED);
|
||||
mIsLocked = false;
|
||||
return Result::SUCCESS;
|
||||
|
||||
@@ -247,6 +247,15 @@ void Tuner::frontendStopTune(uint32_t frontendId) {
|
||||
}
|
||||
}
|
||||
|
||||
void Tuner::frontendStartTune(uint32_t frontendId) {
|
||||
map<uint32_t, uint32_t>::iterator it = mFrontendToDemux.find(frontendId);
|
||||
uint32_t demuxId;
|
||||
if (it != mFrontendToDemux.end()) {
|
||||
demuxId = it->second;
|
||||
mDemuxes[demuxId]->startFrontendInputLoop();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V1_0
|
||||
} // namespace tuner
|
||||
|
||||
@@ -63,6 +63,7 @@ class Tuner : public ITuner {
|
||||
|
||||
void setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId);
|
||||
|
||||
void frontendStartTune(uint32_t frontendId);
|
||||
void frontendStopTune(uint32_t frontendId);
|
||||
|
||||
private:
|
||||
|
||||
@@ -22,6 +22,7 @@ cc_test {
|
||||
"FrontendTests.cpp",
|
||||
"DemuxTests.cpp",
|
||||
"FilterTests.cpp",
|
||||
"DvrTests.cpp",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.tv.tuner@1.0",
|
||||
|
||||
@@ -38,8 +38,6 @@ using ::testing::AssertionResult;
|
||||
|
||||
class DemuxTests {
|
||||
public:
|
||||
sp<ITuner> mService;
|
||||
|
||||
void setService(sp<ITuner> tuner) { mService = tuner; }
|
||||
|
||||
AssertionResult openDemux(sp<IDemux>& demux, uint32_t& demuxId);
|
||||
@@ -51,5 +49,6 @@ class DemuxTests {
|
||||
|
||||
static AssertionResult success() { return ::testing::AssertionSuccess(); }
|
||||
|
||||
sp<ITuner> mService;
|
||||
sp<IDemux> mDemux;
|
||||
};
|
||||
|
||||
267
tv/tuner/1.0/vts/functional/DvrTests.cpp
Normal file
267
tv/tuner/1.0/vts/functional/DvrTests.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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 "DvrTests.h"
|
||||
|
||||
void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf,
|
||||
MQDesc& playbackMQDescriptor) {
|
||||
mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
|
||||
EXPECT_TRUE(mPlaybackMQ);
|
||||
struct PlaybackThreadArgs* threadArgs =
|
||||
(struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs));
|
||||
threadArgs->user = this;
|
||||
threadArgs->playbackConf = &playbackConf;
|
||||
threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ;
|
||||
|
||||
pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs);
|
||||
pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
|
||||
}
|
||||
|
||||
void DvrCallback::stopPlaybackThread() {
|
||||
mPlaybackThreadRunning = false;
|
||||
mKeepWritingPlaybackFMQ = false;
|
||||
|
||||
android::Mutex::Autolock autoLock(mPlaybackThreadLock);
|
||||
}
|
||||
|
||||
void* DvrCallback::__threadLoopPlayback(void* threadArgs) {
|
||||
DvrCallback* const self =
|
||||
static_cast<DvrCallback*>(((struct PlaybackThreadArgs*)threadArgs)->user);
|
||||
self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf,
|
||||
((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) {
|
||||
android::Mutex::Autolock autoLock(mPlaybackThreadLock);
|
||||
mPlaybackThreadRunning = true;
|
||||
|
||||
// Create the EventFlag that is used to signal the HAL impl that data have been
|
||||
// written into the Playback FMQ
|
||||
EventFlag* playbackMQEventFlag;
|
||||
EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
|
||||
android::OK);
|
||||
|
||||
// open the stream and get its length
|
||||
std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary);
|
||||
int writeSize = playbackConf->setting.packetSize * 6;
|
||||
char* buffer = new char[writeSize];
|
||||
ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str());
|
||||
if (!inputData.is_open()) {
|
||||
mPlaybackThreadRunning = false;
|
||||
ALOGW("[vts] Error %s", strerror(errno));
|
||||
}
|
||||
|
||||
while (mPlaybackThreadRunning) {
|
||||
// move the stream pointer for packet size * 6 every read until the end
|
||||
while (*keepWritingPlaybackFMQ) {
|
||||
inputData.read(buffer, writeSize);
|
||||
if (!inputData) {
|
||||
int leftSize = inputData.gcount();
|
||||
if (leftSize == 0) {
|
||||
mPlaybackThreadRunning = false;
|
||||
break;
|
||||
}
|
||||
inputData.clear();
|
||||
inputData.read(buffer, leftSize);
|
||||
// Write the left over of the input data and quit the thread
|
||||
if (leftSize > 0) {
|
||||
EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize));
|
||||
playbackMQEventFlag->wake(
|
||||
static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
|
||||
}
|
||||
mPlaybackThreadRunning = false;
|
||||
break;
|
||||
}
|
||||
// Write input FMQ and notify the Tuner Implementation
|
||||
EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize));
|
||||
playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
|
||||
inputData.seekg(writeSize, inputData.cur);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
ALOGW("[vts] Playback thread end.");
|
||||
|
||||
delete[] buffer;
|
||||
inputData.close();
|
||||
}
|
||||
|
||||
void DvrCallback::testRecordOutput() {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
while (mDataOutputBuffer.empty()) {
|
||||
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
|
||||
EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
|
||||
return;
|
||||
}
|
||||
}
|
||||
stopRecordThread();
|
||||
ALOGW("[vts] record pass and stop");
|
||||
}
|
||||
|
||||
void DvrCallback::startRecordOutputThread(RecordSettings recordSettings,
|
||||
MQDesc& recordMQDescriptor) {
|
||||
mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
|
||||
EXPECT_TRUE(mRecordMQ);
|
||||
struct RecordThreadArgs* threadArgs =
|
||||
(struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
|
||||
threadArgs->user = this;
|
||||
threadArgs->recordSettings = &recordSettings;
|
||||
threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
|
||||
|
||||
pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
|
||||
pthread_setname_np(mRecordThread, "test_record_input_loop");
|
||||
}
|
||||
|
||||
void* DvrCallback::__threadLoopRecord(void* threadArgs) {
|
||||
DvrCallback* const self =
|
||||
static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
|
||||
self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSettings,
|
||||
((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DvrCallback::recordThreadLoop(RecordSettings* /*recordSettings*/, bool* keepReadingRecordFMQ) {
|
||||
ALOGD("[vts] DvrCallback record threadLoop start.");
|
||||
android::Mutex::Autolock autoLock(mRecordThreadLock);
|
||||
mRecordThreadRunning = true;
|
||||
|
||||
// Create the EventFlag that is used to signal the HAL impl that data have been
|
||||
// read from the Record FMQ
|
||||
EventFlag* recordMQEventFlag;
|
||||
EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
|
||||
android::OK);
|
||||
|
||||
while (mRecordThreadRunning) {
|
||||
while (*keepReadingRecordFMQ) {
|
||||
uint32_t efState = 0;
|
||||
android::status_t status = recordMQEventFlag->wait(
|
||||
static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
|
||||
true /* retry on spurious wake */);
|
||||
if (status != android::OK) {
|
||||
ALOGD("[vts] wait for data ready on the record FMQ");
|
||||
continue;
|
||||
}
|
||||
// Our current implementation filter the data and write it into the filter FMQ
|
||||
// immediately after the DATA_READY from the VTS/framework
|
||||
if (!readRecordFMQ()) {
|
||||
ALOGD("[vts] record data failed to be filtered. Ending thread");
|
||||
mRecordThreadRunning = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mRecordThreadRunning = false;
|
||||
ALOGD("[vts] record thread ended.");
|
||||
}
|
||||
|
||||
bool DvrCallback::readRecordFMQ() {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
bool result = false;
|
||||
mDataOutputBuffer.clear();
|
||||
mDataOutputBuffer.resize(mRecordMQ->availableToRead());
|
||||
result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
|
||||
EXPECT_TRUE(result) << "can't read from Record MQ";
|
||||
mMsgCondition.signal();
|
||||
return result;
|
||||
}
|
||||
|
||||
void DvrCallback::stopRecordThread() {
|
||||
mKeepReadingRecordFMQ = false;
|
||||
mRecordThreadRunning = false;
|
||||
android::Mutex::Autolock autoLock(mRecordThreadLock);
|
||||
}
|
||||
|
||||
AssertionResult DvrTests::openDvrInDemux(DvrType type) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
|
||||
// Create dvr callback
|
||||
mDvrCallback = new DvrCallback();
|
||||
|
||||
mDemux->openDvr(type, FMQ_SIZE_1M, mDvrCallback, [&](Result result, const sp<IDvr>& dvr) {
|
||||
mDvr = dvr;
|
||||
status = result;
|
||||
});
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult DvrTests::configDvr(DvrSettings setting) {
|
||||
Result status = mDvr->configure(setting);
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult DvrTests::getDvrMQDescriptor() {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mDvr) << "Test with openDvr first.";
|
||||
|
||||
mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
|
||||
mDvrMQDescriptor = dvrMQDesc;
|
||||
status = result;
|
||||
});
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult DvrTests::attachFilterToDvr(sp<IFilter> filter) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mDvr) << "Test with openDvr first.";
|
||||
|
||||
status = mDvr->attachFilter(filter);
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult DvrTests::detachFilterToDvr(sp<IFilter> filter) {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mDvr) << "Test with openDvr first.";
|
||||
|
||||
status = mDvr->detachFilter(filter);
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult DvrTests::startDvr() {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mDvr) << "Test with openDvr first.";
|
||||
|
||||
status = mDvr->start();
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult DvrTests::stopDvr() {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDemux) << "Test with openDemux first.";
|
||||
EXPECT_TRUE(mDvr) << "Test with openDvr first.";
|
||||
|
||||
status = mDvr->stop();
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
void DvrTests::closeDvr() {
|
||||
ASSERT_TRUE(mDemux);
|
||||
ASSERT_TRUE(mDvr);
|
||||
ASSERT_TRUE(mDvr->close() == Result::SUCCESS);
|
||||
}
|
||||
187
tv/tuner/1.0/vts/functional/DvrTests.h
Normal file
187
tv/tuner/1.0/vts/functional/DvrTests.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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/IDvr.h>
|
||||
#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
|
||||
#include <android/hardware/tv/tuner/1.0/ITuner.h>
|
||||
#include <android/hardware/tv/tuner/1.0/types.h>
|
||||
#include <fmq/MessageQueue.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <utils/Condition.h>
|
||||
#include <utils/Mutex.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include "FilterTests.h"
|
||||
|
||||
using android::Condition;
|
||||
using android::Mutex;
|
||||
using android::sp;
|
||||
using android::hardware::EventFlag;
|
||||
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::DemuxFilterStatus;
|
||||
using android::hardware::tv::tuner::V1_0::DvrSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DvrType;
|
||||
using android::hardware::tv::tuner::V1_0::IDvr;
|
||||
using android::hardware::tv::tuner::V1_0::IDvrCallback;
|
||||
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;
|
||||
|
||||
#define WAIT_TIMEOUT 3000000000
|
||||
|
||||
struct PlaybackConf {
|
||||
string inputDataFile;
|
||||
PlaybackSettings setting;
|
||||
};
|
||||
|
||||
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 stopPlaybackThread();
|
||||
void testRecordOutput();
|
||||
void stopRecordThread();
|
||||
|
||||
void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
|
||||
void startRecordOutputThread(RecordSettings recordSettings, 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* recordSettings;
|
||||
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 DvrTests {
|
||||
public:
|
||||
void setService(sp<ITuner> tuner) { mService = tuner; }
|
||||
void setDemux(sp<IDemux> demux) { mDemux = demux; }
|
||||
|
||||
void startPlaybackInputThread(string dataInputFile, PlaybackSettings settings) {
|
||||
PlaybackConf conf{
|
||||
.inputDataFile = dataInputFile,
|
||||
.setting = settings,
|
||||
};
|
||||
mDvrCallback->startPlaybackInputThread(conf, mDvrMQDescriptor);
|
||||
};
|
||||
|
||||
void startRecordOutputThread(RecordSettings settings) {
|
||||
mDvrCallback->startRecordOutputThread(settings, mDvrMQDescriptor);
|
||||
};
|
||||
|
||||
void stopPlaybackThread() { mDvrCallback->stopPlaybackThread(); }
|
||||
void testRecordOutput() { mDvrCallback->testRecordOutput(); }
|
||||
void stopRecordThread() { mDvrCallback->stopPlaybackThread(); }
|
||||
|
||||
AssertionResult openDvrInDemux(DvrType type);
|
||||
AssertionResult configDvr(DvrSettings setting);
|
||||
AssertionResult getDvrMQDescriptor();
|
||||
AssertionResult attachFilterToDvr(sp<IFilter> filter);
|
||||
AssertionResult detachFilterToDvr(sp<IFilter> filter);
|
||||
AssertionResult stopDvr();
|
||||
AssertionResult startDvr();
|
||||
void closeDvr();
|
||||
|
||||
protected:
|
||||
static AssertionResult failure() { return ::testing::AssertionFailure(); }
|
||||
|
||||
static AssertionResult success() { return ::testing::AssertionSuccess(); }
|
||||
|
||||
sp<ITuner> mService;
|
||||
sp<IDvr> mDvr;
|
||||
sp<IDemux> mDemux;
|
||||
sp<DvrCallback> mDvrCallback;
|
||||
MQDesc mDvrMQDescriptor;
|
||||
|
||||
pthread_t mPlaybackshread;
|
||||
bool mPlaybackThreadRunning;
|
||||
};
|
||||
@@ -149,6 +149,7 @@ class FilterTests {
|
||||
public:
|
||||
void setService(sp<ITuner> tuner) { mService = tuner; }
|
||||
void setDemux(sp<IDemux> demux) { mDemux = demux; }
|
||||
sp<IFilter> getFilterById(uint32_t filterId) { return mFilters[filterId]; }
|
||||
|
||||
std::map<uint32_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
|
||||
|
||||
|
||||
@@ -17,181 +17,8 @@
|
||||
#include "VtsHalTvTunerV1_0TargetTest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/******************************** Start DvrCallback **********************************/
|
||||
void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf,
|
||||
MQDesc& playbackMQDescriptor) {
|
||||
mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
|
||||
EXPECT_TRUE(mPlaybackMQ);
|
||||
struct PlaybackThreadArgs* threadArgs =
|
||||
(struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs));
|
||||
threadArgs->user = this;
|
||||
threadArgs->playbackConf = &playbackConf;
|
||||
threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ;
|
||||
|
||||
pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs);
|
||||
pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
|
||||
}
|
||||
|
||||
void DvrCallback::stopPlaybackThread() {
|
||||
mPlaybackThreadRunning = false;
|
||||
mKeepWritingPlaybackFMQ = false;
|
||||
|
||||
android::Mutex::Autolock autoLock(mPlaybackThreadLock);
|
||||
}
|
||||
|
||||
void* DvrCallback::__threadLoopPlayback(void* threadArgs) {
|
||||
DvrCallback* const self =
|
||||
static_cast<DvrCallback*>(((struct PlaybackThreadArgs*)threadArgs)->user);
|
||||
self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf,
|
||||
((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) {
|
||||
android::Mutex::Autolock autoLock(mPlaybackThreadLock);
|
||||
mPlaybackThreadRunning = true;
|
||||
|
||||
// Create the EventFlag that is used to signal the HAL impl that data have been
|
||||
// written into the Playback FMQ
|
||||
EventFlag* playbackMQEventFlag;
|
||||
EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
|
||||
android::OK);
|
||||
|
||||
// open the stream and get its length
|
||||
std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary);
|
||||
int writeSize = playbackConf->setting.packetSize * 6;
|
||||
char* buffer = new char[writeSize];
|
||||
ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str());
|
||||
if (!inputData.is_open()) {
|
||||
mPlaybackThreadRunning = false;
|
||||
ALOGW("[vts] Error %s", strerror(errno));
|
||||
}
|
||||
|
||||
while (mPlaybackThreadRunning) {
|
||||
// move the stream pointer for packet size * 6 every read until the end
|
||||
while (*keepWritingPlaybackFMQ) {
|
||||
inputData.read(buffer, writeSize);
|
||||
if (!inputData) {
|
||||
int leftSize = inputData.gcount();
|
||||
if (leftSize == 0) {
|
||||
mPlaybackThreadRunning = false;
|
||||
break;
|
||||
}
|
||||
inputData.clear();
|
||||
inputData.read(buffer, leftSize);
|
||||
// Write the left over of the input data and quit the thread
|
||||
if (leftSize > 0) {
|
||||
EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize));
|
||||
playbackMQEventFlag->wake(
|
||||
static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
|
||||
}
|
||||
mPlaybackThreadRunning = false;
|
||||
break;
|
||||
}
|
||||
// Write input FMQ and notify the Tuner Implementation
|
||||
EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize));
|
||||
playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
|
||||
inputData.seekg(writeSize, inputData.cur);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
ALOGW("[vts] Playback thread end.");
|
||||
|
||||
delete[] buffer;
|
||||
inputData.close();
|
||||
}
|
||||
|
||||
void DvrCallback::testRecordOutput() {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
while (mDataOutputBuffer.empty()) {
|
||||
if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
|
||||
EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
|
||||
return;
|
||||
}
|
||||
}
|
||||
stopRecordThread();
|
||||
ALOGW("[vts] record pass and stop");
|
||||
}
|
||||
|
||||
void DvrCallback::startRecordOutputThread(RecordSettings recordSetting,
|
||||
MQDesc& recordMQDescriptor) {
|
||||
mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
|
||||
EXPECT_TRUE(mRecordMQ);
|
||||
struct RecordThreadArgs* threadArgs =
|
||||
(struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
|
||||
threadArgs->user = this;
|
||||
threadArgs->recordSetting = &recordSetting;
|
||||
threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
|
||||
|
||||
pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
|
||||
pthread_setname_np(mRecordThread, "test_record_input_loop");
|
||||
}
|
||||
|
||||
void* DvrCallback::__threadLoopRecord(void* threadArgs) {
|
||||
DvrCallback* const self =
|
||||
static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
|
||||
self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSetting,
|
||||
((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DvrCallback::recordThreadLoop(RecordSettings* /*recordSetting*/, bool* keepReadingRecordFMQ) {
|
||||
ALOGD("[vts] DvrCallback record threadLoop start.");
|
||||
android::Mutex::Autolock autoLock(mRecordThreadLock);
|
||||
mRecordThreadRunning = true;
|
||||
|
||||
// Create the EventFlag that is used to signal the HAL impl that data have been
|
||||
// read from the Record FMQ
|
||||
EventFlag* recordMQEventFlag;
|
||||
EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
|
||||
android::OK);
|
||||
|
||||
while (mRecordThreadRunning) {
|
||||
while (*keepReadingRecordFMQ) {
|
||||
uint32_t efState = 0;
|
||||
android::status_t status = recordMQEventFlag->wait(
|
||||
static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
|
||||
true /* retry on spurious wake */);
|
||||
if (status != android::OK) {
|
||||
ALOGD("[vts] wait for data ready on the record FMQ");
|
||||
continue;
|
||||
}
|
||||
// Our current implementation filter the data and write it into the filter FMQ
|
||||
// immediately after the DATA_READY from the VTS/framework
|
||||
if (!readRecordFMQ()) {
|
||||
ALOGD("[vts] record data failed to be filtered. Ending thread");
|
||||
mRecordThreadRunning = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mRecordThreadRunning = false;
|
||||
ALOGD("[vts] record thread ended.");
|
||||
}
|
||||
|
||||
bool DvrCallback::readRecordFMQ() {
|
||||
android::Mutex::Autolock autoLock(mMsgLock);
|
||||
bool result = false;
|
||||
mDataOutputBuffer.clear();
|
||||
mDataOutputBuffer.resize(mRecordMQ->availableToRead());
|
||||
result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
|
||||
EXPECT_TRUE(result) << "can't read from Record MQ";
|
||||
mMsgCondition.signal();
|
||||
return result;
|
||||
}
|
||||
|
||||
void DvrCallback::stopRecordThread() {
|
||||
mKeepReadingRecordFMQ = false;
|
||||
mRecordThreadRunning = false;
|
||||
android::Mutex::Autolock autoLock(mRecordThreadLock);
|
||||
}
|
||||
/********************************** End DvrCallback ************************************/
|
||||
|
||||
/*======================== Start Descrambler APIs Tests Implementation ========================*/
|
||||
AssertionResult TunerHidlTest::createDescrambler() {
|
||||
AssertionResult TunerHidlTest::createDescrambler(uint32_t demuxId) {
|
||||
Result status;
|
||||
mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
|
||||
mDescrambler = descrambler;
|
||||
@@ -201,21 +28,19 @@ AssertionResult TunerHidlTest::createDescrambler() {
|
||||
return failure();
|
||||
}
|
||||
|
||||
status = mDescrambler->setDemuxSource(mDemuxId);
|
||||
status = mDescrambler->setDemuxSource(demuxId);
|
||||
if (status != Result::SUCCESS) {
|
||||
return failure();
|
||||
}
|
||||
|
||||
// Test if demux source can be set more than once.
|
||||
status = mDescrambler->setDemuxSource(mDemuxId);
|
||||
status = mDescrambler->setDemuxSource(demuxId);
|
||||
return AssertionResult(status == Result::INVALID_STATE);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::closeDescrambler() {
|
||||
Result status;
|
||||
if (!mDescrambler && createDescrambler() == failure()) {
|
||||
return failure();
|
||||
}
|
||||
EXPECT_TRUE(mDescrambler);
|
||||
|
||||
status = mDescrambler->close();
|
||||
mDescrambler = nullptr;
|
||||
@@ -223,40 +48,6 @@ AssertionResult TunerHidlTest::closeDescrambler() {
|
||||
}
|
||||
/*========================= End Descrambler APIs Tests Implementation =========================*/
|
||||
|
||||
/*============================ Start Dvr APIs Tests Implementation ============================*/
|
||||
AssertionResult TunerHidlTest::openDvrInDemux(DvrType type) {
|
||||
Result status;
|
||||
|
||||
// Create dvr callback
|
||||
mDvrCallback = new DvrCallback();
|
||||
|
||||
mDemux->openDvr(type, FMQ_SIZE_1M, mDvrCallback, [&](Result result, const sp<IDvr>& dvr) {
|
||||
mDvr = dvr;
|
||||
status = result;
|
||||
});
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::configDvr(DvrSettings setting) {
|
||||
Result status = mDvr->configure(setting);
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
|
||||
AssertionResult TunerHidlTest::getDvrMQDescriptor() {
|
||||
Result status;
|
||||
EXPECT_TRUE(mDvr) << "Test with openDvr first.";
|
||||
|
||||
mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
|
||||
mDvrMQDescriptor = dvrMQDesc;
|
||||
status = result;
|
||||
});
|
||||
|
||||
return AssertionResult(status == Result::SUCCESS);
|
||||
}
|
||||
/*============================ End Dvr APIs Tests Implementation ============================*/
|
||||
|
||||
/*========================== Start Data Flow Tests Implementation ==========================*/
|
||||
AssertionResult TunerHidlTest::broadcastDataFlowTest(vector<string> /*goldenOutputFiles*/) {
|
||||
// Data Verify Module
|
||||
@@ -417,6 +208,10 @@ AssertionResult TunerHidlTest::recordDataFlowTest(vector<FilterConf> filterConf,
|
||||
void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf,
|
||||
FrontendConfig frontendConf) {
|
||||
uint32_t feId;
|
||||
uint32_t demuxId;
|
||||
sp<IDemux> demux;
|
||||
uint32_t filterId;
|
||||
|
||||
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
|
||||
if (feId == INVALID_ID) {
|
||||
// TODO broadcast test on Cuttlefish needs licensed ts input,
|
||||
@@ -426,13 +221,12 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf,
|
||||
}
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(mDemux, mDemuxId));
|
||||
mFilterTests.setDemux(mDemux);
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
mFilterTests.setDemux(demux);
|
||||
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type));
|
||||
uint32_t filterId;
|
||||
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterConf.setting, filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
|
||||
ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(mFilterTests.startFilter(filterId));
|
||||
// tune test
|
||||
@@ -445,6 +239,67 @@ void TunerHidlTest::broadcastSingleFilterTest(FilterConfig filterConf,
|
||||
ASSERT_TRUE(mDemuxTests.closeDemux());
|
||||
ASSERT_TRUE(mFrontendTests.closeFrontend());
|
||||
}
|
||||
|
||||
void TunerDvrHidlTest::attachSingleFilterToDvrTest(FilterConfig filterConf,
|
||||
FrontendConfig frontendConf, DvrConfig dvrConf) {
|
||||
description("Open and configure a Dvr in Demux.");
|
||||
uint32_t feId;
|
||||
uint32_t demuxId;
|
||||
sp<IDemux> demux;
|
||||
uint32_t filterId;
|
||||
sp<IFilter> filter;
|
||||
|
||||
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
|
||||
ASSERT_TRUE(feId != INVALID_ID);
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
mFilterTests.setDemux(demux);
|
||||
mDvrTests.setDemux(demux);
|
||||
ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type));
|
||||
ASSERT_TRUE(mDvrTests.configDvr(dvrConf.settings));
|
||||
ASSERT_TRUE(mDvrTests.getDvrMQDescriptor());
|
||||
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type));
|
||||
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
|
||||
ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
|
||||
ASSERT_TRUE(mFilterTests.startFilter(filterId));
|
||||
filter = mFilterTests.getFilterById(filterId);
|
||||
ASSERT_TRUE(filter != nullptr);
|
||||
ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter));
|
||||
ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter));
|
||||
ASSERT_TRUE(mFilterTests.stopFilter(filterId));
|
||||
ASSERT_TRUE(mFilterTests.closeFilter(filterId));
|
||||
mDvrTests.closeDvr();
|
||||
ASSERT_TRUE(mDemuxTests.closeDemux());
|
||||
ASSERT_TRUE(mFrontendTests.closeFrontend());
|
||||
}
|
||||
|
||||
void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
|
||||
FrontendConfig frontendConf) {
|
||||
uint32_t feId;
|
||||
uint32_t demuxId;
|
||||
sp<IDemux> demux;
|
||||
uint32_t filterId;
|
||||
|
||||
mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
|
||||
ASSERT_TRUE(feId != INVALID_ID);
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
mFilterTests.setDemux(demux);
|
||||
ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type));
|
||||
ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
|
||||
ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, 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 Test Module ==================================*/
|
||||
/***************************** End Test Implementation *****************************/
|
||||
|
||||
@@ -467,50 +322,56 @@ TEST_P(TunerFrontendHidlTest, BlindScanFrontend) {
|
||||
TEST_P(TunerDemuxHidlTest, openDemux) {
|
||||
description("Open and close a Demux.");
|
||||
uint32_t feId;
|
||||
uint32_t demuxId;
|
||||
sp<IDemux> demux;
|
||||
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.openDemux(demux, demuxId));
|
||||
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(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(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());
|
||||
// TODO use paramterized tests
|
||||
configSingleFilterInDemuxTest(filterArray[TS_VIDEO0], frontendArray[DVBT]);
|
||||
}
|
||||
|
||||
TEST_P(TunerDvrHidlTest, AttachFiltersToRecordTest) {
|
||||
description("Attach a single filter to the record dvr test.");
|
||||
// TODO use paramterized tests
|
||||
attachSingleFilterToDvrTest(filterArray[TS_VIDEO0], frontendArray[DVBT], dvrArray[DVR_RECORD0]);
|
||||
}
|
||||
|
||||
TEST_P(TunerDvrHidlTest, AttachFiltersToPlaybackTest) {
|
||||
description("Attach a single filter to the playback dvr test.");
|
||||
// TODO use paramterized tests
|
||||
attachSingleFilterToDvrTest(filterArray[TS_VIDEO0], frontendArray[DVBT],
|
||||
dvrArray[DVR_PLAYBACK0]);
|
||||
}
|
||||
|
||||
/*============================ Start Descrambler Tests ============================*/
|
||||
/*
|
||||
* TODO: re-enable the tests after finalizing the test refactoring.
|
||||
*/
|
||||
/*TEST_P(TunerHidlTest, CreateDescrambler) {
|
||||
TEST_P(TunerHidlTest, CreateDescrambler) {
|
||||
description("Create Descrambler");
|
||||
ASSERT_TRUE(createDescrambler());
|
||||
uint32_t feId;
|
||||
uint32_t demuxId;
|
||||
sp<IDemux> demux;
|
||||
mFrontendTests.getFrontendIdByType(frontendArray[DVBT].type, feId);
|
||||
ASSERT_TRUE(feId != INVALID_ID);
|
||||
ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
|
||||
ASSERT_TRUE(mFrontendTests.setFrontendCallback());
|
||||
ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
|
||||
ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
|
||||
ASSERT_TRUE(createDescrambler(demuxId));
|
||||
ASSERT_TRUE(mDemuxTests.closeDemux());
|
||||
ASSERT_TRUE(closeDescrambler());
|
||||
}
|
||||
|
||||
TEST_P(TunerHidlTest, CloseDescrambler) {
|
||||
description("Close Descrambler");
|
||||
ASSERT_TRUE(closeDescrambler());
|
||||
}*/
|
||||
/*============================== End Descrambler Tests ==============================*/
|
||||
|
||||
/*============================== Start Data Flow Tests ==============================*/
|
||||
@@ -642,4 +503,9 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
PerInstance, TunerFilterHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
|
||||
android::hardware::PrintInstanceNameToString);
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
PerInstance, TunerDvrHidlTest,
|
||||
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
|
||||
android::hardware::PrintInstanceNameToString);
|
||||
} // namespace
|
||||
|
||||
@@ -15,30 +15,13 @@
|
||||
*/
|
||||
|
||||
#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
|
||||
#include <android/hardware/tv/tuner/1.0/IDvr.h>
|
||||
#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "DemuxTests.h"
|
||||
#include "FilterTests.h"
|
||||
#include "DvrTests.h"
|
||||
#include "FrontendTests.h"
|
||||
|
||||
using android::hardware::tv::tuner::V1_0::DataFormat;
|
||||
using android::hardware::tv::tuner::V1_0::DvrSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DvrType;
|
||||
using android::hardware::tv::tuner::V1_0::IDescrambler;
|
||||
using android::hardware::tv::tuner::V1_0::IDvr;
|
||||
using android::hardware::tv::tuner::V1_0::IDvrCallback;
|
||||
using android::hardware::tv::tuner::V1_0::PlaybackSettings;
|
||||
using android::hardware::tv::tuner::V1_0::PlaybackStatus;
|
||||
using android::hardware::tv::tuner::V1_0::RecordSettings;
|
||||
using android::hardware::tv::tuner::V1_0::RecordStatus;
|
||||
|
||||
struct PlaybackConf {
|
||||
string inputDataFile;
|
||||
PlaybackSettings setting;
|
||||
};
|
||||
|
||||
static AssertionResult failure() {
|
||||
return ::testing::AssertionFailure();
|
||||
@@ -50,89 +33,6 @@ static AssertionResult success() {
|
||||
|
||||
namespace {
|
||||
|
||||
class DvrCallback : public IDvrCallback {
|
||||
public:
|
||||
virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
|
||||
ALOGW("[vts] record status %hhu", status);
|
||||
switch (status) {
|
||||
case DemuxFilterStatus::DATA_READY:
|
||||
break;
|
||||
case DemuxFilterStatus::LOW_WATER:
|
||||
break;
|
||||
case DemuxFilterStatus::HIGH_WATER:
|
||||
case DemuxFilterStatus::OVERFLOW:
|
||||
ALOGW("[vts] record overflow. Flushing");
|
||||
break;
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
|
||||
// android::Mutex::Autolock autoLock(mMsgLock);
|
||||
ALOGW("[vts] playback status %d", status);
|
||||
switch (status) {
|
||||
case PlaybackStatus::SPACE_EMPTY:
|
||||
case PlaybackStatus::SPACE_ALMOST_EMPTY:
|
||||
ALOGW("[vts] keep playback inputing %d", status);
|
||||
mKeepWritingPlaybackFMQ = true;
|
||||
break;
|
||||
case PlaybackStatus::SPACE_ALMOST_FULL:
|
||||
case PlaybackStatus::SPACE_FULL:
|
||||
ALOGW("[vts] stop playback inputing %d", status);
|
||||
mKeepWritingPlaybackFMQ = false;
|
||||
break;
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
void testFilterDataOutput();
|
||||
void stopPlaybackThread();
|
||||
void testRecordOutput();
|
||||
void stopRecordThread();
|
||||
|
||||
void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
|
||||
void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor);
|
||||
static void* __threadLoopPlayback(void* threadArgs);
|
||||
static void* __threadLoopRecord(void* threadArgs);
|
||||
void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
|
||||
void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
|
||||
|
||||
bool readRecordFMQ();
|
||||
|
||||
private:
|
||||
struct PlaybackThreadArgs {
|
||||
DvrCallback* user;
|
||||
PlaybackConf* playbackConf;
|
||||
bool* keepWritingPlaybackFMQ;
|
||||
};
|
||||
struct RecordThreadArgs {
|
||||
DvrCallback* user;
|
||||
RecordSettings* recordSetting;
|
||||
bool* keepReadingRecordFMQ;
|
||||
};
|
||||
uint16_t mDataLength = 0;
|
||||
std::vector<uint8_t> mDataOutputBuffer;
|
||||
|
||||
std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterMQ;
|
||||
std::unique_ptr<FilterMQ> mPlaybackMQ;
|
||||
std::unique_ptr<FilterMQ> mRecordMQ;
|
||||
std::map<uint32_t, EventFlag*> mFilterMQEventFlag;
|
||||
|
||||
android::Mutex mMsgLock;
|
||||
android::Mutex mPlaybackThreadLock;
|
||||
android::Mutex mRecordThreadLock;
|
||||
android::Condition mMsgCondition;
|
||||
|
||||
bool mKeepWritingPlaybackFMQ = true;
|
||||
bool mKeepReadingRecordFMQ = true;
|
||||
bool mPlaybackThreadRunning;
|
||||
bool mRecordThreadRunning;
|
||||
pthread_t mPlaybackThread;
|
||||
pthread_t mRecordThread;
|
||||
|
||||
int mPidFilterOutputCount = 0;
|
||||
};
|
||||
|
||||
class TunerFrontendHidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
@@ -174,8 +74,6 @@ class TunerDemuxHidlTest : public testing::TestWithParam<std::string> {
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
sp<IDemux> mDemux;
|
||||
uint32_t mDemuxId;
|
||||
};
|
||||
|
||||
class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
|
||||
@@ -197,21 +95,47 @@ class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
|
||||
RecordProperty("description", description);
|
||||
}
|
||||
|
||||
void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf);
|
||||
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
FilterTests mFilterTests;
|
||||
sp<IDemux> mDemux;
|
||||
uint32_t mDemuxId;
|
||||
};
|
||||
|
||||
class TunerDvrHidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
mService = ITuner::getService(GetParam());
|
||||
ASSERT_NE(mService, nullptr);
|
||||
initFrontendConfig();
|
||||
initFrontendScanConfig();
|
||||
initFilterConfig();
|
||||
initDvrConfig();
|
||||
|
||||
mFrontendTests.setService(mService);
|
||||
mDemuxTests.setService(mService);
|
||||
mFilterTests.setService(mService);
|
||||
mDvrTests.setService(mService);
|
||||
}
|
||||
|
||||
protected:
|
||||
static void description(const std::string& description) {
|
||||
RecordProperty("description", description);
|
||||
}
|
||||
|
||||
void attachSingleFilterToDvrTest(FilterConfig filterConf, FrontendConfig frontendConf,
|
||||
DvrConfig dvrConf);
|
||||
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
FilterTests mFilterTests;
|
||||
DvrTests mDvrTests;
|
||||
};
|
||||
|
||||
class TunerHidlTest : public testing::TestWithParam<std::string> {
|
||||
public:
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
FilterTests mFilterTests;
|
||||
|
||||
virtual void SetUp() override {
|
||||
mService = ITuner::getService(GetParam());
|
||||
ASSERT_NE(mService, nullptr);
|
||||
@@ -229,23 +153,14 @@ class TunerHidlTest : public testing::TestWithParam<std::string> {
|
||||
RecordProperty("description", description);
|
||||
}
|
||||
|
||||
sp<ITuner> mService;
|
||||
FrontendTests mFrontendTests;
|
||||
DemuxTests mDemuxTests;
|
||||
FilterTests mFilterTests;
|
||||
|
||||
sp<IDescrambler> mDescrambler;
|
||||
sp<IDvr> mDvr;
|
||||
sp<IDemux> mDemux;
|
||||
uint32_t mDemuxId;
|
||||
|
||||
sp<DvrCallback> mDvrCallback;
|
||||
MQDesc mDvrMQDescriptor;
|
||||
MQDesc mRecordMQDescriptor;
|
||||
|
||||
pthread_t mPlaybackshread;
|
||||
bool mPlaybackThreadRunning;
|
||||
|
||||
AssertionResult openDvrInDemux(DvrType type);
|
||||
AssertionResult configDvr(DvrSettings setting);
|
||||
AssertionResult getDvrMQDescriptor();
|
||||
|
||||
AssertionResult createDescrambler();
|
||||
AssertionResult createDescrambler(uint32_t demuxId);
|
||||
AssertionResult closeDescrambler();
|
||||
|
||||
AssertionResult playbackDataFlowTest(vector<FilterConfig> filterConf, PlaybackConf playbackConf,
|
||||
@@ -257,4 +172,4 @@ class TunerHidlTest : public testing::TestWithParam<std::string> {
|
||||
|
||||
void broadcastSingleFilterTest(FilterConfig filterConf, FrontendConfig frontendConf);
|
||||
};
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
@@ -21,12 +21,15 @@
|
||||
#include <hidl/Status.h>
|
||||
#include <hidlmemory/FrameworkUtils.h>
|
||||
|
||||
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::DemuxFilterSettings;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxFilterType;
|
||||
using android::hardware::tv::tuner::V1_0::DemuxTpid;
|
||||
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::FrontendDvbtBandwidth;
|
||||
using android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate;
|
||||
using android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation;
|
||||
@@ -37,6 +40,8 @@ using android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
|
||||
using android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode;
|
||||
using android::hardware::tv::tuner::V1_0::FrontendSettings;
|
||||
using android::hardware::tv::tuner::V1_0::FrontendType;
|
||||
using android::hardware::tv::tuner::V1_0::PlaybackSettings;
|
||||
using android::hardware::tv::tuner::V1_0::RecordSettings;
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -62,9 +67,15 @@ typedef enum {
|
||||
SCAN_MAX,
|
||||
} FrontendScan;
|
||||
|
||||
typedef enum {
|
||||
DVR_RECORD0,
|
||||
DVR_PLAYBACK0,
|
||||
DVR_MAX,
|
||||
} Dvr;
|
||||
|
||||
struct FilterConfig {
|
||||
DemuxFilterType type;
|
||||
DemuxFilterSettings setting;
|
||||
DemuxFilterSettings settings;
|
||||
};
|
||||
|
||||
struct FrontendConfig {
|
||||
@@ -80,10 +91,16 @@ struct ChannelConfig {
|
||||
DemuxTpid audioPid;
|
||||
};
|
||||
|
||||
struct DvrConfig {
|
||||
DvrType type;
|
||||
DvrSettings settings;
|
||||
};
|
||||
|
||||
static FrontendConfig frontendArray[FILTER_MAX];
|
||||
static FrontendConfig frontendScanArray[SCAN_MAX];
|
||||
static ChannelConfig channelArray[FRONTEND_MAX];
|
||||
static FilterConfig filterArray[FILTER_MAX];
|
||||
static DvrConfig dvrArray[DVR_MAX];
|
||||
static vector<string> goldenOutputFiles;
|
||||
|
||||
/** Configuration array for the frontend tune test */
|
||||
@@ -126,40 +143,62 @@ inline void initFilterConfig() {
|
||||
// TS VIDEO filter setting for default implementation testing
|
||||
filterArray[TS_VIDEO0].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_VIDEO0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
|
||||
filterArray[TS_VIDEO0].setting.ts().tpid = 119;
|
||||
filterArray[TS_VIDEO0].setting.ts().filterSettings.av({.isPassthrough = false});
|
||||
filterArray[TS_VIDEO0].settings.ts().tpid = 119;
|
||||
filterArray[TS_VIDEO0].settings.ts().filterSettings.av({.isPassthrough = false});
|
||||
filterArray[TS_VIDEO1].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_VIDEO1].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
|
||||
filterArray[TS_VIDEO1].setting.ts().tpid = 81;
|
||||
filterArray[TS_VIDEO1].setting.ts().filterSettings.av({.isPassthrough = false});
|
||||
filterArray[TS_VIDEO1].settings.ts().tpid = 81;
|
||||
filterArray[TS_VIDEO1].settings.ts().filterSettings.av({.isPassthrough = false});
|
||||
// TS AUDIO filter setting
|
||||
filterArray[TS_AUDIO0].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_AUDIO0].type.subType.tsFilterType(DemuxTsFilterType::AUDIO);
|
||||
filterArray[TS_AUDIO0].setting.ts().tpid = 84;
|
||||
filterArray[TS_AUDIO0].setting.ts().filterSettings.av({.isPassthrough = false});
|
||||
filterArray[TS_AUDIO0].settings.ts().tpid = 84;
|
||||
filterArray[TS_AUDIO0].settings.ts().filterSettings.av({.isPassthrough = false});
|
||||
// TS PES filter setting
|
||||
filterArray[TS_PES0].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_PES0].type.subType.tsFilterType(DemuxTsFilterType::PES);
|
||||
filterArray[TS_PES0].setting.ts().tpid = 256;
|
||||
filterArray[TS_PES0].setting.ts().filterSettings.pesData({
|
||||
filterArray[TS_PES0].settings.ts().tpid = 256;
|
||||
filterArray[TS_PES0].settings.ts().filterSettings.pesData({
|
||||
.isRaw = false,
|
||||
.streamId = 0xbd,
|
||||
});
|
||||
// TS PCR filter setting
|
||||
filterArray[TS_PCR0].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_PCR0].type.subType.tsFilterType(DemuxTsFilterType::PCR);
|
||||
filterArray[TS_PCR0].setting.ts().tpid = 81;
|
||||
filterArray[TS_PCR0].setting.ts().filterSettings.noinit();
|
||||
filterArray[TS_PCR0].settings.ts().tpid = 81;
|
||||
filterArray[TS_PCR0].settings.ts().filterSettings.noinit();
|
||||
// TS filter setting
|
||||
filterArray[TS_TS0].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_TS0].type.subType.tsFilterType(DemuxTsFilterType::TS);
|
||||
filterArray[TS_TS0].setting.ts().tpid = 48;
|
||||
filterArray[TS_TS0].setting.ts().filterSettings.noinit();
|
||||
filterArray[TS_TS0].settings.ts().tpid = 48;
|
||||
filterArray[TS_TS0].settings.ts().filterSettings.noinit();
|
||||
// TS SECTION filter setting
|
||||
filterArray[TS_SECTION0].type.mainType = DemuxFilterMainType::TS;
|
||||
filterArray[TS_SECTION0].type.subType.tsFilterType(DemuxTsFilterType::SECTION);
|
||||
filterArray[TS_SECTION0].setting.ts().tpid = 48;
|
||||
filterArray[TS_SECTION0].setting.ts().filterSettings.section({
|
||||
filterArray[TS_SECTION0].settings.ts().tpid = 48;
|
||||
filterArray[TS_SECTION0].settings.ts().filterSettings.section({
|
||||
.isRaw = false,
|
||||
});
|
||||
};
|
||||
|
||||
/** Configuration array for the dvr test */
|
||||
inline void initDvrConfig() {
|
||||
RecordSettings recordSettings{
|
||||
.statusMask = 0xf,
|
||||
.lowThreshold = 0x1000,
|
||||
.highThreshold = 0x07fff,
|
||||
.dataFormat = DataFormat::TS,
|
||||
.packetSize = 188,
|
||||
};
|
||||
dvrArray[DVR_RECORD0].type = DvrType::RECORD;
|
||||
dvrArray[DVR_RECORD0].settings.record(recordSettings);
|
||||
PlaybackSettings playbackSettings{
|
||||
.statusMask = 0xf,
|
||||
.lowThreshold = 0x1000,
|
||||
.highThreshold = 0x07fff,
|
||||
.dataFormat = DataFormat::TS,
|
||||
.packetSize = 188,
|
||||
};
|
||||
dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK;
|
||||
dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
|
||||
};
|
||||
Reference in New Issue
Block a user