DVR API: class, methods, JNI
Test: make; alcoud;
Change-Id: Iddcffef436dc520c969a3dc4f854e3d4c902c2b8
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 3d89909..c91325a 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -86,6 +86,7 @@
private native Descrambler nativeOpenDescrambler();
+ private native Dvr nativeOpenDvr(int type, int bufferSize);
/**
* Frontend Callback.
@@ -118,6 +119,20 @@
void onFilterStatus(int status);
}
+ /**
+ * DVR Callback.
+ */
+ public interface DvrCallback {
+ /**
+ * Invoked when record status changed.
+ */
+ void onRecordStatus(int status);
+ /**
+ * Invoked when playback status changed.
+ */
+ void onPlaybackStatus(int status);
+ }
+
@Nullable
private EventHandler createEventHandler() {
Looper looper;
@@ -321,4 +336,39 @@
Descrambler descrambler = nativeOpenDescrambler();
return descrambler;
}
+
+ // TODO: consider splitting Dvr to Playback and Recording
+ protected class Dvr {
+ private long mNativeContext;
+ private DvrCallback mCallback;
+
+ private native boolean nativeAttachFilter(Filter filter);
+ private native boolean nativeDetachFilter(Filter filter);
+ private native boolean nativeStartDvr();
+ private native boolean nativeStopDvr();
+ private native boolean nativeFlushDvr();
+
+ private Dvr() {}
+
+ public boolean attachFilter(Filter filter) {
+ return nativeAttachFilter(filter);
+ }
+ public boolean detachFilter(Filter filter) {
+ return nativeDetachFilter(filter);
+ }
+ public boolean start() {
+ return nativeStartDvr();
+ }
+ public boolean stop() {
+ return nativeStopDvr();
+ }
+ public boolean flush() {
+ return nativeFlushDvr();
+ }
+ }
+
+ private Dvr openDvr(int type, int bufferSize) {
+ Dvr dvr = nativeOpenDvr(type, bufferSize);
+ return dvr;
+ }
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index efdd333..f5202fc 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -38,8 +38,10 @@
jfieldID tunerContext;
jfieldID filterContext;
jfieldID descramblerContext;
+ jfieldID dvrContext;
jmethodID frontendInitID;
jmethodID filterInitID;
+ jmethodID dvrInitID;
jmethodID onFrontendEventID;
jmethodID onFilterStatusID;
jmethodID lnbInitID;
@@ -67,6 +69,23 @@
return Void();
}
+/////////////// DvrCallback ///////////////////////
+Return<void> DvrCallback::onRecordStatus(RecordStatus /*status*/) {
+ ALOGD("DvrCallback::onRecordStatus");
+ return Void();
+}
+
+Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus /*status*/) {
+ ALOGD("DvrCallback::onPlaybackStatus");
+ return Void();
+}
+
+void DvrCallback::setDvr(const jobject dvr) {
+ ALOGD("FilterCallback::setDvr");
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ mDvr = env->NewWeakGlobalRef(dvr);
+}
+
/////////////// FilterCallback ///////////////////////
//TODO: implement filter callback
Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& /*filterEvent*/) {
@@ -327,6 +346,39 @@
return filterObj;
}
+jobject JTuner::openDvr(DvrType type, int bufferSize) {
+ ALOGD("JTuner::openDvr");
+ if (mDemux == NULL) {
+ if (!openDemux()) {
+ return NULL;
+ }
+ }
+ sp<IDvr> dvrSp;
+ sp<DvrCallback> callback = new DvrCallback();
+ mDemux->openDvr(type, bufferSize, callback,
+ [&](Result, const sp<IDvr>& dvr) {
+ dvrSp = dvr;
+ });
+
+ if (dvrSp == NULL) {
+ return NULL;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jobject dvrObj =
+ env->NewObject(
+ env->FindClass("android/media/tv/tuner/Tuner$Dvr"),
+ gFields.dvrInitID,
+ mObject);
+
+ dvrSp->incStrong(dvrObj);
+ env->SetLongField(dvrObj, gFields.dvrContext, (jlong)dvrSp.get());
+
+ callback->setDvr(dvrObj);
+
+ return dvrObj;
+}
+
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -369,6 +421,10 @@
return (IFilter *)env->GetLongField(filter, gFields.filterContext);
}
+static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) {
+ return (IDvr *)env->GetLongField(dvr, gFields.dvrContext);
+}
+
static void android_media_tv_Tuner_native_init(JNIEnv *env) {
jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
CHECK(clazz != NULL);
@@ -399,6 +455,10 @@
gFields.descramblerContext = env->GetFieldID(descramblerClazz, "mNativeContext", "J");
gFields.descramblerInitID =
env->GetMethodID(descramblerClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;)V");
+
+ jclass dvrClazz = env->FindClass("android/media/tv/tuner/Tuner$Dvr");
+ gFields.dvrContext = env->GetFieldID(dvrClazz, "mNativeContext", "J");
+ gFields.dvrInitID = env->GetMethodID(dvrClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;)V");
}
static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) {
@@ -493,6 +553,58 @@
return result == Result::SUCCESS;
}
+static jobject android_media_tv_Tuner_open_dvr(JNIEnv *env, jobject thiz, jint type, jint bufferSize) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openDvr(static_cast<DvrType>(type), bufferSize);
+}
+
+static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
+ sp<IDvr> dvrSp = getDvr(env, dvr);
+ sp<IFilter> filterSp = getFilter(env, filter);
+ if (dvrSp == NULL || filterSp == NULL) {
+ return false;
+ }
+ Result result = dvrSp->attachFilter(filterSp);
+ return result == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
+ sp<IDvr> dvrSp = getDvr(env, dvr);
+ sp<IFilter> filterSp = getFilter(env, filter);
+ if (dvrSp == NULL || filterSp == NULL) {
+ return false;
+ }
+ Result result = dvrSp->detachFilter(filterSp);
+ return result == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
+ sp<IDvr> dvrSp = getDvr(env, dvr);
+ if (dvrSp == NULL) {
+ ALOGD("Failed to start dvr: dvr not found");
+ return false;
+ }
+ return dvrSp->start() == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
+ sp<IDvr> dvrSp = getDvr(env, dvr);
+ if (dvrSp == NULL) {
+ ALOGD("Failed to stop dvr: dvr not found");
+ return false;
+ }
+ return dvrSp->stop() == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) {
+ sp<IDvr> dvrSp = getDvr(env, dvr);
+ if (dvrSp == NULL) {
+ ALOGD("Failed to flush dvr: dvr not found");
+ return false;
+ }
+ return dvrSp->flush() == Result::SUCCESS;
+}
+
static const JNINativeMethod gTunerMethods[] = {
{ "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
{ "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup },
@@ -508,6 +620,8 @@
(void *)android_media_tv_Tuner_open_lnb_by_id },
{ "nativeOpenDescrambler", "()Landroid/media/tv/tuner/Tuner$Descrambler;",
(void *)android_media_tv_Tuner_open_descrambler },
+ { "nativeOpenDvr", "(II)Landroid/media/tv/tuner/Tuner$Dvr;",
+ (void *)android_media_tv_Tuner_open_dvr },
};
static const JNINativeMethod gFilterMethods[] = {
@@ -523,6 +637,16 @@
(void *)android_media_tv_Tuner_remove_pid },
};
+static const JNINativeMethod gDvrMethods[] = {
+ { "nativeAttachFilter", "(Landroid/media/tv/tuner/Tuner$Filter;)Z",
+ (void *)android_media_tv_Tuner_attach_filter },
+ { "nativeDetachFilter", "(Landroid/media/tv/tuner/Tuner$Filter;)Z",
+ (void *)android_media_tv_Tuner_detach_filter },
+ { "nativeStartDvr", "()Z", (void *)android_media_tv_Tuner_start_dvr },
+ { "nativeStopDvr", "()Z", (void *)android_media_tv_Tuner_stop_dvr },
+ { "nativeFlushDvr", "()Z", (void *)android_media_tv_Tuner_flush_dvr },
+};
+
static bool register_android_media_tv_Tuner(JNIEnv *env) {
if (AndroidRuntime::registerNativeMethods(
env, "android/media/tv/tuner/Tuner", gTunerMethods, NELEM(gTunerMethods)) != JNI_OK) {
@@ -543,6 +667,13 @@
ALOGE("Failed to register descrambler native methods");
return false;
}
+ if (AndroidRuntime::registerNativeMethods(
+ env, "android/media/tv/tuner/Tuner$Dvr",
+ gDvrMethods,
+ NELEM(gDvrMethods)) != JNI_OK) {
+ ALOGE("Failed to register dvr native methods");
+ return false;
+ }
return true;
}
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index d3aec64..3bf6ec8 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -29,12 +29,15 @@
using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
using ::android::hardware::tv::tuner::V1_0::DemuxPid;
+using ::android::hardware::tv::tuner::V1_0::DvrType;
using ::android::hardware::tv::tuner::V1_0::FrontendEventType;
using ::android::hardware::tv::tuner::V1_0::FrontendId;
using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
using ::android::hardware::tv::tuner::V1_0::IDemux;
using ::android::hardware::tv::tuner::V1_0::IDescrambler;
+using ::android::hardware::tv::tuner::V1_0::IDvr;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
using ::android::hardware::tv::tuner::V1_0::IFilter;
using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
using ::android::hardware::tv::tuner::V1_0::IFrontend;
@@ -44,6 +47,8 @@
using ::android::hardware::tv::tuner::V1_0::ITuner;
using ::android::hardware::tv::tuner::V1_0::LnbEventType;
using ::android::hardware::tv::tuner::V1_0::LnbId;
+using ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using ::android::hardware::tv::tuner::V1_0::RecordStatus;
namespace android {
@@ -55,6 +60,15 @@
LnbId mId;
};
+struct DvrCallback : public IDvrCallback {
+ virtual Return<void> onRecordStatus(RecordStatus status);
+ virtual Return<void> onPlaybackStatus(PlaybackStatus status);
+
+ void setDvr(const jobject dvr);
+private:
+ jweak mDvr;
+};
+
struct FilterCallback : public IFilterCallback {
virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
@@ -85,6 +99,7 @@
jobject openLnbById(int id);
jobject openFilter(DemuxFilterType type, int bufferSize);
jobject openDescrambler();
+ jobject openDvr(DvrType type, int bufferSize);
protected:
bool openDemux();