Add ITunerDvr/ITunerDvrCallback aidl interface and implementation

Note this CL also adds the openDvr implementation and API in ITunerDemux

Test: make
Bug: 159067322
Change-Id: I92dd0d51fc2fe85a55fca691692d872122def082
diff --git a/services/tuner/TunerDemux.cpp b/services/tuner/TunerDemux.cpp
index edd1802..0e0cd3b 100644
--- a/services/tuner/TunerDemux.cpp
+++ b/services/tuner/TunerDemux.cpp
@@ -16,8 +16,8 @@
 
 #define LOG_TAG "TunerDemux"
 
+#include "TunerDvr.h"
 #include "TunerDemux.h"
-#include "TunerFilter.h"
 
 using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
@@ -26,6 +26,7 @@
 using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
 using ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterType;
 using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using ::android::hardware::tv::tuner::V1_0::DvrType;
 using ::android::hardware::tv::tuner::V1_0::Result;
 
 namespace android {
@@ -100,4 +101,27 @@
     return Status::ok();
 }
 
+Status TunerDemux::openDvr(int dvrType, int bufferSize, const shared_ptr<ITunerDvrCallback>& cb,
+        shared_ptr<ITunerDvr>* _aidl_return) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized.");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result res;
+    sp<IDvrCallback> callback = new TunerDvr::DvrCallback(cb);
+    sp<IDvr> hidlDvr;
+    mDemux->openDvr(static_cast<DvrType>(dvrType), bufferSize, callback,
+            [&](Result r, const sp<IDvr>& dvr) {
+                hidlDvr = dvr;
+                res = r;
+            });
+    if (res != Result::SUCCESS) {
+        *_aidl_return = NULL;
+        return Status::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    *_aidl_return = ::ndk::SharedRefBase::make<TunerDvr>(hidlDvr, dvrType);
+    return Status::ok();
+}
 }  // namespace android
diff --git a/services/tuner/TunerDemux.h b/services/tuner/TunerDemux.h
index 6eca8ab..675bb7c 100644
--- a/services/tuner/TunerDemux.h
+++ b/services/tuner/TunerDemux.h
@@ -22,11 +22,16 @@
 
 using Status = ::ndk::ScopedAStatus;
 using ::aidl::android::media::tv::tuner::BnTunerDemux;
+using ::aidl::android::media::tv::tuner::ITunerDvr;
+using ::aidl::android::media::tv::tuner::ITunerDvrCallback;
 using ::aidl::android::media::tv::tuner::ITunerFilter;
 using ::aidl::android::media::tv::tuner::ITunerFilterCallback;
 using ::aidl::android::media::tv::tuner::ITunerFrontend;
 using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IDvr;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
 
+using namespace std;
 
 namespace android {
 
@@ -35,10 +40,13 @@
 public:
     TunerDemux(sp<IDemux> demux, int demuxId);
     virtual ~TunerDemux();
-    Status setFrontendDataSource(const std::shared_ptr<ITunerFrontend>& frontend) override;
+    Status setFrontendDataSource(const shared_ptr<ITunerFrontend>& frontend) override;
     Status openFilter(
-        int mainType, int subtype, int bufferSize, const std::shared_ptr<ITunerFilterCallback>& cb,
-        std::shared_ptr<ITunerFilter>* _aidl_return);
+        int mainType, int subtype, int bufferSize, const shared_ptr<ITunerFilterCallback>& cb,
+        shared_ptr<ITunerFilter>* _aidl_return);
+    Status openDvr(
+        int dvbType, int bufferSize, const shared_ptr<ITunerDvrCallback>& cb,
+        shared_ptr<ITunerDvr>* _aidl_return) override;
 
 private:
     sp<IDemux> mDemux;
diff --git a/services/tuner/TunerDvr.cpp b/services/tuner/TunerDvr.cpp
new file mode 100644
index 0000000..c7227b6
--- /dev/null
+++ b/services/tuner/TunerDvr.cpp
@@ -0,0 +1,207 @@
+/**
+ * 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.
+ */
+
+#define LOG_TAG "TunerDvr"
+
+#include <fmq/ConvertMQDescriptors.h>
+#include "TunerDvr.h"
+#include "TunerFilter.h"
+
+using ::android::hardware::tv::tuner::V1_0::DataFormat;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+namespace android {
+
+TunerDvr::TunerDvr(sp<IDvr> dvr, int type) {
+    mDvr = dvr;
+    mType = static_cast<DvrType>(type);
+}
+
+TunerDvr::~TunerDvr() {
+    mDvr = NULL;
+}
+
+Status TunerDvr::getQueueDesc(AidlMQDesc* _aidl_return) {
+    if (mDvr == NULL) {
+        ALOGE("IDvr is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    MQDesc dvrMQDesc;
+    Result res;
+    mDvr->getQueueDesc([&](Result r, const MQDesc& desc) {
+        dvrMQDesc = desc;
+        res = r;
+    });
+    if (res != Result::SUCCESS) {
+        return Status::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    AidlMQDesc aidlMQDesc;
+    unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(
+                dvrMQDesc,  &aidlMQDesc);
+    *_aidl_return = move(aidlMQDesc);
+    return Status::ok();
+}
+
+Status TunerDvr::configure(const TunerDvrSettings& settings) {
+    if (mDvr == NULL) {
+        ALOGE("IDvr is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result res = mDvr->configure(getHidlDvrSettingsFromAidl(settings));
+    if (res != Result::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return Status::ok();
+}
+
+Status TunerDvr::attachFilter(const shared_ptr<ITunerFilter>& filter) {
+    if (mDvr == NULL) {
+        ALOGE("IDvr is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    ITunerFilter* tunerFilter = filter.get();
+    sp<IFilter> hidlFilter = static_cast<TunerFilter*>(tunerFilter)->getHalFilter();
+    if (hidlFilter == NULL) {
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    Result res = mDvr->attachFilter(hidlFilter);
+    if (res != Result::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return Status::ok();
+}
+
+Status TunerDvr::detachFilter(const shared_ptr<ITunerFilter>& filter) {
+    if (mDvr == NULL) {
+        ALOGE("IDvr is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    ITunerFilter* tunerFilter = filter.get();
+    sp<IFilter> hidlFilter = static_cast<TunerFilter*>(tunerFilter)->getHalFilter();
+    if (hidlFilter == NULL) {
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    Result res = mDvr->detachFilter(hidlFilter);
+    if (res != Result::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return Status::ok();
+}
+
+Status TunerDvr::start() {
+    if (mDvr == NULL) {
+        ALOGE("IDvr is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result res = mDvr->start();
+    if (res != Result::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return Status::ok();
+}
+
+Status TunerDvr::stop() {
+    if (mDvr == NULL) {
+        ALOGE("IDvr is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result res = mDvr->stop();
+    if (res != Result::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return Status::ok();
+}
+
+Status TunerDvr::flush() {
+    if (mDvr == NULL) {
+        ALOGE("IDvr is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result res = mDvr->flush();
+    if (res != Result::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return Status::ok();
+}
+
+Status TunerDvr::close() {
+    if (mDvr == NULL) {
+        ALOGE("IDvr is not initialized");
+        return Status::fromServiceSpecificError(static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    Result res = mDvr->close();
+    if (res != Result::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return Status::ok();
+}
+
+DvrSettings TunerDvr::getHidlDvrSettingsFromAidl(TunerDvrSettings settings) {
+    DvrSettings s;
+    switch (mType) {
+        case DvrType::PLAYBACK: {
+            s.playback({
+                .statusMask = static_cast<uint8_t>(settings.statusMask),
+                .lowThreshold = static_cast<uint32_t>(settings.lowThreshold),
+                .highThreshold = static_cast<uint32_t>(settings.highThreshold),
+                .dataFormat = static_cast<DataFormat>(settings.dataFormat),
+                .packetSize = static_cast<uint8_t>(settings.packetSize),
+            });
+            return s;
+        }
+        case DvrType::RECORD: {
+            s.record({
+                .statusMask = static_cast<uint8_t>(settings.statusMask),
+                .lowThreshold = static_cast<uint32_t>(settings.lowThreshold),
+                .highThreshold = static_cast<uint32_t>(settings.highThreshold),
+                .dataFormat = static_cast<DataFormat>(settings.dataFormat),
+                .packetSize = static_cast<uint8_t>(settings.packetSize),
+            });
+            return s;
+        }
+        default:
+            break;
+    }
+    return s;
+}
+
+/////////////// IDvrCallback ///////////////////////
+
+Return<void> TunerDvr::DvrCallback::onRecordStatus(const RecordStatus status) {
+    if (mTunerDvrCallback != NULL) {
+        mTunerDvrCallback->onRecordStatus(static_cast<int>(status));
+    }
+    return Void();
+}
+
+Return<void> TunerDvr::DvrCallback::onPlaybackStatus(const PlaybackStatus status) {
+    if (mTunerDvrCallback != NULL) {
+        mTunerDvrCallback->onPlaybackStatus(static_cast<int>(status));
+    }
+    return Void();
+}
+}  // namespace android
diff --git a/services/tuner/TunerDvr.h b/services/tuner/TunerDvr.h
new file mode 100644
index 0000000..a508e99
--- /dev/null
+++ b/services/tuner/TunerDvr.h
@@ -0,0 +1,97 @@
+/**
+ * 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.
+ */
+
+#ifndef ANDROID_MEDIA_TUNERDVR_H
+#define ANDROID_MEDIA_TUNERDVR_H
+
+#include <aidl/android/media/tv/tuner/BnTunerDvr.h>
+#include <aidl/android/media/tv/tuner/ITunerDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <fmq/MessageQueue.h>
+
+#include <TunerFilter.h>
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::hardware::common::fmq::GrantorDescriptor;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::media::tv::tuner::BnTunerDvr;
+using ::aidl::android::media::tv::tuner::ITunerDvrCallback;
+using ::aidl::android::media::tv::tuner::ITunerFilter;
+using ::aidl::android::media::tv::tuner::TunerDvrSettings;
+
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::hardware::tv::tuner::V1_0::DvrSettings;
+using ::android::hardware::tv::tuner::V1_0::DvrType;
+using ::android::hardware::tv::tuner::V1_0::IDvr;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+using ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using ::android::hardware::tv::tuner::V1_0::RecordStatus;
+
+using namespace std;
+
+namespace android {
+
+using MQDesc = MQDescriptorSync<uint8_t>;
+using AidlMQDesc = MQDescriptor<int8_t, SynchronizedReadWrite>;
+
+class TunerDvr : public BnTunerDvr {
+
+public:
+    TunerDvr(sp<IDvr> dvr, int type);
+    ~TunerDvr();
+
+    Status getQueueDesc(AidlMQDesc* _aidl_return) override;
+
+    Status configure(const TunerDvrSettings& settings) override;
+
+    Status attachFilter(const shared_ptr<ITunerFilter>& filter) override;
+
+    Status detachFilter(const shared_ptr<ITunerFilter>& filter) override;
+
+    Status start() override;
+
+    Status stop() override;
+
+    Status flush() override;
+
+    Status close() override;
+
+    struct DvrCallback : public IDvrCallback {
+        DvrCallback(const shared_ptr<ITunerDvrCallback> tunerDvrCallback)
+                : mTunerDvrCallback(tunerDvrCallback) {};
+
+        virtual Return<void> onRecordStatus(const RecordStatus status);
+        virtual Return<void> onPlaybackStatus(const PlaybackStatus status);
+
+        private:
+            shared_ptr<ITunerDvrCallback> mTunerDvrCallback;
+    };
+
+private:
+    DvrSettings getHidlDvrSettingsFromAidl(TunerDvrSettings settings);
+
+    sp<IDvr> mDvr;
+    DvrType mType;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_TUNERDVR_H
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index e4f1926..722d36d 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -149,6 +149,10 @@
     return Status::ok();
 }
 
+sp<IFilter> TunerFilter::getHalFilter() {
+    return mFilter;
+}
+
 /////////////// FilterCallback ///////////////////////
 
 void TunerFilter::FilterCallback::getMediaEvent(
diff --git a/services/tuner/TunerFilter.h b/services/tuner/TunerFilter.h
index 3259e37..7f5838c 100644
--- a/services/tuner/TunerFilter.h
+++ b/services/tuner/TunerFilter.h
@@ -53,6 +53,7 @@
     Status start() override;
     Status stop() override;
     Status flush() override;
+    sp<IFilter> getHalFilter();
 
     struct FilterCallback : public IFilterCallback {
         FilterCallback(const std::shared_ptr<ITunerFilterCallback> tunerFilterCallback)
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerDemux.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerDemux.aidl
index 0e4e99c..f6de618 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerDemux.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerDemux.aidl
@@ -16,6 +16,8 @@
 
 package android.media.tv.tuner;
 
+import android.media.tv.tuner.ITunerDvr;
+import android.media.tv.tuner.ITunerDvrCallback;
 import android.media.tv.tuner.ITunerFilter;
 import android.media.tv.tuner.ITunerFilterCallback;
 import android.media.tv.tuner.ITunerFrontend;
@@ -37,4 +39,9 @@
      */
     ITunerFilter openFilter(
         in int mainType, in int subtype, in int bufferSize, in ITunerFilterCallback cb);
+
+    /**
+     * Open a DVR (Digital Video Record) instance in the demux.
+     */
+    ITunerDvr openDvr(in int dvbType, in int bufferSize, in ITunerDvrCallback cb);
 }
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerDvr.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerDvr.aidl
new file mode 100644
index 0000000..8f1601b
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerDvr.aidl
@@ -0,0 +1,69 @@
+/**
+ * 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.
+ */
+
+package android.media.tv.tuner;
+
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.media.tv.tuner.ITunerFilter;
+import android.media.tv.tuner.TunerDvrSettings;
+
+/**
+ * Tuner Dvr interface handles tuner related operations.
+ *
+ * {@hide}
+ */
+interface ITunerDvr {
+    /**
+     * Get the descriptor of the DVR's FMQ.
+     */
+    MQDescriptor<byte, SynchronizedReadWrite> getQueueDesc();
+
+    /**
+     * Configure the DVR.
+     */
+    void configure(in TunerDvrSettings settings);
+
+    /**
+     * Attach one filter to DVR interface for recording.
+     */
+    void attachFilter(in ITunerFilter filter);
+
+    /**
+     * Detach one filter from the DVR's recording.
+     */
+    void detachFilter(in ITunerFilter filter);
+
+    /**
+     * Start DVR.
+     */
+    void start();
+
+    /**
+     * Stop DVR.
+     */
+    void stop();
+
+    /**
+     * Flush DVR data.
+     */
+    void flush();
+
+    /**
+     * close the DVR instance to release resource for DVR.
+     */
+    void close();
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerDvrCallback.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerDvrCallback.aidl
new file mode 100644
index 0000000..e234fe5
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerDvrCallback.aidl
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+
+package android.media.tv.tuner;
+
+/**
+ * TunerDvrCallback interface handles tuner dvr related callbacks.
+ *
+ * {@hide}
+ */
+interface ITunerDvrCallback {
+    /**
+     * Notify the client a new status of the demux's record.
+     */
+    void onRecordStatus(in int status);
+
+    /**
+     * Notify the client a new status of the demux's playback.
+     */
+    void onPlaybackStatus(in int status);
+}
diff --git a/services/tuner/aidl/android/media/tv/tuner/TunerDvrSettings.aidl b/services/tuner/aidl/android/media/tv/tuner/TunerDvrSettings.aidl
new file mode 100644
index 0000000..4ec4d75
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/TunerDvrSettings.aidl
@@ -0,0 +1,34 @@
+/**
+ * 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.
+ */
+
+package android.media.tv.tuner;
+
+/**
+ * Dvr Settings interface.
+ *
+ * {@hide}
+ */
+parcelable TunerDvrSettings {
+    int statusMask;
+
+    int lowThreshold;
+
+    int highThreshold;
+
+    int dataFormat;
+
+    int packetSize;
+}