blob: 09852966573bc66cea9b2eef5bed7a7889f59186 [file] [log] [blame]
/*
* Copyright 2021 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.
*/
#pragma once
#include <aidl/android/hardware/tv/tuner/BnFilter.h>
#include <aidl/android/hardware/tv/tuner/Constant.h>
#include <aidl/android/hardware/tv/tuner/DemuxFilterEvent.h>
#include <aidl/android/hardware/tv/tuner/DemuxFilterStatus.h>
#include <fmq/AidlMessageQueue.h>
#include <inttypes.h>
#include <ion/ion.h>
#include <math.h>
#include <sys/stat.h>
#include <atomic>
#include <condition_variable>
#include <set>
#include <thread>
#include "Demux.h"
#include "Dvr.h"
#include "Frontend.h"
using namespace std;
namespace aidl {
namespace android {
namespace hardware {
namespace tv {
namespace tuner {
using ::aidl::android::hardware::common::NativeHandle;
using ::aidl::android::hardware::common::fmq::MQDescriptor;
using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
using ::android::AidlMessageQueue;
using ::android::hardware::EventFlag;
using FilterMQ = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
const uint32_t BUFFER_SIZE = 0x800000; // 8 MB
class Demux;
class Dvr;
class FilterCallbackScheduler final {
public:
FilterCallbackScheduler(const std::shared_ptr<IFilterCallback>& cb);
~FilterCallbackScheduler();
void onFilterEvent(DemuxFilterEvent&& event);
void onFilterStatus(const DemuxFilterStatus& status);
void setTimeDelayHint(int timeDelay);
void setDataSizeDelayHint(int dataSizeDelay);
bool hasCallbackRegistered() const;
void flushEvents();
private:
void start();
void stop();
void threadLoop();
void threadLoopOnce();
// function needs to be called while holding mLock
bool isDataSizeDelayConditionMetLocked();
static int getDemuxFilterEventDataLength(const DemuxFilterEvent& event);
private:
std::shared_ptr<IFilterCallback> mCallback;
std::thread mCallbackThread;
std::atomic<bool> mIsRunning;
// mLock protects mCallbackBuffer, mIsConditionMet, mCv, mDataLength,
// mTimeDelayInMs, and mDataSizeDelayInBytes
std::mutex mLock;
std::vector<DemuxFilterEvent> mCallbackBuffer;
bool mIsConditionMet;
std::condition_variable mCv;
int mDataLength;
int mTimeDelayInMs;
int mDataSizeDelayInBytes;
};
class Filter : public BnFilter {
friend class FilterCallbackScheduler;
public:
Filter(DemuxFilterType type, int64_t filterId, uint32_t bufferSize,
const std::shared_ptr<IFilterCallback>& cb, std::shared_ptr<Demux> demux);
~Filter();
::ndk::ScopedAStatus getQueueDesc(
MQDescriptor<int8_t, SynchronizedReadWrite>* out_queue) override;
::ndk::ScopedAStatus close() override;
::ndk::ScopedAStatus configure(const DemuxFilterSettings& in_settings) override;
::ndk::ScopedAStatus configureAvStreamType(const AvStreamType& in_avStreamType) override;
::ndk::ScopedAStatus configureIpCid(int32_t in_ipCid) override;
::ndk::ScopedAStatus configureMonitorEvent(int32_t in_monitorEventTypes) override;
::ndk::ScopedAStatus start() override;
::ndk::ScopedAStatus stop() override;
::ndk::ScopedAStatus flush() override;
::ndk::ScopedAStatus getAvSharedHandle(NativeHandle* out_avMemory,
int64_t* _aidl_return) override;
::ndk::ScopedAStatus getId(int32_t* _aidl_return) override;
::ndk::ScopedAStatus getId64Bit(int64_t* _aidl_return) override;
::ndk::ScopedAStatus releaseAvHandle(const NativeHandle& in_avMemory,
int64_t in_avDataId) override;
::ndk::ScopedAStatus setDataSource(const std::shared_ptr<IFilter>& in_filter) override;
::ndk::ScopedAStatus setDelayHint(const FilterDelayHint& in_hint) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
/**
* To create a FilterMQ and its Event Flag.
*
* Return false is any of the above processes fails.
*/
bool createFilterMQ();
uint16_t getTpid();
void updateFilterOutput(vector<int8_t>& data);
void updateRecordOutput(vector<int8_t>& data);
void updatePts(uint64_t pts);
::ndk::ScopedAStatus startFilterHandler();
::ndk::ScopedAStatus startRecordFilterHandler();
void attachFilterToRecord(const std::shared_ptr<Dvr> dvr);
void detachFilterFromRecord();
void freeSharedAvHandle();
bool isMediaFilter() { return mIsMediaFilter; };
bool isPcrFilter() { return mIsPcrFilter; };
bool isRecordFilter() { return mIsRecordFilter; };
private:
// Demux service
std::shared_ptr<Demux> mDemux;
// Dvr reference once the filter is attached to any
std::shared_ptr<Dvr> mDvr = nullptr;
FilterCallbackScheduler mCallbackScheduler;
int64_t mFilterId;
int32_t mCid = static_cast<int32_t>(Constant::INVALID_IP_FILTER_CONTEXT_ID);
uint32_t mBufferSize;
DemuxFilterType mType;
bool mIsMediaFilter = false;
bool mIsPcrFilter = false;
bool mIsRecordFilter = false;
DemuxFilterSettings mFilterSettings;
uint16_t mTpid;
std::shared_ptr<IFilter> mDataSource;
bool mIsDataSourceDemux = true;
vector<int8_t> mFilterOutput;
vector<int8_t> mRecordFilterOutput;
int64_t mPts = 0;
unique_ptr<FilterMQ> mFilterMQ;
bool mIsUsingFMQ = false;
EventFlag* mFilterEventsFlag;
vector<DemuxFilterEvent> mFilterEvents;
// Thread handlers
std::thread mFilterThread;
// FMQ status local records
DemuxFilterStatus mFilterStatus;
/**
* If a specific filter's writing loop is still running
*/
std::atomic<bool> mFilterThreadRunning;
/**
* How many times a filter should write
* TODO make this dynamic/random/can take as a parameter
*/
const uint16_t SECTION_WRITE_COUNT = 10;
bool DEBUG_FILTER = false;
/**
* Filter handlers to handle the data filtering.
* They are also responsible to write the filtered output into the filter FMQ
* and update the filterEvent bound with the same filterId.
*/
::ndk::ScopedAStatus startSectionFilterHandler();
::ndk::ScopedAStatus startPesFilterHandler();
::ndk::ScopedAStatus startTsFilterHandler();
::ndk::ScopedAStatus startMediaFilterHandler();
::ndk::ScopedAStatus startPcrFilterHandler();
::ndk::ScopedAStatus startTemiFilterHandler();
::ndk::ScopedAStatus startFilterLoop();
void deleteEventFlag();
bool writeDataToFilterMQ(const std::vector<int8_t>& data);
bool readDataFromMQ();
bool writeSectionsAndCreateEvent(vector<int8_t>& data);
void maySendFilterStatusCallback();
DemuxFilterStatus checkFilterStatusChange(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.
*/
bool startFilterDispatcher();
static void* __threadLoopFilter(void* user);
void filterThreadLoop();
int createAvIonFd(int size);
uint8_t* getIonBuffer(int fd, int size);
native_handle_t* createNativeHandle(int fd);
::ndk::ScopedAStatus createMediaFilterEventWithIon(vector<int8_t>& output);
::ndk::ScopedAStatus createIndependentMediaEvents(vector<int8_t>& output);
::ndk::ScopedAStatus createShareMemMediaEvents(vector<int8_t>& output);
bool sameFile(int fd1, int fd2);
void createMediaEvent(vector<DemuxFilterEvent>&, bool isAudioPresentation);
void createTsRecordEvent(vector<DemuxFilterEvent>&);
void createMmtpRecordEvent(vector<DemuxFilterEvent>&);
void createSectionEvent(vector<DemuxFilterEvent>&);
void createPesEvent(vector<DemuxFilterEvent>&);
void createDownloadEvent(vector<DemuxFilterEvent>&);
void createIpPayloadEvent(vector<DemuxFilterEvent>&);
void createTemiEvent(vector<DemuxFilterEvent>&);
void createMonitorEvent(vector<DemuxFilterEvent>&);
void createRestartEvent(vector<DemuxFilterEvent>&);
/**
* Lock to protect writes to the FMQs
*/
std::mutex mWriteLock;
/**
* Lock to protect writes to the filter event
*/
// TODO make each filter separate event lock
std::mutex mFilterEventsLock;
/**
* Lock to protect writes to the input status
*/
std::mutex mFilterStatusLock;
std::mutex mFilterOutputLock;
std::mutex mRecordFilterOutputLock;
// handle single Section filter
uint32_t mSectionSizeLeft = 0;
vector<int8_t> mSectionOutput;
// temp handle single PES filter
// TODO handle mulptiple Pes filters
uint32_t mPesSizeLeft = 0;
vector<int8_t> mPesOutput;
// A map from data id to ion handle
std::map<uint64_t, int> mDataId2Avfd;
uint64_t mLastUsedDataId = 1;
int mAvBufferCopyCount = 0;
// Shared A/V memory handle
native_handle_t* mSharedAvMemHandle = nullptr;
bool mUsingSharedAvMem = false;
int64_t mSharedAvMemOffset = 0;
uint32_t mAudioStreamType;
uint32_t mVideoStreamType;
// Scrambling status to be monitored
uint32_t mStatuses = 0;
bool mConfigured = false;
int mStartId = 0;
uint8_t mScramblingStatusMonitored = 0;
uint8_t mIpCidMonitored = 0;
};
} // namespace tuner
} // namespace tv
} // namespace hardware
} // namespace android
} // namespace aidl