Use AidlMessageQueue for tuner service

Test: mmm
Change-Id: I002823d97400b8865edadfadc0293f304f93e0d8
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index 2b3de17..56cb34c 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -32,14 +32,17 @@
 using ::aidl::android::media::tv::tuner::TunerFrontendIsdbsCapabilities;
 using ::aidl::android::media::tv::tuner::TunerFrontendIsdbtCapabilities;
 using ::android::hardware::hidl_vec;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
 using ::android::hardware::tv::tuner::V1_0::FrontendId;
 using ::android::hardware::tv::tuner::V1_0::FrontendType;
 using ::android::hardware::tv::tuner::V1_0::Result;
 
 namespace android {
 
-sp<ITuner> TunerService::mTuner;
-
 TunerService::TunerService() {}
 TunerService::~TunerService() {}
 
@@ -47,17 +50,160 @@
     std::shared_ptr<TunerService> service =
             ::ndk::SharedRefBase::make<TunerService>();
     AServiceManager_addService(service->asBinder().get(), getServiceName());
+}
+
+template <typename HidlPayload, typename AidlPayload, typename AidlFlavor>
+bool TunerService::unsafeHidlToAidlMQDescriptor(
+        const hardware::MQDescriptor<HidlPayload, FlavorTypeToValue<AidlFlavor>::value>& hidlDesc,
+        MQDescriptor<AidlPayload, AidlFlavor>* aidlDesc) {
+    // TODO: use the builtin coversion method when it's merged.
+    ALOGD("unsafeHidlToAidlMQDescriptor");
+    static_assert(sizeof(HidlPayload) == sizeof(AidlPayload), "Payload types are incompatible");
+    static_assert(
+            has_typedef_fixed_size<AidlPayload>::value == true ||
+            std::is_fundamental<AidlPayload>::value ||
+            std::is_enum<AidlPayload>::value,
+            "Only fundamental types, enums, and AIDL parcelables annotated with @FixedSize "
+            "and built for the NDK backend are supported as AIDL payload types.");
+    aidlDesc->fileDescriptor = ndk::ScopedFileDescriptor(dup(hidlDesc.handle()->data[0]));
+    for (const auto& grantor : hidlDesc.grantors()) {
+        if (static_cast<int32_t>(grantor.offset) < 0 || static_cast<int64_t>(grantor.extent) < 0) {
+            ALOGD("Unsafe static_cast of grantor fields. offset=%d, extend=%ld",
+                    static_cast<int32_t>(grantor.offset), static_cast<long>(grantor.extent));
+            logError(
+                    "Unsafe static_cast of grantor fields. Either the hardware::MQDescriptor is "
+                    "invalid, or the MessageQueue is too large to be described by AIDL.");
+            return false;
+        }
+        aidlDesc->grantors.push_back(
+                GrantorDescriptor {
+                        .offset = static_cast<int32_t>(grantor.offset),
+                        .extent = static_cast<int64_t>(grantor.extent)
+                });
+    }
+    if (static_cast<int32_t>(hidlDesc.getQuantum()) < 0 ||
+            static_cast<int32_t>(hidlDesc.getFlags()) < 0) {
+        ALOGD("Unsafe static_cast of quantum or flags. Quantum=%d, flags=%d",
+                static_cast<int32_t>(hidlDesc.getQuantum()),
+                static_cast<int32_t>(hidlDesc.getFlags()));
+        logError(
+                "Unsafe static_cast of quantum or flags. Either the hardware::MQDescriptor is "
+                "invalid, or the MessageQueue is too large to be described by AIDL.");
+        return false;
+    }
+    aidlDesc->quantum = static_cast<int32_t>(hidlDesc.getQuantum());
+    aidlDesc->flags = static_cast<int32_t>(hidlDesc.getFlags());
+    return true;
+}
+
+bool TunerService::getITuner() {
+    ALOGD("getITuner");
+    if (mTuner != nullptr) {
+        return true;
+    }
     mTuner = ITuner::getService();
     if (mTuner == nullptr) {
-        ALOGE("Failed to get ITuner service.");
+        ALOGE("Failed to get ITuner service");
+        return false;
     }
+    return true;
+}
+
+Result TunerService::openDemux() {
+    ALOGD("openDemux");
+    if (!getITuner()) {
+        return Result::NOT_INITIALIZED;
+    }
+    if (mDemux != nullptr) {
+        return Result::SUCCESS;
+    }
+    Result res;
+    uint32_t id;
+    sp<IDemux> demuxSp;
+    mTuner->openDemux([&](Result r, uint32_t demuxId, const sp<IDemux>& demux) {
+        demuxSp = demux;
+        id = demuxId;
+        res = r;
+        ALOGD("open demux, id = %d", demuxId);
+    });
+    if (res == Result::SUCCESS) {
+        mDemux = demuxSp;
+    } else {
+        ALOGD("open demux failed, res = %d", res);
+    }
+    return res;
+}
+
+Result TunerService::openFilter() {
+    ALOGD("openFilter");
+    if (!getITuner()) {
+        return Result::NOT_INITIALIZED;
+    }
+    DemuxFilterMainType mainType = DemuxFilterMainType::TS;
+    DemuxFilterType filterType {
+        .mainType = mainType,
+    };
+    filterType.subType.tsFilterType(DemuxTsFilterType::VIDEO);
+
+    sp<FilterCallback> callback = new FilterCallback();
+    Result res;
+    mDemux->openFilter(filterType, 16000000, callback,
+            [&](Result r, const sp<IFilter>& filter) {
+                mFilter = filter;
+                res = r;
+            });
+    if (res != Result::SUCCESS || mFilter == NULL) {
+        ALOGD("Failed to open filter, type = %d", filterType.mainType);
+        return res;
+    }
+
+    return Result::SUCCESS;
+}
+
+Result TunerService::configFilter() {
+    ALOGD("configFilter");
+    if (mFilter == NULL) {
+        ALOGD("Failed to configure filter: filter not found");
+        return Result::NOT_INITIALIZED;
+    }
+    DemuxFilterSettings filterSettings;
+    DemuxTsFilterSettings tsFilterSettings {
+        .tpid = 256,
+    };
+    DemuxFilterAvSettings filterAvSettings {
+        .isPassthrough = false,
+    };
+    tsFilterSettings.filterSettings.av(filterAvSettings);
+    filterSettings.ts(tsFilterSettings);
+    Result res = mFilter->configure(filterSettings);
+
+    if (res != Result::SUCCESS) {
+        ALOGD("config filter failed, res = %d", res);
+        return res;
+    }
+
+    Result getQueueDescResult = Result::UNKNOWN_ERROR;
+    mFilter->getQueueDesc(
+            [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
+                mFilterMQDesc = desc;
+                getQueueDescResult = r;
+                ALOGD("getFilterQueueDesc");
+            });
+    if (getQueueDescResult == Result::SUCCESS) {
+        unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(
+                mFilterMQDesc,  &mAidlMQDesc);
+        mAidlMq = new (std::nothrow) AidlMessageQueue(mAidlMQDesc);
+        EventFlag::createEventFlag(mAidlMq->getEventFlagWord(), &mEventFlag);
+    } else {
+        ALOGD("get MQDesc failed, res = %d", getQueueDescResult);
+    }
+    return getQueueDescResult;
 }
 
 Status TunerService::getFrontendIds(std::vector<int32_t>* ids, int32_t* /* _aidl_return */) {
-    if (mTuner == nullptr) {
-        ALOGE("ITuner service is not init.");
+    if (!getITuner()) {
         return ::ndk::ScopedAStatus::fromServiceSpecificError(
-                static_cast<int32_t>(Result::UNAVAILABLE));
+                static_cast<int32_t>(Result::NOT_INITIALIZED));
     }
     hidl_vec<FrontendId> feIds;
     Result res;
@@ -221,4 +367,24 @@
     info.caps = caps;
     return info;
 }
+
+Status TunerService::getFmqSyncReadWrite(
+        MQDescriptor<int8_t, SynchronizedReadWrite>* mqDesc, bool* _aidl_return) {
+    ALOGD("getFmqSyncReadWrite");
+    // TODO: put the following methods AIDL, and should be called from clients.
+    openDemux();
+    openFilter();
+    configFilter();
+    mFilter->start();
+    if (mqDesc == nullptr) {
+        ALOGD("getFmqSyncReadWrite null MQDescriptor.");
+        *_aidl_return = false;
+    } else {
+        ALOGD("getFmqSyncReadWrite true");
+        *_aidl_return = true;
+        *mqDesc = std::move(mAidlMQDesc);
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
 } // namespace android