Merge "Tuner JNI: Dvr and DvrCallback" into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-04-01 00:02:48 +00:00
committed by Android (Google) Code Review
5 changed files with 231 additions and 92 deletions

View File

@@ -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;
} }
@@ -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;
} }

View File

@@ -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.
@@ -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);
@@ -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.
@@ -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");
}
} }
/** /**

View File

@@ -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.
* *
@@ -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);
@@ -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.
@@ -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");
}
} }
/** /**
@@ -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);
} }
} }

View File

@@ -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;
@@ -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();
} }
@@ -214,27 +226,40 @@ void DvrCallback::setDvr(const jobject dvr) {
mDvr = env->NewWeakGlobalRef(dvr); mDvr = env->NewWeakGlobalRef(dvr);
} }
/////////////// Dvr /////////////////////// DvrCallback::~DvrCallback() {
JNIEnv *env = AndroidRuntime::getJNIEnv();
Dvr::Dvr(sp<IDvr> sp, jweak obj) : mDvrSp(sp), mDvrObj(obj), mDvrMQEventFlag(nullptr) {} if (mDvr != NULL) {
env->DeleteWeakGlobalRef(mDvr);
Dvr::~Dvr() { mDvr = NULL;
EventFlag::deleteEventFlag(&mDvrMQEventFlag); }
} }
int Dvr::close() { /////////////// Dvr ///////////////////////
Dvr::Dvr(sp<IDvr> sp, jobject obj) : mDvrSp(sp), mDvrMQEventFlag(nullptr) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
mDvrObj = env->NewWeakGlobalRef(obj);
}
Dvr::~Dvr() {
JNIEnv *env = AndroidRuntime::getJNIEnv();
env->DeleteWeakGlobalRef(mDvrObj);
mDvrObj = NULL;
}
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;
} }
@@ -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) {
@@ -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;
@@ -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");
@@ -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);
@@ -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);
@@ -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));
} }
@@ -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) {
@@ -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<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
if (dvrSp == NULL || iFilterSp == NULL) {
return false;
}
Result result = dvrSp->attachFilter(iFilterSp);
return (int) result;
}
static int android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
sp<IFilter> iFilterSp = getFilter(env, filter)->getIFilter();
if (dvrSp == NULL || iFilterSp == NULL) {
return false;
}
Result result = dvrSp->detachFilter(iFilterSp);
return (int) result;
}
static int android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) {
sp<Dvr> dvrSp = getDvr(env, dvr); sp<Dvr> dvrSp = getDvr(env, dvr);
if (dvrSp == NULL) {
return (jint) Result::NOT_INITIALIZED;
}
sp<Filter> filterSp = getFilter(env, filter);
if (filterSp == NULL) {
return (jint) Result::INVALID_ARGUMENT;
}
sp<IDvr> iDvrSp = dvrSp->getIDvr(); sp<IDvr> iDvrSp = dvrSp->getIDvr();
sp<IFilter> iFilterSp = filterSp->getIFilter();
Result result = iDvrSp->attachFilter(iFilterSp);
return (jint) result;
}
static jint android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
sp<Dvr> dvrSp = getDvr(env, dvr);
if (dvrSp == NULL) {
return (jint) Result::NOT_INITIALIZED;
}
sp<Filter> filterSp = getFilter(env, filter);
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 jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) {
sp<Dvr> dvrSp = getDvr(env, dvr);
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) {
@@ -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) { static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
sp<Dvr> dvrSp = getDvr(env, dvr);
sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
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) {
@@ -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();
@@ -2947,10 +3003,36 @@ 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) {
@@ -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();
@@ -3001,10 +3083,17 @@ 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[] = {

View File

@@ -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 {
@@ -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);
@@ -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);
@@ -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;
}; };