blob: 4016c5a0e9477f712d3df588962163ef939091df [file] [log] [blame]
/*
* Copyright (C) 2019 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.
*/
#define LOG_TAG "android.hardware.tv.tuner@1.0-Demux"
#include "Demux.h"
#include <utils/Log.h>
namespace android {
namespace hardware {
namespace tv {
namespace tuner {
namespace V1_0 {
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) {
mDemuxId = demuxId;
}
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) {
ALOGV("%s", __FUNCTION__);
mSourceFrontendId = frontendId;
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() {
ALOGV("%s", __FUNCTION__);
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 V1_0
} // namespace tuner
} // namespace tv
} // namespace hardware
} // namespace android