Tuner HAL Filter APIs default implementation
Bug: 135709325 Test: manual Change-Id: If10acac560d3130105079121602be576eb0b225a
This commit is contained in:
parent
2dfa337903
commit
a609d5a0e2
5 changed files with 465 additions and 1 deletions
|
@ -16,6 +16,8 @@ cc_defaults {
|
||||||
shared_libs: [
|
shared_libs: [
|
||||||
"android.hardware.tv.tuner@1.0",
|
"android.hardware.tv.tuner@1.0",
|
||||||
"android.hidl.memory@1.0",
|
"android.hidl.memory@1.0",
|
||||||
|
"libcutils",
|
||||||
|
"libfmq",
|
||||||
"libhidlbase",
|
"libhidlbase",
|
||||||
"libhidlmemory",
|
"libhidlmemory",
|
||||||
"libhidltransport",
|
"libhidltransport",
|
||||||
|
|
|
@ -26,12 +26,81 @@ namespace tuner {
|
||||||
namespace V1_0 {
|
namespace V1_0 {
|
||||||
namespace implementation {
|
namespace implementation {
|
||||||
|
|
||||||
|
#define WAIT_TIMEOUT 3000000000
|
||||||
|
|
||||||
|
const std::vector<uint8_t> fakeDataInputBuffer{
|
||||||
|
0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
|
||||||
|
0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
|
||||||
|
0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
|
||||||
|
0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
|
||||||
|
0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
|
||||||
|
0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
|
||||||
|
0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
|
||||||
|
0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
|
||||||
|
0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
|
||||||
|
0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
|
||||||
|
0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
|
||||||
|
0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
|
||||||
|
0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
|
||||||
|
0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
|
||||||
|
0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
|
||||||
|
0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
|
||||||
|
0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
|
||||||
|
0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
|
||||||
|
0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
|
||||||
|
0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
|
||||||
|
0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
|
||||||
|
0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
|
||||||
|
0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
|
||||||
|
0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
|
||||||
|
0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
|
||||||
|
0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
|
||||||
|
0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
|
||||||
|
0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
|
||||||
|
0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
|
||||||
|
0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
|
||||||
|
0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
|
||||||
|
0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
|
||||||
|
0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
|
||||||
|
0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
|
||||||
|
0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
|
||||||
|
0x73, 0x63, 0x65, 0x6e, 0x65,
|
||||||
|
};
|
||||||
|
|
||||||
Demux::Demux(uint32_t demuxId) {
|
Demux::Demux(uint32_t demuxId) {
|
||||||
mDemuxId = demuxId;
|
mDemuxId = demuxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
Demux::~Demux() {}
|
Demux::~Demux() {}
|
||||||
|
|
||||||
|
bool Demux::createAndSaveMQ(uint32_t bufferSize, uint32_t filterId) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
// Create a synchronized FMQ that supports blocking read/write
|
||||||
|
std::unique_ptr<FilterMQ> tmpFilterMQ =
|
||||||
|
std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(bufferSize, true));
|
||||||
|
if (!tmpFilterMQ->isValid()) {
|
||||||
|
ALOGW("Failed to create FMQ of filter with id: %d", filterId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mFilterMQs.resize(filterId + 1);
|
||||||
|
mFilterMQs[filterId] = std::move(tmpFilterMQ);
|
||||||
|
|
||||||
|
EventFlag* mFilterEventFlag;
|
||||||
|
if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &mFilterEventFlag) !=
|
||||||
|
OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mFilterEventFlags.resize(filterId + 1);
|
||||||
|
mFilterEventFlags[filterId] = mFilterEventFlag;
|
||||||
|
mFilterWriteCount.resize(filterId + 1);
|
||||||
|
mFilterWriteCount[filterId] = 0;
|
||||||
|
mThreadRunning.resize(filterId + 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
|
Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
|
||||||
ALOGV("%s", __FUNCTION__);
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
@ -40,11 +109,292 @@ Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
|
||||||
return Result::SUCCESS;
|
return Result::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Return<void> Demux::addFilter(DemuxFilterType type, uint32_t bufferSize,
|
||||||
|
const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
uint32_t filterId = mLastUsedFilterId + 1;
|
||||||
|
mLastUsedFilterId += 1;
|
||||||
|
|
||||||
|
if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) {
|
||||||
|
ALOGW("callback can't be null");
|
||||||
|
_hidl_cb(Result::INVALID_ARGUMENT, filterId);
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
// Add callback
|
||||||
|
mDemuxCallbacks.resize(filterId + 1);
|
||||||
|
mDemuxCallbacks[filterId] = cb;
|
||||||
|
|
||||||
|
// Mapping from the filter ID to the filter type
|
||||||
|
mFilterTypes.resize(filterId + 1);
|
||||||
|
mFilterTypes[filterId] = type;
|
||||||
|
|
||||||
|
if (!createAndSaveMQ(bufferSize, filterId)) {
|
||||||
|
_hidl_cb(Result::UNKNOWN_ERROR, -1);
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
_hidl_cb(Result::SUCCESS, filterId);
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<void> Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
if (filterId < 0 || filterId > mLastUsedFilterId) {
|
||||||
|
ALOGW("No filter with id: %d exists", filterId);
|
||||||
|
_hidl_cb(Result::INVALID_ARGUMENT, FilterMQ::Descriptor());
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
_hidl_cb(Result::SUCCESS, *mFilterMQs[filterId]->getDesc());
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<Result> Demux::configureFilter(uint32_t /* filterId */,
|
||||||
|
const DemuxFilterSettings& /* settings */) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<Result> Demux::startFilter(uint32_t filterId) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
if (filterId < 0 || filterId > mLastUsedFilterId) {
|
||||||
|
ALOGW("No filter with id: %d exists", filterId);
|
||||||
|
return Result::INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
DemuxFilterType filterType = mFilterTypes[filterId];
|
||||||
|
Result result;
|
||||||
|
DemuxFilterEvent event{
|
||||||
|
.filterId = filterId,
|
||||||
|
.filterType = filterType,
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (filterType) {
|
||||||
|
case DemuxFilterType::SECTION:
|
||||||
|
result = startSectionFilterHandler(event);
|
||||||
|
break;
|
||||||
|
case DemuxFilterType::PES:
|
||||||
|
result = startPesFilterHandler(event);
|
||||||
|
break;
|
||||||
|
case DemuxFilterType::TS:
|
||||||
|
result = startTsFilterHandler();
|
||||||
|
return Result::SUCCESS;
|
||||||
|
case DemuxFilterType::AUDIO:
|
||||||
|
case DemuxFilterType::VIDEO:
|
||||||
|
result = startMediaFilterHandler(event);
|
||||||
|
break;
|
||||||
|
case DemuxFilterType::RECORD:
|
||||||
|
result = startRecordFilterHandler(event);
|
||||||
|
break;
|
||||||
|
case DemuxFilterType::PCR:
|
||||||
|
result = startPcrFilterHandler();
|
||||||
|
return Result::SUCCESS;
|
||||||
|
default:
|
||||||
|
return Result::UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<Result> Demux::stopFilter(uint32_t /* filterId */) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<Result> Demux::flushFilter(uint32_t /* filterId */) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<Result> Demux::removeFilter(uint32_t /* filterId */) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<void> Demux::getAvSyncHwId(uint32_t /* filterId */, getAvSyncHwId_cb _hidl_cb) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
AvSyncHwId avSyncHwId = 0;
|
||||||
|
|
||||||
|
_hidl_cb(Result::SUCCESS, avSyncHwId);
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<void> Demux::getAvSyncTime(AvSyncHwId /* avSyncHwId */, getAvSyncTime_cb _hidl_cb) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
uint64_t avSyncTime = 0;
|
||||||
|
|
||||||
|
_hidl_cb(Result::SUCCESS, avSyncTime);
|
||||||
|
return Void();
|
||||||
|
}
|
||||||
|
|
||||||
Return<Result> Demux::close() {
|
Return<Result> Demux::close() {
|
||||||
ALOGV("%s", __FUNCTION__);
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
return Result::SUCCESS;
|
return Result::SUCCESS;
|
||||||
;
|
}
|
||||||
|
|
||||||
|
bool Demux::writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum) {
|
||||||
|
event.events.resize(sectionNum);
|
||||||
|
for (int i = 0; i < sectionNum; i++) {
|
||||||
|
DemuxFilterSectionEvent secEvent;
|
||||||
|
secEvent = {
|
||||||
|
// temp dump meta data
|
||||||
|
.tableId = 0,
|
||||||
|
.version = 1,
|
||||||
|
.sectionNum = 1,
|
||||||
|
.dataLength = 530,
|
||||||
|
};
|
||||||
|
event.events[i].section(secEvent);
|
||||||
|
if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Demux::writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId) {
|
||||||
|
std::lock_guard<std::mutex> lock(mWriteLock);
|
||||||
|
if (mFilterMQs[filterId]->write(data.data(), data.size())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Demux::startSectionFilterHandler(DemuxFilterEvent event) {
|
||||||
|
struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs));
|
||||||
|
threadArgs->user = this;
|
||||||
|
threadArgs->event = &event;
|
||||||
|
|
||||||
|
pthread_create(&mThreadId, NULL, __threadLoop, (void*)threadArgs);
|
||||||
|
pthread_setname_np(mThreadId, "demux_filter_waiting_loop");
|
||||||
|
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Demux::startPesFilterHandler(DemuxFilterEvent& event) {
|
||||||
|
// TODO generate multiple events in one event callback
|
||||||
|
DemuxFilterPesEvent pesEvent;
|
||||||
|
pesEvent = {
|
||||||
|
// temp dump meta data
|
||||||
|
.streamId = 0,
|
||||||
|
.dataLength = 530,
|
||||||
|
};
|
||||||
|
event.events.resize(1);
|
||||||
|
event.events[0].pes(pesEvent);
|
||||||
|
/*pthread_create(&mThreadId, NULL, __threadLoop, this);
|
||||||
|
pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/
|
||||||
|
if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) {
|
||||||
|
return Result::INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mDemuxCallbacks[event.filterId] == nullptr) {
|
||||||
|
return Result::NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDemuxCallbacks[event.filterId]->onFilterEvent(event);
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Demux::startTsFilterHandler() {
|
||||||
|
// TODO handle starting TS filter
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Demux::startMediaFilterHandler(DemuxFilterEvent& event) {
|
||||||
|
DemuxFilterMediaEvent mediaEvent;
|
||||||
|
mediaEvent = {
|
||||||
|
// temp dump meta data
|
||||||
|
.pts = 0,
|
||||||
|
.dataLength = 530,
|
||||||
|
.secureMemory = nullptr,
|
||||||
|
};
|
||||||
|
event.events.resize(1);
|
||||||
|
event.events[0].media() = mediaEvent;
|
||||||
|
// TODO handle write FQM for media stream
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Demux::startRecordFilterHandler(DemuxFilterEvent& event) {
|
||||||
|
DemuxFilterRecordEvent recordEvent;
|
||||||
|
recordEvent = {
|
||||||
|
// temp dump meta data
|
||||||
|
.tpid = 0,
|
||||||
|
.packetNum = 0,
|
||||||
|
};
|
||||||
|
recordEvent.indexMask.tsIndexMask() = 0x01;
|
||||||
|
event.events.resize(1);
|
||||||
|
event.events[0].ts() = recordEvent;
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Demux::startPcrFilterHandler() {
|
||||||
|
// TODO handle starting PCR filter
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Demux::__threadLoop(void* threadArg) {
|
||||||
|
Demux* const self = static_cast<Demux*>(((struct ThreadArgs*)threadArg)->user);
|
||||||
|
self->filterThreadLoop(((struct ThreadArgs*)threadArg)->event);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Demux::filterThreadLoop(DemuxFilterEvent* event) {
|
||||||
|
uint32_t filterId = event->filterId;
|
||||||
|
ALOGD("[Demux] filter %d threadLoop start.", filterId);
|
||||||
|
mThreadRunning[filterId] = true;
|
||||||
|
|
||||||
|
while (mThreadRunning[filterId]) {
|
||||||
|
uint32_t efState = 0;
|
||||||
|
// We do not wait for the last round of writen data to be read to finish the thread
|
||||||
|
// because the VTS can verify the reading itself.
|
||||||
|
for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
|
||||||
|
DemuxFilterEvent filterEvent{
|
||||||
|
.filterId = filterId,
|
||||||
|
.filterType = event->filterType,
|
||||||
|
};
|
||||||
|
if (!writeSectionsAndCreateEvent(filterEvent, 2)) {
|
||||||
|
ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mFilterWriteCount[filterId]++;
|
||||||
|
if (mDemuxCallbacks[filterId] == nullptr) {
|
||||||
|
ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// After successfully write, send a callback and wait for the read to be done
|
||||||
|
mDemuxCallbacks[filterId]->onFilterEvent(filterEvent);
|
||||||
|
// We do not wait for the last read to be done
|
||||||
|
// VTS can verify the read result itself.
|
||||||
|
if (i == SECTION_WRITE_COUNT - 1) {
|
||||||
|
ALOGD("[Demux] filter %d writing done. Ending thread", filterId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (mThreadRunning[filterId]) {
|
||||||
|
status_t status = mFilterEventFlags[filterId]->wait(
|
||||||
|
static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
|
||||||
|
WAIT_TIMEOUT, true /* retry on spurious wake */);
|
||||||
|
if (status != OK) {
|
||||||
|
ALOGD("[Demux] wait for data consumed");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mFilterWriteCount[filterId] = 0;
|
||||||
|
mThreadRunning[filterId] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ALOGD("[Demux] filter thread ended.");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace implementation
|
} // namespace implementation
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#define ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_
|
#define ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_
|
||||||
|
|
||||||
#include <android/hardware/tv/tuner/1.0/IDemux.h>
|
#include <android/hardware/tv/tuner/1.0/IDemux.h>
|
||||||
|
#include <fmq/MessageQueue.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -28,9 +29,16 @@ namespace tuner {
|
||||||
namespace V1_0 {
|
namespace V1_0 {
|
||||||
namespace implementation {
|
namespace implementation {
|
||||||
|
|
||||||
|
using ::android::hardware::EventFlag;
|
||||||
|
using ::android::hardware::kSynchronizedReadWrite;
|
||||||
|
using ::android::hardware::MessageQueue;
|
||||||
|
using ::android::hardware::MQDescriptorSync;
|
||||||
using ::android::hardware::tv::tuner::V1_0::IDemux;
|
using ::android::hardware::tv::tuner::V1_0::IDemux;
|
||||||
|
using ::android::hardware::tv::tuner::V1_0::IDemuxCallback;
|
||||||
using ::android::hardware::tv::tuner::V1_0::Result;
|
using ::android::hardware::tv::tuner::V1_0::Result;
|
||||||
|
|
||||||
|
using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
|
||||||
|
|
||||||
class Demux : public IDemux {
|
class Demux : public IDemux {
|
||||||
public:
|
public:
|
||||||
Demux(uint32_t demuxId);
|
Demux(uint32_t demuxId);
|
||||||
|
@ -39,10 +47,90 @@ class Demux : public IDemux {
|
||||||
|
|
||||||
virtual Return<Result> close() override;
|
virtual Return<Result> close() override;
|
||||||
|
|
||||||
|
virtual Return<void> addFilter(DemuxFilterType type, uint32_t bufferSize,
|
||||||
|
const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) override;
|
||||||
|
|
||||||
|
virtual Return<void> getFilterQueueDesc(uint32_t filterId,
|
||||||
|
getFilterQueueDesc_cb _hidl_cb) override;
|
||||||
|
|
||||||
|
virtual Return<Result> configureFilter(uint32_t filterId,
|
||||||
|
const DemuxFilterSettings& settings) override;
|
||||||
|
|
||||||
|
virtual Return<Result> startFilter(uint32_t filterId) override;
|
||||||
|
|
||||||
|
virtual Return<Result> stopFilter(uint32_t filterId) override;
|
||||||
|
|
||||||
|
virtual Return<Result> flushFilter(uint32_t filterId) override;
|
||||||
|
|
||||||
|
virtual Return<Result> removeFilter(uint32_t filterId) override;
|
||||||
|
|
||||||
|
virtual Return<void> getAvSyncHwId(uint32_t filterId, getAvSyncHwId_cb _hidl_cb) override;
|
||||||
|
|
||||||
|
virtual Return<void> getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual ~Demux();
|
virtual ~Demux();
|
||||||
|
/**
|
||||||
|
* To create a FilterMQ with the the next available Filter ID.
|
||||||
|
* Creating Event Flag at the same time.
|
||||||
|
* Add the successfully created/saved FilterMQ into the local list.
|
||||||
|
*
|
||||||
|
* Return false is any of the above processes fails.
|
||||||
|
*/
|
||||||
|
bool createAndSaveMQ(uint32_t bufferSize, uint32_t filterId);
|
||||||
|
void deleteEventFlag();
|
||||||
|
bool writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId);
|
||||||
|
Result startSectionFilterHandler(DemuxFilterEvent event);
|
||||||
|
Result startPesFilterHandler(DemuxFilterEvent& event);
|
||||||
|
Result startTsFilterHandler();
|
||||||
|
Result startMediaFilterHandler(DemuxFilterEvent& event);
|
||||||
|
Result startRecordFilterHandler(DemuxFilterEvent& event);
|
||||||
|
Result startPcrFilterHandler();
|
||||||
|
bool writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum);
|
||||||
|
void filterThreadLoop(DemuxFilterEvent* event);
|
||||||
|
static void* __threadLoop(void* data);
|
||||||
|
|
||||||
uint32_t mDemuxId;
|
uint32_t mDemuxId;
|
||||||
uint32_t mSourceFrontendId;
|
uint32_t mSourceFrontendId;
|
||||||
|
/**
|
||||||
|
* Record the last used filer id. Initial value is -1.
|
||||||
|
* Filter Id starts with 0.
|
||||||
|
*/
|
||||||
|
uint32_t mLastUsedFilterId = -1;
|
||||||
|
/**
|
||||||
|
* A list of created FilterMQ ptrs.
|
||||||
|
* The array number is the filter ID.
|
||||||
|
*/
|
||||||
|
vector<unique_ptr<FilterMQ>> mFilterMQs;
|
||||||
|
vector<DemuxFilterType> mFilterTypes;
|
||||||
|
vector<EventFlag*> mFilterEventFlags;
|
||||||
|
/**
|
||||||
|
* Demux callbacks used on filter events or IO buffer status
|
||||||
|
*/
|
||||||
|
vector<sp<IDemuxCallback>> mDemuxCallbacks;
|
||||||
|
/**
|
||||||
|
* How many times a specific filter has written since started
|
||||||
|
*/
|
||||||
|
vector<uint16_t> mFilterWriteCount;
|
||||||
|
pthread_t mThreadId = 0;
|
||||||
|
/**
|
||||||
|
* If a specific filter's writing loop is still running
|
||||||
|
*/
|
||||||
|
vector<bool> mThreadRunning;
|
||||||
|
/**
|
||||||
|
* Lock to protect writes to the FMQs
|
||||||
|
*/
|
||||||
|
std::mutex mWriteLock;
|
||||||
|
/**
|
||||||
|
* How many times a filter should write
|
||||||
|
* TODO make this dynamic/random/can take as a parameter
|
||||||
|
*/
|
||||||
|
const uint16_t SECTION_WRITE_COUNT = 10;
|
||||||
|
// A struct that passes the arguments to a newly created filter thread
|
||||||
|
struct ThreadArgs {
|
||||||
|
Demux* user;
|
||||||
|
DemuxFilterEvent* event;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace implementation
|
} // namespace implementation
|
||||||
|
|
|
@ -44,6 +44,24 @@ Return<Result> Descrambler::setDemuxSource(uint32_t demuxId) {
|
||||||
return Result::SUCCESS;
|
return Result::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Return<Result> Descrambler::setKeyToken(const hidl_vec<uint8_t>& /* keyToken */) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<Result> Descrambler::addPid(uint16_t /* pid */) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Return<Result> Descrambler::removePid(uint16_t /* pid */) {
|
||||||
|
ALOGV("%s", __FUNCTION__);
|
||||||
|
|
||||||
|
return Result::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
Return<Result> Descrambler::close() {
|
Return<Result> Descrambler::close() {
|
||||||
ALOGV("%s", __FUNCTION__);
|
ALOGV("%s", __FUNCTION__);
|
||||||
mDemuxSet = false;
|
mDemuxSet = false;
|
||||||
|
|
|
@ -38,6 +38,12 @@ class Descrambler : public IDescrambler {
|
||||||
|
|
||||||
virtual Return<Result> setDemuxSource(uint32_t demuxId) override;
|
virtual Return<Result> setDemuxSource(uint32_t demuxId) override;
|
||||||
|
|
||||||
|
virtual Return<Result> setKeyToken(const hidl_vec<uint8_t>& keyToken) override;
|
||||||
|
|
||||||
|
virtual Return<Result> addPid(uint16_t pid) override;
|
||||||
|
|
||||||
|
virtual Return<Result> removePid(uint16_t pid) override;
|
||||||
|
|
||||||
virtual Return<Result> close() override;
|
virtual Return<Result> close() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue