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

Commit f5722376 authored by Patrick Rohr's avatar Patrick Rohr Committed by Android (Google) Code Review
Browse files

Merge "Add VTS for FilterDelayHint"

parents faa07fef 1586d21f
Loading
Loading
Loading
Loading
+14 −12
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "FilterTests.h"

#include <inttypes.h>
#include <algorithm>

#include <aidl/android/hardware/tv/tuner/DemuxFilterMonitorEventType.h>
#include <aidlcommonsupport/NativeHandle.h>
@@ -31,23 +32,24 @@ using ::aidl::android::hardware::common::NativeHandle;
    mPidFilterOutputCount++;
    mMsgCondition.signal();

    // HACK: we need to cast the const away as DemuxFilterEvent contains a ScopedFileDescriptor
    // that cannot be copied.
    for (auto&& e : const_cast<std::vector<DemuxFilterEvent>&>(events)) {
        auto it = mFilterEventPromises.find(e.getTag());
        if (it != mFilterEventPromises.cend()) {
            it->second.set_value(std::move(e));
            mFilterEventPromises.erase(it);
        }
    for (auto it = mFilterCallbackVerifiers.begin(); it != mFilterCallbackVerifiers.end();) {
        auto& [verifier, promise] = *it;
        if (verifier(events)) {
            promise.set_value();
            it = mFilterCallbackVerifiers.erase(it);
        } else {
            ++it;
        }
    };

    return ::ndk::ScopedAStatus::ok();
}

std::future<DemuxFilterEvent> FilterCallback::getNextFilterEventWithTag(DemuxFilterEvent::Tag tag) {
    // Note: this currently only supports one future per DemuxFilterEvent::Tag.
    mFilterEventPromises[tag] = std::promise<DemuxFilterEvent>();
    return mFilterEventPromises[tag].get_future();
std::future<void> FilterCallback::verifyFilterCallback(FilterCallbackVerifier&& verifier) {
    std::promise<void> promise;
    auto future = promise.get_future();
    mFilterCallbackVerifiers.emplace_back(std::move(verifier), std::move(promise));
    return future;
}

void FilterCallback::testFilterDataOutput() {
+11 −2
Original line number Diff line number Diff line
@@ -60,9 +60,18 @@ using MQDesc = MQDescriptor<int8_t, SynchronizedReadWrite>;

class FilterCallback : public BnFilterCallback {
  public:
    /**
     * A FilterCallbackVerifier is used to test and verify filter callbacks.
     * The function should return true when a callback has been handled by this
     * filter verifier. This will cause the associated future to be unblocked.
     * If the function returns false, we continue to wait for future callbacks
     * (the future remains blocked).
     */
    using FilterCallbackVerifier = std::function<bool(const std::vector<DemuxFilterEvent>&)>;

    virtual ::ndk::ScopedAStatus onFilterEvent(const vector<DemuxFilterEvent>& events) override;

    std::future<DemuxFilterEvent> getNextFilterEventWithTag(DemuxFilterEvent::Tag tag);
    std::future<void> verifyFilterCallback(FilterCallbackVerifier&& verifier);

    virtual ::ndk::ScopedAStatus onFilterStatus(const DemuxFilterStatus /*status*/) override {
        return ::ndk::ScopedAStatus::ok();
@@ -85,7 +94,7 @@ class FilterCallback : public BnFilterCallback {
    int32_t mFilterId;
    std::shared_ptr<IFilter> mFilter;

    std::unordered_map<DemuxFilterEvent::Tag, std::promise<DemuxFilterEvent>> mFilterEventPromises;
    std::vector<std::pair<FilterCallbackVerifier, std::promise<void>>> mFilterCallbackVerifiers;
    native_handle_t* mAvSharedHandle = nullptr;
    uint64_t mAvSharedMemSize = -1;

+113 −25
Original line number Diff line number Diff line
@@ -640,10 +640,51 @@ TEST_P(TunerFilterAidlTest, testTimeFilter) {
    testTimeFilter(timeFilterMap[timeFilter.timeFilterId]);
}

// TODO: move boilerplate into text fixture
TEST_P(TunerFilterAidlTest, FilterTimeDelayHintTest) {
    description("Test filter delay hint.");
static bool isMediaFilter(const FilterConfig& filterConfig) {
    switch (filterConfig.type.mainType) {
        case DemuxFilterMainType::TS: {
            // TS Audio and Video filters are media filters
            auto tsFilterType =
                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::tsFilterType>();
            return (tsFilterType == DemuxTsFilterType::AUDIO ||
                    tsFilterType == DemuxTsFilterType::VIDEO);
        }
        case DemuxFilterMainType::MMTP: {
            // MMTP Audio and Video filters are media filters
            auto mmtpFilterType =
                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>();
            return (mmtpFilterType == DemuxMmtpFilterType::AUDIO ||
                    mmtpFilterType == DemuxMmtpFilterType::VIDEO);
        }
        default:
            return false;
    }
}

static int getDemuxFilterEventDataLength(const DemuxFilterEvent& event) {
    switch (event.getTag()) {
        case DemuxFilterEvent::Tag::section:
            return event.get<DemuxFilterEvent::Tag::section>().dataLength;
        case DemuxFilterEvent::Tag::media:
            return event.get<DemuxFilterEvent::Tag::media>().dataLength;
        case DemuxFilterEvent::Tag::pes:
            return event.get<DemuxFilterEvent::Tag::pes>().dataLength;
        case DemuxFilterEvent::Tag::download:
            return event.get<DemuxFilterEvent::Tag::download>().dataLength;
        case DemuxFilterEvent::Tag::ipPayload:
            return event.get<DemuxFilterEvent::Tag::ipPayload>().dataLength;

        case DemuxFilterEvent::Tag::tsRecord:
        case DemuxFilterEvent::Tag::mmtpRecord:
        case DemuxFilterEvent::Tag::temi:
        case DemuxFilterEvent::Tag::monitorEvent:
        case DemuxFilterEvent::Tag::startId:
            return 0;
    }
}

// TODO: move boilerplate into text fixture
void TunerFilterAidlTest::testDelayHint(const FilterConfig& filterConf) {
    int32_t feId;
    int32_t demuxId;
    std::shared_ptr<IDemux> demux;
@@ -657,40 +698,87 @@ TEST_P(TunerFilterAidlTest, FilterTimeDelayHintTest) {
    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
    mFilterTests.setDemux(demux);

    const auto& filterConf = filterMap[live.ipFilterId];
    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
    ASSERT_TRUE(mFilterTests.configIpFilterCid(filterConf.ipCid, filterId));

    bool mediaFilter = isMediaFilter(filterConf);
    auto filter = mFilterTests.getFilterById(filterId);

    auto delayValue = std::chrono::milliseconds(5000);
    auto timeDelayInMs = std::chrono::milliseconds(filterConf.timeDelayInMs);
    if (timeDelayInMs.count() > 0) {
        FilterDelayHint delayHint;
        delayHint.hintType = FilterDelayHintType::TIME_DELAY_IN_MS;
    delayHint.hintValue = delayValue.count();
        delayHint.hintValue = timeDelayInMs.count();

    auto status = filter->setDelayHint(delayHint);
    ASSERT_TRUE(status.isOk());
        // setDelayHint should fail for media filters.
        ASSERT_EQ(filter->setDelayHint(delayHint).isOk(), !mediaFilter);
    }

    auto startTime = std::chrono::steady_clock::now();
    ASSERT_TRUE(mFilterTests.startFilter(filterId));
    int dataDelayInBytes = filterConf.dataDelayInBytes;
    if (dataDelayInBytes > 0) {
        FilterDelayHint delayHint;
        delayHint.hintType = FilterDelayHintType::DATA_SIZE_DELAY_IN_BYTES;
        delayHint.hintValue = dataDelayInBytes;

        // setDelayHint should fail for media filters.
        ASSERT_EQ(filter->setDelayHint(delayHint).isOk(), !mediaFilter);
    }

    // start and stop filter in order to circumvent callback scheduler race
    // conditions after adjusting filter delays.
    mFilterTests.startFilter(filterId);
    mFilterTests.stopFilter(filterId);

    if (!mediaFilter) {
        auto cb = mFilterTests.getFilterCallbacks().at(filterId);
    auto future = cb->getNextFilterEventWithTag(DemuxFilterEvent::Tag::ipPayload);
        int callbackSize = 0;
        auto future = cb->verifyFilterCallback(
                [&callbackSize](const std::vector<DemuxFilterEvent>& events) {
                    for (const auto& event : events) {
                        callbackSize += getDemuxFilterEventDataLength(event);
                    }
                    return true;
                });

        // The configure stage can also produce events, so we should set the delay
        // hint beforehand.
        ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));

        auto startTime = std::chrono::steady_clock::now();
        ASSERT_TRUE(mFilterTests.startFilter(filterId));

        // block and wait for callback to be received.
    ASSERT_EQ(future.wait_for(std::chrono::seconds(10)), std::future_status::ready);
        auto timeout = std::chrono::seconds(30);
        ASSERT_EQ(future.wait_for(timeout), std::future_status::ready);
        auto duration = std::chrono::steady_clock::now() - startTime;
    ASSERT_GE(duration, delayValue);

    // cleanup
        bool delayHintTest = duration >= timeDelayInMs;
        bool dataSizeTest = callbackSize >= dataDelayInBytes;

        if (timeDelayInMs.count() > 0 && dataDelayInBytes > 0) {
            ASSERT_TRUE(delayHintTest || dataSizeTest);
        } else {
            // if only one of time delay / data delay is configured, one of them
            // holds true by default, so we want both assertions to be true.
            ASSERT_TRUE(delayHintTest && dataSizeTest);
        }

        ASSERT_TRUE(mFilterTests.stopFilter(filterId));
    }

    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
    ASSERT_TRUE(mDemuxTests.closeDemux());
    ASSERT_TRUE(mFrontendTests.closeFrontend());
}

TEST_P(TunerFilterAidlTest, FilterDelayHintTest) {
    description("Test filter time delay hint.");

    for (const auto& obj : filterMap) {
        testDelayHint(obj.second);
    }
}

TEST_P(TunerPlaybackAidlTest, PlaybackDataFlowWithTsSectionFilterTest) {
    description("Feed ts data from playback and configure Ts section filter to get output");
    if (!playback.support || playback.sectionFilterId.compare(emptyHardwareId) == 0) {
+1 −0
Original line number Diff line number Diff line
@@ -140,6 +140,7 @@ class TunerFilterAidlTest : public testing::TestWithParam<std::string> {
    void reconfigSingleFilterInDemuxTest(FilterConfig filterConf, FilterConfig filterReconf,
                                         FrontendConfig frontendConf);
    void testTimeFilter(TimeFilterConfig filterConf);
    void testDelayHint(const FilterConfig& filterConf);

    DemuxFilterType getLinkageFilterType(int bit) {
        DemuxFilterType type;
+8 −0
Original line number Diff line number Diff line
@@ -96,6 +96,8 @@ struct FilterConfig {
    AvStreamType streamType;
    int32_t ipCid;
    int32_t monitorEventTypes;
    int timeDelayInMs = 0;
    int dataDelayInBytes = 0;

    bool operator<(const FilterConfig& /*c*/) const { return false; }
};
@@ -336,6 +338,12 @@ struct TunerTestingConfigAidlReader1_0 {
                if (filterConfig.hasMonitorEventTypes()) {
                    filterMap[id].monitorEventTypes = (int32_t)filterConfig.getMonitorEventTypes();
                }
                if (filterConfig.hasTimeDelayInMs()) {
                    filterMap[id].timeDelayInMs = filterConfig.getTimeDelayInMs();
                }
                if (filterConfig.hasDataDelayInBytes()) {
                    filterMap[id].dataDelayInBytes = filterConfig.getDataDelayInBytes();
                }
                if (filterConfig.hasAvFilterSettings_optional()) {
                    auto av = filterConfig.getFirstAvFilterSettings_optional();
                    if (av->hasAudioStreamType_optional()) {
Loading