Tuner JNI: time filter
Test: make; acloud create;
Change-Id: I6bd53f6831e021d14b8d5762850a083acdbcf26a
diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java
index 30aaa02..ce18dc7 100644
--- a/media/java/android/media/tv/tuner/TunerUtils.java
+++ b/media/java/android/media/tv/tuner/TunerUtils.java
@@ -16,6 +16,7 @@
package android.media.tv.tuner;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.tv.tuner.V1_0.Constants;
@@ -142,5 +143,33 @@
"Invalid filter types. Main type=" + mainType + ", subtype=" + subtype);
}
+ /**
+ * Gets an throwable instance for the corresponding result.
+ */
+ @Nullable
+ public static void throwExceptionForResult(
+ @TunerConstants.Result int r, @Nullable String msg) {
+ if (msg == null) {
+ msg = "";
+ }
+ switch (r) {
+ case TunerConstants.RESULT_INVALID_ARGUMENT:
+ throw new IllegalArgumentException(msg);
+ case TunerConstants.RESULT_INVALID_STATE:
+ throw new IllegalStateException(msg);
+ case TunerConstants.RESULT_NOT_INITIALIZED:
+ throw new IllegalStateException("Invalid state: not initialized. " + msg);
+ case TunerConstants.RESULT_OUT_OF_MEMORY:
+ throw new OutOfMemoryError(msg);
+ case TunerConstants.RESULT_UNAVAILABLE:
+ throw new IllegalStateException("Invalid state: resource unavailable. " + msg);
+ case TunerConstants.RESULT_UNKNOWN_ERROR:
+ throw new RuntimeException("Unknown error" + msg);
+ default:
+ break;
+ }
+ throw new RuntimeException("Unexpected result " + r + ". " + msg);
+ }
+
private TunerUtils() {}
}
diff --git a/media/java/android/media/tv/tuner/filter/TimeFilter.java b/media/java/android/media/tv/tuner/filter/TimeFilter.java
index a926d59..371ccc4 100644
--- a/media/java/android/media/tv/tuner/filter/TimeFilter.java
+++ b/media/java/android/media/tv/tuner/filter/TimeFilter.java
@@ -17,7 +17,9 @@
package android.media.tv.tuner.filter;
import android.annotation.SystemApi;
+import android.media.tv.tuner.TunerConstants;
import android.media.tv.tuner.TunerConstants.Result;
+import android.media.tv.tuner.TunerUtils;
/**
* A timer filter is used to filter data based on timestamps.
@@ -51,6 +53,8 @@
private native Long nativeGetSourceTime();
private native int nativeClose();
+ private long mNativeContext;
+
private boolean mEnable = false;
// Called by JNI code
@@ -139,6 +143,9 @@
*/
@Override
public void close() {
- nativeClose();
+ int res = nativeClose();
+ if (res != TunerConstants.RESULT_SUCCESS) {
+ TunerUtils.throwExceptionForResult(res, "Failed to close time filter.");
+ }
}
}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index ac59003..a12deb5 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -117,10 +117,12 @@
struct fields_t {
jfieldID tunerContext;
jfieldID filterContext;
+ jfieldID timeFilterContext;
jfieldID descramblerContext;
jfieldID dvrContext;
jmethodID frontendInitID;
jmethodID filterInitID;
+ jmethodID timeFilterInitID;
jmethodID dvrInitID;
jmethodID onFrontendEventID;
jmethodID onFilterStatusID;
@@ -236,6 +238,25 @@
return mFilterSp;
}
+/////////////// TimeFilter ///////////////////////
+
+TimeFilter::TimeFilter(sp<ITimeFilter> sp, jobject obj) : mTimeFilterSp(sp) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ mTimeFilterObj = env->NewWeakGlobalRef(obj);
+}
+
+TimeFilter::~TimeFilter() {
+ ALOGD("~TimeFilter");
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ env->DeleteWeakGlobalRef(mTimeFilterObj);
+ mTimeFilterObj = NULL;
+}
+
+sp<ITimeFilter> TimeFilter::getITimeFilter() {
+ return mTimeFilterSp;
+}
+
/////////////// FrontendCallback ///////////////////////
FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {}
@@ -702,6 +723,36 @@
return filterObj;
}
+jobject JTuner::openTimeFilter() {
+ if (mDemux == NULL) {
+ if (!openDemux()) {
+ return NULL;
+ }
+ }
+ sp<ITimeFilter> iTimeFilterSp;
+ Result res;
+ mDemux->openTimeFilter(
+ [&](Result r, const sp<ITimeFilter>& filter) {
+ iTimeFilterSp = filter;
+ res = r;
+ });
+
+ if (res != Result::SUCCESS || iTimeFilterSp == NULL) {
+ return NULL;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jobject timeFilterObj =
+ env->NewObject(
+ env->FindClass("android/media/tv/tuner/filter/TimeFilter"),
+ gFields.timeFilterInitID);
+ sp<TimeFilter> timeFilterSp = new TimeFilter(iTimeFilterSp, timeFilterObj);
+ timeFilterSp->incStrong(timeFilterObj);
+ env->SetLongField(timeFilterObj, gFields.timeFilterContext, (jlong)timeFilterSp.get());
+
+ return timeFilterObj;
+}
+
jobject JTuner::openDvr(DvrType type, int bufferSize) {
ALOGD("JTuner::openDvr");
if (mDemux == NULL) {
@@ -1281,6 +1332,10 @@
gFields.onFilterStatusID =
env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
+ jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter");
+ gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J");
+ gFields.timeFilterInitID = env->GetMethodID(timeFilterClazz, "<init>", "()V");
+
jclass descramblerClazz = env->FindClass("android/media/tv/tuner/Descrambler");
gFields.descramblerContext = env->GetFieldID(descramblerClazz, "mNativeContext", "J");
gFields.descramblerInitID =
@@ -1376,18 +1431,35 @@
static jobject android_media_tv_Tuner_open_filter(
JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) {
sp<JTuner> tuner = getTuner(env, thiz);
+ DemuxFilterMainType mainType = static_cast<DemuxFilterMainType>(type);
DemuxFilterType filterType {
- .mainType = static_cast<DemuxFilterMainType>(type),
+ .mainType = mainType,
};
- // TODO: other sub types
- filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
+ switch(mainType) {
+ case DemuxFilterMainType::TS:
+ filterType.subType.tsFilterType(static_cast<DemuxTsFilterType>(subType));
+ break;
+ case DemuxFilterMainType::MMTP:
+ filterType.subType.mmtpFilterType(static_cast<DemuxMmtpFilterType>(subType));
+ break;
+ case DemuxFilterMainType::IP:
+ filterType.subType.ipFilterType(static_cast<DemuxIpFilterType>(subType));
+ break;
+ case DemuxFilterMainType::TLV:
+ filterType.subType.tlvFilterType(static_cast<DemuxTlvFilterType>(subType));
+ break;
+ case DemuxFilterMainType::ALP:
+ filterType.subType.alpFilterType(static_cast<DemuxAlpFilterType>(subType));
+ break;
+ }
return tuner->openFilter(filterType, bufferSize);
}
-static jobject android_media_tv_Tuner_open_time_filter(JNIEnv, jobject) {
- return NULL;
+static jobject android_media_tv_Tuner_open_time_filter(JNIEnv *env, jobject thiz) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openTimeFilter();
}
static DemuxFilterSectionBits getFilterSectionBits(JNIEnv *env, const jobject& settings) {
@@ -1848,26 +1920,98 @@
return 0;
}
-// TODO: implement TimeFilter functions
+static sp<TimeFilter> getTimeFilter(JNIEnv *env, jobject filter) {
+ return (TimeFilter *)env->GetLongField(filter, gFields.timeFilterContext);
+}
+
static int android_media_tv_Tuner_time_filter_set_timestamp(
- JNIEnv, jobject, jlong) {
- return 0;
+ JNIEnv *env, jobject filter, jlong timestamp) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed set timestamp: time filter not found");
+ return (int) Result::INVALID_STATE;
+ }
+ sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+ Result r = iFilterSp->setTimeStamp(static_cast<uint64_t>(timestamp));
+ return (int) r;
}
-static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv, jobject) {
- return 0;
+static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv *env, jobject filter) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed clear timestamp: time filter not found");
+ return (int) Result::INVALID_STATE;
+ }
+ sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+ Result r = iFilterSp->clearTimeStamp();
+ return (int) r;
}
-static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv, jobject) {
- return NULL;
+static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv *env, jobject filter) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed get timestamp: time filter not found");
+ return NULL;
+ }
+
+ sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+ Result res;
+ uint64_t timestamp;
+ iFilterSp->getTimeStamp(
+ [&](Result r, uint64_t t) {
+ res = r;
+ timestamp = t;
+ });
+ if (res != Result::SUCCESS) {
+ return NULL;
+ }
+
+ jclass longClazz = env->FindClass("java/lang/Long");
+ jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
+
+ jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp));
+ return longObj;
}
-static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv, jobject) {
- return NULL;
+static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv *env, jobject filter) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed get source time: time filter not found");
+ return NULL;
+ }
+
+ sp<ITimeFilter> iFilterSp = filterSp->getITimeFilter();
+ Result res;
+ uint64_t timestamp;
+ iFilterSp->getSourceTime(
+ [&](Result r, uint64_t t) {
+ res = r;
+ timestamp = t;
+ });
+ if (res != Result::SUCCESS) {
+ return NULL;
+ }
+
+ jclass longClazz = env->FindClass("java/lang/Long");
+ jmethodID longInit = env->GetMethodID(longClazz, "<init>", "(J)V");
+
+ jobject longObj = env->NewObject(longClazz, longInit, static_cast<jlong>(timestamp));
+ return longObj;
}
-static int android_media_tv_Tuner_time_filter_close(JNIEnv, jobject) {
- return 0;
+static int android_media_tv_Tuner_time_filter_close(JNIEnv *env, jobject filter) {
+ sp<TimeFilter> filterSp = getTimeFilter(env, filter);
+ if (filterSp == NULL) {
+ ALOGD("Failed close time filter: time filter not found");
+ return (int) Result::INVALID_STATE;
+ }
+
+ Result r = filterSp->getITimeFilter()->close();
+ if (r == Result::SUCCESS) {
+ filterSp->decStrong(filter);
+ env->SetLongField(filter, gFields.timeFilterContext, 0);
+ }
+ return (int) r;
}
static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index cfe99b3..381c125 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -54,6 +54,7 @@
using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
using ::android::hardware::tv::tuner::V1_0::ILnb;
using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
+using ::android::hardware::tv::tuner::V1_0::ITimeFilter;
using ::android::hardware::tv::tuner::V1_0::ITuner;
using ::android::hardware::tv::tuner::V1_0::LnbEventType;
using ::android::hardware::tv::tuner::V1_0::LnbId;
@@ -128,6 +129,14 @@
jweak mFilterObj;
};
+struct TimeFilter : public RefBase {
+ TimeFilter(sp<ITimeFilter> sp, jweak obj);
+ ~TimeFilter();
+ sp<ITimeFilter> getITimeFilter();
+ sp<ITimeFilter> mTimeFilterSp;
+ jweak mTimeFilterObj;
+};
+
struct JTuner : public RefBase {
JTuner(JNIEnv *env, jobject thiz);
sp<ITuner> getTunerService();
@@ -143,6 +152,7 @@
jobject getLnbIds();
jobject openLnbById(int id);
jobject openFilter(DemuxFilterType type, int bufferSize);
+ jobject openTimeFilter();
jobject openDescrambler();
jobject openDvr(DvrType type, int bufferSize);