From f657da2d54772e076fdca0b1003d97df39113ac2 Mon Sep 17 00:00:00 2001 From: shubang Date: Wed, 5 Feb 2020 16:27:06 -0800 Subject: [PATCH] Tuner JNI: time filter Test: make; acloud create; Change-Id: I6bd53f6831e021d14b8d5762850a083acdbcf26a --- .../android/media/tv/tuner/TunerUtils.java | 29 +++ .../media/tv/tuner/filter/TimeFilter.java | 9 +- media/jni/android_media_tv_Tuner.cpp | 176 ++++++++++++++++-- media/jni/android_media_tv_Tuner.h | 10 + 4 files changed, 207 insertions(+), 17 deletions(-) diff --git a/media/java/android/media/tv/tuner/TunerUtils.java b/media/java/android/media/tv/tuner/TunerUtils.java index 30aaa0271eb08..ce18dc71e3d98 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 @@ public final class TunerUtils { "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 a926d59cdd031..371ccc44337af 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 @@ public class TimeFilter implements AutoCloseable { private native Long nativeGetSourceTime(); private native int nativeClose(); + private long mNativeContext; + private boolean mEnable = false; // Called by JNI code @@ -139,6 +143,9 @@ public class TimeFilter implements AutoCloseable { */ @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 ac59003de5e6e..a12deb5096cd1 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -117,10 +117,12 @@ using ::android::hardware::tv::tuner::V1_0::Result; 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 @@ sp Filter::getIFilter() { return mFilterSp; } +/////////////// TimeFilter /////////////////////// + +TimeFilter::TimeFilter(sp 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 TimeFilter::getITimeFilter() { + return mTimeFilterSp; +} + /////////////// FrontendCallback /////////////////////// FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {} @@ -702,6 +723,36 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { return filterObj; } +jobject JTuner::openTimeFilter() { + if (mDemux == NULL) { + if (!openDemux()) { + return NULL; + } + } + sp iTimeFilterSp; + Result res; + mDemux->openTimeFilter( + [&](Result r, const sp& 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 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 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { 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, "", "()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_lnb_by_id(JNIEnv *env, jobject thiz, static jobject android_media_tv_Tuner_open_filter( JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) { sp tuner = getTuner(env, thiz); + DemuxFilterMainType mainType = static_cast(type); DemuxFilterType filterType { - .mainType = static_cast(type), + .mainType = mainType, }; - // TODO: other sub types - filterType.subType.tsFilterType(static_cast(subType)); + switch(mainType) { + case DemuxFilterMainType::TS: + filterType.subType.tsFilterType(static_cast(subType)); + break; + case DemuxFilterMainType::MMTP: + filterType.subType.mmtpFilterType(static_cast(subType)); + break; + case DemuxFilterMainType::IP: + filterType.subType.ipFilterType(static_cast(subType)); + break; + case DemuxFilterMainType::TLV: + filterType.subType.tlvFilterType(static_cast(subType)); + break; + case DemuxFilterMainType::ALP: + filterType.subType.alpFilterType(static_cast(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 tuner = getTuner(env, thiz); + return tuner->openTimeFilter(); } static DemuxFilterSectionBits getFilterSectionBits(JNIEnv *env, const jobject& settings) { @@ -1848,26 +1920,98 @@ static int android_media_tv_Tuner_close_filter(JNIEnv*, jobject) { return 0; } -// TODO: implement TimeFilter functions +static sp 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 filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed set timestamp: time filter not found"); + return (int) Result::INVALID_STATE; + } + sp iFilterSp = filterSp->getITimeFilter(); + Result r = iFilterSp->setTimeStamp(static_cast(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 filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed clear timestamp: time filter not found"); + return (int) Result::INVALID_STATE; + } + sp 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 filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed get timestamp: time filter not found"); + return NULL; + } + + sp 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, "", "(J)V"); + + jobject longObj = env->NewObject(longClazz, longInit, static_cast(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 filterSp = getTimeFilter(env, filter); + if (filterSp == NULL) { + ALOGD("Failed get source time: time filter not found"); + return NULL; + } + + sp 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, "", "(J)V"); + + jobject longObj = env->NewObject(longClazz, longInit, static_cast(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 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 cfe99b399979c..381c125be0681 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::IFrontend; 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 @@ struct Filter : public RefBase { jweak mFilterObj; }; +struct TimeFilter : public RefBase { + TimeFilter(sp sp, jweak obj); + ~TimeFilter(); + sp getITimeFilter(); + sp mTimeFilterSp; + jweak mTimeFilterObj; +}; + struct JTuner : public RefBase { JTuner(JNIEnv *env, jobject thiz); sp getTunerService(); @@ -143,6 +152,7 @@ struct JTuner : public RefBase { jobject getLnbIds(); jobject openLnbById(int id); jobject openFilter(DemuxFilterType type, int bufferSize); + jobject openTimeFilter(); jobject openDescrambler(); jobject openDvr(DvrType type, int bufferSize);