diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java index 7932dcb06d884..ea066321f376f 100644 --- a/media/java/android/media/tv/tuner/Lnb.java +++ b/media/java/android/media/tv/tuner/Lnb.java @@ -156,7 +156,7 @@ public class Lnb implements AutoCloseable { private long mNativeContext; - Lnb(int id) { + private Lnb(int id) { mId = id; } diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index bcbc12b51a732..08a33f1f861c7 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -43,7 +43,11 @@ import android.media.tv.tuner.frontend.FrontendStatus; import android.media.tv.tuner.frontend.FrontendStatus.FrontendStatusType; import android.media.tv.tuner.frontend.OnTuneEventListener; import android.media.tv.tuner.frontend.ScanCallback; +import android.media.tv.tunerresourcemanager.ResourceClientProfile; +import android.media.tv.tunerresourcemanager.TunerLnbRequest; +import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.os.Message; @@ -67,6 +71,7 @@ public class Tuner implements AutoCloseable { private static final String TAG = "MediaTvTuner"; private static final boolean DEBUG = false; + private static final int MSG_RESOURCE_LOST = 1; private static final int MSG_ON_FILTER_EVENT = 2; private static final int MSG_ON_FILTER_STATUS = 3; private static final int MSG_ON_LNB_EVENT = 4; @@ -93,6 +98,8 @@ public class Tuner implements AutoCloseable { } private final Context mContext; + private final TunerResourceManager mTunerResourceManager; + private final int mClientId; private List mFrontendIds; private Frontend mFrontend; @@ -102,6 +109,7 @@ public class Tuner implements AutoCloseable { private List mLnbIds; private Lnb mLnb; + private Integer mLnbId; @Nullable private OnTuneEventListener mOnTuneEventListener; @Nullable @@ -115,6 +123,15 @@ public class Tuner implements AutoCloseable { @Nullable private Executor mOnResourceLostListenerExecutor; + + private final TunerResourceManager.ResourcesReclaimListener mResourceListener = + new TunerResourceManager.ResourcesReclaimListener() { + @Override + public void onReclaimResources() { + mHandler.sendMessage(mHandler.obtainMessage(MSG_RESOURCE_LOST)); + } + }; + /** * Constructs a Tuner instance. * @@ -127,6 +144,14 @@ public class Tuner implements AutoCloseable { @TvInputService.PriorityHintUseCaseType int useCase) { nativeSetup(); mContext = context; + mTunerResourceManager = (TunerResourceManager) + context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE); + + int[] clientId = new int[1]; + ResourceClientProfile profile = new ResourceClientProfile(tvInputSessionId, useCase); + mTunerResourceManager.registerClientProfile( + profile, new HandlerExecutor(mHandler), mResourceListener, clientId); + mClientId = clientId[0]; } /** @@ -226,6 +251,7 @@ public class Tuner implements AutoCloseable { private native List nativeGetLnbIds(); private native Lnb nativeOpenLnbById(int id); + private native Lnb nativeOpenLnbByName(String name); private native Descrambler nativeOpenDescrambler(); @@ -275,6 +301,14 @@ public class Tuner implements AutoCloseable { } break; } + case MSG_RESOURCE_LOST: { + if (mOnResourceLostListener != null + && mOnResourceLostListenerExecutor != null) { + mOnResourceLostListenerExecutor.execute( + () -> mOnResourceLostListener.onResourceLost(Tuner.this)); + } + break; + } default: // fall through } @@ -698,7 +732,10 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); TunerUtils.checkTunerPermission(mContext); - return openLnbByName(null, executor, cb); + if (mLnbId == null && !requestLnb()) { + return null; + } + return nativeOpenLnbById(mLnbId); } /** @@ -714,11 +751,21 @@ public class Tuner implements AutoCloseable { @Nullable public Lnb openLnbByName(@NonNull String name, @CallbackExecutor @NonNull Executor executor, @NonNull LnbCallback cb) { + Objects.requireNonNull(name, "LNB name must not be null"); Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); TunerUtils.checkTunerPermission(mContext); - // TODO: use resource manager to get LNB ID. - return new Lnb(0); + return nativeOpenLnbByName(name); + } + + private boolean requestLnb() { + int[] lnbId = new int[1]; + TunerLnbRequest request = new TunerLnbRequest(mClientId); + boolean granted = mTunerResourceManager.requestLnb(request, lnbId); + if (granted) { + mLnbId = lnbId[0]; + } + return granted; } /** diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 01f068a05fc36..679f18a6fbeca 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -1072,6 +1072,37 @@ jobject JTuner::openLnbById(int id) { return lnbObj; } +jobject JTuner::openLnbByName(jstring name) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + std::string lnbName(env->GetStringUTFChars(name, nullptr)); + sp iLnbSp; + Result res; + LnbId id; + mTuner->openLnbByName(lnbName, [&](Result r, LnbId lnbId, const sp& lnb) { + res = r; + iLnbSp = lnb; + id = lnbId; + }); + if (res != Result::SUCCESS || iLnbSp == nullptr) { + ALOGE("Failed to open lnb"); + return NULL; + } + mLnb = iLnbSp; + sp lnbCb = new LnbCallback(mObject, id); + mLnb->setCallback(lnbCb); + + jobject lnbObj = env->NewObject( + env->FindClass("android/media/tv/tuner/Lnb"), + gFields.lnbInitID, + id); + + sp lnbSp = new Lnb(iLnbSp, lnbObj); + lnbSp->incStrong(lnbObj); + env->SetLongField(lnbObj, gFields.lnbContext, (jlong) lnbSp.get()); + + return lnbObj; +} + int JTuner::tune(const FrontendSettings& settings) { if (mFe == NULL) { ALOGE("frontend is not initialized"); @@ -1872,8 +1903,7 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { jclass lnbClazz = env->FindClass("android/media/tv/tuner/Lnb"); gFields.lnbContext = env->GetFieldID(lnbClazz, "mNativeContext", "J"); - gFields.lnbInitID = - env->GetMethodID(lnbClazz, "", "(I)V"); + gFields.lnbInitID = env->GetMethodID(lnbClazz, "", "(I)V"); jclass filterClazz = env->FindClass("android/media/tv/tuner/filter/Filter"); gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J"); @@ -1996,6 +2026,12 @@ static jobject android_media_tv_Tuner_open_lnb_by_id(JNIEnv *env, jobject thiz, return tuner->openLnbById(id); } +static jobject android_media_tv_Tuner_open_lnb_by_name(JNIEnv *env, jobject thiz, jstring name) { + sp tuner = getTuner(env, thiz); + return tuner->openLnbByName(name); +} + + static jobject android_media_tv_Tuner_open_filter( JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) { sp tuner = getTuner(env, thiz); @@ -2888,6 +2924,8 @@ static const JNINativeMethod gTunerMethods[] = { (void *)android_media_tv_Tuner_get_lnb_ids }, { "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Lnb;", (void *)android_media_tv_Tuner_open_lnb_by_id }, + { "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;", + (void *)android_media_tv_Tuner_open_lnb_by_name }, { "nativeOpenDescrambler", "()Landroid/media/tv/tuner/Descrambler;", (void *)android_media_tv_Tuner_open_descrambler }, { "nativeOpenDvrRecorder", "(J)Landroid/media/tv/tuner/dvr/DvrRecorder;", diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index d3298a851fdde..3b8682f0a61bf 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -180,6 +180,7 @@ struct JTuner : public RefBase { int setLna(bool enable); jobject getLnbIds(); jobject openLnbById(int id); + jobject openLnbByName(jstring name); jobject openFilter(DemuxFilterType type, int bufferSize); jobject openTimeFilter(); jobject openDescrambler();