Loading media/java/android/media/tv/tuner/Tuner.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -906,6 +906,7 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(l, "OnRecordStatusChangedListener must not be null"); Objects.requireNonNull(l, "OnRecordStatusChangedListener must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); DvrRecorder dvr = nativeOpenDvrRecorder(bufferSize); DvrRecorder dvr = nativeOpenDvrRecorder(bufferSize); dvr.setListener(executor, l); return dvr; return dvr; } } Loading @@ -928,6 +929,7 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(l, "OnPlaybackStatusChangedListener must not be null"); Objects.requireNonNull(l, "OnPlaybackStatusChangedListener must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); DvrPlayback dvr = nativeOpenDvrPlayback(bufferSize); DvrPlayback dvr = nativeOpenDvrPlayback(bufferSize); dvr.setListener(executor, l); return dvr; return dvr; } } Loading media/java/android/media/tv/tuner/dvr/DvrPlayback.java +22 −1 Original line number Original line Diff line number Diff line Loading @@ -21,12 +21,15 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.hardware.tv.tuner.V1_0.Constants; import android.hardware.tv.tuner.V1_0.Constants; import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.TunerUtils; import android.media.tv.tuner.filter.Filter; import android.media.tv.tuner.filter.Filter; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; /** /** * Digital Video Record (DVR) class which provides playback control on Demux's input buffer. * Digital Video Record (DVR) class which provides playback control on Demux's input buffer. Loading Loading @@ -70,6 +73,8 @@ public class DvrPlayback implements AutoCloseable { public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL; public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL; private long mNativeContext; private long mNativeContext; private OnPlaybackStatusChangedListener mListener; private Executor mExecutor; private native int nativeAttachFilter(Filter filter); private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); Loading @@ -85,6 +90,19 @@ public class DvrPlayback implements AutoCloseable { private DvrPlayback() { private DvrPlayback() { } } /** @hide */ public void setListener( @NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) { mExecutor = executor; mListener = listener; } private void onPlaybackStatusChanged(int status) { if (mExecutor != null && mListener != null) { mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status)); } } /** /** * Attaches a filter to DVR interface for recording. * Attaches a filter to DVR interface for recording. Loading Loading @@ -164,7 +182,10 @@ public class DvrPlayback implements AutoCloseable { */ */ @Override @Override public void close() { public void close() { nativeClose(); int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "failed to close DVR playback"); } } } /** /** Loading media/java/android/media/tv/tuner/dvr/DvrRecorder.java +27 −1 Original line number Original line Diff line number Diff line Loading @@ -19,10 +19,14 @@ package android.media.tv.tuner.dvr; import android.annotation.BytesLong; import android.annotation.BytesLong; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.TunerUtils; import android.media.tv.tuner.filter.Filter; import android.media.tv.tuner.filter.Filter; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import java.util.concurrent.Executor; /** /** * Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer. * Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer. * * Loading @@ -31,6 +35,8 @@ import android.os.ParcelFileDescriptor; @SystemApi @SystemApi public class DvrRecorder implements AutoCloseable { public class DvrRecorder implements AutoCloseable { private long mNativeContext; private long mNativeContext; private OnRecordStatusChangedListener mListener; private Executor mExecutor; private native int nativeAttachFilter(Filter filter); private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); Loading @@ -46,6 +52,19 @@ public class DvrRecorder implements AutoCloseable { private DvrRecorder() { private DvrRecorder() { } } /** @hide */ public void setListener( @NonNull Executor executor, @NonNull OnRecordStatusChangedListener listener) { mExecutor = executor; mListener = listener; } private void onRecordStatusChanged(int status) { if (mExecutor != null && mListener != null) { mExecutor.execute(() -> mListener.onRecordStatusChanged(status)); } } /** /** * Attaches a filter to DVR interface for recording. * Attaches a filter to DVR interface for recording. Loading Loading @@ -125,7 +144,10 @@ public class DvrRecorder implements AutoCloseable { */ */ @Override @Override public void close() { public void close() { nativeClose(); int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "failed to close DVR recorder"); } } } /** /** Loading Loading @@ -163,6 +185,10 @@ public class DvrRecorder implements AutoCloseable { */ */ @BytesLong @BytesLong public long write(@NonNull byte[] bytes, @BytesLong long offset, @BytesLong long size) { public long write(@NonNull byte[] bytes, @BytesLong long offset, @BytesLong long size) { if (size + offset > bytes.length) { throw new ArrayIndexOutOfBoundsException( "Array length=" + bytes.length + ", offset=" + offset + ", size=" + size); } return nativeWrite(bytes, offset, size); return nativeWrite(bytes, offset, size); } } } } media/jni/android_media_tv_Tuner.cpp +163 −74 Original line number Original line Diff line number Diff line Loading @@ -151,6 +151,8 @@ struct fields_t { jmethodID onFilterEventID; jmethodID onFilterEventID; jmethodID lnbInitID; jmethodID lnbInitID; jmethodID onLnbEventID; jmethodID onLnbEventID; jmethodID onDvrRecordStatusID; jmethodID onDvrPlaybackStatusID; jmethodID descramblerInitID; jmethodID descramblerInitID; jmethodID linearBlockInitID; jmethodID linearBlockInitID; jmethodID linearBlockSetInternalStateID; jmethodID linearBlockSetInternalStateID; Loading Loading @@ -198,13 +200,23 @@ sp<ILnb> Lnb::getILnb() { } } /////////////// DvrCallback /////////////////////// /////////////// DvrCallback /////////////////////// Return<void> DvrCallback::onRecordStatus(RecordStatus /*status*/) { Return<void> DvrCallback::onRecordStatus(RecordStatus status) { ALOGD("DvrCallback::onRecordStatus"); ALOGD("DvrCallback::onRecordStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod( mDvr, gFields.onDvrRecordStatusID, (jint) status); return Void(); return Void(); } } Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus /*status*/) { Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus status) { ALOGD("DvrCallback::onPlaybackStatus"); ALOGD("DvrCallback::onPlaybackStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod( mDvr, gFields.onDvrPlaybackStatusID, (jint) status); return Void(); return Void(); } } Loading @@ -214,27 +226,40 @@ void DvrCallback::setDvr(const jobject dvr) { mDvr = env->NewWeakGlobalRef(dvr); mDvr = env->NewWeakGlobalRef(dvr); } } DvrCallback::~DvrCallback() { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mDvr != NULL) { env->DeleteWeakGlobalRef(mDvr); mDvr = NULL; } } /////////////// Dvr /////////////////////// /////////////// Dvr /////////////////////// Dvr::Dvr(sp<IDvr> sp, jweak obj) : mDvrSp(sp), mDvrObj(obj), mDvrMQEventFlag(nullptr) {} Dvr::Dvr(sp<IDvr> sp, jobject obj) : mDvrSp(sp), mDvrMQEventFlag(nullptr) { JNIEnv *env = AndroidRuntime::getJNIEnv(); mDvrObj = env->NewWeakGlobalRef(obj); } Dvr::~Dvr() { Dvr::~Dvr() { EventFlag::deleteEventFlag(&mDvrMQEventFlag); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mDvrObj); mDvrObj = NULL; } } int Dvr::close() { jint Dvr::close() { Result r = mDvrSp->close(); Result r = mDvrSp->close(); if (r == Result::SUCCESS) { if (r == Result::SUCCESS) { EventFlag::deleteEventFlag(&mDvrMQEventFlag); EventFlag::deleteEventFlag(&mDvrMQEventFlag); } } return (int)r; return (jint) r; } } sp<IDvr> Dvr::getIDvr() { sp<IDvr> Dvr::getIDvr() { return mDvrSp; return mDvrSp; } } DvrMQ& Dvr::getDvrMQ() { MQ& Dvr::getDvrMQ() { return *mDvrMQ; return *mDvrMQ; } } Loading Loading @@ -558,6 +583,14 @@ void FilterCallback::setFilter(const jobject filter) { mFilter = env->NewWeakGlobalRef(filter); mFilter = env->NewWeakGlobalRef(filter); } } FilterCallback::~FilterCallback() { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mFilter != NULL) { env->DeleteWeakGlobalRef(mFilter); mFilter = NULL; } } /////////////// Filter /////////////////////// /////////////// Filter /////////////////////// Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) { Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) { Loading Loading @@ -785,6 +818,7 @@ JTuner::JTuner(JNIEnv *env, jobject thiz) JTuner::~JTuner() { JTuner::~JTuner() { JNIEnv *env = AndroidRuntime::getJNIEnv(); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mObject); env->DeleteGlobalRef(mClass); env->DeleteGlobalRef(mClass); mTuner = NULL; mTuner = NULL; mClass = NULL; mClass = NULL; Loading Loading @@ -1988,10 +2022,14 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { jclass dvrRecorderClazz = env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"); jclass dvrRecorderClazz = env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"); gFields.dvrRecorderContext = env->GetFieldID(dvrRecorderClazz, "mNativeContext", "J"); gFields.dvrRecorderContext = env->GetFieldID(dvrRecorderClazz, "mNativeContext", "J"); gFields.dvrRecorderInitID = env->GetMethodID(dvrRecorderClazz, "<init>", "()V"); gFields.dvrRecorderInitID = env->GetMethodID(dvrRecorderClazz, "<init>", "()V"); gFields.onDvrRecordStatusID = env->GetMethodID(dvrRecorderClazz, "onRecordStatusChanged", "(I)V"); jclass dvrPlaybackClazz = env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"); jclass dvrPlaybackClazz = env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"); gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J"); gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J"); gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "<init>", "()V"); gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "<init>", "()V"); gFields.onDvrPlaybackStatusID = env->GetMethodID(dvrRecorderClazz, "onPlaybackStatusChanged", "(I)V"); jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V"); gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V"); Loading Loading @@ -2485,10 +2523,11 @@ static DemuxFilterSettings getFilterConfiguration( return filterSettings; return filterSettings; } } static jint copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jlong offset, jlong size) { static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyteArray buffer, jlong offset, jlong size) { ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset); ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset); jlong available = filter->mFilterMQ->availableToRead(); jlong available = mq->availableToRead(); ALOGD("copyData, available=%ld", (long) available); ALOGD("copyData, available=%ld", (long) available); size = std::min(size, available); size = std::min(size, available); Loading @@ -2500,9 +2539,9 @@ static jint copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jlong of return 0; return 0; } } if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) { if (mq->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) { env->ReleaseByteArrayElements(buffer, dst, 0); env->ReleaseByteArrayElements(buffer, dst, 0); filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); flag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); } else { } else { ALOGD("Failed to read FMQ"); ALOGD("Failed to read FMQ"); env->ReleaseByteArrayElements(buffer, dst, 0); env->ReleaseByteArrayElements(buffer, dst, 0); Loading Loading @@ -2537,7 +2576,7 @@ static jint android_media_tv_Tuner_configure_filter( ALOGD("getFilterQueueDesc"); ALOGD("getFilterQueueDesc"); }); }); if (getQueueDescResult == Result::SUCCESS) { if (getQueueDescResult == Result::SUCCESS) { filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true); filterSp->mFilterMQ = std::make_unique<MQ>(filterMQDesc, true); EventFlag::createEventFlag( EventFlag::createEventFlag( filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); } } Loading Loading @@ -2622,7 +2661,7 @@ static jint android_media_tv_Tuner_read_filter_fmq( ALOGD("Failed to read filter FMQ: filter not found"); ALOGD("Failed to read filter FMQ: filter not found"); return (jint) Result::INVALID_STATE; return (jint) Result::INVALID_STATE; } } return copyData(env, filterSp, buffer, offset, size); return copyData(env, filterSp->mFilterMQ, filterSp->mFilterMQEventFlag, buffer, offset, size); } } static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) { static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) { Loading Loading @@ -2781,36 +2820,48 @@ static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) return tuner->getDemuxCaps(); return tuner->getDemuxCaps(); } } static int android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); sp<Dvr> dvrSp = getDvr(env, dvr); sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL) { if (dvrSp == NULL || iFilterSp == NULL) { return (jint) Result::NOT_INITIALIZED; return false; } } Result result = dvrSp->attachFilter(iFilterSp); sp<Filter> filterSp = getFilter(env, filter); return (int) result; if (filterSp == NULL) { return (jint) Result::INVALID_ARGUMENT; } sp<IDvr> iDvrSp = dvrSp->getIDvr(); sp<IFilter> iFilterSp = filterSp->getIFilter(); Result result = iDvrSp->attachFilter(iFilterSp); return (jint) result; } } static int android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { static jint android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); sp<Dvr> dvrSp = getDvr(env, dvr); sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL) { if (dvrSp == NULL || iFilterSp == NULL) { return (jint) Result::NOT_INITIALIZED; return false; } } Result result = dvrSp->detachFilter(iFilterSp); sp<Filter> filterSp = getFilter(env, filter); return (int) result; if (filterSp == NULL) { return (jint) Result::INVALID_ARGUMENT; } sp<IDvr> iDvrSp = dvrSp->getIDvr(); sp<IFilter> iFilterSp = filterSp->getIFilter(); Result result = iDvrSp->detachFilter(iFilterSp); return (jint) result; } } static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) { static jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) { sp<Dvr> dvrSp = getDvr(env, dvr); sp<Dvr> dvrSp = getDvr(env, dvr); sp<IDvr> iDvrSp = dvrSp->getIDvr(); if (dvrSp == NULL) { if (dvrSp == NULL) { ALOGD("Failed to configure dvr: dvr not found"); ALOGD("Failed to configure dvr: dvr not found"); return (int)Result::INVALID_STATE; return (int)Result::NOT_INITIALIZED; } } sp<IDvr> iDvrSp = dvrSp->getIDvr(); Result result = iDvrSp->configure(getDvrSettings(env, settings)); Result result = iDvrSp->configure(getDvrSettings(env, settings)); if (result != Result::SUCCESS) { return (jint) result; } MQDescriptorSync<uint8_t> dvrMQDesc; MQDescriptorSync<uint8_t> dvrMQDesc; if (result == Result::SUCCESS) { Result getQueueDescResult = Result::UNKNOWN_ERROR; Result getQueueDescResult = Result::UNKNOWN_ERROR; iDvrSp->getQueueDesc( iDvrSp->getQueueDesc( [&](Result r, const MQDescriptorSync<uint8_t>& desc) { [&](Result r, const MQDescriptorSync<uint8_t>& desc) { Loading @@ -2819,48 +2870,53 @@ static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobjec ALOGD("getDvrQueueDesc"); ALOGD("getDvrQueueDesc"); }); }); if (getQueueDescResult == Result::SUCCESS) { if (getQueueDescResult == Result::SUCCESS) { dvrSp->mDvrMQ = std::make_unique<DvrMQ>(dvrMQDesc, true); dvrSp->mDvrMQ = std::make_unique<MQ>(dvrMQDesc, true); EventFlag::createEventFlag( EventFlag::createEventFlag( dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag)); dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag)); } } return (jint) getQueueDescResult; } } return (int)result; } static int android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { if (dvrSp == NULL) { ALOGD("Failed to start dvr: dvr not found"); ALOGD("Failed to start dvr: dvr not found"); return false; return (jint) Result::NOT_INITIALIZED; } } sp<IDvr> iDvrSp = dvrSp->getIDvr(); Result result = dvrSp->start(); Result result = iDvrSp->start(); return (int) result; return (jint) result; } } static int android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) { static jint android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { if (dvrSp == NULL) { ALOGD("Failed to stop dvr: dvr not found"); ALOGD("Failed to stop dvr: dvr not found"); return false; return (jint) Result::NOT_INITIALIZED; } } Result result = dvrSp->stop(); sp<IDvr> iDvrSp = dvrSp->getIDvr(); return (int) result; Result result = iDvrSp->stop(); return (jint) result; } } static int android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) { static jint android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { if (dvrSp == NULL) { ALOGD("Failed to flush dvr: dvr not found"); ALOGD("Failed to flush dvr: dvr not found"); return false; return (jint) Result::NOT_INITIALIZED; } } Result result = dvrSp->flush(); sp<IDvr> iDvrSp = dvrSp->getIDvr(); return (int) result; Result result = iDvrSp->flush(); return (jint) result; } } static int android_media_tv_Tuner_close_dvr(JNIEnv*, jobject) { static jint android_media_tv_Tuner_close_dvr(JNIEnv* env, jobject dvr) { return 0; sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { ALOGD("Failed to close dvr: dvr not found"); return (jint) Result::NOT_INITIALIZED; } return dvrSp->close(); } } static sp<Lnb> getLnb(JNIEnv *env, jobject lnb) { static sp<Lnb> getLnb(JNIEnv *env, jobject lnb) { Loading Loading @@ -2916,7 +2972,7 @@ static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong siz long available = dvrSp->mDvrMQ->availableToWrite(); long available = dvrSp->mDvrMQ->availableToWrite(); long write = std::min((long) size, available); long write = std::min((long) size, available); DvrMQ::MemTransaction tx; MQ::MemTransaction tx; long ret = 0; long ret = 0; if (dvrSp->mDvrMQ->beginWrite(write, &tx)) { if (dvrSp->mDvrMQ->beginWrite(write, &tx)) { auto first = tx.getFirstRegion(); auto first = tx.getFirstRegion(); Loading Loading @@ -2947,11 +3003,37 @@ static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong siz } } static jlong android_media_tv_Tuner_read_dvr_from_array( static jlong android_media_tv_Tuner_read_dvr_from_array( JNIEnv /* *env */, jobject /* dvr */, jbyteArray /* bytes */, jlong /* offset */, JNIEnv* env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) { jlong /* size */) { sp<Dvr> dvrSp = getDvr(env, dvr); //TODO: impl if (dvrSp == NULL) { ALOGW("Failed to read dvr: dvr not found"); return 0; return 0; } } if (dvrSp->mDvrMQ == NULL) { ALOGW("Failed to read dvr: dvr not configured"); return 0; } jlong available = dvrSp->mDvrMQ->availableToWrite(); size = std::min(size, available); jboolean isCopy; jbyte *src = env->GetByteArrayElements(buffer, &isCopy); if (src == nullptr) { ALOGD("Failed to GetByteArrayElements"); return 0; } if (dvrSp->mDvrMQ->write(reinterpret_cast<unsigned char*>(src) + offset, size)) { env->ReleaseByteArrayElements(buffer, src, 0); dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); } else { ALOGD("Failed to write FMQ"); env->ReleaseByteArrayElements(buffer, src, 0); return 0; } return size; } static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong size) { static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong size) { sp<Dvr> dvrSp = getDvr(env, dvr); sp<Dvr> dvrSp = getDvr(env, dvr); Loading @@ -2965,13 +3047,13 @@ static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong si return 0; return 0; } } DvrMQ& dvrMq = dvrSp->getDvrMQ(); MQ& dvrMq = dvrSp->getDvrMQ(); long available = dvrMq.availableToRead(); long available = dvrMq.availableToRead(); long toRead = std::min((long) size, available); long toRead = std::min((long) size, available); long ret = 0; long ret = 0; DvrMQ::MemTransaction tx; MQ::MemTransaction tx; if (dvrMq.beginRead(toRead, &tx)) { if (dvrMq.beginRead(toRead, &tx)) { auto first = tx.getFirstRegion(); auto first = tx.getFirstRegion(); auto data = first.getAddress(); auto data = first.getAddress(); Loading Loading @@ -3001,11 +3083,18 @@ static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong si } } static jlong android_media_tv_Tuner_write_dvr_to_array( static jlong android_media_tv_Tuner_write_dvr_to_array( JNIEnv /* *env */, jobject /* dvr */, jbyteArray /* bytes */, jlong /* offset */, JNIEnv *env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) { jlong /* size */) { sp<Dvr> dvrSp = getDvr(env, dvr); //TODO: impl if (dvrSp == NULL) { ALOGW("Failed to write dvr: dvr not found"); return 0; return 0; } } if (dvrSp->mDvrMQ == NULL) { ALOGW("Failed to write dvr: dvr not configured"); return 0; } return copyData(env, dvrSp->mDvrMQ, dvrSp->mDvrMQEventFlag, buffer, offset, size); } static const JNINativeMethod gTunerMethods[] = { static const JNINativeMethod gTunerMethods[] = { { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init }, { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init }, Loading media/jni/android_media_tv_Tuner.h +7 −6 Original line number Original line Diff line number Diff line Loading @@ -62,8 +62,7 @@ using ::android::hardware::tv::tuner::V1_0::PlaybackStatus; using ::android::hardware::tv::tuner::V1_0::RecordStatus; using ::android::hardware::tv::tuner::V1_0::RecordStatus; using ::android::hardware::tv::tuner::V1_0::Result; using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; using MQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; namespace android { namespace android { Loading @@ -84,6 +83,7 @@ struct Lnb : public RefBase { }; }; struct DvrCallback : public IDvrCallback { struct DvrCallback : public IDvrCallback { ~DvrCallback(); virtual Return<void> onRecordStatus(RecordStatus status); virtual Return<void> onRecordStatus(RecordStatus status); virtual Return<void> onPlaybackStatus(PlaybackStatus status); virtual Return<void> onPlaybackStatus(PlaybackStatus status); Loading @@ -95,18 +95,19 @@ private: struct Dvr : public RefBase { struct Dvr : public RefBase { Dvr(sp<IDvr> sp, jweak obj); Dvr(sp<IDvr> sp, jweak obj); ~Dvr(); ~Dvr(); int close(); jint close(); DvrMQ& getDvrMQ(); MQ& getDvrMQ(); sp<IDvr> getIDvr(); sp<IDvr> getIDvr(); sp<IDvr> mDvrSp; sp<IDvr> mDvrSp; jweak mDvrObj; jweak mDvrObj; std::unique_ptr<DvrMQ> mDvrMQ; std::unique_ptr<MQ> mDvrMQ; EventFlag* mDvrMQEventFlag; EventFlag* mDvrMQEventFlag; std::string mFilePath; std::string mFilePath; int mFd; int mFd; }; }; struct FilterCallback : public IFilterCallback { struct FilterCallback : public IFilterCallback { ~FilterCallback(); virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent); virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent); virtual Return<void> onFilterStatus(const DemuxFilterStatus status); virtual Return<void> onFilterStatus(const DemuxFilterStatus status); Loading Loading @@ -149,7 +150,7 @@ struct Filter : public RefBase { int close(); int close(); sp<IFilter> getIFilter(); sp<IFilter> getIFilter(); sp<IFilter> mFilterSp; sp<IFilter> mFilterSp; std::unique_ptr<FilterMQ> mFilterMQ; std::unique_ptr<MQ> mFilterMQ; EventFlag* mFilterMQEventFlag; EventFlag* mFilterMQEventFlag; jweak mFilterObj; jweak mFilterObj; }; }; Loading Loading
media/java/android/media/tv/tuner/Tuner.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -906,6 +906,7 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(l, "OnRecordStatusChangedListener must not be null"); Objects.requireNonNull(l, "OnRecordStatusChangedListener must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); DvrRecorder dvr = nativeOpenDvrRecorder(bufferSize); DvrRecorder dvr = nativeOpenDvrRecorder(bufferSize); dvr.setListener(executor, l); return dvr; return dvr; } } Loading @@ -928,6 +929,7 @@ public class Tuner implements AutoCloseable { Objects.requireNonNull(l, "OnPlaybackStatusChangedListener must not be null"); Objects.requireNonNull(l, "OnPlaybackStatusChangedListener must not be null"); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX); DvrPlayback dvr = nativeOpenDvrPlayback(bufferSize); DvrPlayback dvr = nativeOpenDvrPlayback(bufferSize); dvr.setListener(executor, l); return dvr; return dvr; } } Loading
media/java/android/media/tv/tuner/dvr/DvrPlayback.java +22 −1 Original line number Original line Diff line number Diff line Loading @@ -21,12 +21,15 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.hardware.tv.tuner.V1_0.Constants; import android.hardware.tv.tuner.V1_0.Constants; import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.TunerUtils; import android.media.tv.tuner.filter.Filter; import android.media.tv.tuner.filter.Filter; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import java.lang.annotation.Retention; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; /** /** * Digital Video Record (DVR) class which provides playback control on Demux's input buffer. * Digital Video Record (DVR) class which provides playback control on Demux's input buffer. Loading Loading @@ -70,6 +73,8 @@ public class DvrPlayback implements AutoCloseable { public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL; public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL; private long mNativeContext; private long mNativeContext; private OnPlaybackStatusChangedListener mListener; private Executor mExecutor; private native int nativeAttachFilter(Filter filter); private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); Loading @@ -85,6 +90,19 @@ public class DvrPlayback implements AutoCloseable { private DvrPlayback() { private DvrPlayback() { } } /** @hide */ public void setListener( @NonNull Executor executor, @NonNull OnPlaybackStatusChangedListener listener) { mExecutor = executor; mListener = listener; } private void onPlaybackStatusChanged(int status) { if (mExecutor != null && mListener != null) { mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status)); } } /** /** * Attaches a filter to DVR interface for recording. * Attaches a filter to DVR interface for recording. Loading Loading @@ -164,7 +182,10 @@ public class DvrPlayback implements AutoCloseable { */ */ @Override @Override public void close() { public void close() { nativeClose(); int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "failed to close DVR playback"); } } } /** /** Loading
media/java/android/media/tv/tuner/dvr/DvrRecorder.java +27 −1 Original line number Original line Diff line number Diff line Loading @@ -19,10 +19,14 @@ package android.media.tv.tuner.dvr; import android.annotation.BytesLong; import android.annotation.BytesLong; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.SystemApi; import android.media.tv.tuner.Tuner; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.Tuner.Result; import android.media.tv.tuner.TunerUtils; import android.media.tv.tuner.filter.Filter; import android.media.tv.tuner.filter.Filter; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import java.util.concurrent.Executor; /** /** * Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer. * Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer. * * Loading @@ -31,6 +35,8 @@ import android.os.ParcelFileDescriptor; @SystemApi @SystemApi public class DvrRecorder implements AutoCloseable { public class DvrRecorder implements AutoCloseable { private long mNativeContext; private long mNativeContext; private OnRecordStatusChangedListener mListener; private Executor mExecutor; private native int nativeAttachFilter(Filter filter); private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); Loading @@ -46,6 +52,19 @@ public class DvrRecorder implements AutoCloseable { private DvrRecorder() { private DvrRecorder() { } } /** @hide */ public void setListener( @NonNull Executor executor, @NonNull OnRecordStatusChangedListener listener) { mExecutor = executor; mListener = listener; } private void onRecordStatusChanged(int status) { if (mExecutor != null && mListener != null) { mExecutor.execute(() -> mListener.onRecordStatusChanged(status)); } } /** /** * Attaches a filter to DVR interface for recording. * Attaches a filter to DVR interface for recording. Loading Loading @@ -125,7 +144,10 @@ public class DvrRecorder implements AutoCloseable { */ */ @Override @Override public void close() { public void close() { nativeClose(); int res = nativeClose(); if (res != Tuner.RESULT_SUCCESS) { TunerUtils.throwExceptionForResult(res, "failed to close DVR recorder"); } } } /** /** Loading Loading @@ -163,6 +185,10 @@ public class DvrRecorder implements AutoCloseable { */ */ @BytesLong @BytesLong public long write(@NonNull byte[] bytes, @BytesLong long offset, @BytesLong long size) { public long write(@NonNull byte[] bytes, @BytesLong long offset, @BytesLong long size) { if (size + offset > bytes.length) { throw new ArrayIndexOutOfBoundsException( "Array length=" + bytes.length + ", offset=" + offset + ", size=" + size); } return nativeWrite(bytes, offset, size); return nativeWrite(bytes, offset, size); } } } }
media/jni/android_media_tv_Tuner.cpp +163 −74 Original line number Original line Diff line number Diff line Loading @@ -151,6 +151,8 @@ struct fields_t { jmethodID onFilterEventID; jmethodID onFilterEventID; jmethodID lnbInitID; jmethodID lnbInitID; jmethodID onLnbEventID; jmethodID onLnbEventID; jmethodID onDvrRecordStatusID; jmethodID onDvrPlaybackStatusID; jmethodID descramblerInitID; jmethodID descramblerInitID; jmethodID linearBlockInitID; jmethodID linearBlockInitID; jmethodID linearBlockSetInternalStateID; jmethodID linearBlockSetInternalStateID; Loading Loading @@ -198,13 +200,23 @@ sp<ILnb> Lnb::getILnb() { } } /////////////// DvrCallback /////////////////////// /////////////// DvrCallback /////////////////////// Return<void> DvrCallback::onRecordStatus(RecordStatus /*status*/) { Return<void> DvrCallback::onRecordStatus(RecordStatus status) { ALOGD("DvrCallback::onRecordStatus"); ALOGD("DvrCallback::onRecordStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod( mDvr, gFields.onDvrRecordStatusID, (jint) status); return Void(); return Void(); } } Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus /*status*/) { Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus status) { ALOGD("DvrCallback::onPlaybackStatus"); ALOGD("DvrCallback::onPlaybackStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod( mDvr, gFields.onDvrPlaybackStatusID, (jint) status); return Void(); return Void(); } } Loading @@ -214,27 +226,40 @@ void DvrCallback::setDvr(const jobject dvr) { mDvr = env->NewWeakGlobalRef(dvr); mDvr = env->NewWeakGlobalRef(dvr); } } DvrCallback::~DvrCallback() { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mDvr != NULL) { env->DeleteWeakGlobalRef(mDvr); mDvr = NULL; } } /////////////// Dvr /////////////////////// /////////////// Dvr /////////////////////// Dvr::Dvr(sp<IDvr> sp, jweak obj) : mDvrSp(sp), mDvrObj(obj), mDvrMQEventFlag(nullptr) {} Dvr::Dvr(sp<IDvr> sp, jobject obj) : mDvrSp(sp), mDvrMQEventFlag(nullptr) { JNIEnv *env = AndroidRuntime::getJNIEnv(); mDvrObj = env->NewWeakGlobalRef(obj); } Dvr::~Dvr() { Dvr::~Dvr() { EventFlag::deleteEventFlag(&mDvrMQEventFlag); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mDvrObj); mDvrObj = NULL; } } int Dvr::close() { jint Dvr::close() { Result r = mDvrSp->close(); Result r = mDvrSp->close(); if (r == Result::SUCCESS) { if (r == Result::SUCCESS) { EventFlag::deleteEventFlag(&mDvrMQEventFlag); EventFlag::deleteEventFlag(&mDvrMQEventFlag); } } return (int)r; return (jint) r; } } sp<IDvr> Dvr::getIDvr() { sp<IDvr> Dvr::getIDvr() { return mDvrSp; return mDvrSp; } } DvrMQ& Dvr::getDvrMQ() { MQ& Dvr::getDvrMQ() { return *mDvrMQ; return *mDvrMQ; } } Loading Loading @@ -558,6 +583,14 @@ void FilterCallback::setFilter(const jobject filter) { mFilter = env->NewWeakGlobalRef(filter); mFilter = env->NewWeakGlobalRef(filter); } } FilterCallback::~FilterCallback() { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mFilter != NULL) { env->DeleteWeakGlobalRef(mFilter); mFilter = NULL; } } /////////////// Filter /////////////////////// /////////////// Filter /////////////////////// Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) { Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) { Loading Loading @@ -785,6 +818,7 @@ JTuner::JTuner(JNIEnv *env, jobject thiz) JTuner::~JTuner() { JTuner::~JTuner() { JNIEnv *env = AndroidRuntime::getJNIEnv(); JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mObject); env->DeleteGlobalRef(mClass); env->DeleteGlobalRef(mClass); mTuner = NULL; mTuner = NULL; mClass = NULL; mClass = NULL; Loading Loading @@ -1988,10 +2022,14 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { jclass dvrRecorderClazz = env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"); jclass dvrRecorderClazz = env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"); gFields.dvrRecorderContext = env->GetFieldID(dvrRecorderClazz, "mNativeContext", "J"); gFields.dvrRecorderContext = env->GetFieldID(dvrRecorderClazz, "mNativeContext", "J"); gFields.dvrRecorderInitID = env->GetMethodID(dvrRecorderClazz, "<init>", "()V"); gFields.dvrRecorderInitID = env->GetMethodID(dvrRecorderClazz, "<init>", "()V"); gFields.onDvrRecordStatusID = env->GetMethodID(dvrRecorderClazz, "onRecordStatusChanged", "(I)V"); jclass dvrPlaybackClazz = env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"); jclass dvrPlaybackClazz = env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"); gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J"); gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J"); gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "<init>", "()V"); gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "<init>", "()V"); gFields.onDvrPlaybackStatusID = env->GetMethodID(dvrRecorderClazz, "onPlaybackStatusChanged", "(I)V"); jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V"); gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V"); Loading Loading @@ -2485,10 +2523,11 @@ static DemuxFilterSettings getFilterConfiguration( return filterSettings; return filterSettings; } } static jint copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jlong offset, jlong size) { static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyteArray buffer, jlong offset, jlong size) { ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset); ALOGD("copyData, size=%ld, offset=%ld", (long) size, (long) offset); jlong available = filter->mFilterMQ->availableToRead(); jlong available = mq->availableToRead(); ALOGD("copyData, available=%ld", (long) available); ALOGD("copyData, available=%ld", (long) available); size = std::min(size, available); size = std::min(size, available); Loading @@ -2500,9 +2539,9 @@ static jint copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jlong of return 0; return 0; } } if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) { if (mq->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) { env->ReleaseByteArrayElements(buffer, dst, 0); env->ReleaseByteArrayElements(buffer, dst, 0); filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); flag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); } else { } else { ALOGD("Failed to read FMQ"); ALOGD("Failed to read FMQ"); env->ReleaseByteArrayElements(buffer, dst, 0); env->ReleaseByteArrayElements(buffer, dst, 0); Loading Loading @@ -2537,7 +2576,7 @@ static jint android_media_tv_Tuner_configure_filter( ALOGD("getFilterQueueDesc"); ALOGD("getFilterQueueDesc"); }); }); if (getQueueDescResult == Result::SUCCESS) { if (getQueueDescResult == Result::SUCCESS) { filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true); filterSp->mFilterMQ = std::make_unique<MQ>(filterMQDesc, true); EventFlag::createEventFlag( EventFlag::createEventFlag( filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); } } Loading Loading @@ -2622,7 +2661,7 @@ static jint android_media_tv_Tuner_read_filter_fmq( ALOGD("Failed to read filter FMQ: filter not found"); ALOGD("Failed to read filter FMQ: filter not found"); return (jint) Result::INVALID_STATE; return (jint) Result::INVALID_STATE; } } return copyData(env, filterSp, buffer, offset, size); return copyData(env, filterSp->mFilterMQ, filterSp->mFilterMQEventFlag, buffer, offset, size); } } static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) { static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) { Loading Loading @@ -2781,36 +2820,48 @@ static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) return tuner->getDemuxCaps(); return tuner->getDemuxCaps(); } } static int android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); sp<Dvr> dvrSp = getDvr(env, dvr); sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL) { if (dvrSp == NULL || iFilterSp == NULL) { return (jint) Result::NOT_INITIALIZED; return false; } } Result result = dvrSp->attachFilter(iFilterSp); sp<Filter> filterSp = getFilter(env, filter); return (int) result; if (filterSp == NULL) { return (jint) Result::INVALID_ARGUMENT; } sp<IDvr> iDvrSp = dvrSp->getIDvr(); sp<IFilter> iFilterSp = filterSp->getIFilter(); Result result = iDvrSp->attachFilter(iFilterSp); return (jint) result; } } static int android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { static jint android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); sp<Dvr> dvrSp = getDvr(env, dvr); sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL) { if (dvrSp == NULL || iFilterSp == NULL) { return (jint) Result::NOT_INITIALIZED; return false; } } Result result = dvrSp->detachFilter(iFilterSp); sp<Filter> filterSp = getFilter(env, filter); return (int) result; if (filterSp == NULL) { return (jint) Result::INVALID_ARGUMENT; } sp<IDvr> iDvrSp = dvrSp->getIDvr(); sp<IFilter> iFilterSp = filterSp->getIFilter(); Result result = iDvrSp->detachFilter(iFilterSp); return (jint) result; } } static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) { static jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) { sp<Dvr> dvrSp = getDvr(env, dvr); sp<Dvr> dvrSp = getDvr(env, dvr); sp<IDvr> iDvrSp = dvrSp->getIDvr(); if (dvrSp == NULL) { if (dvrSp == NULL) { ALOGD("Failed to configure dvr: dvr not found"); ALOGD("Failed to configure dvr: dvr not found"); return (int)Result::INVALID_STATE; return (int)Result::NOT_INITIALIZED; } } sp<IDvr> iDvrSp = dvrSp->getIDvr(); Result result = iDvrSp->configure(getDvrSettings(env, settings)); Result result = iDvrSp->configure(getDvrSettings(env, settings)); if (result != Result::SUCCESS) { return (jint) result; } MQDescriptorSync<uint8_t> dvrMQDesc; MQDescriptorSync<uint8_t> dvrMQDesc; if (result == Result::SUCCESS) { Result getQueueDescResult = Result::UNKNOWN_ERROR; Result getQueueDescResult = Result::UNKNOWN_ERROR; iDvrSp->getQueueDesc( iDvrSp->getQueueDesc( [&](Result r, const MQDescriptorSync<uint8_t>& desc) { [&](Result r, const MQDescriptorSync<uint8_t>& desc) { Loading @@ -2819,48 +2870,53 @@ static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobjec ALOGD("getDvrQueueDesc"); ALOGD("getDvrQueueDesc"); }); }); if (getQueueDescResult == Result::SUCCESS) { if (getQueueDescResult == Result::SUCCESS) { dvrSp->mDvrMQ = std::make_unique<DvrMQ>(dvrMQDesc, true); dvrSp->mDvrMQ = std::make_unique<MQ>(dvrMQDesc, true); EventFlag::createEventFlag( EventFlag::createEventFlag( dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag)); dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag)); } } return (jint) getQueueDescResult; } } return (int)result; } static int android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { if (dvrSp == NULL) { ALOGD("Failed to start dvr: dvr not found"); ALOGD("Failed to start dvr: dvr not found"); return false; return (jint) Result::NOT_INITIALIZED; } } sp<IDvr> iDvrSp = dvrSp->getIDvr(); Result result = dvrSp->start(); Result result = iDvrSp->start(); return (int) result; return (jint) result; } } static int android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) { static jint android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { if (dvrSp == NULL) { ALOGD("Failed to stop dvr: dvr not found"); ALOGD("Failed to stop dvr: dvr not found"); return false; return (jint) Result::NOT_INITIALIZED; } } Result result = dvrSp->stop(); sp<IDvr> iDvrSp = dvrSp->getIDvr(); return (int) result; Result result = iDvrSp->stop(); return (jint) result; } } static int android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) { static jint android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) { sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr(); sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { if (dvrSp == NULL) { ALOGD("Failed to flush dvr: dvr not found"); ALOGD("Failed to flush dvr: dvr not found"); return false; return (jint) Result::NOT_INITIALIZED; } } Result result = dvrSp->flush(); sp<IDvr> iDvrSp = dvrSp->getIDvr(); return (int) result; Result result = iDvrSp->flush(); return (jint) result; } } static int android_media_tv_Tuner_close_dvr(JNIEnv*, jobject) { static jint android_media_tv_Tuner_close_dvr(JNIEnv* env, jobject dvr) { return 0; sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { ALOGD("Failed to close dvr: dvr not found"); return (jint) Result::NOT_INITIALIZED; } return dvrSp->close(); } } static sp<Lnb> getLnb(JNIEnv *env, jobject lnb) { static sp<Lnb> getLnb(JNIEnv *env, jobject lnb) { Loading Loading @@ -2916,7 +2972,7 @@ static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong siz long available = dvrSp->mDvrMQ->availableToWrite(); long available = dvrSp->mDvrMQ->availableToWrite(); long write = std::min((long) size, available); long write = std::min((long) size, available); DvrMQ::MemTransaction tx; MQ::MemTransaction tx; long ret = 0; long ret = 0; if (dvrSp->mDvrMQ->beginWrite(write, &tx)) { if (dvrSp->mDvrMQ->beginWrite(write, &tx)) { auto first = tx.getFirstRegion(); auto first = tx.getFirstRegion(); Loading Loading @@ -2947,11 +3003,37 @@ static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong siz } } static jlong android_media_tv_Tuner_read_dvr_from_array( static jlong android_media_tv_Tuner_read_dvr_from_array( JNIEnv /* *env */, jobject /* dvr */, jbyteArray /* bytes */, jlong /* offset */, JNIEnv* env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) { jlong /* size */) { sp<Dvr> dvrSp = getDvr(env, dvr); //TODO: impl if (dvrSp == NULL) { ALOGW("Failed to read dvr: dvr not found"); return 0; return 0; } } if (dvrSp->mDvrMQ == NULL) { ALOGW("Failed to read dvr: dvr not configured"); return 0; } jlong available = dvrSp->mDvrMQ->availableToWrite(); size = std::min(size, available); jboolean isCopy; jbyte *src = env->GetByteArrayElements(buffer, &isCopy); if (src == nullptr) { ALOGD("Failed to GetByteArrayElements"); return 0; } if (dvrSp->mDvrMQ->write(reinterpret_cast<unsigned char*>(src) + offset, size)) { env->ReleaseByteArrayElements(buffer, src, 0); dvrSp->mDvrMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); } else { ALOGD("Failed to write FMQ"); env->ReleaseByteArrayElements(buffer, src, 0); return 0; } return size; } static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong size) { static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong size) { sp<Dvr> dvrSp = getDvr(env, dvr); sp<Dvr> dvrSp = getDvr(env, dvr); Loading @@ -2965,13 +3047,13 @@ static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong si return 0; return 0; } } DvrMQ& dvrMq = dvrSp->getDvrMQ(); MQ& dvrMq = dvrSp->getDvrMQ(); long available = dvrMq.availableToRead(); long available = dvrMq.availableToRead(); long toRead = std::min((long) size, available); long toRead = std::min((long) size, available); long ret = 0; long ret = 0; DvrMQ::MemTransaction tx; MQ::MemTransaction tx; if (dvrMq.beginRead(toRead, &tx)) { if (dvrMq.beginRead(toRead, &tx)) { auto first = tx.getFirstRegion(); auto first = tx.getFirstRegion(); auto data = first.getAddress(); auto data = first.getAddress(); Loading Loading @@ -3001,11 +3083,18 @@ static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong si } } static jlong android_media_tv_Tuner_write_dvr_to_array( static jlong android_media_tv_Tuner_write_dvr_to_array( JNIEnv /* *env */, jobject /* dvr */, jbyteArray /* bytes */, jlong /* offset */, JNIEnv *env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) { jlong /* size */) { sp<Dvr> dvrSp = getDvr(env, dvr); //TODO: impl if (dvrSp == NULL) { ALOGW("Failed to write dvr: dvr not found"); return 0; return 0; } } if (dvrSp->mDvrMQ == NULL) { ALOGW("Failed to write dvr: dvr not configured"); return 0; } return copyData(env, dvrSp->mDvrMQ, dvrSp->mDvrMQEventFlag, buffer, offset, size); } static const JNINativeMethod gTunerMethods[] = { static const JNINativeMethod gTunerMethods[] = { { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init }, { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init }, Loading
media/jni/android_media_tv_Tuner.h +7 −6 Original line number Original line Diff line number Diff line Loading @@ -62,8 +62,7 @@ using ::android::hardware::tv::tuner::V1_0::PlaybackStatus; using ::android::hardware::tv::tuner::V1_0::RecordStatus; using ::android::hardware::tv::tuner::V1_0::RecordStatus; using ::android::hardware::tv::tuner::V1_0::Result; using ::android::hardware::tv::tuner::V1_0::Result; using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; using MQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>; namespace android { namespace android { Loading @@ -84,6 +83,7 @@ struct Lnb : public RefBase { }; }; struct DvrCallback : public IDvrCallback { struct DvrCallback : public IDvrCallback { ~DvrCallback(); virtual Return<void> onRecordStatus(RecordStatus status); virtual Return<void> onRecordStatus(RecordStatus status); virtual Return<void> onPlaybackStatus(PlaybackStatus status); virtual Return<void> onPlaybackStatus(PlaybackStatus status); Loading @@ -95,18 +95,19 @@ private: struct Dvr : public RefBase { struct Dvr : public RefBase { Dvr(sp<IDvr> sp, jweak obj); Dvr(sp<IDvr> sp, jweak obj); ~Dvr(); ~Dvr(); int close(); jint close(); DvrMQ& getDvrMQ(); MQ& getDvrMQ(); sp<IDvr> getIDvr(); sp<IDvr> getIDvr(); sp<IDvr> mDvrSp; sp<IDvr> mDvrSp; jweak mDvrObj; jweak mDvrObj; std::unique_ptr<DvrMQ> mDvrMQ; std::unique_ptr<MQ> mDvrMQ; EventFlag* mDvrMQEventFlag; EventFlag* mDvrMQEventFlag; std::string mFilePath; std::string mFilePath; int mFd; int mFd; }; }; struct FilterCallback : public IFilterCallback { struct FilterCallback : public IFilterCallback { ~FilterCallback(); virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent); virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent); virtual Return<void> onFilterStatus(const DemuxFilterStatus status); virtual Return<void> onFilterStatus(const DemuxFilterStatus status); Loading Loading @@ -149,7 +150,7 @@ struct Filter : public RefBase { int close(); int close(); sp<IFilter> getIFilter(); sp<IFilter> getIFilter(); sp<IFilter> mFilterSp; sp<IFilter> mFilterSp; std::unique_ptr<FilterMQ> mFilterMQ; std::unique_ptr<MQ> mFilterMQ; EventFlag* mFilterMQEventFlag; EventFlag* mFilterMQEventFlag; jweak mFilterObj; jweak mFilterObj; }; }; Loading