Loading tv/tuner/1.0/default/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ cc_defaults { shared_libs: [ "android.hardware.tv.tuner@1.0", "android.hidl.memory@1.0", "libcutils", "libfmq", "libhidlbase", "libhidlmemory", "liblog", Loading tv/tuner/1.0/default/Demux.cpp +351 −1 Original line number Diff line number Diff line Loading @@ -26,12 +26,81 @@ 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__); Loading @@ -40,11 +109,292 @@ Return<Result> Demux::setFrontendDataSource(uint32_t 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 Loading tv/tuner/1.0/default/Demux.h +88 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_ #include <android/hardware/tv/tuner/1.0/IDemux.h> #include <fmq/MessageQueue.h> using namespace std; Loading @@ -28,9 +29,16 @@ namespace tuner { namespace V1_0 { 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::IDemuxCallback; using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; class Demux : public IDemux { public: Demux(uint32_t demuxId); Loading @@ -39,10 +47,90 @@ class Demux : public IDemux { 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: 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 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 Loading tv/tuner/1.0/default/Descrambler.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,24 @@ Return<Result> Descrambler::setDemuxSource(uint32_t demuxId) { 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() { ALOGV("%s", __FUNCTION__); mDemuxSet = false; Loading tv/tuner/1.0/default/Descrambler.h +6 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,12 @@ class Descrambler : public IDescrambler { 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; private: Loading Loading
tv/tuner/1.0/default/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ cc_defaults { shared_libs: [ "android.hardware.tv.tuner@1.0", "android.hidl.memory@1.0", "libcutils", "libfmq", "libhidlbase", "libhidlmemory", "liblog", Loading
tv/tuner/1.0/default/Demux.cpp +351 −1 Original line number Diff line number Diff line Loading @@ -26,12 +26,81 @@ 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__); Loading @@ -40,11 +109,292 @@ Return<Result> Demux::setFrontendDataSource(uint32_t 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 Loading
tv/tuner/1.0/default/Demux.h +88 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_ #include <android/hardware/tv/tuner/1.0/IDemux.h> #include <fmq/MessageQueue.h> using namespace std; Loading @@ -28,9 +29,16 @@ namespace tuner { namespace V1_0 { 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::IDemuxCallback; using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; class Demux : public IDemux { public: Demux(uint32_t demuxId); Loading @@ -39,10 +47,90 @@ class Demux : public IDemux { 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: 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 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 Loading
tv/tuner/1.0/default/Descrambler.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -44,6 +44,24 @@ Return<Result> Descrambler::setDemuxSource(uint32_t demuxId) { 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() { ALOGV("%s", __FUNCTION__); mDemuxSet = false; Loading
tv/tuner/1.0/default/Descrambler.h +6 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,12 @@ class Descrambler : public IDescrambler { 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; private: Loading