diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp index 889e42ed06..080116c4a9 100644 --- a/tv/tuner/1.0/default/Demux.cpp +++ b/tv/tuner/1.0/default/Demux.cpp @@ -100,6 +100,8 @@ Return Demux::addFilter(DemuxFilterType type, uint32_t bufferSize, mFilterEventFlags.resize(filterId + 1); mFilterThreadRunning.resize(filterId + 1); mFilterThreads.resize(filterId + 1); + mFilterPids.resize(filterId + 1); + mFilterOutputs.resize(filterId + 1); } mUsedFilterIds.insert(filterId); @@ -142,10 +144,34 @@ Return Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb return Void(); } -Return Demux::configureFilter(uint32_t /* filterId */, - const DemuxFilterSettings& /* settings */) { +Return Demux::configureFilter(uint32_t filterId, const DemuxFilterSettings& settings) { ALOGV("%s", __FUNCTION__); + switch (mFilterEvents[filterId].filterType) { + case DemuxFilterType::SECTION: + mFilterPids[filterId] = settings.section().tpid; + break; + case DemuxFilterType::PES: + mFilterPids[filterId] = settings.pesData().tpid; + break; + case DemuxFilterType::TS: + mFilterPids[filterId] = settings.ts().tpid; + break; + case DemuxFilterType::AUDIO: + mFilterPids[filterId] = settings.audio().tpid; + break; + case DemuxFilterType::VIDEO: + mFilterPids[filterId] = settings.video().tpid; + break; + case DemuxFilterType::RECORD: + mFilterPids[filterId] = settings.record().tpid; + break; + case DemuxFilterType::PCR: + mFilterPids[filterId] = settings.pcr().tpid; + break; + default: + return Result::UNKNOWN_ERROR; + } return Result::SUCCESS; } @@ -158,36 +184,16 @@ Return Demux::startFilter(uint32_t filterId) { return Result::INVALID_ARGUMENT; } - switch (mFilterEvents[filterId].filterType) { - case DemuxFilterType::SECTION: - result = startFilterLoop(filterId); - break; - case DemuxFilterType::PES: - result = startPesFilterHandler(filterId); - break; - case DemuxFilterType::TS: - result = startTsFilterHandler(); - return Result::SUCCESS; - case DemuxFilterType::AUDIO: - case DemuxFilterType::VIDEO: - result = startMediaFilterHandler(filterId); - break; - case DemuxFilterType::RECORD: - result = startRecordFilterHandler(filterId); - break; - case DemuxFilterType::PCR: - result = startPcrFilterHandler(); - return Result::SUCCESS; - default: - return Result::UNKNOWN_ERROR; - } + result = startFilterLoop(filterId); return result; } -Return Demux::stopFilter(uint32_t /* filterId */) { +Return Demux::stopFilter(uint32_t filterId) { ALOGV("%s", __FUNCTION__); + mFilterThreadRunning[filterId] = false; + return Result::SUCCESS; } @@ -238,6 +244,8 @@ Return Demux::close() { mFilterMQs.clear(); mFilterEvents.clear(); mFilterEventFlags.clear(); + mFilterOutputs.clear(); + mFilterPids.clear(); mLastUsedFilterId = -1; return Result::SUCCESS; @@ -277,19 +285,21 @@ Return Demux::getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) { return Void(); } -Return Demux::configureOutput(const DemuxOutputSettings& /* settings */) { +Return Demux::configureOutput(const DemuxOutputSettings& settings) { + ALOGV("%s", __FUNCTION__); + + mOutputConfigured = true; + mOutputSettings = settings; + return Result::SUCCESS; +} + +Return Demux::attachOutputFilter(uint32_t /*filterId*/) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; } -Return Demux::attachOutputTsFilter(uint32_t /*filterId*/) { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Demux::detachOutputTsFilter(uint32_t /* filterId */) { +Return Demux::detachOutputFilter(uint32_t /* filterId */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; @@ -353,15 +363,26 @@ Return Demux::getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) { return Void(); } -Return Demux::configureInput(const DemuxInputSettings& /* settings */) { +Return Demux::configureInput(const DemuxInputSettings& settings) { ALOGV("%s", __FUNCTION__); + mInputConfigured = true; + mInputSettings = settings; + return Result::SUCCESS; } Return Demux::startInput() { ALOGV("%s", __FUNCTION__); + if (!mInputCallback) { + return Result::NOT_INITIALIZED; + } + + if (!mInputConfigured) { + return Result::INVALID_STATE; + } + pthread_create(&mInputThread, NULL, __threadLoopInput, this); pthread_setname_np(mInputThread, "demux_input_waiting_loop"); @@ -373,6 +394,8 @@ Return Demux::startInput() { Return Demux::stopInput() { ALOGV("%s", __FUNCTION__); + mInputThreadRunning = false; + return Result::SUCCESS; } @@ -403,36 +426,43 @@ Result Demux::startFilterLoop(uint32_t filterId) { return Result::SUCCESS; } -Result Demux::startSectionFilterHandler(uint32_t filterId, vector data) { - if (!writeSectionsAndCreateEvent(filterId, data)) { +Result Demux::startSectionFilterHandler(uint32_t filterId) { + if (mFilterOutputs[filterId].empty()) { + return Result::SUCCESS; + } + if (!writeSectionsAndCreateEvent(filterId, mFilterOutputs[filterId])) { ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId); return Result::UNKNOWN_ERROR; } + mFilterOutputs[filterId].clear(); + return Result::SUCCESS; } Result Demux::startPesFilterHandler(uint32_t filterId) { - // TODO generate multiple events in one event callback + std::lock_guard lock(mFilterEventLock); DemuxFilterPesEvent pesEvent; + if (mFilterOutputs[filterId].empty()) { + return Result::SUCCESS; + } + + // TODO extract PES from TS + if (!writeDataToFilterMQ(mFilterOutputs[filterId], filterId)) { + mFilterOutputs[filterId].clear(); + return Result::INVALID_STATE; + } pesEvent = { // temp dump meta data .streamId = 0, - .dataLength = 530, + .dataLength = static_cast(mFilterOutputs[filterId].size()), }; - mFilterEvents[filterId].events.resize(1); - mFilterEvents[filterId].events[0].pes(pesEvent); - /*pthread_create(&mThreadId, NULL, __threadLoop, this); - pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/ - if (!writeDataToFilterMQ(fakeDataInputBuffer, filterId)) { - return Result::INVALID_STATE; - } + int size = mFilterEvents[filterId].events.size(); + mFilterEvents[filterId].events.resize(size + 1); + mFilterEvents[filterId].events[size].pes(pesEvent); - if (mDemuxCallbacks[filterId] == nullptr) { - return Result::NOT_INITIALIZED; - } + mFilterOutputs[filterId].clear(); - mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]); return Result::SUCCESS; } @@ -499,18 +529,18 @@ bool Demux::createFilterMQ(uint32_t bufferSize, uint32_t filterId) { bool Demux::writeSectionsAndCreateEvent(uint32_t filterId, vector data) { // TODO check how many sections has been read std::lock_guard lock(mFilterEventLock); - int size = mFilterEvents[filterId].events.size(); - mFilterEvents[filterId].events.resize(size + 1); if (!writeDataToFilterMQ(data, filterId)) { return false; } + int size = mFilterEvents[filterId].events.size(); + mFilterEvents[filterId].events.resize(size + 1); DemuxFilterSectionEvent secEvent; secEvent = { // temp dump meta data .tableId = 0, .version = 1, .sectionNum = 1, - .dataLength = 530, + .dataLength = static_cast(data.size()), }; mFilterEvents[filterId].events[size].section(secEvent); return true; @@ -525,20 +555,32 @@ bool Demux::writeDataToFilterMQ(const std::vector& data, uint32_t filte } bool Demux::filterAndOutputData() { - ALOGD("[Demux] start to dispatch data to filters"); + Result result; + set::iterator it; + // Read input data from the input FMQ int size = mInputMQ->availableToRead(); + int inputPacketSize = mInputSettings.packetSize; vector dataOutputBuffer; - dataOutputBuffer.resize(size); - mInputMQ->read(dataOutputBuffer.data(), size); + dataOutputBuffer.resize(inputPacketSize); - Result result; - // Filter the data and feed the output to each filter - set::iterator it; + // Dispatch the packet to the PID matching filter output buffer + for (int i = 0; i < size / inputPacketSize; i++) { + mInputMQ->read(dataOutputBuffer.data(), inputPacketSize); + for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { + uint16_t pid = ((dataOutputBuffer[1] & 0x1f) << 8) | ((dataOutputBuffer[2] & 0xff)); + if (pid == mFilterPids[*it]) { + mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), dataOutputBuffer.begin(), + dataOutputBuffer.end()); + } + } + } + + // Handle the output data per filter type for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) { switch (mFilterEvents[*it].filterType) { case DemuxFilterType::SECTION: - result = startSectionFilterHandler(*it, dataOutputBuffer); + result = startSectionFilterHandler(*it); break; case DemuxFilterType::PES: result = startPesFilterHandler(*it); @@ -657,12 +699,42 @@ void Demux::inputThreadLoop() { ALOGD("[Demux] input data failed to be filtered. Ending thread"); break; } + + maySendInputStatusCallback(); } mInputThreadRunning = false; ALOGD("[Demux] input thread ended."); } +void Demux::maySendInputStatusCallback() { + std::lock_guard lock(mInputStatusLock); + int availableToRead = mInputMQ->availableToRead(); + int availableToWrite = mInputMQ->availableToWrite(); + + DemuxInputStatus newStatus = + checkStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold, + mInputSettings.lowThreshold); + if (mIntputStatus != newStatus) { + mInputCallback->onInputStatus(newStatus); + mIntputStatus = newStatus; + } +} + +DemuxInputStatus Demux::checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold) { + if (availableToWrite == 0) { + return DemuxInputStatus::SPACE_FULL; + } else if (availableToRead > highThreshold) { + return DemuxInputStatus::SPACE_ALMOST_FULL; + } else if (availableToRead < lowThreshold) { + return DemuxInputStatus::SPACE_ALMOST_EMPTY; + } else if (availableToRead == 0) { + return DemuxInputStatus::SPACE_EMPTY; + } + return mIntputStatus; +} + } // namespace implementation } // namespace V1_0 } // namespace tuner diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h index 2fdde8dcf8..eaf6ac3ed9 100644 --- a/tv/tuner/1.0/default/Demux.h +++ b/tv/tuner/1.0/default/Demux.h @@ -91,9 +91,9 @@ class Demux : public IDemux { virtual Return configureOutput(const DemuxOutputSettings& settings) override; - virtual Return attachOutputTsFilter(uint32_t filterId) override; + virtual Return attachOutputFilter(uint32_t filterId) override; - virtual Return detachOutputTsFilter(uint32_t filterId) override; + virtual Return detachOutputFilter(uint32_t filterId) override; virtual Return startOutput() override; @@ -115,7 +115,7 @@ class Demux : public IDemux { * They are also responsible to write the filtered output into the filter FMQ * and update the filterEvent bound with the same filterId. */ - Result startSectionFilterHandler(uint32_t filterId, vector data); + Result startSectionFilterHandler(uint32_t filterId); Result startPesFilterHandler(uint32_t filterId); Result startTsFilterHandler(); Result startMediaFilterHandler(uint32_t filterId); @@ -136,6 +136,9 @@ class Demux : public IDemux { bool writeDataToFilterMQ(const std::vector& data, uint32_t filterId); bool readDataFromMQ(); bool writeSectionsAndCreateEvent(uint32_t filterId, vector data); + void maySendInputStatusCallback(); + DemuxInputStatus checkStatusChange(uint32_t availableToWrite, uint32_t availableToRead, + uint32_t highThreshold, uint32_t lowThreshold); /** * A dispatcher to read and dispatch input data to all the started filters. * Each filter handler handles the data filtering/output writing/filterEvent updating. @@ -169,6 +172,8 @@ class Demux : public IDemux { * A list of created FilterMQ ptrs. * The array number is the filter ID. */ + vector mFilterPids; + vector> mFilterOutputs; vector> mFilterMQs; vector mFilterEventFlags; vector mFilterEvents; @@ -182,10 +187,18 @@ class Demux : public IDemux { vector> mDemuxCallbacks; sp mInputCallback; sp mOutputCallback; + bool mInputConfigured = false; + bool mOutputConfigured = false; + DemuxInputSettings mInputSettings; + DemuxOutputSettings mOutputSettings; + // Thread handlers pthread_t mInputThread; pthread_t mOutputThread; vector mFilterThreads; + + // FMQ status local records + DemuxInputStatus mIntputStatus; /** * If a specific filter's writing loop is still running */ @@ -198,7 +211,12 @@ class Demux : public IDemux { /** * Lock to protect writes to the filter event */ + // TODO make each filter separate event lock std::mutex mFilterEventLock; + /** + * Lock to protect writes to the input status + */ + std::mutex mInputStatusLock; /** * How many times a filter should write * TODO make this dynamic/random/can take as a parameter diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp index 0609d05121..6f87d1b8b3 100644 --- a/tv/tuner/1.0/default/Frontend.cpp +++ b/tv/tuner/1.0/default/Frontend.cpp @@ -105,13 +105,7 @@ Return Frontend::setLna(bool /* bEnable */) { return Result::SUCCESS; } -Return Frontend::setLnb(const sp& /* lnb */) { - ALOGV("%s", __FUNCTION__); - - return Result::SUCCESS; -} - -Return Frontend::sendDiseqcMessage(const hidl_vec& /* diseqcMessage */) { +Return Frontend::setLnb(uint32_t /* lnb */) { ALOGV("%s", __FUNCTION__); return Result::SUCCESS; diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h index fc586b5174..f881e8b641 100644 --- a/tv/tuner/1.0/default/Frontend.h +++ b/tv/tuner/1.0/default/Frontend.h @@ -56,11 +56,9 @@ class Frontend : public IFrontend { virtual Return getStatus(const hidl_vec& statusTypes, getStatus_cb _hidl_cb) override; - virtual Return sendDiseqcMessage(const hidl_vec& diseqcMessage) override; - virtual Return setLna(bool bEnable) override; - virtual Return setLnb(const sp& lnb) override; + virtual Return setLnb(uint32_t lnb) override; FrontendType getFrontendType(); diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp index b81bb1508b..1446f7f344 100644 --- a/tv/tuner/1.0/default/Lnb.cpp +++ b/tv/tuner/1.0/default/Lnb.cpp @@ -48,6 +48,12 @@ Return Lnb::setSatellitePosition(FrontendLnbPosition /* position */) { return Result::SUCCESS; } +Return Lnb::sendDiseqcMessage(const hidl_vec& /* diseqcMessage */) { + ALOGV("%s", __FUNCTION__); + + return Result::SUCCESS; +} + Return Lnb::close() { ALOGV("%s", __FUNCTION__); diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h index df7e0fe2b3..4c251f7591 100644 --- a/tv/tuner/1.0/default/Lnb.h +++ b/tv/tuner/1.0/default/Lnb.h @@ -38,12 +38,14 @@ class Lnb : public ILnb { public: Lnb(); - virtual Return setVoltage(FrontendLnbVoltage voltage); + virtual Return setVoltage(FrontendLnbVoltage voltage) override; virtual Return setTone(FrontendLnbTone tone) override; virtual Return setSatellitePosition(FrontendLnbPosition position) override; + virtual Return sendDiseqcMessage(const hidl_vec& diseqcMessage) override; + virtual Return close() override; private: diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp index 00831aea30..a4a8ca5043 100644 --- a/tv/tuner/1.0/default/Tuner.cpp +++ b/tv/tuner/1.0/default/Tuner.cpp @@ -87,6 +87,15 @@ Return Tuner::openDemux(openDemux_cb _hidl_cb) { return Void(); } +Return Tuner::getDemuxCaps(getDemuxCaps_cb _hidl_cb) { + ALOGV("%s", __FUNCTION__); + + DemuxCapabilities caps; + + _hidl_cb(Result::SUCCESS, caps); + return Void(); +} + Return Tuner::openDescrambler(openDescrambler_cb _hidl_cb) { ALOGV("%s", __FUNCTION__); diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h index 62227eefcd..c089864d32 100644 --- a/tv/tuner/1.0/default/Tuner.h +++ b/tv/tuner/1.0/default/Tuner.h @@ -39,6 +39,8 @@ class Tuner : public ITuner { virtual Return openDemux(openDemux_cb _hidl_cb) override; + virtual Return getDemuxCaps(getDemuxCaps_cb _hidl_cb) override; + virtual Return openDescrambler(openDescrambler_cb _hidl_cb) override; virtual Return getFrontendInfo(FrontendId frontendId,