Merge "Tuner JNI: Dvr and DvrCallback" into rvc-dev am: d9f9a8d70f
Change-Id: I58b3c16f0314bc83c8d39100afa0754132b00784
This commit is contained in:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,86 +2820,103 @@ 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));
|
||||||
MQDescriptorSync<uint8_t> dvrMQDesc;
|
if (result != Result::SUCCESS) {
|
||||||
if (result == Result::SUCCESS) {
|
return (jint) result;
|
||||||
Result getQueueDescResult = Result::UNKNOWN_ERROR;
|
|
||||||
iDvrSp->getQueueDesc(
|
|
||||||
[&](Result r, const MQDescriptorSync<uint8_t>& desc) {
|
|
||||||
dvrMQDesc = desc;
|
|
||||||
getQueueDescResult = r;
|
|
||||||
ALOGD("getDvrQueueDesc");
|
|
||||||
});
|
|
||||||
if (getQueueDescResult == Result::SUCCESS) {
|
|
||||||
dvrSp->mDvrMQ = std::make_unique<DvrMQ>(dvrMQDesc, true);
|
|
||||||
EventFlag::createEventFlag(
|
|
||||||
dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return (int)result;
|
MQDescriptorSync<uint8_t> dvrMQDesc;
|
||||||
|
Result getQueueDescResult = Result::UNKNOWN_ERROR;
|
||||||
|
iDvrSp->getQueueDesc(
|
||||||
|
[&](Result r, const MQDescriptorSync<uint8_t>& desc) {
|
||||||
|
dvrMQDesc = desc;
|
||||||
|
getQueueDescResult = r;
|
||||||
|
ALOGD("getDvrQueueDesc");
|
||||||
|
});
|
||||||
|
if (getQueueDescResult == Result::SUCCESS) {
|
||||||
|
dvrSp->mDvrMQ = std::make_unique<MQ>(dvrMQDesc, true);
|
||||||
|
EventFlag::createEventFlag(
|
||||||
|
dvrSp->mDvrMQ->getEventFlagWord(), &(dvrSp->mDvrMQEventFlag));
|
||||||
|
}
|
||||||
|
return (jint) getQueueDescResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
return 0;
|
ALOGW("Failed to read dvr: dvr not found");
|
||||||
|
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) {
|
||||||
return 0;
|
ALOGW("Failed to write dvr: dvr not found");
|
||||||
|
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[] = {
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user