Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7b2330d authored by Amy's avatar Amy Committed by android-build-merger
Browse files

Tuner HAL Filter APIs default implementation

am: 481066c7

Change-Id: Ibbd540dbb5baee46360d3fe9469212cfd8f550ba
parents a843f717 481066c7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@ cc_defaults {
    shared_libs: [
        "android.hardware.tv.tuner@1.0",
        "android.hidl.memory@1.0",
        "libcutils",
        "libfmq",
        "libhidlbase",
        "libhidlmemory",
        "liblog",
+351 −1
Original line number Diff line number Diff line
@@ -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__);

@@ -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
+88 −0
Original line number Diff line number Diff line
@@ -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;

@@ -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);
@@ -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
+18 −0
Original line number Diff line number Diff line
@@ -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;
+6 −0
Original line number Diff line number Diff line
@@ -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: