/* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "TvTuner-JNI" #include #include "android_media_MediaCodecLinearBlock.h" #include "android_media_tv_Tuner.h" #include "android_runtime/AndroidRuntime.h" #include #include #include #include #include #pragma GCC diagnostic ignored "-Wunused-function" using ::android::hardware::Void; using ::android::hardware::hidl_bitfield; using ::android::hardware::hidl_vec; using ::android::hardware::tv::tuner::V1_0::AudioExtraMetaData; using ::android::hardware::tv::tuner::V1_0::DataFormat; using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType; using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType; using ::android::hardware::tv::tuner::V1_0::DemuxCapabilities; using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterIpPayloadEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType; using ::android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterMmtpRecordEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionBits; using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterTemiEvent; using ::android::hardware::tv::tuner::V1_0::DemuxFilterTsRecordEvent; using ::android::hardware::tv::tuner::V1_0::DemuxIpAddress; using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterType; using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType; using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid; using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; using ::android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType; using ::android::hardware::tv::tuner::V1_0::DemuxScHevcIndex; using ::android::hardware::tv::tuner::V1_0::DemuxScIndex; using ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterType; using ::android::hardware::tv::tuner::V1_0::DemuxTpid; using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType; using ::android::hardware::tv::tuner::V1_0::DemuxTsIndex; using ::android::hardware::tv::tuner::V1_0::DvrSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogType; using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Bandwidth; using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3CodeRate; using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3DemodOutputFormat; using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Fec; using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Modulation; using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3PlpSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Settings; using ::android::hardware::tv::tuner::V1_0::FrontendAtsc3TimeInterleaveMode; using ::android::hardware::tv::tuner::V1_0::FrontendAtscSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAtscModulation; using ::android::hardware::tv::tuner::V1_0::FrontendDvbcAnnex; using ::android::hardware::tv::tuner::V1_0::FrontendDvbcModulation; using ::android::hardware::tv::tuner::V1_0::FrontendDvbcOuterFec; using ::android::hardware::tv::tuner::V1_0::FrontendDvbcSettings; using ::android::hardware::tv::tuner::V1_0::FrontendDvbcSpectralInversion; using ::android::hardware::tv::tuner::V1_0::FrontendDvbsCodeRate; using ::android::hardware::tv::tuner::V1_0::FrontendDvbsModulation; using ::android::hardware::tv::tuner::V1_0::FrontendDvbsPilot; using ::android::hardware::tv::tuner::V1_0::FrontendDvbsRolloff; using ::android::hardware::tv::tuner::V1_0::FrontendDvbsSettings; using ::android::hardware::tv::tuner::V1_0::FrontendDvbsStandard; using ::android::hardware::tv::tuner::V1_0::FrontendDvbsVcmMode; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtPlpMode; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtSettings; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtStandard; using ::android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode; using ::android::hardware::tv::tuner::V1_0::FrontendInnerFec; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Coderate; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Modulation; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Rolloff; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Settings; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsCoderate; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsModulation; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsRolloff; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsSettings; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbsStreamIdType; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtBandwidth; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtCoderate; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtGuardInterval; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtMode; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtModulation; using ::android::hardware::tv::tuner::V1_0::FrontendIsdbtSettings; using ::android::hardware::tv::tuner::V1_0::FrontendModulationStatus; using ::android::hardware::tv::tuner::V1_0::FrontendScanAtsc3PlpInfo; using ::android::hardware::tv::tuner::V1_0::FrontendStatus; using ::android::hardware::tv::tuner::V1_0::FrontendStatusAtsc3PlpInfo; using ::android::hardware::tv::tuner::V1_0::FrontendStatusType; using ::android::hardware::tv::tuner::V1_0::FrontendType; using ::android::hardware::tv::tuner::V1_0::LnbPosition; using ::android::hardware::tv::tuner::V1_0::LnbTone; using ::android::hardware::tv::tuner::V1_0::LnbVoltage; using ::android::hardware::tv::tuner::V1_0::PlaybackSettings; using ::android::hardware::tv::tuner::V1_0::RecordSettings; using ::android::hardware::tv::tuner::V1_1::AudioStreamType; using ::android::hardware::tv::tuner::V1_1::AvStreamType; using ::android::hardware::tv::tuner::V1_1::Constant; using ::android::hardware::tv::tuner::V1_1::Constant64Bit; using ::android::hardware::tv::tuner::V1_1::FrontendAnalogAftFlag; using ::android::hardware::tv::tuner::V1_1::FrontendAnalogSettingsExt1_1; using ::android::hardware::tv::tuner::V1_1::FrontendBandwidth; using ::android::hardware::tv::tuner::V1_1::FrontendCableTimeInterleaveMode; using ::android::hardware::tv::tuner::V1_1::FrontendDvbcBandwidth; using ::android::hardware::tv::tuner::V1_1::FrontendDvbsScanType; using ::android::hardware::tv::tuner::V1_1::FrontendDvbcSettingsExt1_1; using ::android::hardware::tv::tuner::V1_1::FrontendDvbsSettingsExt1_1; using ::android::hardware::tv::tuner::V1_1::FrontendDvbtSettingsExt1_1; using ::android::hardware::tv::tuner::V1_1::FrontendDtmbBandwidth; using ::android::hardware::tv::tuner::V1_1::FrontendDtmbCapabilities; using ::android::hardware::tv::tuner::V1_1::FrontendDtmbCodeRate; using ::android::hardware::tv::tuner::V1_1::FrontendDtmbGuardInterval; using ::android::hardware::tv::tuner::V1_1::FrontendDtmbModulation; using ::android::hardware::tv::tuner::V1_1::FrontendDtmbSettings; using ::android::hardware::tv::tuner::V1_1::FrontendDtmbTimeInterleaveMode; using ::android::hardware::tv::tuner::V1_1::FrontendDtmbTransmissionMode; using ::android::hardware::tv::tuner::V1_1::FrontendGuardInterval; using ::android::hardware::tv::tuner::V1_1::FrontendInterleaveMode; using ::android::hardware::tv::tuner::V1_1::FrontendModulation; using ::android::hardware::tv::tuner::V1_1::FrontendRollOff; using ::android::hardware::tv::tuner::V1_1::FrontendSpectralInversion; using ::android::hardware::tv::tuner::V1_1::FrontendStatusExt1_1; using ::android::hardware::tv::tuner::V1_1::FrontendStatusTypeExt1_1; using ::android::hardware::tv::tuner::V1_1::FrontendTransmissionMode; using ::android::hardware::tv::tuner::V1_1::VideoStreamType; struct fields_t { jfieldID tunerContext; jfieldID lnbContext; jfieldID filterContext; jfieldID timeFilterContext; jfieldID descramblerContext; jfieldID dvrRecorderContext; jfieldID dvrPlaybackContext; jfieldID mediaEventContext; jmethodID frontendInitID; jmethodID filterInitID; jmethodID timeFilterInitID; jmethodID dvrRecorderInitID; jmethodID dvrPlaybackInitID; jmethodID onFrontendEventID; jmethodID onFilterStatusID; jmethodID onFilterEventID; jmethodID lnbInitID; jmethodID onLnbEventID; jmethodID onLnbDiseqcMessageID; jmethodID onDvrRecordStatusID; jmethodID onDvrPlaybackStatusID; jmethodID descramblerInitID; jmethodID linearBlockInitID; jmethodID linearBlockSetInternalStateID; }; static fields_t gFields; static int IP_V4_LENGTH = 4; static int IP_V6_LENGTH = 16; void DestroyCallback(const C2Buffer * buf, void *arg) { android::sp event = (android::MediaEvent *)arg; android::Mutex::Autolock autoLock(event->mLock); if (event->mLinearBlockObj != NULL) { JNIEnv *env = android::AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(event->mLinearBlockObj); event->mLinearBlockObj = NULL; } event->mAvHandleRefCnt--; event->finalize(); event->decStrong(buf); } namespace android { /////////////// LnbClientCallbackImpl /////////////////////// void LnbClientCallbackImpl::onEvent(const LnbEventType lnbEventType) { ALOGD("LnbClientCallbackImpl::onEvent, type=%d", lnbEventType); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject lnb(env->NewLocalRef(mLnbObj)); if (!env->IsSameObject(lnb, nullptr)) { env->CallVoidMethod( lnb, gFields.onLnbEventID, (jint)lnbEventType); } else { ALOGE("LnbClientCallbackImpl::onEvent:" "Lnb object has been freed. Ignoring callback."); } } void LnbClientCallbackImpl::onDiseqcMessage(const hidl_vec& diseqcMessage) { ALOGD("LnbClientCallbackImpl::onDiseqcMessage"); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject lnb(env->NewLocalRef(mLnbObj)); if (!env->IsSameObject(lnb, nullptr)) { jbyteArray array = env->NewByteArray(diseqcMessage.size()); env->SetByteArrayRegion( array, 0, diseqcMessage.size(), reinterpret_cast(diseqcMessage[0])); env->CallVoidMethod( lnb, gFields.onLnbDiseqcMessageID, array); } else { ALOGE("LnbClientCallbackImpl::onDiseqcMessage:" "Lnb object has been freed. Ignoring callback."); } } void LnbClientCallbackImpl::setLnb(jweak lnbObj) { ALOGD("LnbClientCallbackImpl::setLnb"); mLnbObj = lnbObj; } LnbClientCallbackImpl::~LnbClientCallbackImpl() { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mLnbObj != NULL) { env->DeleteWeakGlobalRef(mLnbObj); mLnbObj = NULL; } } /////////////// DvrClientCallbackImpl /////////////////////// void DvrClientCallbackImpl::onRecordStatus(RecordStatus status) { ALOGD("DvrClientCallbackImpl::onRecordStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject dvr(env->NewLocalRef(mDvrObj)); if (!env->IsSameObject(dvr, nullptr)) { env->CallVoidMethod( dvr, gFields.onDvrRecordStatusID, (jint) status); } else { ALOGE("DvrClientCallbackImpl::onRecordStatus:" "Dvr object has been freed. Ignoring callback."); } } void DvrClientCallbackImpl::onPlaybackStatus(PlaybackStatus status) { ALOGD("DvrClientCallbackImpl::onPlaybackStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject dvr(env->NewLocalRef(mDvrObj)); if (!env->IsSameObject(dvr, nullptr)) { env->CallVoidMethod( dvr, gFields.onDvrPlaybackStatusID, (jint) status); } else { ALOGE("DvrClientCallbackImpl::onPlaybackStatus:" "Dvr object has been freed. Ignoring callback."); } } void DvrClientCallbackImpl::setDvr(jweak dvrObj) { ALOGD("DvrClientCallbackImpl::setDvr"); mDvrObj = dvrObj; } DvrClientCallbackImpl::~DvrClientCallbackImpl() { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mDvrObj != NULL) { env->DeleteWeakGlobalRef(mDvrObj); mDvrObj = NULL; } } /////////////// C2DataIdInfo /////////////////////// C2DataIdInfo::C2DataIdInfo(uint32_t index, uint64_t value) : C2Param(kParamSize, index) { CHECK(isGlobal()); CHECK_EQ(C2Param::INFO, kind()); mInfo = StubInfo(value); memcpy(static_cast(this) + 1, static_cast(&mInfo) + 1, kParamSize - sizeof(C2Param)); } /////////////// MediaEvent /////////////////////// MediaEvent::MediaEvent(sp filterClient, hidl_handle avHandle, uint64_t dataId, uint64_t dataSize, jobject obj) : mFilterClient(filterClient), mDataId(dataId), mDataSize(dataSize), mBuffer(nullptr), mDataIdRefCnt(0), mAvHandleRefCnt(0), mIonHandle(nullptr) { JNIEnv *env = AndroidRuntime::getJNIEnv(); mMediaEventObj = env->NewWeakGlobalRef(obj); mAvHandle = native_handle_clone(avHandle.getNativeHandle()); mLinearBlockObj = NULL; } MediaEvent::~MediaEvent() { JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mMediaEventObj); mMediaEventObj = NULL; native_handle_delete(mAvHandle); if (mIonHandle != NULL) { delete mIonHandle; } std::shared_ptr pC2Buffer = mC2Buffer.lock(); if (pC2Buffer != NULL) { pC2Buffer->unregisterOnDestroyNotify(&DestroyCallback, this); } if (mLinearBlockObj != NULL) { env->DeleteWeakGlobalRef(mLinearBlockObj); mLinearBlockObj = NULL; } mFilterClient = NULL; } void MediaEvent::finalize() { if (mAvHandleRefCnt == 0 && mFilterClient != NULL) { mFilterClient->releaseAvHandle( mAvHandle, mDataIdRefCnt == 0 ? mDataId : 0); native_handle_close(mAvHandle); } } jobject MediaEvent::getLinearBlock() { ALOGD("MediaEvent::getLinearBlock"); if (mAvHandle == NULL) { return NULL; } if (mLinearBlockObj != NULL) { return mLinearBlockObj; } int fd; int numInts = 0; int memIndex; int dataSize; SharedHandleInfo info = mFilterClient->getAvSharedHandleInfo(); native_handle_t* avSharedHandle = info.sharedHandle; uint64_t avSharedMemSize = info.size; if (mAvHandle->numFds == 0) { if (avSharedHandle == NULL) { ALOGE("Shared AV memory handle is not initialized."); return NULL; } if (avSharedHandle->numFds == 0) { ALOGE("Shared AV memory handle is empty."); return NULL; } fd = avSharedHandle->data[0]; dataSize = avSharedMemSize; numInts = avSharedHandle->numInts; if (numInts > 0) { // If the first int in the shared native handle has value, use it as the index memIndex = avSharedHandle->data[avSharedHandle->numFds]; } } else { fd = mAvHandle->data[0]; dataSize = mDataSize; numInts = mAvHandle->numInts; if (numInts > 0) { // Otherwise if the first int in the av native handle returned from the filter // event has value, use it as the index memIndex = mAvHandle->data[mAvHandle->numFds]; } else { if (avSharedHandle != NULL) { numInts = avSharedHandle->numInts; if (numInts > 0) { // If the first int in the shared native handle has value, use it as the index memIndex = avSharedHandle->data[avSharedHandle->numFds]; } } } } mIonHandle = new C2HandleIon(dup(fd), dataSize); std::shared_ptr block = _C2BlockFactory::CreateLinearBlock(mIonHandle); if (block != nullptr) { // CreateLinearBlock delete mIonHandle after it create block successfully. // ToDo: coordinate who is response to delete mIonHandle mIonHandle = NULL; JNIEnv *env = AndroidRuntime::getJNIEnv(); std::unique_ptr context{new JMediaCodecLinearBlock}; context->mBlock = block; std::shared_ptr pC2Buffer = context->toC2Buffer(0, dataSize); context->mBuffer = pC2Buffer; mC2Buffer = pC2Buffer; if (numInts > 0) { std::shared_ptr c2param = std::make_shared(memIndex, mDataId); std::shared_ptr info(std::static_pointer_cast(c2param)); pC2Buffer->setInfo(info); } pC2Buffer->registerOnDestroyNotify(&DestroyCallback, this); incStrong(pC2Buffer.get()); jobject linearBlock = env->NewObject( env->FindClass("android/media/MediaCodec$LinearBlock"), gFields.linearBlockInitID); env->CallVoidMethod( linearBlock, gFields.linearBlockSetInternalStateID, (jlong)context.release(), true); mLinearBlockObj = env->NewWeakGlobalRef(linearBlock); mAvHandleRefCnt++; return linearBlock; } else { native_handle_close(const_cast( reinterpret_cast(mIonHandle))); native_handle_delete(const_cast( reinterpret_cast(mIonHandle))); mIonHandle = NULL; return NULL; } } uint64_t MediaEvent::getAudioHandle() { mDataIdRefCnt++; return mDataId; } /////////////// FilterClientCallbackImpl /////////////////////// jobjectArray FilterClientCallbackImpl::getSectionEvent( jobjectArray& arr, const std::vector& events) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/SectionEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(IIII)V"); for (int i = 0; i < events.size(); i++) { auto event = events[i]; DemuxFilterSectionEvent sectionEvent = event.section(); jint tableId = static_cast(sectionEvent.tableId); jint version = static_cast(sectionEvent.version); jint sectionNum = static_cast(sectionEvent.sectionNum); jint dataLength = static_cast(sectionEvent.dataLength); jobject obj = env->NewObject(eventClazz, eventInit, tableId, version, sectionNum, dataLength); env->SetObjectArrayElement(arr, i, obj); } return arr; } jobjectArray FilterClientCallbackImpl::getMediaEvent( jobjectArray& arr, const std::vector& events) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(IZJJJLandroid/media/MediaCodec$LinearBlock;" "ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V"); jfieldID eventContext = env->GetFieldID(eventClazz, "mNativeContext", "J"); for (int i = 0; i < events.size(); i++) { auto event = events[i]; DemuxFilterMediaEvent mediaEvent = event.media(); jobject audioDescriptor = NULL; if (mediaEvent.extraMetaData.getDiscriminator() == DemuxFilterMediaEvent::ExtraMetaData::hidl_discriminator::audio) { jclass adClazz = env->FindClass("android/media/tv/tuner/filter/AudioDescriptor"); jmethodID adInit = env->GetMethodID(adClazz, "", "(BBCBBB)V"); AudioExtraMetaData ad = mediaEvent.extraMetaData.audio(); jbyte adFade = static_cast(ad.adFade); jbyte adPan = static_cast(ad.adPan); jchar versionTextTag = static_cast(ad.versionTextTag); jbyte adGainCenter = static_cast(ad.adGainCenter); jbyte adGainFront = static_cast(ad.adGainFront); jbyte adGainSurround = static_cast(ad.adGainSurround); audioDescriptor = env->NewObject(adClazz, adInit, adFade, adPan, versionTextTag, adGainCenter, adGainFront, adGainSurround); } jlong dataLength = static_cast(mediaEvent.dataLength); jint streamId = static_cast(mediaEvent.streamId); jboolean isPtsPresent = static_cast(mediaEvent.isPtsPresent); jlong pts = static_cast(mediaEvent.pts); jlong offset = static_cast(mediaEvent.offset); jboolean isSecureMemory = static_cast(mediaEvent.isSecureMemory); jlong avDataId = static_cast(mediaEvent.avDataId); jint mpuSequenceNumber = static_cast(mediaEvent.mpuSequenceNumber); jboolean isPesPrivateData = static_cast(mediaEvent.isPesPrivateData); jobject obj = env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, dataLength, offset, NULL, isSecureMemory, avDataId, mpuSequenceNumber, isPesPrivateData, audioDescriptor); if (mediaEvent.avMemory.getNativeHandle() != NULL || mediaEvent.avDataId != 0) { sp mediaEventSp = new MediaEvent(mFilterClient, mediaEvent.avMemory, mediaEvent.avDataId, dataLength + offset, obj); mediaEventSp->mAvHandleRefCnt++; env->SetLongField(obj, eventContext, (jlong) mediaEventSp.get()); mediaEventSp->incStrong(obj); } env->SetObjectArrayElement(arr, i, obj); } return arr; } jobjectArray FilterClientCallbackImpl::getPesEvent( jobjectArray& arr, const std::vector& events) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/PesEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(III)V"); for (int i = 0; i < events.size(); i++) { auto event = events[i]; DemuxFilterPesEvent pesEvent = event.pes(); jint streamId = static_cast(pesEvent.streamId); jint dataLength = static_cast(pesEvent.dataLength); jint mpuSequenceNumber = static_cast(pesEvent.mpuSequenceNumber); jobject obj = env->NewObject(eventClazz, eventInit, streamId, dataLength, mpuSequenceNumber); env->SetObjectArrayElement(arr, i, obj); } return arr; } jobjectArray FilterClientCallbackImpl::getTsRecordEvent( jobjectArray& arr, const std::vector& events, const std::vector& eventsExt) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TsRecordEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(IIIJJI)V"); for (int i = 0; i < events.size(); i++) { auto event = events[i]; DemuxFilterTsRecordEvent tsRecordEvent = event.tsRecord(); DemuxPid pid = tsRecordEvent.pid; jint jpid = static_cast(Constant::INVALID_TS_PID); if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::tPid) { jpid = static_cast(pid.tPid()); } else if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::mmtpPid) { jpid = static_cast(pid.mmtpPid()); } jint sc = 0; if (tsRecordEvent.scIndexMask.getDiscriminator() == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::sc) { sc = static_cast(tsRecordEvent.scIndexMask.sc()); } else if (tsRecordEvent.scIndexMask.getDiscriminator() == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::scHevc) { sc = static_cast(tsRecordEvent.scIndexMask.scHevc()); } jint ts = static_cast(tsRecordEvent.tsIndexMask); jlong byteNumber = static_cast(tsRecordEvent.byteNumber); jlong pts; jlong firstMbInSlice; if (eventsExt.size() > i && eventsExt[i].getDiscriminator() == DemuxFilterEventExt::Event::hidl_discriminator::tsRecord) { pts = static_cast(eventsExt[i].tsRecord().pts); firstMbInSlice = static_cast(eventsExt[i].tsRecord().firstMbInSlice); } else { pts = static_cast(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP); firstMbInSlice = static_cast(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE); } jobject obj = env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber, pts, firstMbInSlice); env->SetObjectArrayElement(arr, i, obj); } return arr; } jobjectArray FilterClientCallbackImpl::getMmtpRecordEvent( jobjectArray& arr, const std::vector& events, const std::vector& eventsExt) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MmtpRecordEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(IJIJII)V"); for (int i = 0; i < events.size(); i++) { auto event = events[i]; DemuxFilterMmtpRecordEvent mmtpRecordEvent = event.mmtpRecord(); jint scHevcIndexMask = static_cast(mmtpRecordEvent.scHevcIndexMask); jlong byteNumber = static_cast(mmtpRecordEvent.byteNumber); jint mpuSequenceNumber; jlong pts; jlong firstMbInSlice; jlong tsIndexMask; if (eventsExt.size() > i && eventsExt[i].getDiscriminator() == DemuxFilterEventExt::Event::hidl_discriminator::mmtpRecord) { mpuSequenceNumber = static_cast(eventsExt[i].mmtpRecord().mpuSequenceNumber); pts = static_cast(eventsExt[i].mmtpRecord().pts); firstMbInSlice = static_cast(eventsExt[i].mmtpRecord().firstMbInSlice); tsIndexMask = static_cast(eventsExt[i].mmtpRecord().tsIndexMask); } else { mpuSequenceNumber = static_cast(Constant::INVALID_MMTP_RECORD_EVENT_MPT_SEQUENCE_NUM); pts = static_cast(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP); firstMbInSlice = static_cast(Constant::INVALID_FIRST_MACROBLOCK_IN_SLICE); tsIndexMask = 0; } jobject obj = env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber, mpuSequenceNumber, pts, firstMbInSlice, tsIndexMask); env->SetObjectArrayElement(arr, i, obj); } return arr; } jobjectArray FilterClientCallbackImpl::getDownloadEvent( jobjectArray& arr, const std::vector& events) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/DownloadEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(IIIII)V"); for (int i = 0; i < events.size(); i++) { auto event = events[i]; DemuxFilterDownloadEvent downloadEvent = event.download(); jint itemId = static_cast(downloadEvent.itemId); jint mpuSequenceNumber = static_cast(downloadEvent.mpuSequenceNumber); jint itemFragmentIndex = static_cast(downloadEvent.itemFragmentIndex); jint lastItemFragmentIndex = static_cast(downloadEvent.lastItemFragmentIndex); jint dataLength = static_cast(downloadEvent.dataLength); jobject obj = env->NewObject(eventClazz, eventInit, itemId, mpuSequenceNumber, itemFragmentIndex, lastItemFragmentIndex, dataLength); env->SetObjectArrayElement(arr, i, obj); } return arr; } jobjectArray FilterClientCallbackImpl::getIpPayloadEvent( jobjectArray& arr, const std::vector& events) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpPayloadEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(I)V"); for (int i = 0; i < events.size(); i++) { auto event = events[i]; DemuxFilterIpPayloadEvent ipPayloadEvent = event.ipPayload(); jint dataLength = static_cast(ipPayloadEvent.dataLength); jobject obj = env->NewObject(eventClazz, eventInit, dataLength); env->SetObjectArrayElement(arr, i, obj); } return arr; } jobjectArray FilterClientCallbackImpl::getTemiEvent( jobjectArray& arr, const std::vector& events) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TemiEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(JB[B)V"); for (int i = 0; i < events.size(); i++) { auto event = events[i]; DemuxFilterTemiEvent temiEvent = event.temi(); jlong pts = static_cast(temiEvent.pts); jbyte descrTag = static_cast(temiEvent.descrTag); std::vector descrData = temiEvent.descrData; jbyteArray array = env->NewByteArray(descrData.size()); env->SetByteArrayRegion( array, 0, descrData.size(), reinterpret_cast(&descrData[0])); jobject obj = env->NewObject(eventClazz, eventInit, pts, descrTag, array); env->SetObjectArrayElement(arr, i, obj); } return arr; } jobjectArray FilterClientCallbackImpl::getScramblingStatusEvent( jobjectArray& arr, const std::vector& eventsExt) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/ScramblingStatusEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(I)V"); auto scramblingStatus = eventsExt[0].monitorEvent().scramblingStatus(); jobject obj = env->NewObject(eventClazz, eventInit, static_cast(scramblingStatus)); env->SetObjectArrayElement(arr, 0, obj); return arr; } jobjectArray FilterClientCallbackImpl::getIpCidChangeEvent( jobjectArray& arr, const std::vector& eventsExt) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpCidChangeEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(I)V"); auto cid = eventsExt[0].monitorEvent().cid(); jobject obj = env->NewObject(eventClazz, eventInit, static_cast(cid)); env->SetObjectArrayElement(arr, 0, obj); return arr; } jobjectArray FilterClientCallbackImpl::getRestartEvent( jobjectArray& arr, const std::vector& eventsExt) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/RestartEvent"); jmethodID eventInit = env->GetMethodID(eventClazz, "", "(I)V"); auto startId = eventsExt[0].startId(); jobject obj = env->NewObject(eventClazz, eventInit, static_cast(startId)); env->SetObjectArrayElement(arr, 0, obj); return arr; } void FilterClientCallbackImpl::onFilterEvent_1_1(const DemuxFilterEvent& filterEvent, const DemuxFilterEventExt& filterEventExt) { ALOGD("FilterClientCallbackImpl::onFilterEvent_1_1"); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobjectArray array; std::vector events = filterEvent.events; std::vector eventsExt = filterEventExt.events; jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/FilterEvent"); if (events.empty() && !eventsExt.empty()) { // Monitor event should be sent with one DemuxFilterMonitorEvent in DemuxFilterEventExt. array = env->NewObjectArray(1, eventClazz, NULL); auto eventExt = eventsExt[0]; switch (eventExt.getDiscriminator()) { case DemuxFilterEventExt::Event::hidl_discriminator::monitorEvent: { switch (eventExt.monitorEvent().getDiscriminator()) { case DemuxFilterMonitorEvent::hidl_discriminator::scramblingStatus: { array = getScramblingStatusEvent(array, eventsExt); break; } case DemuxFilterMonitorEvent::hidl_discriminator::cid: { array = getIpCidChangeEvent(array, eventsExt); break; } default: { break; } } break; } case DemuxFilterEventExt::Event::hidl_discriminator::startId: { array = getRestartEvent(array, eventsExt); break; } default: { break; } } } if (!events.empty()) { array = env->NewObjectArray(events.size(), eventClazz, NULL); auto event = events[0]; switch (event.getDiscriminator()) { case DemuxFilterEvent::Event::hidl_discriminator::media: { array = getMediaEvent(array, events); break; } case DemuxFilterEvent::Event::hidl_discriminator::section: { array = getSectionEvent(array, events); break; } case DemuxFilterEvent::Event::hidl_discriminator::pes: { array = getPesEvent(array, events); break; } case DemuxFilterEvent::Event::hidl_discriminator::tsRecord: { array = getTsRecordEvent(array, events, eventsExt); break; } case DemuxFilterEvent::Event::hidl_discriminator::mmtpRecord: { array = getMmtpRecordEvent(array, events, eventsExt); break; } case DemuxFilterEvent::Event::hidl_discriminator::download: { array = getDownloadEvent(array, events); break; } case DemuxFilterEvent::Event::hidl_discriminator::ipPayload: { array = getIpPayloadEvent(array, events); break; } case DemuxFilterEvent::Event::hidl_discriminator::temi: { array = getTemiEvent(array, events); break; } default: { break; } } } jobject filter(env->NewLocalRef(mFilterObj)); if (!env->IsSameObject(filter, nullptr)) { env->CallVoidMethod( filter, gFields.onFilterEventID, array); } else { ALOGE("FilterClientCallbackImpl::onFilterEvent_1_1:" "Filter object has been freed. Ignoring callback."); } } void FilterClientCallbackImpl::onFilterEvent(const DemuxFilterEvent& filterEvent) { ALOGD("FilterClientCallbackImpl::onFilterEvent"); std::vector emptyEventsExt; DemuxFilterEventExt emptyFilterEventExt { .events = emptyEventsExt, }; return onFilterEvent_1_1(filterEvent, emptyFilterEventExt); } void FilterClientCallbackImpl::onFilterStatus(const DemuxFilterStatus status) { ALOGD("FilterClientCallbackImpl::onFilterStatus"); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject filter(env->NewLocalRef(mFilterObj)); if (!env->IsSameObject(filter, nullptr)) { env->CallVoidMethod( filter, gFields.onFilterStatusID, (jint)status); } else { ALOGE("FilterClientCallbackImpl::onFilterStatus:" "Filter object has been freed. Ignoring callback."); } } void FilterClientCallbackImpl::setFilter(jweak filterObj, sp filterClient) { ALOGD("FilterClientCallbackImpl::setFilter"); // Java Object mFilterObj = filterObj; mFilterClient = filterClient; } FilterClientCallbackImpl::~FilterClientCallbackImpl() { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mFilterObj != NULL) { env->DeleteWeakGlobalRef(mFilterObj); mFilterObj = NULL; } mFilterClient = NULL; } /////////////// FrontendClientCallbackImpl /////////////////////// FrontendClientCallbackImpl::FrontendClientCallbackImpl(jweak tunerObj) : mObject(tunerObj) {} void FrontendClientCallbackImpl::onEvent(FrontendEventType frontendEventType) { ALOGD("FrontendClientCallbackImpl::onEvent, type=%d", frontendEventType); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject frontend(env->NewLocalRef(mObject)); if (!env->IsSameObject(frontend, nullptr)) { env->CallVoidMethod( frontend, gFields.onFrontendEventID, (jint)frontendEventType); } else { ALOGE("FrontendClientCallbackImpl::onEvent:" "Frontend object has been freed. Ignoring callback."); } } void FrontendClientCallbackImpl::onScanMessage( FrontendScanMessageType type, const FrontendScanMessage& message) { ALOGD("FrontendClientCallbackImpl::onScanMessage, type=%d", type); JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass clazz = env->FindClass("android/media/tv/tuner/Tuner"); jobject frontend(env->NewLocalRef(mObject)); if (env->IsSameObject(frontend, nullptr)) { ALOGE("FrontendClientCallbackImpl::onScanMessage:" "Frontend object has been freed. Ignoring callback."); return; } switch(type) { case FrontendScanMessageType::LOCKED: { if (message.isLocked()) { env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onLocked", "()V")); } break; } case FrontendScanMessageType::END: { if (message.isEnd()) { env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onScanStopped", "()V")); } break; } case FrontendScanMessageType::PROGRESS_PERCENT: { env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onProgress", "(I)V"), (jint) message.progressPercent()); break; } case FrontendScanMessageType::FREQUENCY: { std::vector v = message.frequencies(); jintArray freqs = env->NewIntArray(v.size()); env->SetIntArrayRegion(freqs, 0, v.size(), reinterpret_cast(&v[0])); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onFrequenciesReport", "([I)V"), freqs); break; } case FrontendScanMessageType::SYMBOL_RATE: { std::vector v = message.symbolRates(); jintArray symbolRates = env->NewIntArray(v.size()); env->SetIntArrayRegion(symbolRates, 0, v.size(), reinterpret_cast(&v[0])); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onSymbolRates", "([I)V"), symbolRates); break; } case FrontendScanMessageType::HIERARCHY: { env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onHierarchy", "(I)V"), (jint) message.hierarchy()); break; } case FrontendScanMessageType::ANALOG_TYPE: { env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onSignalType", "(I)V"), (jint) message.analogType()); break; } case FrontendScanMessageType::PLP_IDS: { std::vector v = message.plpIds(); std::vector jintV(v.begin(), v.end()); jintArray plpIds = env->NewIntArray(v.size()); env->SetIntArrayRegion(plpIds, 0, jintV.size(), &jintV[0]); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onPlpIds", "([I)V"), plpIds); break; } case FrontendScanMessageType::GROUP_IDS: { std::vector v = message.groupIds(); std::vector jintV(v.begin(), v.end()); jintArray groupIds = env->NewIntArray(v.size()); env->SetIntArrayRegion(groupIds, 0, jintV.size(), &jintV[0]); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onGroupIds", "([I)V"), groupIds); break; } case FrontendScanMessageType::INPUT_STREAM_IDS: { std::vector v = message.inputStreamIds(); std::vector jintV(v.begin(), v.end()); jintArray streamIds = env->NewIntArray(v.size()); env->SetIntArrayRegion(streamIds, 0, jintV.size(), &jintV[0]); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onInputStreamIds", "([I)V"), streamIds); break; } case FrontendScanMessageType::STANDARD: { FrontendScanMessage::Standard std = message.std(); jint standard; if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::sStd) { standard = (jint) std.sStd(); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onDvbsStandard", "(I)V"), standard); } else if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::tStd) { standard = (jint) std.tStd(); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onDvbtStandard", "(I)V"), standard); } else if (std.getDiscriminator() == FrontendScanMessage::Standard::hidl_discriminator::sifStd) { standard = (jint) std.sifStd(); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onAnalogSifStandard", "(I)V"), standard); } break; } case FrontendScanMessageType::ATSC3_PLP_INFO: { jclass plpClazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3PlpInfo"); jmethodID init = env->GetMethodID(plpClazz, "", "(IZ)V"); std::vector plpInfos = message.atsc3PlpInfos(); jobjectArray array = env->NewObjectArray(plpInfos.size(), plpClazz, NULL); for (int i = 0; i < plpInfos.size(); i++) { auto info = plpInfos[i]; jint plpId = (jint) info.plpId; jboolean lls = (jboolean) info.bLlsFlag; jobject obj = env->NewObject(plpClazz, init, plpId, lls); env->SetObjectArrayElement(array, i, obj); } env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onAtsc3PlpInfos", "([Landroid/media/tv/tuner/frontend/Atsc3PlpInfo;)V"), array); break; } } } void FrontendClientCallbackImpl::onScanMessageExt1_1(FrontendScanMessageTypeExt1_1 type, const FrontendScanMessageExt1_1& message) { ALOGD("FrontendClientCallbackImpl::onScanMessageExt1_1, type=%d", type); JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass clazz = env->FindClass("android/media/tv/tuner/Tuner"); jobject frontend(env->NewLocalRef(mObject)); if (env->IsSameObject(frontend, nullptr)) { ALOGE("FrontendClientCallbackImpl::onScanMessageExt1_1:" "Frontend object has been freed. Ignoring callback."); return; } switch(type) { case FrontendScanMessageTypeExt1_1::MODULATION: { jint modulation = -1; switch (message.modulation().getDiscriminator()) { case FrontendModulation::hidl_discriminator::dvbc: { modulation = (jint) message.modulation().dvbc(); break; } case FrontendModulation::hidl_discriminator::dvbt: { modulation = (jint) message.modulation().dvbt(); break; } case FrontendModulation::hidl_discriminator::dvbs: { modulation = (jint) message.modulation().dvbs(); break; } case FrontendModulation::hidl_discriminator::isdbs: { modulation = (jint) message.modulation().isdbs(); break; } case FrontendModulation::hidl_discriminator::isdbs3: { modulation = (jint) message.modulation().isdbs3(); break; } case FrontendModulation::hidl_discriminator::isdbt: { modulation = (jint) message.modulation().isdbt(); break; } case FrontendModulation::hidl_discriminator::atsc: { modulation = (jint) message.modulation().atsc(); break; } case FrontendModulation::hidl_discriminator::atsc3: { modulation = (jint) message.modulation().atsc3(); break; } case FrontendModulation::hidl_discriminator::dtmb: { modulation = (jint) message.modulation().dtmb(); break; } default: { break; } } if (modulation > 0) { env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onModulationReported", "(I)V"), modulation); } break; } case FrontendScanMessageTypeExt1_1::HIGH_PRIORITY: { bool isHighPriority = message.isHighPriority(); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onPriorityReported", "(Z)V"), isHighPriority); break; } case FrontendScanMessageTypeExt1_1::DVBC_ANNEX: { jint dvbcAnnex = (jint) message.annex(); env->CallVoidMethod( frontend, env->GetMethodID(clazz, "onDvbcAnnexReported", "(I)V"), dvbcAnnex); break; } default: break; } } FrontendClientCallbackImpl::~FrontendClientCallbackImpl() { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (mObject != NULL) { env->DeleteWeakGlobalRef(mObject); mObject = NULL; } } /////////////// Tuner /////////////////////// sp JTuner::mTunerClient; JTuner::JTuner(JNIEnv *env, jobject thiz) : mClass(NULL) { jclass clazz = env->GetObjectClass(thiz); CHECK(clazz != NULL); mClass = (jclass)env->NewGlobalRef(clazz); mObject = env->NewWeakGlobalRef(thiz); if (mTunerClient == NULL) { mTunerClient = new TunerClient(); } } JTuner::~JTuner() { if (mFeClient != NULL) { mFeClient->close(); } if (mDemuxClient != NULL) { mDemuxClient->close(); } JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mObject); env->DeleteGlobalRef(mClass); mTunerClient = NULL; mFeClient = NULL; mDemuxClient = NULL; mClass = NULL; mObject = NULL; } jint JTuner::getTunerVersion() { ALOGD("JTuner::getTunerVersion()"); return (jint) mTunerClient->getHalTunerVersion(); } jobject JTuner::getFrontendIds() { ALOGD("JTuner::getFrontendIds()"); vector ids = mTunerClient->getFrontendIds(); if (ids.size() == 0) { ALOGW("Frontend isn't available"); return NULL; } JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass arrayListClazz = env->FindClass("java/util/ArrayList"); jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z"); jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "", "()V")); jclass integerClazz = env->FindClass("java/lang/Integer"); jmethodID intInit = env->GetMethodID(integerClazz, "", "(I)V"); for (int i=0; i < ids.size(); i++) { jobject idObj = env->NewObject(integerClazz, intInit, ids[i]); env->CallBooleanMethod(obj, arrayListAdd, idObj); } return obj; } jobject JTuner::openFrontendByHandle(int feHandle) { // TODO: Handle reopening frontend with different handle sp feClient = mTunerClient->openFrontend(feHandle); if (feClient == NULL) { ALOGE("Failed to open frontend"); return NULL; } mFeClient = feClient; mFeId = mFeClient->getId(); if (mDemuxClient != NULL) { mDemuxClient->setFrontendDataSource(mFeClient); } JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject tuner(env->NewLocalRef(mObject)); if (env->IsSameObject(tuner, nullptr)) { ALOGE("openFrontendByHandle" "Tuner object has been freed. Failed to open frontend."); return NULL; } sp feClientCb = new FrontendClientCallbackImpl(mObject); mFeClient->setCallback(feClientCb); // TODO: add more fields to frontend return env->NewObject( env->FindClass("android/media/tv/tuner/Tuner$Frontend"), gFields.frontendInitID, tuner, (jint) mFeId); } jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(II)V"); jint typeCap = caps.analogCaps().typeCap; jint sifStandardCap = caps.analogCaps().sifStandardCap; return env->NewObject(clazz, capsInit, typeCap, sifStandardCap); } jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(IIIIII)V"); jint bandwidthCap = caps.atsc3Caps().bandwidthCap; jint modulationCap = caps.atsc3Caps().modulationCap; jint timeInterleaveModeCap = caps.atsc3Caps().timeInterleaveModeCap; jint codeRateCap = caps.atsc3Caps().codeRateCap; jint fecCap = caps.atsc3Caps().fecCap; jint demodOutputFormatCap = caps.atsc3Caps().demodOutputFormatCap; return env->NewObject(clazz, capsInit, bandwidthCap, modulationCap, timeInterleaveModeCap, codeRateCap, fecCap, demodOutputFormatCap); } jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AtscFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(I)V"); jint modulationCap = caps.atscCaps().modulationCap; return env->NewObject(clazz, capsInit, modulationCap); } jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(IJI)V"); jint modulationCap = caps.dvbcCaps().modulationCap; jlong fecCap = caps.dvbcCaps().fecCap; jint annexCap = caps.dvbcCaps().annexCap; return env->NewObject(clazz, capsInit, modulationCap, fecCap, annexCap); } jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(IJI)V"); jint modulationCap = caps.dvbsCaps().modulationCap; jlong innerfecCap = caps.dvbsCaps().innerfecCap; jint standard = caps.dvbsCaps().standard; return env->NewObject(clazz, capsInit, modulationCap, innerfecCap, standard); } jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(IIIIIIZZ)V"); jint transmissionModeCap = caps.dvbtCaps().transmissionModeCap; jint bandwidthCap = caps.dvbtCaps().bandwidthCap; jint constellationCap = caps.dvbtCaps().constellationCap; jint coderateCap = caps.dvbtCaps().coderateCap; jint hierarchyCap = caps.dvbtCaps().hierarchyCap; jint guardIntervalCap = caps.dvbtCaps().guardIntervalCap; jboolean isT2Supported = caps.dvbtCaps().isT2Supported; jboolean isMisoSupported = caps.dvbtCaps().isMisoSupported; return env->NewObject(clazz, capsInit, transmissionModeCap, bandwidthCap, constellationCap, coderateCap, hierarchyCap, guardIntervalCap, isT2Supported, isMisoSupported); } jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(II)V"); jint modulationCap = caps.isdbs3Caps().modulationCap; jint coderateCap = caps.isdbs3Caps().coderateCap; return env->NewObject(clazz, capsInit, modulationCap, coderateCap); } jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbsFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(II)V"); jint modulationCap = caps.isdbsCaps().modulationCap; jint coderateCap = caps.isdbsCaps().coderateCap; return env->NewObject(clazz, capsInit, modulationCap, coderateCap); } jobject JTuner::getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbtFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(IIIII)V"); jint modeCap = caps.isdbtCaps().modeCap; jint bandwidthCap = caps.isdbtCaps().bandwidthCap; jint modulationCap = caps.isdbtCaps().modulationCap; jint coderateCap = caps.isdbtCaps().coderateCap; jint guardIntervalCap = caps.isdbtCaps().guardIntervalCap; return env->NewObject(clazz, capsInit, modeCap, bandwidthCap, modulationCap, coderateCap, guardIntervalCap); } jobject JTuner::getDtmbFrontendCaps(JNIEnv *env, int id) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DtmbFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(IIIIII)V"); shared_ptr dtmbCaps = mTunerClient->getFrontendDtmbCapabilities(id); if (dtmbCaps == NULL) { return NULL; } jint modulationCap = dtmbCaps->modulationCap; jint transmissionModeCap = dtmbCaps->transmissionModeCap; jint guardIntervalCap = dtmbCaps->guardIntervalCap; jint interleaveModeCap = dtmbCaps->interleaveModeCap; jint codeRateCap = dtmbCaps->codeRateCap; jint bandwidthCap = dtmbCaps->bandwidthCap; return env->NewObject(clazz, capsInit, modulationCap, transmissionModeCap, guardIntervalCap, interleaveModeCap, codeRateCap, bandwidthCap); } jobject JTuner::getFrontendInfo(int id) { shared_ptr feInfo; feInfo = mTunerClient->getFrontendInfo(id); if (feInfo == NULL) { return NULL; } JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendInfo"); jmethodID infoInit = env->GetMethodID(clazz, "", "(IIIIIIII[ILandroid/media/tv/tuner/frontend/FrontendCapabilities;)V"); jint type = (jint) feInfo->type; jint minFrequency = feInfo->minFrequency; jint maxFrequency = feInfo->maxFrequency; jint minSymbolRate = feInfo->minSymbolRate; jint maxSymbolRate = feInfo->maxSymbolRate; jint acquireRange = feInfo->acquireRange; jint exclusiveGroupId = feInfo->exclusiveGroupId; jintArray statusCaps = env->NewIntArray(feInfo->statusCaps.size()); env->SetIntArrayRegion( statusCaps, 0, feInfo->statusCaps.size(), reinterpret_cast(&feInfo->statusCaps[0])); FrontendInfo::FrontendCapabilities caps = feInfo->frontendCaps; jobject jcaps = NULL; if (feInfo->type == static_cast( ::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) { jcaps = getDtmbFrontendCaps(env, id); } switch(feInfo->type) { case FrontendType::ANALOG: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::analogCaps == caps.getDiscriminator()) { jcaps = getAnalogFrontendCaps(env, caps); } break; case FrontendType::ATSC3: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atsc3Caps == caps.getDiscriminator()) { jcaps = getAtsc3FrontendCaps(env, caps); } break; case FrontendType::ATSC: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atscCaps == caps.getDiscriminator()) { jcaps = getAtscFrontendCaps(env, caps); } break; case FrontendType::DVBC: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbcCaps == caps.getDiscriminator()) { jcaps = getDvbcFrontendCaps(env, caps); } break; case FrontendType::DVBS: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbsCaps == caps.getDiscriminator()) { jcaps = getDvbsFrontendCaps(env, caps); } break; case FrontendType::DVBT: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbtCaps == caps.getDiscriminator()) { jcaps = getDvbtFrontendCaps(env, caps); } break; case FrontendType::ISDBS: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbsCaps == caps.getDiscriminator()) { jcaps = getIsdbsFrontendCaps(env, caps); } break; case FrontendType::ISDBS3: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbs3Caps == caps.getDiscriminator()) { jcaps = getIsdbs3FrontendCaps(env, caps); } break; case FrontendType::ISDBT: if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbtCaps == caps.getDiscriminator()) { jcaps = getIsdbtFrontendCaps(env, caps); } break; default: break; } return env->NewObject( clazz, infoInit, (jint) id, type, minFrequency, maxFrequency, minSymbolRate, maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps); } jobject JTuner::openLnbByHandle(int handle) { if (mTunerClient == NULL) { return NULL; } sp lnbClient; sp callback = new LnbClientCallbackImpl(); lnbClient = mTunerClient->openLnb(handle); if (lnbClient == NULL) { ALOGD("Failed to open lnb, handle = %d", handle); return NULL; } if (lnbClient->setCallback(callback) != Result::SUCCESS) { ALOGD("Failed to set lnb callback"); return NULL; } JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject lnbObj = env->NewObject( env->FindClass("android/media/tv/tuner/Lnb"), gFields.lnbInitID); lnbClient->incStrong(lnbObj); env->SetLongField(lnbObj, gFields.lnbContext, (jlong)lnbClient.get()); callback->setLnb(env->NewWeakGlobalRef(lnbObj)); return lnbObj; } jobject JTuner::openLnbByName(jstring name) { if (mTunerClient == NULL) { return NULL; } JNIEnv *env = AndroidRuntime::getJNIEnv(); std::string lnbName(env->GetStringUTFChars(name, nullptr)); sp lnbClient; sp callback = new LnbClientCallbackImpl(); lnbClient = mTunerClient->openLnbByName(lnbName); if (lnbClient == NULL) { ALOGD("Failed to open lnb by name, name = %s", lnbName.c_str()); return NULL; } if (lnbClient->setCallback(callback) != Result::SUCCESS) { ALOGD("Failed to set lnb callback"); return NULL; } jobject lnbObj = env->NewObject( env->FindClass("android/media/tv/tuner/Lnb"), gFields.lnbInitID); lnbClient->incStrong(lnbObj); env->SetLongField(lnbObj, gFields.lnbContext, (jlong)lnbClient.get()); callback->setLnb(env->NewWeakGlobalRef(lnbObj)); return lnbObj; } int JTuner::tune(const FrontendSettings& settings, const FrontendSettingsExt1_1& settingsExt1_1) { if (mFeClient == nullptr) { ALOGE("frontend is not initialized"); return (int)Result::INVALID_STATE; } return (int) mFeClient->tune(settings, settingsExt1_1); } int JTuner::stopTune() { if (mFeClient == nullptr) { ALOGE("frontend is not initialized"); return (int)Result::INVALID_STATE; } return (int) mFeClient->stopTune(); } int JTuner::scan(const FrontendSettings& settings, FrontendScanType scanType, const FrontendSettingsExt1_1& settingsExt1_1) { if (mFeClient == NULL) { ALOGE("frontend client is not initialized"); return (int)Result::INVALID_STATE; } Result result = mFeClient->scan(settings, scanType, settingsExt1_1); return (int)result; } int JTuner::stopScan() { if (mFeClient == NULL) { ALOGE("frontend client is not initialized"); return (int)Result::INVALID_STATE; } Result result = mFeClient->stopScan(); return (int)result; } int JTuner::setLnb(sp lnbClient) { if (mFeClient == NULL) { ALOGE("frontend client is not initialized"); return (int)Result::INVALID_STATE; } if (lnbClient == NULL) { ALOGE("lnb is not initialized"); return (int)Result::INVALID_STATE; } Result result = mFeClient->setLnb(lnbClient); return (int)result; } int JTuner::setLna(bool enable) { if (mFeClient == NULL) { ALOGE("frontend client is not initialized"); return (int)Result::INVALID_STATE; } Result result = mFeClient->setLna(enable); return (int)result; } Result JTuner::openDemux(int handle) { if (mTunerClient == nullptr) { return Result::NOT_INITIALIZED; } if (mDemuxClient == nullptr) { mDemuxClient = mTunerClient->openDemux(handle); if (mDemuxClient == NULL) { ALOGE("Failed to open demux"); return Result::UNKNOWN_ERROR; } if (mFeClient != NULL) { mDemuxClient->setFrontendDataSource(mFeClient); } } return Result::SUCCESS; } jint JTuner::close() { Result res = Result::SUCCESS; if (mFeClient != NULL) { res = mFeClient->close(); if (res != Result::SUCCESS) { return (jint) res; } mFeClient = NULL; } if (mDemuxClient != NULL) { res = mDemuxClient->close(); if (res != Result::SUCCESS) { return (jint) res; } mDemuxClient = NULL; } return (jint) res; } jobject JTuner::getAvSyncHwId(sp filterClient) { if (mDemuxClient == NULL) { return NULL; } int avSyncHwId = mDemuxClient->getAvSyncHwId(filterClient); if (avSyncHwId >= 0) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass integerClazz = env->FindClass("java/lang/Integer"); jmethodID intInit = env->GetMethodID(integerClazz, "", "(I)V"); return env->NewObject(integerClazz, intInit, avSyncHwId); } return NULL; } jobject JTuner::getAvSyncTime(jint id) { if (mDemuxClient == NULL) { return NULL; } long time = mDemuxClient->getAvSyncTime((int)id); if (time >= 0) { JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass longClazz = env->FindClass("java/lang/Long"); jmethodID longInit = env->GetMethodID(longClazz, "", "(J)V"); return env->NewObject(longClazz, longInit, static_cast(time)); } return NULL; } int JTuner::connectCiCam(jint id) { if (mDemuxClient == NULL) { return (int)Result::NOT_INITIALIZED; } Result r = mDemuxClient->connectCiCam((int)id); return (int) r; } int JTuner::linkCiCam(int id) { if (mFeClient == NULL) { ALOGE("frontend client is not initialized"); return (int)Constant::INVALID_LTS_ID; } return mFeClient->linkCiCamToFrontend(id); } int JTuner::disconnectCiCam() { if (mDemuxClient == NULL) { return (int)Result::NOT_INITIALIZED; } Result r = mDemuxClient->disconnectCiCam(); return (int) r; } int JTuner::unlinkCiCam(int id) { if (mFeClient == NULL) { ALOGE("frontend client is not initialized"); return (int)Result::INVALID_STATE; } Result r = mFeClient->unlinkCiCamToFrontend(id); return (int) r; } jobject JTuner::openDescrambler() { ALOGD("JTuner::openDescrambler"); if (mTunerClient == nullptr || mDemuxClient == nullptr) { return NULL; } sp descramblerClient = mTunerClient->openDescrambler(0/*unused*/); if (descramblerClient == NULL) { ALOGD("Failed to open descrambler"); return NULL; } descramblerClient->setDemuxSource(mDemuxClient); JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject descramblerObj = env->NewObject( env->FindClass("android/media/tv/tuner/Descrambler"), gFields.descramblerInitID); descramblerClient->incStrong(descramblerObj); env->SetLongField(descramblerObj, gFields.descramblerContext, (jlong)descramblerClient.get()); return descramblerObj; } jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { if (mDemuxClient == NULL) { return NULL; } sp filterClient; sp callback = new FilterClientCallbackImpl(); filterClient = mDemuxClient->openFilter(type, bufferSize, callback); if (filterClient == NULL) { ALOGD("Failed to open filter, type = %d", type.mainType); return NULL; } uint64_t fId; Result res = filterClient->getId64Bit(fId); if (res != Result::SUCCESS) { uint32_t id; filterClient->getId(id); fId = static_cast(id); } JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject filterObj = env->NewObject( env->FindClass("android/media/tv/tuner/filter/Filter"), gFields.filterInitID, (jlong) fId); filterClient->incStrong(filterObj); env->SetLongField(filterObj, gFields.filterContext, (jlong)filterClient.get()); callback->setFilter(env->NewWeakGlobalRef(filterObj), filterClient); return filterObj; } jobject JTuner::openTimeFilter() { if (mDemuxClient == NULL) { return NULL; } JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject timeFilterObj = env->NewObject( env->FindClass("android/media/tv/tuner/filter/TimeFilter"), gFields.timeFilterInitID); sp timeFilterClient = mDemuxClient->openTimeFilter(); if (timeFilterClient == NULL) { ALOGD("Failed to open time filter."); return NULL; } timeFilterClient->incStrong(timeFilterObj); env->SetLongField(timeFilterObj, gFields.timeFilterContext, (jlong)timeFilterClient.get()); return timeFilterObj; } jobject JTuner::openDvr(DvrType type, jlong bufferSize) { ALOGD("JTuner::openDvr"); if (mDemuxClient == NULL) { return NULL; } sp dvrClient; sp callback = new DvrClientCallbackImpl(); dvrClient = mDemuxClient->openDvr(type, (int) bufferSize, callback); if (dvrClient == NULL) { return NULL; } JNIEnv *env = AndroidRuntime::getJNIEnv(); jobject dvrObj; if (type == DvrType::RECORD) { dvrObj = env->NewObject( env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"), gFields.dvrRecorderInitID); dvrClient->incStrong(dvrObj); env->SetLongField(dvrObj, gFields.dvrRecorderContext, (jlong)dvrClient.get()); } else { dvrObj = env->NewObject( env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"), gFields.dvrPlaybackInitID); dvrClient->incStrong(dvrObj); env->SetLongField(dvrObj, gFields.dvrPlaybackContext, (jlong)dvrClient.get()); } callback->setDvr(env->NewWeakGlobalRef(dvrObj)); return dvrObj; } jobject JTuner::getDemuxCaps() { if (mTunerClient == NULL) { return NULL; } shared_ptr caps; caps = mTunerClient->getDemuxCaps(); if (caps == NULL) { return NULL; } JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass clazz = env->FindClass("android/media/tv/tuner/DemuxCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(IIIIIIIIIJI[IZ)V"); jint numDemux = caps->numDemux; jint numRecord = caps->numRecord; jint numPlayback = caps->numPlayback; jint numTsFilter = caps->numTsFilter; jint numSectionFilter = caps->numSectionFilter; jint numAudioFilter = caps->numAudioFilter; jint numVideoFilter = caps->numVideoFilter; jint numPesFilter = caps->numPesFilter; jint numPcrFilter = caps->numPcrFilter; jlong numBytesInSectionFilter = caps->numBytesInSectionFilter; jint filterCaps = static_cast(caps->filterCaps); jboolean bTimeFilter = caps->bTimeFilter; jintArray linkCaps = env->NewIntArray(caps->linkCaps.size()); env->SetIntArrayRegion( linkCaps, 0, caps->linkCaps.size(), reinterpret_cast(&caps->linkCaps[0])); return env->NewObject(clazz, capsInit, numDemux, numRecord, numPlayback, numTsFilter, numSectionFilter, numAudioFilter, numVideoFilter, numPesFilter, numPcrFilter, numBytesInSectionFilter, filterCaps, linkCaps, bTimeFilter); } jobject JTuner::getFrontendStatus(jintArray types) { if (mFeClient == NULL) { return NULL; } JNIEnv *env = AndroidRuntime::getJNIEnv(); jsize size = env->GetArrayLength(types); jint intTypes[size]; env->GetIntArrayRegion(types, 0, size, intTypes); std::vector v; std::vector v_1_1; for (int i = 0; i < size; i++) { if (isV1_1ExtendedStatusType(intTypes[i])) { v_1_1.push_back(static_cast(intTypes[i])); } else { v.push_back(static_cast(intTypes[i])); } } hidl_vec status = mFeClient->getStatus(v); hidl_vec status_1_1 = mFeClient->getStatusExtended_1_1(v_1_1); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendStatus"); jmethodID init = env->GetMethodID(clazz, "", "()V"); jobject statusObj = env->NewObject(clazz, init); jclass intClazz = env->FindClass("java/lang/Integer"); jmethodID initInt = env->GetMethodID(intClazz, "", "(I)V"); jclass booleanClazz = env->FindClass("java/lang/Boolean"); jmethodID initBoolean = env->GetMethodID(booleanClazz, "", "(Z)V"); for (auto s : status) { switch(s.getDiscriminator()) { case FrontendStatus::hidl_discriminator::isDemodLocked: { jfieldID field = env->GetFieldID(clazz, "mIsDemodLocked", "Ljava/lang/Boolean;"); jobject newBooleanObj = env->NewObject( booleanClazz, initBoolean, static_cast(s.isDemodLocked())); env->SetObjectField(statusObj, field, newBooleanObj); break; } case FrontendStatus::hidl_discriminator::snr: { jfieldID field = env->GetFieldID(clazz, "mSnr", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.snr())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::ber: { jfieldID field = env->GetFieldID(clazz, "mBer", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.ber())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::per: { jfieldID field = env->GetFieldID(clazz, "mPer", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.per())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::preBer: { jfieldID field = env->GetFieldID(clazz, "mPerBer", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.preBer())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::signalQuality: { jfieldID field = env->GetFieldID(clazz, "mSignalQuality", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.signalQuality())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::signalStrength: { jfieldID field = env->GetFieldID(clazz, "mSignalStrength", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.signalStrength())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::symbolRate: { jfieldID field = env->GetFieldID(clazz, "mSymbolRate", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.symbolRate())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::innerFec: { jfieldID field = env->GetFieldID(clazz, "mInnerFec", "Ljava/lang/Long;"); jclass longClazz = env->FindClass("java/lang/Long"); jmethodID initLong = env->GetMethodID(longClazz, "", "(J)V"); jobject newLongObj = env->NewObject( longClazz, initLong, static_cast(s.innerFec())); env->SetObjectField(statusObj, field, newLongObj); break; } case FrontendStatus::hidl_discriminator::modulation: { jfieldID field = env->GetFieldID(clazz, "mModulation", "Ljava/lang/Integer;"); FrontendModulationStatus modulation = s.modulation(); jint intModulation; bool valid = true; switch(modulation.getDiscriminator()) { case FrontendModulationStatus::hidl_discriminator::dvbc: { intModulation = static_cast(modulation.dvbc()); break; } case FrontendModulationStatus::hidl_discriminator::dvbs: { intModulation = static_cast(modulation.dvbs()); break; } case FrontendModulationStatus::hidl_discriminator::isdbs: { intModulation = static_cast(modulation.isdbs()); break; } case FrontendModulationStatus::hidl_discriminator::isdbs3: { intModulation = static_cast(modulation.isdbs3()); break; } case FrontendModulationStatus::hidl_discriminator::isdbt: { intModulation = static_cast(modulation.isdbt()); break; } default: { valid = false; break; } } if (valid) { jobject newIntegerObj = env->NewObject(intClazz, initInt, intModulation); env->SetObjectField(statusObj, field, newIntegerObj); } break; } case FrontendStatus::hidl_discriminator::inversion: { jfieldID field = env->GetFieldID(clazz, "mInversion", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.inversion())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::lnbVoltage: { jfieldID field = env->GetFieldID(clazz, "mLnbVoltage", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.lnbVoltage())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::plpId: { jfieldID field = env->GetFieldID(clazz, "mPlpId", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.plpId())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::isEWBS: { jfieldID field = env->GetFieldID(clazz, "mIsEwbs", "Ljava/lang/Boolean;"); jobject newBooleanObj = env->NewObject( booleanClazz, initBoolean, static_cast(s.isEWBS())); env->SetObjectField(statusObj, field, newBooleanObj); break; } case FrontendStatus::hidl_discriminator::agc: { jfieldID field = env->GetFieldID(clazz, "mAgc", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.agc())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::isLnaOn: { jfieldID field = env->GetFieldID(clazz, "mIsLnaOn", "Ljava/lang/Boolean;"); jobject newBooleanObj = env->NewObject( booleanClazz, initBoolean, static_cast(s.isLnaOn())); env->SetObjectField(statusObj, field, newBooleanObj); break; } case FrontendStatus::hidl_discriminator::isLayerError: { jfieldID field = env->GetFieldID(clazz, "mIsLayerErrors", "[Z"); hidl_vec layerErr = s.isLayerError(); jbooleanArray valObj = env->NewBooleanArray(layerErr.size()); for (size_t i = 0; i < layerErr.size(); i++) { jboolean x = layerErr[i]; env->SetBooleanArrayRegion(valObj, i, 1, &x); } env->SetObjectField(statusObj, field, valObj); break; } case FrontendStatus::hidl_discriminator::mer: { jfieldID field = env->GetFieldID(clazz, "mMer", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.mer())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::freqOffset: { jfieldID field = env->GetFieldID(clazz, "mFreqOffset", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.freqOffset())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::hierarchy: { jfieldID field = env->GetFieldID(clazz, "mHierarchy", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.hierarchy())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatus::hidl_discriminator::isRfLocked: { jfieldID field = env->GetFieldID(clazz, "mIsRfLocked", "Ljava/lang/Boolean;"); jobject newBooleanObj = env->NewObject( booleanClazz, initBoolean, static_cast(s.isRfLocked())); env->SetObjectField(statusObj, field, newBooleanObj); break; } case FrontendStatus::hidl_discriminator::plpInfo: { jfieldID field = env->GetFieldID(clazz, "mPlpInfo", "[Landroid/media/tv/tuner/frontend/FrontendStatus$Atsc3PlpTuningInfo;"); jclass plpClazz = env->FindClass( "android/media/tv/tuner/frontend/FrontendStatus$Atsc3PlpTuningInfo"); jmethodID initPlp = env->GetMethodID(plpClazz, "", "(IZI)V"); hidl_vec plpInfos = s.plpInfo(); jobjectArray valObj = env->NewObjectArray(plpInfos.size(), plpClazz, NULL); for (int i = 0; i < plpInfos.size(); i++) { auto info = plpInfos[i]; jint plpId = (jint) info.plpId; jboolean isLocked = (jboolean) info.isLocked; jint uec = (jint) info.uec; jobject plpObj = env->NewObject(plpClazz, initPlp, plpId, isLocked, uec); env->SetObjectArrayElement(valObj, i, plpObj); } env->SetObjectField(statusObj, field, valObj); break; } default: { break; } } } for (auto s : status_1_1) { switch(s.getDiscriminator()) { case FrontendStatusExt1_1::hidl_discriminator::modulations: { jfieldID field = env->GetFieldID(clazz, "mModulationsExt", "[I"); std::vector v = s.modulations(); jintArray valObj = env->NewIntArray(v.size()); bool valid = false; jint m[1]; for (int i = 0; i < v.size(); i++) { auto modulation = v[i]; switch(modulation.getDiscriminator()) { case FrontendModulation::hidl_discriminator::dvbc: { m[0] = static_cast(modulation.dvbc()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } case FrontendModulation::hidl_discriminator::dvbs: { m[0] = static_cast(modulation.dvbs()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } case FrontendModulation::hidl_discriminator::dvbt: { m[0] = static_cast(modulation.dvbt()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } case FrontendModulation::hidl_discriminator::isdbs: { m[0] = static_cast(modulation.isdbs()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } case FrontendModulation::hidl_discriminator::isdbs3: { m[0] = static_cast(modulation.isdbs3()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } case FrontendModulation::hidl_discriminator::isdbt: { m[0] = static_cast(modulation.isdbt()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } case FrontendModulation::hidl_discriminator::atsc: { m[0] = static_cast(modulation.atsc()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } case FrontendModulation::hidl_discriminator::atsc3: { m[0] = static_cast(modulation.atsc3()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } case FrontendModulation::hidl_discriminator::dtmb: { m[0] = static_cast(modulation.dtmb()); env->SetIntArrayRegion(valObj, i, 1, m); valid = true; break; } default: break; } } if (valid) { env->SetObjectField(statusObj, field, valObj); } break; } case FrontendStatusExt1_1::hidl_discriminator::bers: { jfieldID field = env->GetFieldID(clazz, "mBers", "[I"); std::vector v = s.bers(); jintArray valObj = env->NewIntArray(v.size()); env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast(&v[0])); env->SetObjectField(statusObj, field, valObj); break; } case FrontendStatusExt1_1::hidl_discriminator::codeRates: { jfieldID field = env->GetFieldID(clazz, "mCodeRates", "[I"); std::vector<::android::hardware::tv::tuner::V1_1::FrontendInnerFec> v = s.codeRates(); jintArray valObj = env->NewIntArray(v.size()); env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast(&v[0])); env->SetObjectField(statusObj, field, valObj); break; } case FrontendStatusExt1_1::hidl_discriminator::bandwidth: { jfieldID field = env->GetFieldID(clazz, "mBandwidth", "Ljava/lang/Integer;"); auto bandwidth = s.bandwidth(); jint intBandwidth; bool valid = true; switch(bandwidth.getDiscriminator()) { case FrontendBandwidth::hidl_discriminator::atsc3: { intBandwidth = static_cast(bandwidth.atsc3()); break; } case FrontendBandwidth::hidl_discriminator::dvbt: { intBandwidth = static_cast(bandwidth.dvbt()); break; } case FrontendBandwidth::hidl_discriminator::dvbc: { intBandwidth = static_cast(bandwidth.dvbc()); break; } case FrontendBandwidth::hidl_discriminator::isdbt: { intBandwidth = static_cast(bandwidth.isdbt()); break; } case FrontendBandwidth::hidl_discriminator::dtmb: { intBandwidth = static_cast(bandwidth.dtmb()); break; } default: valid = false; break; } if (valid) { jobject newIntegerObj = env->NewObject(intClazz, initInt, intBandwidth); env->SetObjectField(statusObj, field, newIntegerObj); } break; } case FrontendStatusExt1_1::hidl_discriminator::interval: { jfieldID field = env->GetFieldID(clazz, "mGuardInterval", "Ljava/lang/Integer;"); auto interval = s.interval(); jint intInterval; bool valid = true; switch(interval.getDiscriminator()) { case FrontendGuardInterval::hidl_discriminator::dvbt: { intInterval = static_cast(interval.dvbt()); break; } case FrontendGuardInterval::hidl_discriminator::isdbt: { intInterval = static_cast(interval.isdbt()); break; } case FrontendGuardInterval::hidl_discriminator::dtmb: { intInterval = static_cast(interval.dtmb()); break; } default: valid = false; break; } if (valid) { jobject newIntegerObj = env->NewObject(intClazz, initInt, intInterval); env->SetObjectField(statusObj, field, newIntegerObj); } break; } case FrontendStatusExt1_1::hidl_discriminator::transmissionMode: { jfieldID field = env->GetFieldID(clazz, "mTransmissionMode", "Ljava/lang/Integer;"); auto transmissionMode = s.transmissionMode(); jint intTransmissionMode; bool valid = true; switch(transmissionMode.getDiscriminator()) { case FrontendTransmissionMode::hidl_discriminator::dvbt: { intTransmissionMode = static_cast(transmissionMode.dvbt()); break; } case FrontendTransmissionMode::hidl_discriminator::isdbt: { intTransmissionMode = static_cast(transmissionMode.isdbt()); break; } case FrontendTransmissionMode::hidl_discriminator::dtmb: { intTransmissionMode = static_cast(transmissionMode.dtmb()); break; } default: valid = false; break; } if (valid) { jobject newIntegerObj = env->NewObject(intClazz, initInt, intTransmissionMode); env->SetObjectField(statusObj, field, newIntegerObj); } break; } case FrontendStatusExt1_1::hidl_discriminator::uec: { jfieldID field = env->GetFieldID(clazz, "mUec", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.uec())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatusExt1_1::hidl_discriminator::systemId: { jfieldID field = env->GetFieldID(clazz, "mSystemId", "Ljava/lang/Integer;"); jobject newIntegerObj = env->NewObject( intClazz, initInt, static_cast(s.systemId())); env->SetObjectField(statusObj, field, newIntegerObj); break; } case FrontendStatusExt1_1::hidl_discriminator::interleaving: { jfieldID field = env->GetFieldID(clazz, "mInterleaving", "[I"); std::vector v = s.interleaving(); jintArray valObj = env->NewIntArray(v.size()); bool valid = false; jint in[1]; for (int i = 0; i < v.size(); i++) { auto interleaving = v[i]; switch(interleaving.getDiscriminator()) { case FrontendInterleaveMode::hidl_discriminator::atsc3: { in[0] = static_cast(interleaving.atsc3()); env->SetIntArrayRegion(valObj, i, 1, in); valid = true; break; } case FrontendInterleaveMode::hidl_discriminator::dvbc: { in[0] = static_cast(interleaving.dvbc()); env->SetIntArrayRegion(valObj, i, 1, in); valid = true; break; } case FrontendInterleaveMode::hidl_discriminator::dtmb: { in[0] = static_cast(interleaving.dtmb()); env->SetIntArrayRegion(valObj, i, 1, in); valid = true; break; } default: break; } } if (valid) { env->SetObjectField(statusObj, field, valObj); } break; } case FrontendStatusExt1_1::hidl_discriminator::isdbtSegment: { jfieldID field = env->GetFieldID(clazz, "mIsdbtSegment", "[I"); std::vector v = s.isdbtSegment(); jintArray valObj = env->NewIntArray(v.size()); env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast(&v[0])); env->SetObjectField(statusObj, field, valObj); break; } case FrontendStatusExt1_1::hidl_discriminator::tsDataRate: { jfieldID field = env->GetFieldID(clazz, "mTsDataRate", "[I"); std::vector v = s.tsDataRate(); jintArray valObj = env->NewIntArray(v.size()); env->SetIntArrayRegion(valObj, 0, v.size(), reinterpret_cast(&v[0])); env->SetObjectField(statusObj, field, valObj); break; } case FrontendStatusExt1_1::hidl_discriminator::rollOff: { jfieldID field = env->GetFieldID(clazz, "mRollOff", "Ljava/lang/Integer;"); auto rollOff = s.rollOff(); jint intRollOff; bool valid = true; switch(rollOff.getDiscriminator()) { case FrontendRollOff::hidl_discriminator::dvbs: { intRollOff = static_cast(rollOff.dvbs()); break; } case FrontendRollOff::hidl_discriminator::isdbs: { intRollOff = static_cast(rollOff.isdbs()); break; } case FrontendRollOff::hidl_discriminator::isdbs3: { intRollOff = static_cast(rollOff.isdbs3()); break; } default: valid = false; break; } if (valid) { jobject newIntegerObj = env->NewObject(intClazz, initInt, intRollOff); env->SetObjectField(statusObj, field, newIntegerObj); } break; } case FrontendStatusExt1_1::hidl_discriminator::isMiso: { jfieldID field = env->GetFieldID(clazz, "mIsMisoEnabled", "Ljava/lang/Boolean;"); jobject newBooleanObj = env->NewObject( booleanClazz, initBoolean, static_cast(s.isMiso())); env->SetObjectField(statusObj, field, newBooleanObj); break; } case FrontendStatusExt1_1::hidl_discriminator::isLinear: { jfieldID field = env->GetFieldID(clazz, "mIsLinear", "Ljava/lang/Boolean;"); jobject newBooleanObj = env->NewObject( booleanClazz, initBoolean, static_cast(s.isLinear())); env->SetObjectField(statusObj, field, newBooleanObj); break; } case FrontendStatusExt1_1::hidl_discriminator::isShortFrames: { jfieldID field = env->GetFieldID(clazz, "mIsShortFrames", "Ljava/lang/Boolean;"); jobject newBooleanObj = env->NewObject( booleanClazz, initBoolean, static_cast(s.isShortFrames())); env->SetObjectField(statusObj, field, newBooleanObj); break; } default: { break; } } } return statusObj; } bool JTuner::isV1_1ExtendedStatusType(int type) { return (type > static_cast(FrontendStatusType::ATSC3_PLP_INFO) && type <= static_cast(FrontendStatusTypeExt1_1::IS_SHORT_FRAMES)); } jint JTuner::closeFrontend() { Result r = Result::SUCCESS; if (mFeClient != NULL) { r = mFeClient->close(); } if (r == Result::SUCCESS) { mFeClient = NULL; } return (jint) r; } jint JTuner::closeDemux() { Result r = Result::SUCCESS; if (mDemuxClient != NULL) { r = mDemuxClient->close(); } if (r == Result::SUCCESS) { mDemuxClient = NULL; } return (jint) r; } } // namespace android //////////////////////////////////////////////////////////////////////////////// using namespace android; static sp setTuner(JNIEnv *env, jobject thiz, const sp &tuner) { sp old = (JTuner *)env->GetLongField(thiz, gFields.tunerContext); if (tuner != NULL) { tuner->incStrong(thiz); } if (old != NULL) { old->decStrong(thiz); } if (tuner != NULL) { env->SetLongField(thiz, gFields.tunerContext, (jlong)tuner.get()); } return old; } static sp getTuner(JNIEnv *env, jobject thiz) { return (JTuner *)env->GetLongField(thiz, gFields.tunerContext); } static sp getDescramblerClient(JNIEnv *env, jobject descrambler) { return (DescramblerClient *)env->GetLongField(descrambler, gFields.descramblerContext); } static DemuxPid getDemuxPid(int pidType, int pid) { DemuxPid demuxPid; if ((int)pidType == 1) { demuxPid.tPid(static_cast(pid)); } else if ((int)pidType == 2) { demuxPid.mmtpPid(static_cast(pid)); } return demuxPid; } static uint32_t getFrontendSettingsFreq(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings"); jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I"); uint32_t freq = static_cast(env->GetIntField(settings, freqField)); return freq; } static uint32_t getFrontendSettingsEndFreq(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings"); jfieldID endFreqField = env->GetFieldID(clazz, "mEndFrequency", "I"); uint32_t endFreq = static_cast(env->GetIntField(settings, endFreqField)); return endFreq; } static FrontendSpectralInversion getFrontendSettingsSpectralInversion( JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/FrontendSettings"); jfieldID inversionField = env->GetFieldID(clazz, "mSpectralInversion", "I"); FrontendSpectralInversion inversion = static_cast(env->GetIntField(settings, inversionField)); return inversion; } static FrontendSettings getAnalogFrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendSettings"); FrontendAnalogType analogType = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mSignalType", "I"))); FrontendAnalogSifStandard sifStandard = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mSifStandard", "I"))); FrontendAnalogSettings frontendAnalogSettings { .frequency = freq, .type = analogType, .sifStandard = sifStandard, }; frontendSettings.analog(frontendAnalogSettings); return frontendSettings; } static void getAnalogFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings, FrontendSettingsExt1_1& settingsExt1_1) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendSettings"); FrontendAnalogAftFlag aftFlag = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mAftFlag", "I"))); FrontendAnalogSettingsExt1_1 analogExt1_1 { .aftFlag = aftFlag, }; settingsExt1_1.settingExt.analog(analogExt1_1); } static hidl_vec getAtsc3PlpSettings( JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendSettings"); jobjectArray plpSettings = reinterpret_cast( env->GetObjectField(settings, env->GetFieldID( clazz, "mPlpSettings", "[Landroid/media/tv/tuner/frontend/Atsc3PlpSettings;"))); int len = env->GetArrayLength(plpSettings); jclass plpClazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3PlpSettings"); hidl_vec plps = hidl_vec(len); // parse PLP settings for (int i = 0; i < len; i++) { jobject plp = env->GetObjectArrayElement(plpSettings, i); uint8_t plpId = static_cast( env->GetIntField(plp, env->GetFieldID(plpClazz, "mPlpId", "I"))); FrontendAtsc3Modulation modulation = static_cast( env->GetIntField(plp, env->GetFieldID(plpClazz, "mModulation", "I"))); FrontendAtsc3TimeInterleaveMode interleaveMode = static_cast( env->GetIntField( plp, env->GetFieldID(plpClazz, "mInterleaveMode", "I"))); FrontendAtsc3CodeRate codeRate = static_cast( env->GetIntField(plp, env->GetFieldID(plpClazz, "mCodeRate", "I"))); FrontendAtsc3Fec fec = static_cast( env->GetIntField(plp, env->GetFieldID(plpClazz, "mFec", "I"))); FrontendAtsc3PlpSettings frontendAtsc3PlpSettings { .plpId = plpId, .modulation = modulation, .interleaveMode = interleaveMode, .codeRate = codeRate, .fec = fec, }; plps[i] = frontendAtsc3PlpSettings; } return plps; } static FrontendSettings getAtsc3FrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendSettings"); FrontendAtsc3Bandwidth bandwidth = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mBandwidth", "I"))); FrontendAtsc3DemodOutputFormat demod = static_cast( env->GetIntField( settings, env->GetFieldID(clazz, "mDemodOutputFormat", "I"))); hidl_vec plps = getAtsc3PlpSettings(env, settings); FrontendAtsc3Settings frontendAtsc3Settings { .frequency = freq, .bandwidth = bandwidth, .demodOutputFormat = demod, .plpSettings = plps, }; frontendSettings.atsc3(frontendAtsc3Settings); return frontendSettings; } static FrontendSettings getAtscFrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AtscFrontendSettings"); FrontendAtscModulation modulation = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I"))); FrontendAtscSettings frontendAtscSettings { .frequency = freq, .modulation = modulation, }; frontendSettings.atsc(frontendAtscSettings); return frontendSettings; } static FrontendSettings getDvbcFrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendSettings"); FrontendDvbcModulation modulation = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I"))); FrontendInnerFec innerFec = static_cast( env->GetLongField(settings, env->GetFieldID(clazz, "mInnerFec", "J"))); uint32_t symbolRate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I"))); FrontendDvbcOuterFec outerFec = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mOuterFec", "I"))); FrontendDvbcAnnex annex = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mAnnex", "I"))); FrontendDvbcSpectralInversion spectralInversion = static_cast( env->GetIntField( settings, env->GetFieldID(clazz, "mSpectralInversion", "I"))); FrontendDvbcSettings frontendDvbcSettings { .frequency = freq, .modulation = modulation, .fec = innerFec, .symbolRate = symbolRate, .outerFec = outerFec, .annex = annex, .spectralInversion = spectralInversion, }; frontendSettings.dvbc(frontendDvbcSettings); return frontendSettings; } static void getDvbcFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings, FrontendSettingsExt1_1& settingsExt1_1) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendSettings"); FrontendCableTimeInterleaveMode interleaveMode = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mInterleaveMode", "I"))); FrontendDvbcBandwidth bandwidth = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mBandwidth", "I"))); FrontendDvbcSettingsExt1_1 dvbcExt1_1 { .interleaveMode = interleaveMode, .bandwidth = bandwidth, }; settingsExt1_1.settingExt.dvbc(dvbcExt1_1); } static FrontendDvbsCodeRate getDvbsCodeRate(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings"); jobject jcodeRate = env->GetObjectField(settings, env->GetFieldID( clazz, "mCodeRate", "Landroid/media/tv/tuner/frontend/DvbsCodeRate;")); jclass codeRateClazz = env->FindClass("android/media/tv/tuner/frontend/DvbsCodeRate"); FrontendInnerFec innerFec = static_cast( env->GetLongField( jcodeRate, env->GetFieldID(codeRateClazz, "mInnerFec", "J"))); bool isLinear = static_cast( env->GetBooleanField( jcodeRate, env->GetFieldID(codeRateClazz, "mIsLinear", "Z"))); bool isShortFrames = static_cast( env->GetBooleanField( jcodeRate, env->GetFieldID(codeRateClazz, "mIsShortFrames", "Z"))); uint32_t bitsPer1000Symbol = static_cast( env->GetIntField( jcodeRate, env->GetFieldID( codeRateClazz, "mBitsPer1000Symbol", "I"))); FrontendDvbsCodeRate coderate { .fec = innerFec, .isLinear = isLinear, .isShortFrames = isShortFrames, .bitsPer1000Symbol = bitsPer1000Symbol, }; return coderate; } static FrontendSettings getDvbsFrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings"); FrontendDvbsModulation modulation = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I"))); uint32_t symbolRate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I"))); FrontendDvbsRolloff rolloff = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mRolloff", "I"))); FrontendDvbsPilot pilot = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mPilot", "I"))); uint32_t inputStreamId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mInputStreamId", "I"))); FrontendDvbsStandard standard = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mStandard", "I"))); FrontendDvbsVcmMode vcmMode = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mVcmMode", "I"))); FrontendDvbsSettings frontendDvbsSettings { .frequency = freq, .modulation = modulation, .symbolRate = symbolRate, .rolloff = rolloff, .pilot = pilot, .inputStreamId = inputStreamId, .standard = standard, .vcmMode = vcmMode, }; jobject jcodeRate = env->GetObjectField(settings, env->GetFieldID(clazz, "mCodeRate", "Landroid/media/tv/tuner/frontend/DvbsCodeRate;")); if (jcodeRate != NULL) { frontendDvbsSettings.coderate = getDvbsCodeRate(env, settings); } frontendSettings.dvbs(frontendDvbsSettings); return frontendSettings; } static void getDvbsFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings, FrontendSettingsExt1_1& settingsExt1_1) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendSettings"); FrontendDvbsScanType scanType = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mScanType", "I"))); bool isDiseqcRxMessage = static_cast(env->GetBooleanField( settings, env->GetFieldID(clazz, "mIsDiseqcRxMessage", "Z"))); FrontendDvbsSettingsExt1_1 dvbsExt1_1 { .scanType = scanType, .isDiseqcRxMessage = isDiseqcRxMessage, }; settingsExt1_1.settingExt.dvbs(dvbsExt1_1); } static FrontendSettings getDvbtFrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendSettings"); FrontendDvbtTransmissionMode transmissionMode = static_cast( env->GetIntField( settings, env->GetFieldID(clazz, "mTransmissionMode", "I"))); FrontendDvbtBandwidth bandwidth = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mBandwidth", "I"))); FrontendDvbtConstellation constellation = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mConstellation", "I"))); FrontendDvbtHierarchy hierarchy = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mHierarchy", "I"))); FrontendDvbtCoderate hpCoderate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mHpCodeRate", "I"))); FrontendDvbtCoderate lpCoderate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mLpCodeRate", "I"))); FrontendDvbtGuardInterval guardInterval = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mGuardInterval", "I"))); bool isHighPriority = static_cast( env->GetBooleanField( settings, env->GetFieldID(clazz, "mIsHighPriority", "Z"))); FrontendDvbtStandard standard = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mStandard", "I"))); bool isMiso = static_cast( env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsMiso", "Z"))); FrontendDvbtPlpMode plpMode = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mPlpMode", "I"))); uint8_t plpId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mPlpId", "I"))); uint8_t plpGroupId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mPlpGroupId", "I"))); FrontendDvbtSettings frontendDvbtSettings { .frequency = freq, .transmissionMode = transmissionMode, .bandwidth = bandwidth, .constellation = constellation, .hierarchy = hierarchy, .hpCoderate = hpCoderate, .lpCoderate = lpCoderate, .guardInterval = guardInterval, .isHighPriority = isHighPriority, .standard = standard, .isMiso = isMiso, .plpMode = plpMode, .plpId = plpId, .plpGroupId = plpGroupId, }; frontendSettings.dvbt(frontendDvbtSettings); return frontendSettings; } static void getDvbtFrontendSettingsExt1_1(JNIEnv *env, const jobject& settings, FrontendSettingsExt1_1& settingsExt1_1) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendSettings"); FrontendDvbtSettingsExt1_1 dvbtExt1_1; int transmissionMode = env->GetIntField(settings, env->GetFieldID(clazz, "mTransmissionMode", "I")); dvbtExt1_1.transmissionMode = static_cast< ::android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode>( transmissionMode); int constellation = env->GetIntField(settings, env->GetFieldID(clazz, "mConstellation", "I")); dvbtExt1_1.constellation = static_cast< ::android::hardware::tv::tuner::V1_1::FrontendDvbtConstellation>(constellation); settingsExt1_1.settingExt.dvbt(dvbtExt1_1); } static FrontendSettings getIsdbsFrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbsFrontendSettings"); uint16_t streamId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I"))); FrontendIsdbsStreamIdType streamIdType = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mStreamIdType", "I"))); FrontendIsdbsModulation modulation = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I"))); FrontendIsdbsCoderate coderate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mCodeRate", "I"))); uint32_t symbolRate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I"))); FrontendIsdbsRolloff rolloff = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mRolloff", "I"))); FrontendIsdbsSettings frontendIsdbsSettings { .frequency = freq, .streamId = streamId, .streamIdType = streamIdType, .modulation = modulation, .coderate = coderate, .symbolRate = symbolRate, .rolloff = rolloff, }; frontendSettings.isdbs(frontendIsdbsSettings); return frontendSettings; } static FrontendSettings getIsdbs3FrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Isdbs3FrontendSettings"); uint16_t streamId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I"))); FrontendIsdbsStreamIdType streamIdType = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mStreamIdType", "I"))); FrontendIsdbs3Modulation modulation = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I"))); FrontendIsdbs3Coderate coderate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mCodeRate", "I"))); uint32_t symbolRate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mSymbolRate", "I"))); FrontendIsdbs3Rolloff rolloff = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mRolloff", "I"))); FrontendIsdbs3Settings frontendIsdbs3Settings { .frequency = freq, .streamId = streamId, .streamIdType = streamIdType, .modulation = modulation, .coderate = coderate, .symbolRate = symbolRate, .rolloff = rolloff, }; frontendSettings.isdbs3(frontendIsdbs3Settings); return frontendSettings; } static FrontendSettings getIsdbtFrontendSettings(JNIEnv *env, const jobject& settings) { FrontendSettings frontendSettings; uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbtFrontendSettings"); FrontendIsdbtModulation modulation = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I"))); FrontendIsdbtBandwidth bandwidth = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mBandwidth", "I"))); FrontendIsdbtMode mode = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mMode", "I"))); FrontendIsdbtCoderate coderate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mCodeRate", "I"))); FrontendIsdbtGuardInterval guardInterval = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mGuardInterval", "I"))); uint32_t serviceAreaId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mServiceAreaId", "I"))); FrontendIsdbtSettings frontendIsdbtSettings { .frequency = freq, .modulation = modulation, .bandwidth = bandwidth, .mode = mode, .coderate = coderate, .guardInterval = guardInterval, .serviceAreaId = serviceAreaId, }; frontendSettings.isdbt(frontendIsdbtSettings); return frontendSettings; } static void getDtmbFrontendSettings(JNIEnv *env, const jobject& settings, FrontendSettingsExt1_1& settingsExt1_1) { uint32_t freq = getFrontendSettingsFreq(env, settings); jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DtmbFrontendSettings"); FrontendDtmbModulation modulation = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mModulation", "I"))); FrontendDtmbBandwidth bandwidth = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mBandwidth", "I"))); FrontendDtmbTransmissionMode transmissionMode = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mTransmissionMode", "I"))); FrontendDtmbCodeRate codeRate = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mCodeRate", "I"))); FrontendDtmbGuardInterval guardInterval = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mGuardInterval", "I"))); FrontendDtmbTimeInterleaveMode interleaveMode = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mTimeInterleaveMode", "I"))); FrontendDtmbSettings frontendDtmbSettings { .frequency = freq, .modulation = modulation, .bandwidth = bandwidth, .transmissionMode = transmissionMode, .codeRate = codeRate, .guardInterval = guardInterval, .interleaveMode = interleaveMode, }; settingsExt1_1.settingExt.dtmb(frontendDtmbSettings); } static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) { ALOGD("getFrontendSettings %d", type); if (type == static_cast(::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) { return FrontendSettings(); } FrontendType feType = static_cast(type); switch(feType) { case FrontendType::ANALOG: return getAnalogFrontendSettings(env, settings); case FrontendType::ATSC3: return getAtsc3FrontendSettings(env, settings); case FrontendType::ATSC: return getAtscFrontendSettings(env, settings); case FrontendType::DVBC: return getDvbcFrontendSettings(env, settings); case FrontendType::DVBS: return getDvbsFrontendSettings(env, settings); case FrontendType::DVBT: return getDvbtFrontendSettings(env, settings); case FrontendType::ISDBS: return getIsdbsFrontendSettings(env, settings); case FrontendType::ISDBS3: return getIsdbs3FrontendSettings(env, settings); case FrontendType::ISDBT: return getIsdbtFrontendSettings(env, settings); default: // should never happen because a type is associated with a subclass of // FrontendSettings and not set by users jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Unsupported frontend type %d", type); return FrontendSettings(); } } static FrontendSettingsExt1_1 getFrontendSettingsExt1_1( JNIEnv *env, int type, jobject settings, int tunerVersion) { ALOGD("getFrontendSettingsExt1_1 %d", type); FrontendSettingsExt1_1 settingsExt1_1 { .endFrequency = static_cast(Constant::INVALID_FRONTEND_SETTING_FREQUENCY), .inversion = FrontendSpectralInversion::UNDEFINED, }; settingsExt1_1.settingExt.noinit(); if (tunerVersion < TUNER_VERSION_1_1) { return settingsExt1_1; } if (type == static_cast(::android::hardware::tv::tuner::V1_1::FrontendType::DTMB)) { getDtmbFrontendSettings(env, settings, settingsExt1_1); } else { FrontendType feType = static_cast(type); switch(feType) { case FrontendType::DVBS: getDvbsFrontendSettingsExt1_1(env, settings, settingsExt1_1); break; case FrontendType::DVBT: getDvbtFrontendSettingsExt1_1(env, settings, settingsExt1_1); break; case FrontendType::ANALOG: getAnalogFrontendSettingsExt1_1(env, settings, settingsExt1_1); break; case FrontendType::ATSC3: break; case FrontendType::ATSC: break; case FrontendType::DVBC: getDvbcFrontendSettingsExt1_1(env, settings, settingsExt1_1); break; case FrontendType::ISDBS: break; case FrontendType::ISDBS3: break; case FrontendType::ISDBT: break; default: // should never happen because a type is associated with a subclass of // FrontendSettings and not set by users jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Unsupported frontend type %d", type); return FrontendSettingsExt1_1(); } } uint32_t endFreq = getFrontendSettingsEndFreq(env, settings); FrontendSpectralInversion inversion = getFrontendSettingsSpectralInversion(env, settings); settingsExt1_1.endFrequency = endFreq; settingsExt1_1.inversion = inversion; return settingsExt1_1; } static sp getFilterClient(JNIEnv *env, jobject filter) { return (FilterClient *)env->GetLongField(filter, gFields.filterContext); } static sp getLnbClient(JNIEnv *env, jobject lnb) { return (LnbClient *)env->GetLongField(lnb, gFields.lnbContext); } static DvrSettings getDvrSettings(JNIEnv *env, jobject settings, bool isRecorder) { DvrSettings dvrSettings; jclass clazz = env->FindClass("android/media/tv/tuner/dvr/DvrSettings"); uint32_t statusMask = static_cast(env->GetIntField( settings, env->GetFieldID(clazz, "mStatusMask", "I"))); uint32_t lowThreshold = static_cast(env->GetLongField( settings, env->GetFieldID(clazz, "mLowThreshold", "J"))); uint32_t highThreshold = static_cast(env->GetLongField( settings, env->GetFieldID(clazz, "mHighThreshold", "J"))); uint8_t packetSize = static_cast(env->GetLongField( settings, env->GetFieldID(clazz, "mPacketSize", "J"))); DataFormat dataFormat = static_cast(env->GetIntField( settings, env->GetFieldID(clazz, "mDataFormat", "I"))); if (isRecorder) { RecordSettings recordSettings { .statusMask = static_cast(statusMask), .lowThreshold = lowThreshold, .highThreshold = highThreshold, .dataFormat = dataFormat, .packetSize = packetSize, }; dvrSettings.record(recordSettings); } else { PlaybackSettings PlaybackSettings { .statusMask = statusMask, .lowThreshold = lowThreshold, .highThreshold = highThreshold, .dataFormat = dataFormat, .packetSize = packetSize, }; dvrSettings.playback(PlaybackSettings); } return dvrSettings; } static sp getDvrClient(JNIEnv *env, jobject dvr) { bool isRecorder = env->IsInstanceOf(dvr, env->FindClass("android/media/tv/tuner/dvr/DvrRecorder")); jfieldID fieldId = isRecorder ? gFields.dvrRecorderContext : gFields.dvrPlaybackContext; return (DvrClient *)env->GetLongField(dvr, fieldId); } static void android_media_tv_Tuner_native_init(JNIEnv *env) { jclass clazz = env->FindClass("android/media/tv/tuner/Tuner"); CHECK(clazz != NULL); gFields.tunerContext = env->GetFieldID(clazz, "mNativeContext", "J"); CHECK(gFields.tunerContext != NULL); gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V"); jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend"); gFields.frontendInitID = env->GetMethodID(frontendClazz, "", "(Landroid/media/tv/tuner/Tuner;I)V"); jclass lnbClazz = env->FindClass("android/media/tv/tuner/Lnb"); gFields.lnbContext = env->GetFieldID(lnbClazz, "mNativeContext", "J"); gFields.lnbInitID = env->GetMethodID(lnbClazz, "", "()V"); gFields.onLnbEventID = env->GetMethodID(lnbClazz, "onEvent", "(I)V"); gFields.onLnbDiseqcMessageID = env->GetMethodID(lnbClazz, "onDiseqcMessage", "([B)V"); jclass filterClazz = env->FindClass("android/media/tv/tuner/filter/Filter"); gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J"); gFields.filterInitID = env->GetMethodID(filterClazz, "", "(J)V"); gFields.onFilterStatusID = env->GetMethodID(filterClazz, "onFilterStatus", "(I)V"); gFields.onFilterEventID = env->GetMethodID(filterClazz, "onFilterEvent", "([Landroid/media/tv/tuner/filter/FilterEvent;)V"); jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter"); gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J"); gFields.timeFilterInitID = env->GetMethodID(timeFilterClazz, "", "()V"); jclass descramblerClazz = env->FindClass("android/media/tv/tuner/Descrambler"); gFields.descramblerContext = env->GetFieldID(descramblerClazz, "mNativeContext", "J"); gFields.descramblerInitID = env->GetMethodID(descramblerClazz, "", "()V"); jclass dvrRecorderClazz = env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"); gFields.dvrRecorderContext = env->GetFieldID(dvrRecorderClazz, "mNativeContext", "J"); gFields.dvrRecorderInitID = env->GetMethodID(dvrRecorderClazz, "", "()V"); gFields.onDvrRecordStatusID = env->GetMethodID(dvrRecorderClazz, "onRecordStatusChanged", "(I)V"); jclass dvrPlaybackClazz = env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"); gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J"); gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "", "()V"); gFields.onDvrPlaybackStatusID = env->GetMethodID(dvrPlaybackClazz, "onPlaybackStatusChanged", "(I)V"); jclass mediaEventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent"); gFields.mediaEventContext = env->GetFieldID(mediaEventClazz, "mNativeContext", "J"); jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "", "()V"); gFields.linearBlockSetInternalStateID = env->GetMethodID(linearBlockClazz, "setInternalStateLocked", "(JZ)V"); } static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) { sp tuner = new JTuner(env, thiz); setTuner(env, thiz, tuner); } static jint android_media_tv_Tuner_native_get_tuner_version(JNIEnv *env, jobject thiz) { sp tuner = getTuner(env, thiz); return tuner->getTunerVersion(); } static jobject android_media_tv_Tuner_get_frontend_ids(JNIEnv *env, jobject thiz) { sp tuner = getTuner(env, thiz); return tuner->getFrontendIds(); } static jobject android_media_tv_Tuner_open_frontend_by_handle( JNIEnv *env, jobject thiz, jint handle) { sp tuner = getTuner(env, thiz); return tuner->openFrontendByHandle(handle); } static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) { sp tuner = getTuner(env, thiz); FrontendSettings setting = getFrontendSettings(env, type, settings); FrontendSettingsExt1_1 settingExt = getFrontendSettingsExt1_1( env, type, settings, tuner->getTunerVersion()); return tuner->tune(setting, settingExt); } static int android_media_tv_Tuner_stop_tune(JNIEnv *env, jobject thiz) { sp tuner = getTuner(env, thiz); return tuner->stopTune(); } static int android_media_tv_Tuner_scan( JNIEnv *env, jobject thiz, jint settingsType, jobject settings, jint scanType) { sp tuner = getTuner(env, thiz); FrontendSettings setting = getFrontendSettings(env, settingsType, settings); FrontendSettingsExt1_1 settingExt = getFrontendSettingsExt1_1( env, settingsType, settings, tuner->getTunerVersion()); return tuner->scan(setting, static_cast(scanType), settingExt); } static int android_media_tv_Tuner_stop_scan(JNIEnv *env, jobject thiz) { sp tuner = getTuner(env, thiz); return tuner->stopScan(); } static int android_media_tv_Tuner_set_lnb(JNIEnv *env, jobject thiz, jobject lnb) { sp tuner = getTuner(env, thiz); sp lnbClient = getLnbClient(env, lnb); if (lnbClient == NULL) { ALOGE("lnb is not initialized"); return (int)Result::INVALID_STATE; } return tuner->setLnb(lnbClient); } static int android_media_tv_Tuner_set_lna(JNIEnv *env, jobject thiz, jboolean enable) { sp tuner = getTuner(env, thiz); return tuner->setLna(enable); } static jobject android_media_tv_Tuner_get_frontend_status( JNIEnv* env, jobject thiz, jintArray types) { sp tuner = getTuner(env, thiz); return tuner->getFrontendStatus(types); } static jobject android_media_tv_Tuner_get_av_sync_hw_id( JNIEnv *env, jobject thiz, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to get sync ID. Filter client not found"); return NULL; } sp tuner = getTuner(env, thiz); return tuner->getAvSyncHwId(filterClient); } static jobject android_media_tv_Tuner_get_av_sync_time(JNIEnv *env, jobject thiz, jint id) { sp tuner = getTuner(env, thiz); return tuner->getAvSyncTime(id); } static int android_media_tv_Tuner_connect_cicam(JNIEnv *env, jobject thiz, jint id) { sp tuner = getTuner(env, thiz); return tuner->connectCiCam(id); } static int android_media_tv_Tuner_link_cicam(JNIEnv *env, jobject thiz, jint id) { sp tuner = getTuner(env, thiz); return tuner->linkCiCam(id); } static int android_media_tv_Tuner_disconnect_cicam(JNIEnv *env, jobject thiz) { sp tuner = getTuner(env, thiz); return tuner->disconnectCiCam(); } static int android_media_tv_Tuner_unlink_cicam(JNIEnv *env, jobject thiz, jint id) { sp tuner = getTuner(env, thiz); return tuner->unlinkCiCam(id); } static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv *env, jobject thiz, jint id) { sp tuner = getTuner(env, thiz); return tuner->getFrontendInfo(id); } static jobject android_media_tv_Tuner_open_lnb_by_handle(JNIEnv *env, jobject thiz, jint handle) { sp tuner = getTuner(env, thiz); return tuner->openLnbByHandle(handle); } static jobject android_media_tv_Tuner_open_lnb_by_name(JNIEnv *env, jobject thiz, jstring name) { sp tuner = getTuner(env, thiz); return tuner->openLnbByName(name); } static jobject android_media_tv_Tuner_open_filter( JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) { sp tuner = getTuner(env, thiz); DemuxFilterMainType mainType = static_cast(type); DemuxFilterType filterType { .mainType = mainType, }; switch(mainType) { case DemuxFilterMainType::TS: filterType.subType.tsFilterType(static_cast(subType)); break; case DemuxFilterMainType::MMTP: filterType.subType.mmtpFilterType(static_cast(subType)); break; case DemuxFilterMainType::IP: filterType.subType.ipFilterType(static_cast(subType)); break; case DemuxFilterMainType::TLV: filterType.subType.tlvFilterType(static_cast(subType)); break; case DemuxFilterMainType::ALP: filterType.subType.alpFilterType(static_cast(subType)); break; } return tuner->openFilter(filterType, bufferSize); } static jobject android_media_tv_Tuner_open_time_filter(JNIEnv *env, jobject thiz) { sp tuner = getTuner(env, thiz); return tuner->openTimeFilter(); } static DemuxFilterSectionBits getFilterSectionBits(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithSectionBits"); jbyteArray jfilterBytes = static_cast( env->GetObjectField(settings, env->GetFieldID(clazz, "mFilter", "[B"))); jsize size = env->GetArrayLength(jfilterBytes); std::vector filterBytes(size); env->GetByteArrayRegion( jfilterBytes, 0, size, reinterpret_cast(&filterBytes[0])); jbyteArray jmask = static_cast( env->GetObjectField(settings, env->GetFieldID(clazz, "mMask", "[B"))); size = env->GetArrayLength(jmask); std::vector mask(size); env->GetByteArrayRegion(jmask, 0, size, reinterpret_cast(&mask[0])); jbyteArray jmode = static_cast( env->GetObjectField(settings, env->GetFieldID(clazz, "mMode", "[B"))); size = env->GetArrayLength(jmode); std::vector mode(size); env->GetByteArrayRegion(jmode, 0, size, reinterpret_cast(&mode[0])); DemuxFilterSectionBits filterSectionBits { .filter = filterBytes, .mask = mask, .mode = mode, }; return filterSectionBits; } static DemuxFilterSectionSettings::Condition::TableInfo getFilterTableInfo( JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithTableInfo"); uint16_t tableId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mTableId", "I"))); uint16_t version = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mVersion", "I"))); DemuxFilterSectionSettings::Condition::TableInfo tableInfo { .tableId = tableId, .version = version, }; return tableInfo; } static DemuxFilterSectionSettings getFilterSectionSettings(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/filter/SectionSettings"); bool isCheckCrc = static_cast( env->GetBooleanField(settings, env->GetFieldID(clazz, "mCrcEnabled", "Z"))); bool isRepeat = static_cast( env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRepeat", "Z"))); bool isRaw = static_cast( env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRaw", "Z"))); DemuxFilterSectionSettings filterSectionSettings { .isCheckCrc = isCheckCrc, .isRepeat = isRepeat, .isRaw = isRaw, }; if (env->IsInstanceOf( settings, env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithSectionBits"))) { filterSectionSettings.condition.sectionBits(getFilterSectionBits(env, settings)); } else if (env->IsInstanceOf( settings, env->FindClass("android/media/tv/tuner/filter/SectionSettingsWithTableInfo"))) { filterSectionSettings.condition.tableInfo(getFilterTableInfo(env, settings)); } return filterSectionSettings; } static DemuxFilterAvSettings getFilterAvSettings(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/filter/AvSettings"); bool isPassthrough = static_cast( env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsPassthrough", "Z"))); DemuxFilterAvSettings filterAvSettings { .isPassthrough = isPassthrough, }; return filterAvSettings; } static bool getAvStreamType(JNIEnv *env, jobject filterConfigObj, AvStreamType& type) { jobject settingsObj = env->GetObjectField( filterConfigObj, env->GetFieldID( env->FindClass("android/media/tv/tuner/filter/FilterConfiguration"), "mSettings", "Landroid/media/tv/tuner/filter/Settings;")); jclass clazz = env->FindClass("android/media/tv/tuner/filter/AvSettings"); AvStreamType streamType; AudioStreamType audioStreamType = static_cast( env->GetIntField(settingsObj, env->GetFieldID(clazz, "mAudioStreamType", "I"))); if (audioStreamType != AudioStreamType::UNDEFINED) { type.audio(audioStreamType); return true; } VideoStreamType videoStreamType = static_cast( env->GetIntField(settingsObj, env->GetFieldID(clazz, "mVideoStreamType", "I"))); if (videoStreamType != VideoStreamType::UNDEFINED) { type.video(videoStreamType); return true; } return false; } static DemuxFilterPesDataSettings getFilterPesDataSettings(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/filter/PesSettings"); uint16_t streamId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mStreamId", "I"))); bool isRaw = static_cast( env->GetBooleanField(settings, env->GetFieldID(clazz, "mIsRaw", "Z"))); DemuxFilterPesDataSettings filterPesDataSettings { .streamId = streamId, .isRaw = isRaw, }; return filterPesDataSettings; } static DemuxFilterRecordSettings getFilterRecordSettings(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/filter/RecordSettings"); hidl_bitfield tsIndexMask = static_cast>( env->GetIntField(settings, env->GetFieldID(clazz, "mTsIndexMask", "I"))); DemuxRecordScIndexType scIndexType = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mScIndexType", "I"))); jint scIndexMask = env->GetIntField(settings, env->GetFieldID(clazz, "mScIndexMask", "I")); DemuxFilterRecordSettings filterRecordSettings { .tsIndexMask = tsIndexMask, .scIndexType = scIndexType, }; if (scIndexType == DemuxRecordScIndexType::SC) { filterRecordSettings.scIndexMask.sc(static_cast>(scIndexMask)); } else if (scIndexType == DemuxRecordScIndexType::SC_HEVC) { filterRecordSettings.scIndexMask.scHevc( static_cast>(scIndexMask)); } return filterRecordSettings; } static DemuxFilterDownloadSettings getFilterDownloadSettings(JNIEnv *env, const jobject& settings) { jclass clazz = env->FindClass("android/media/tv/tuner/filter/DownloadSettings"); uint32_t downloadId = static_cast( env->GetIntField(settings, env->GetFieldID(clazz, "mDownloadId", "I"))); DemuxFilterDownloadSettings filterDownloadSettings { .downloadId = downloadId, }; return filterDownloadSettings; } static DemuxIpAddress getDemuxIpAddress(JNIEnv *env, const jobject& config) { jclass clazz = env->FindClass("android/media/tv/tuner/filter/IpFilterConfiguration"); jbyteArray jsrcIpAddress = static_cast( env->GetObjectField(config, env->GetFieldID(clazz, "mSrcIpAddress", "[B"))); jsize srcSize = env->GetArrayLength(jsrcIpAddress); jbyteArray jdstIpAddress = static_cast( env->GetObjectField(config, env->GetFieldID(clazz, "mDstIpAddress", "[B"))); jsize dstSize = env->GetArrayLength(jdstIpAddress); DemuxIpAddress res; if (srcSize != dstSize) { // should never happen. Validated on Java size. jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "IP address lengths don't match. srcLength=%d, dstLength=%d", srcSize, dstSize); return res; } if (srcSize == IP_V4_LENGTH) { uint8_t srcAddr[IP_V4_LENGTH]; uint8_t dstAddr[IP_V4_LENGTH]; env->GetByteArrayRegion( jsrcIpAddress, 0, srcSize, reinterpret_cast(srcAddr)); env->GetByteArrayRegion( jdstIpAddress, 0, dstSize, reinterpret_cast(dstAddr)); res.srcIpAddress.v4(srcAddr); res.dstIpAddress.v4(dstAddr); } else if (srcSize == IP_V6_LENGTH) { uint8_t srcAddr[IP_V6_LENGTH]; uint8_t dstAddr[IP_V6_LENGTH]; env->GetByteArrayRegion( jsrcIpAddress, 0, srcSize, reinterpret_cast(srcAddr)); env->GetByteArrayRegion( jdstIpAddress, 0, dstSize, reinterpret_cast(dstAddr)); res.srcIpAddress.v6(srcAddr); res.dstIpAddress.v6(dstAddr); } else { // should never happen. Validated on Java size. jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid IP address length %d", srcSize); return res; } uint16_t srcPort = static_cast( env->GetIntField(config, env->GetFieldID(clazz, "mSrcPort", "I"))); uint16_t dstPort = static_cast( env->GetIntField(config, env->GetFieldID(clazz, "mDstPort", "I"))); res.srcPort = srcPort; res.dstPort = dstPort; return res; } static DemuxFilterSettings getFilterConfiguration( JNIEnv *env, int type, int subtype, jobject filterConfigObj) { DemuxFilterSettings filterSettings; jobject settingsObj = env->GetObjectField( filterConfigObj, env->GetFieldID( env->FindClass("android/media/tv/tuner/filter/FilterConfiguration"), "mSettings", "Landroid/media/tv/tuner/filter/Settings;")); DemuxFilterMainType mainType = static_cast(type); switch (mainType) { case DemuxFilterMainType::TS: { jclass clazz = env->FindClass("android/media/tv/tuner/filter/TsFilterConfiguration"); uint16_t tpid = static_cast( env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mTpid", "I"))); DemuxTsFilterSettings tsFilterSettings { .tpid = tpid, }; if (settingsObj != NULL) { DemuxTsFilterType tsType = static_cast(subtype); switch (tsType) { case DemuxTsFilterType::SECTION: tsFilterSettings.filterSettings.section( getFilterSectionSettings(env, settingsObj)); break; case DemuxTsFilterType::AUDIO: case DemuxTsFilterType::VIDEO: tsFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj)); break; case DemuxTsFilterType::PES: tsFilterSettings.filterSettings.pesData( getFilterPesDataSettings(env, settingsObj)); break; case DemuxTsFilterType::RECORD: tsFilterSettings.filterSettings.record( getFilterRecordSettings(env, settingsObj)); break; default: break; } } filterSettings.ts(tsFilterSettings); break; } case DemuxFilterMainType::MMTP: { jclass clazz = env->FindClass("android/media/tv/tuner/filter/MmtpFilterConfiguration"); uint16_t mmtpPid = static_cast( env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mMmtpPid", "I"))); DemuxMmtpFilterSettings mmtpFilterSettings { .mmtpPid = mmtpPid, }; if (settingsObj != NULL) { DemuxMmtpFilterType mmtpType = static_cast(subtype); switch (mmtpType) { case DemuxMmtpFilterType::SECTION: mmtpFilterSettings.filterSettings.section( getFilterSectionSettings(env, settingsObj)); break; case DemuxMmtpFilterType::AUDIO: case DemuxMmtpFilterType::VIDEO: mmtpFilterSettings.filterSettings.av(getFilterAvSettings(env, settingsObj)); break; case DemuxMmtpFilterType::PES: mmtpFilterSettings.filterSettings.pesData( getFilterPesDataSettings(env, settingsObj)); break; case DemuxMmtpFilterType::RECORD: mmtpFilterSettings.filterSettings.record( getFilterRecordSettings(env, settingsObj)); break; case DemuxMmtpFilterType::DOWNLOAD: mmtpFilterSettings.filterSettings.download( getFilterDownloadSettings(env, settingsObj)); break; default: break; } } filterSettings.mmtp(mmtpFilterSettings); break; } case DemuxFilterMainType::IP: { DemuxIpAddress ipAddr = getDemuxIpAddress(env, filterConfigObj); DemuxIpFilterSettings ipFilterSettings { .ipAddr = ipAddr, }; DemuxIpFilterType ipType = static_cast(subtype); if (ipType == DemuxIpFilterType::SECTION && settingsObj != NULL) { ipFilterSettings.filterSettings.section( getFilterSectionSettings(env, settingsObj)); } else if (ipType == DemuxIpFilterType::IP) { jclass clazz = env->FindClass( "android/media/tv/tuner/filter/IpFilterConfiguration"); bool bPassthrough = static_cast( env->GetBooleanField( filterConfigObj, env->GetFieldID( clazz, "mPassthrough", "Z"))); ipFilterSettings.filterSettings.bPassthrough(bPassthrough); } filterSettings.ip(ipFilterSettings); break; } case DemuxFilterMainType::TLV: { jclass clazz = env->FindClass("android/media/tv/tuner/filter/TlvFilterConfiguration"); uint8_t packetType = static_cast( env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I"))); bool isCompressedIpPacket = static_cast( env->GetBooleanField( filterConfigObj, env->GetFieldID(clazz, "mIsCompressedIpPacket", "Z"))); DemuxTlvFilterSettings tlvFilterSettings { .packetType = packetType, .isCompressedIpPacket = isCompressedIpPacket, }; DemuxTlvFilterType tlvType = static_cast(subtype); if (tlvType == DemuxTlvFilterType::SECTION && settingsObj != NULL) { tlvFilterSettings.filterSettings.section( getFilterSectionSettings(env, settingsObj)); } else if (tlvType == DemuxTlvFilterType::TLV) { bool bPassthrough = static_cast( env->GetBooleanField( filterConfigObj, env->GetFieldID( clazz, "mPassthrough", "Z"))); tlvFilterSettings.filterSettings.bPassthrough(bPassthrough); } filterSettings.tlv(tlvFilterSettings); break; } case DemuxFilterMainType::ALP: { jclass clazz = env->FindClass("android/media/tv/tuner/filter/AlpFilterConfiguration"); uint8_t packetType = static_cast( env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mPacketType", "I"))); DemuxAlpLengthType lengthType = static_cast( env->GetIntField(filterConfigObj, env->GetFieldID(clazz, "mLengthType", "I"))); DemuxAlpFilterSettings alpFilterSettings { .packetType = packetType, .lengthType = lengthType, }; if (settingsObj != NULL) { DemuxAlpFilterType alpType = static_cast(subtype); switch (alpType) { case DemuxAlpFilterType::SECTION: alpFilterSettings.filterSettings.section( getFilterSectionSettings(env, settingsObj)); break; default: break; } } filterSettings.alp(alpFilterSettings); break; } default: { break; } } return filterSettings; } static Result configureIpFilterContextId( JNIEnv *env, sp filterClient, jobject ipFilterConfigObj) { jclass clazz = env->FindClass( "android/media/tv/tuner/filter/IpFilterConfiguration"); uint32_t cid = env->GetIntField(ipFilterConfigObj, env->GetFieldID( clazz, "mIpFilterContextId", "I")); return filterClient->configureIpFilterContextId(cid); } static bool isAvFilterSettings(DemuxFilterSettings filterSettings) { return (filterSettings.getDiscriminator() == DemuxFilterSettings::hidl_discriminator::ts && filterSettings.ts().filterSettings.getDiscriminator() == DemuxTsFilterSettings::FilterSettings::hidl_discriminator::av) || (filterSettings.getDiscriminator() == DemuxFilterSettings::hidl_discriminator::mmtp && filterSettings.mmtp().filterSettings.getDiscriminator() == DemuxMmtpFilterSettings::FilterSettings::hidl_discriminator::av); } static jint android_media_tv_Tuner_configure_filter( JNIEnv *env, jobject filter, int type, int subtype, jobject settings) { ALOGD("configure filter type=%d, subtype=%d", type, subtype); sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to configure filter: filter not found"); return (jint) Result::NOT_INITIALIZED; } DemuxFilterSettings filterSettings = getFilterConfiguration(env, type, subtype, settings); Result res = filterClient->configure(filterSettings); if (res != Result::SUCCESS) { return (jint) res; } if (static_cast(type) == DemuxFilterMainType::IP) { res = configureIpFilterContextId(env, filterClient, settings); if (res != Result::SUCCESS) { return (jint) res; } } AvStreamType streamType; if (isAvFilterSettings(filterSettings) && getAvStreamType(env, settings, streamType)) { res = filterClient->configureAvStreamType(streamType); } return (jint) res; } static jint android_media_tv_Tuner_get_filter_id(JNIEnv* env, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to get filter ID: filter client not found"); return (int) Result::NOT_INITIALIZED; } uint32_t id; Result res = filterClient->getId(id); if (res != Result::SUCCESS) { return (jint) Constant::INVALID_FILTER_ID; } return (jint) id; } static jlong android_media_tv_Tuner_get_filter_64bit_id(JNIEnv* env, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to get filter ID 64 bit: filter client not found"); return (int) Result::NOT_INITIALIZED; } uint64_t id; Result res = filterClient->getId64Bit(id); return (res == Result::SUCCESS) ? static_cast(id) : static_cast( ::android::hardware::tv::tuner::V1_1::Constant64Bit::INVALID_FILTER_ID_64BIT); } static jint android_media_tv_Tuner_configure_monitor_event( JNIEnv* env, jobject filter, int monitorEventType) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to configure scrambling event: filter client not found"); return (int) Result::NOT_INITIALIZED; } Result res = filterClient->configureMonitorEvent(monitorEventType); return (jint) res; } static jint android_media_tv_Tuner_set_filter_data_source( JNIEnv* env, jobject filter, jobject srcFilter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to set filter data source: filter client not found"); return (int) Result::NOT_INITIALIZED; } Result res; if (srcFilter == NULL) { res = filterClient->setDataSource(NULL); } else { sp srcClient = getFilterClient(env, srcFilter); if (srcClient == NULL) { ALOGD("Failed to set filter data source: src filter not found"); return (jint) Result::INVALID_ARGUMENT; } res = filterClient->setDataSource(srcClient); } return (jint) res; } static jint android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to start filter: filter client not found"); return (int) Result::NOT_INITIALIZED; } return (jint) filterClient->start(); } static jint android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to stop filter: filter client not found"); return (int) Result::NOT_INITIALIZED; } return (jint) filterClient->stop(); } static jint android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { ALOGD("Failed to flush filter: filter client not found"); return (int) Result::NOT_INITIALIZED; } return (jint) filterClient->flush(); } static jint android_media_tv_Tuner_read_filter_fmq( JNIEnv *env, jobject filter, jbyteArray buffer, jlong offset, jlong size) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Failed to read filter FMQ: filter client not found"); return -1; } jboolean isCopy; jbyte *dst = env->GetByteArrayElements(buffer, &isCopy); ALOGD("copyData, isCopy=%d", isCopy); if (dst == nullptr) { jniThrowRuntimeException(env, "Failed to GetByteArrayElements"); return -1; } int realReadSize = filterClient->read(reinterpret_cast(dst) + offset, size); env->ReleaseByteArrayElements(buffer, dst, 0); return (jint) realReadSize; } static jint android_media_tv_Tuner_close_filter(JNIEnv *env, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Failed to close filter: filter client not found"); return 0; } return (jint) filterClient->close(); } static sp getTimeFilterClient(JNIEnv *env, jobject filter) { return (TimeFilterClient *)env->GetLongField(filter, gFields.timeFilterContext); } static int android_media_tv_Tuner_time_filter_set_timestamp( JNIEnv *env, jobject filter, jlong timestamp) { sp timeFilterClient = getTimeFilterClient(env, filter); if (timeFilterClient == NULL) { ALOGD("Failed set timestamp: time filter client not found"); return (int) Result::INVALID_STATE; } Result r = timeFilterClient->setTimeStamp(static_cast(timestamp)); return (int) r; } static int android_media_tv_Tuner_time_filter_clear_timestamp(JNIEnv *env, jobject filter) { sp timeFilterClient = getTimeFilterClient(env, filter); if (timeFilterClient == NULL) { ALOGD("Failed clear timestamp: time filter client not found"); return (int) Result::INVALID_STATE; } Result r = timeFilterClient->clearTimeStamp(); return (int) r; } static jobject android_media_tv_Tuner_time_filter_get_timestamp(JNIEnv *env, jobject filter) { sp timeFilterClient = getTimeFilterClient(env, filter); if (timeFilterClient == NULL) { ALOGD("Failed get timestamp: time filter client not found"); return NULL; } uint64_t timestamp = timeFilterClient->getTimeStamp(); if (timestamp == (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP) { return NULL; } jclass longClazz = env->FindClass("java/lang/Long"); jmethodID longInit = env->GetMethodID(longClazz, "", "(J)V"); jobject longObj = env->NewObject(longClazz, longInit, static_cast(timestamp)); return longObj; } static jobject android_media_tv_Tuner_time_filter_get_source_time(JNIEnv *env, jobject filter) { sp timeFilterClient = getTimeFilterClient(env, filter); if (timeFilterClient == NULL) { ALOGD("Failed get source time: time filter client not found"); return NULL; } uint64_t timestamp = timeFilterClient->getSourceTime(); if (timestamp == (long)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP) { return NULL; } jclass longClazz = env->FindClass("java/lang/Long"); jmethodID longInit = env->GetMethodID(longClazz, "", "(J)V"); jobject longObj = env->NewObject(longClazz, longInit, static_cast(timestamp)); return longObj; } static int android_media_tv_Tuner_time_filter_close(JNIEnv *env, jobject filter) { sp timeFilterClient = getTimeFilterClient(env, filter); if (timeFilterClient == NULL) { ALOGD("Failed close time filter: time filter client not found"); return (int) Result::INVALID_STATE; } Result r = timeFilterClient->close(); if (r == Result::SUCCESS) { timeFilterClient->decStrong(filter); env->SetLongField(filter, gFields.timeFilterContext, 0); } return (int) r; } static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz, jint) { sp tuner = getTuner(env, thiz); return tuner->openDescrambler(); } static jint android_media_tv_Tuner_descrambler_add_pid( JNIEnv *env, jobject descrambler, jint pidType, jint pid, jobject filter) { sp descramblerClient = getDescramblerClient(env, descrambler); if (descramblerClient == NULL) { return (jint) Result::NOT_INITIALIZED; } sp filterClient = (filter == NULL) ? NULL : getFilterClient(env, filter); Result result = descramblerClient->addPid(getDemuxPid((int)pidType, (int)pid), filterClient); return (jint) result; } static jint android_media_tv_Tuner_descrambler_remove_pid( JNIEnv *env, jobject descrambler, jint pidType, jint pid, jobject filter) { sp descramblerClient = getDescramblerClient(env, descrambler); if (descramblerClient == NULL) { return (jint) Result::NOT_INITIALIZED; } sp filterClient = (filter == NULL) ? NULL : getFilterClient(env, filter); Result result = descramblerClient->removePid(getDemuxPid((int)pidType, (int)pid), filterClient); return (jint) result; } static jint android_media_tv_Tuner_descrambler_set_key_token( JNIEnv* env, jobject descrambler, jbyteArray keyToken) { sp descramblerClient = getDescramblerClient(env, descrambler); if (descramblerClient == NULL) { return (jint) Result::NOT_INITIALIZED; } int size = env->GetArrayLength(keyToken); std::vector v(size); env->GetByteArrayRegion(keyToken, 0, size, reinterpret_cast(&v[0])); Result result = descramblerClient->setKeyToken(v); return (jint) result; } static jint android_media_tv_Tuner_close_descrambler(JNIEnv* env, jobject descrambler) { sp descramblerClient = getDescramblerClient(env, descrambler); if (descramblerClient == NULL) { return (jint) Result::NOT_INITIALIZED; } Result r = descramblerClient->close(); if (r == Result::SUCCESS) { descramblerClient->decStrong(descrambler); } return (jint) r; } static jobject android_media_tv_Tuner_open_dvr_recorder( JNIEnv* env, jobject thiz, jlong bufferSize) { sp tuner = getTuner(env, thiz); return tuner->openDvr(DvrType::RECORD, bufferSize); } static jobject android_media_tv_Tuner_open_dvr_playback( JNIEnv* env, jobject thiz, jlong bufferSize) { sp tuner = getTuner(env, thiz); return tuner->openDvr(DvrType::PLAYBACK, bufferSize); } static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) { sp tuner = getTuner(env, thiz); return tuner->getDemuxCaps(); } static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint handle) { sp tuner = getTuner(env, thiz); return (jint) tuner->openDemux(handle); } static jint android_media_tv_Tuner_close_tuner(JNIEnv* env, jobject thiz) { sp tuner = getTuner(env, thiz); setTuner(env, thiz, NULL); return (jint) tuner->close(); } static jint android_media_tv_Tuner_close_demux(JNIEnv* env, jobject thiz, jint /* handle */) { sp tuner = getTuner(env, thiz); return tuner->closeDemux(); } static jint android_media_tv_Tuner_close_frontend(JNIEnv* env, jobject thiz, jint /* handle */) { sp tuner = getTuner(env, thiz); return tuner->closeFrontend(); } static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { return (jint) Result::INVALID_ARGUMENT; } sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { return (jint) Result::NOT_INITIALIZED; } Result result = dvrClient->attachFilter(filterClient); return (jint) result; } static jint android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp filterClient = getFilterClient(env, filter); if (filterClient == NULL) { return (jint) Result::INVALID_ARGUMENT; } sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { return (jint) Result::NOT_INITIALIZED; } Result result = dvrClient->detachFilter(filterClient); return (jint) result; } static jint android_media_tv_Tuner_configure_dvr(JNIEnv *env, jobject dvr, jobject settings) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { ALOGD("Failed to configure dvr: dvr client not found"); return (int)Result::NOT_INITIALIZED; } bool isRecorder = env->IsInstanceOf(dvr, env->FindClass("android/media/tv/tuner/dvr/DvrRecorder")); Result result = dvrClient->configure(getDvrSettings(env, settings, isRecorder)); return (jint) result; } static jint android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { ALOGD("Failed to start dvr: dvr client not found"); return (jint) Result::NOT_INITIALIZED; } Result result = dvrClient->start(); return (jint) result; } static jint android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { ALOGD("Failed to stop dvr: dvr client not found"); return (jint) Result::NOT_INITIALIZED; } Result result = dvrClient->stop(); return (jint) result; } static jint android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { ALOGD("Failed to flush dvr: dvr client not found"); return (jint) Result::NOT_INITIALIZED; } Result result = dvrClient->flush(); return (jint) result; } static jint android_media_tv_Tuner_close_dvr(JNIEnv* env, jobject dvr) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { ALOGD("Failed to close dvr: dvr client not found"); return (jint) Result::NOT_INITIALIZED; } return (jint) dvrClient->close(); } static jint android_media_tv_Tuner_lnb_set_voltage(JNIEnv* env, jobject lnb, jint voltage) { sp lnbClient = getLnbClient(env, lnb); Result r = lnbClient->setVoltage(static_cast(voltage)); return (jint) r; } static int android_media_tv_Tuner_lnb_set_tone(JNIEnv* env, jobject lnb, jint tone) { sp lnbClient = getLnbClient(env, lnb); Result r = lnbClient->setTone(static_cast(tone)); return (jint) r; } static int android_media_tv_Tuner_lnb_set_position(JNIEnv* env, jobject lnb, jint position) { sp lnbClient = getLnbClient(env, lnb); Result r = lnbClient->setSatellitePosition(static_cast(position)); return (jint) r; } static int android_media_tv_Tuner_lnb_send_diseqc_msg(JNIEnv* env, jobject lnb, jbyteArray msg) { sp lnbClient = getLnbClient(env, lnb); int size = env->GetArrayLength(msg); std::vector v(size); env->GetByteArrayRegion(msg, 0, size, reinterpret_cast(&v[0])); Result r = lnbClient->sendDiseqcMessage(v); return (jint) r; } static int android_media_tv_Tuner_close_lnb(JNIEnv* env, jobject lnb) { sp lnbClient = getLnbClient(env, lnb); Result r = lnbClient->close(); if (r == Result::SUCCESS) { lnbClient->decStrong(lnb); env->SetLongField(lnb, gFields.lnbContext, 0); } return (jint) r; } static void android_media_tv_Tuner_dvr_set_fd(JNIEnv *env, jobject dvr, jint fd) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { ALOGD("Failed to set FD for dvr: dvr client not found"); return; } dvrClient->setFd((int)fd); ALOGD("set fd = %d", fd); } static jlong android_media_tv_Tuner_read_dvr(JNIEnv *env, jobject dvr, jlong size) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Failed to read dvr: dvr client not found"); return -1; } return (jlong) dvrClient->readFromFile(size); } static jlong android_media_tv_Tuner_read_dvr_from_array( JNIEnv* env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { ALOGW("Failed to read dvr: dvr client not found"); return -1; } jboolean isCopy; jbyte *src = env->GetByteArrayElements(buffer, &isCopy); if (src == nullptr) { ALOGD("Failed to GetByteArrayElements"); return -1; } long realSize = dvrClient->readFromBuffer(reinterpret_cast(src) + offset, size); env->ReleaseByteArrayElements(buffer, src, 0); return (jlong) realSize; } static jlong android_media_tv_Tuner_write_dvr(JNIEnv *env, jobject dvr, jlong size) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Failed to write dvr: dvr client not found"); return -1; } return (jlong) dvrClient->writeToFile(size); } static jlong android_media_tv_Tuner_write_dvr_to_array( JNIEnv *env, jobject dvr, jbyteArray buffer, jlong offset, jlong size) { sp dvrClient = getDvrClient(env, dvr); if (dvrClient == NULL) { ALOGW("Failed to read dvr: dvr client not found"); return -1; } jboolean isCopy; jbyte *dst = env->GetByteArrayElements(buffer, &isCopy); ALOGD("copyData, isCopy=%d", isCopy); if (dst == nullptr) { jniThrowRuntimeException(env, "Failed to GetByteArrayElements"); return -1; } long realSize = dvrClient->writeToBuffer(reinterpret_cast(dst) + offset, size); env->ReleaseByteArrayElements(buffer, dst, 0); return (jlong) realSize; } static sp getMediaEventSp(JNIEnv *env, jobject mediaEventObj) { return (MediaEvent *)env->GetLongField(mediaEventObj, gFields.mediaEventContext); } static jobject android_media_tv_Tuner_media_event_get_linear_block( JNIEnv* env, jobject mediaEventObj) { sp mediaEventSp = getMediaEventSp(env, mediaEventObj); if (mediaEventSp == NULL) { ALOGD("Failed get MediaEvent"); return NULL; } android::Mutex::Autolock autoLock(mediaEventSp->mLock); return mediaEventSp->getLinearBlock(); } static jobject android_media_tv_Tuner_media_event_get_audio_handle( JNIEnv* env, jobject mediaEventObj) { sp mediaEventSp = getMediaEventSp(env, mediaEventObj); if (mediaEventSp == NULL) { ALOGD("Failed get MediaEvent"); return NULL; } android::Mutex::Autolock autoLock(mediaEventSp->mLock); uint64_t audioHandle = mediaEventSp->getAudioHandle(); jclass longClazz = env->FindClass("java/lang/Long"); jmethodID longInit = env->GetMethodID(longClazz, "", "(J)V"); jobject longObj = env->NewObject(longClazz, longInit, static_cast(audioHandle)); return longObj; } static void android_media_tv_Tuner_media_event_finalize(JNIEnv* env, jobject mediaEventObj) { sp mediaEventSp = getMediaEventSp(env, mediaEventObj); if (mediaEventSp == NULL) { ALOGD("Failed get MediaEvent"); return; } android::Mutex::Autolock autoLock(mediaEventSp->mLock); mediaEventSp->mAvHandleRefCnt--; mediaEventSp->finalize(); mediaEventSp->decStrong(mediaEventObj); } static const JNINativeMethod gTunerMethods[] = { { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init }, { "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup }, { "nativeGetTunerVersion", "()I", (void *)android_media_tv_Tuner_native_get_tuner_version }, { "nativeGetFrontendIds", "()Ljava/util/List;", (void *)android_media_tv_Tuner_get_frontend_ids }, { "nativeOpenFrontendByHandle", "(I)Landroid/media/tv/tuner/Tuner$Frontend;", (void *)android_media_tv_Tuner_open_frontend_by_handle }, { "nativeTune", "(ILandroid/media/tv/tuner/frontend/FrontendSettings;)I", (void *)android_media_tv_Tuner_tune }, { "nativeStopTune", "()I", (void *)android_media_tv_Tuner_stop_tune }, { "nativeScan", "(ILandroid/media/tv/tuner/frontend/FrontendSettings;I)I", (void *)android_media_tv_Tuner_scan }, { "nativeStopScan", "()I", (void *)android_media_tv_Tuner_stop_scan }, { "nativeSetLnb", "(Landroid/media/tv/tuner/Lnb;)I", (void *)android_media_tv_Tuner_set_lnb }, { "nativeSetLna", "(Z)I", (void *)android_media_tv_Tuner_set_lna }, { "nativeGetFrontendStatus", "([I)Landroid/media/tv/tuner/frontend/FrontendStatus;", (void *)android_media_tv_Tuner_get_frontend_status }, { "nativeGetAvSyncHwId", "(Landroid/media/tv/tuner/filter/Filter;)Ljava/lang/Integer;", (void *)android_media_tv_Tuner_get_av_sync_hw_id }, { "nativeGetAvSyncTime", "(I)Ljava/lang/Long;", (void *)android_media_tv_Tuner_get_av_sync_time }, { "nativeConnectCiCam", "(I)I", (void *)android_media_tv_Tuner_connect_cicam }, { "nativeLinkCiCam", "(I)I", (void *)android_media_tv_Tuner_link_cicam }, { "nativeUnlinkCiCam", "(I)I", (void *)android_media_tv_Tuner_unlink_cicam }, { "nativeDisconnectCiCam", "()I", (void *)android_media_tv_Tuner_disconnect_cicam }, { "nativeGetFrontendInfo", "(I)Landroid/media/tv/tuner/frontend/FrontendInfo;", (void *)android_media_tv_Tuner_get_frontend_info }, { "nativeOpenFilter", "(IIJ)Landroid/media/tv/tuner/filter/Filter;", (void *)android_media_tv_Tuner_open_filter }, { "nativeOpenTimeFilter", "()Landroid/media/tv/tuner/filter/TimeFilter;", (void *)android_media_tv_Tuner_open_time_filter }, { "nativeOpenLnbByHandle", "(I)Landroid/media/tv/tuner/Lnb;", (void *)android_media_tv_Tuner_open_lnb_by_handle }, { "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;", (void *)android_media_tv_Tuner_open_lnb_by_name }, { "nativeOpenDescramblerByHandle", "(I)Landroid/media/tv/tuner/Descrambler;", (void *)android_media_tv_Tuner_open_descrambler }, { "nativeOpenDvrRecorder", "(J)Landroid/media/tv/tuner/dvr/DvrRecorder;", (void *)android_media_tv_Tuner_open_dvr_recorder }, { "nativeOpenDvrPlayback", "(J)Landroid/media/tv/tuner/dvr/DvrPlayback;", (void *)android_media_tv_Tuner_open_dvr_playback }, { "nativeGetDemuxCapabilities", "()Landroid/media/tv/tuner/DemuxCapabilities;", (void *)android_media_tv_Tuner_get_demux_caps }, { "nativeOpenDemuxByhandle", "(I)I", (void *)android_media_tv_Tuner_open_demux }, { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_tuner }, { "nativeCloseFrontend", "(I)I", (void *)android_media_tv_Tuner_close_frontend }, { "nativeCloseDemux", "(I)I", (void *)android_media_tv_Tuner_close_demux }, }; static const JNINativeMethod gFilterMethods[] = { { "nativeConfigureFilter", "(IILandroid/media/tv/tuner/filter/FilterConfiguration;)I", (void *)android_media_tv_Tuner_configure_filter }, { "nativeGetId", "()I", (void *)android_media_tv_Tuner_get_filter_id }, { "nativeGetId64Bit", "()J", (void *)android_media_tv_Tuner_get_filter_64bit_id }, { "nativeConfigureMonitorEvent", "(I)I", (void *)android_media_tv_Tuner_configure_monitor_event }, { "nativeSetDataSource", "(Landroid/media/tv/tuner/filter/Filter;)I", (void *)android_media_tv_Tuner_set_filter_data_source }, { "nativeStartFilter", "()I", (void *)android_media_tv_Tuner_start_filter }, { "nativeStopFilter", "()I", (void *)android_media_tv_Tuner_stop_filter }, { "nativeFlushFilter", "()I", (void *)android_media_tv_Tuner_flush_filter }, { "nativeRead", "([BJJ)I", (void *)android_media_tv_Tuner_read_filter_fmq }, { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_filter }, }; static const JNINativeMethod gTimeFilterMethods[] = { { "nativeSetTimestamp", "(J)I", (void *)android_media_tv_Tuner_time_filter_set_timestamp }, { "nativeClearTimestamp", "()I", (void *)android_media_tv_Tuner_time_filter_clear_timestamp }, { "nativeGetTimestamp", "()Ljava/lang/Long;", (void *)android_media_tv_Tuner_time_filter_get_timestamp }, { "nativeGetSourceTime", "()Ljava/lang/Long;", (void *)android_media_tv_Tuner_time_filter_get_source_time }, { "nativeClose", "()I", (void *)android_media_tv_Tuner_time_filter_close }, }; static const JNINativeMethod gDescramblerMethods[] = { { "nativeAddPid", "(IILandroid/media/tv/tuner/filter/Filter;)I", (void *)android_media_tv_Tuner_descrambler_add_pid }, { "nativeRemovePid", "(IILandroid/media/tv/tuner/filter/Filter;)I", (void *)android_media_tv_Tuner_descrambler_remove_pid }, { "nativeSetKeyToken", "([B)I", (void *)android_media_tv_Tuner_descrambler_set_key_token }, { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_descrambler }, }; static const JNINativeMethod gDvrRecorderMethods[] = { { "nativeAttachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I", (void *)android_media_tv_Tuner_attach_filter }, { "nativeDetachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I", (void *)android_media_tv_Tuner_detach_filter }, { "nativeConfigureDvr", "(Landroid/media/tv/tuner/dvr/DvrSettings;)I", (void *)android_media_tv_Tuner_configure_dvr }, { "nativeStartDvr", "()I", (void *)android_media_tv_Tuner_start_dvr }, { "nativeStopDvr", "()I", (void *)android_media_tv_Tuner_stop_dvr }, { "nativeFlushDvr", "()I", (void *)android_media_tv_Tuner_flush_dvr }, { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_dvr }, { "nativeSetFileDescriptor", "(I)V", (void *)android_media_tv_Tuner_dvr_set_fd }, { "nativeWrite", "(J)J", (void *)android_media_tv_Tuner_write_dvr }, { "nativeWrite", "([BJJ)J", (void *)android_media_tv_Tuner_write_dvr_to_array }, }; static const JNINativeMethod gDvrPlaybackMethods[] = { { "nativeAttachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I", (void *)android_media_tv_Tuner_attach_filter }, { "nativeDetachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I", (void *)android_media_tv_Tuner_detach_filter }, { "nativeConfigureDvr", "(Landroid/media/tv/tuner/dvr/DvrSettings;)I", (void *)android_media_tv_Tuner_configure_dvr }, { "nativeStartDvr", "()I", (void *)android_media_tv_Tuner_start_dvr }, { "nativeStopDvr", "()I", (void *)android_media_tv_Tuner_stop_dvr }, { "nativeFlushDvr", "()I", (void *)android_media_tv_Tuner_flush_dvr }, { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_dvr }, { "nativeSetFileDescriptor", "(I)V", (void *)android_media_tv_Tuner_dvr_set_fd }, { "nativeRead", "(J)J", (void *)android_media_tv_Tuner_read_dvr }, { "nativeRead", "([BJJ)J", (void *)android_media_tv_Tuner_read_dvr_from_array }, }; static const JNINativeMethod gLnbMethods[] = { { "nativeSetVoltage", "(I)I", (void *)android_media_tv_Tuner_lnb_set_voltage }, { "nativeSetTone", "(I)I", (void *)android_media_tv_Tuner_lnb_set_tone }, { "nativeSetSatellitePosition", "(I)I", (void *)android_media_tv_Tuner_lnb_set_position }, { "nativeSendDiseqcMessage", "([B)I", (void *)android_media_tv_Tuner_lnb_send_diseqc_msg }, { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_lnb }, }; static const JNINativeMethod gMediaEventMethods[] = { { "nativeGetLinearBlock", "()Landroid/media/MediaCodec$LinearBlock;", (void *)android_media_tv_Tuner_media_event_get_linear_block }, { "nativeGetAudioHandle", "()Ljava/lang/Long;", (void *)android_media_tv_Tuner_media_event_get_audio_handle }, { "nativeFinalize", "()V", (void *)android_media_tv_Tuner_media_event_finalize }, }; static bool register_android_media_tv_Tuner(JNIEnv *env) { if (AndroidRuntime::registerNativeMethods( env, "android/media/tv/tuner/Tuner", gTunerMethods, NELEM(gTunerMethods)) != JNI_OK) { ALOGE("Failed to register tuner native methods"); return false; } if (AndroidRuntime::registerNativeMethods( env, "android/media/tv/tuner/filter/Filter", gFilterMethods, NELEM(gFilterMethods)) != JNI_OK) { ALOGE("Failed to register filter native methods"); return false; } if (AndroidRuntime::registerNativeMethods( env, "android/media/tv/tuner/filter/TimeFilter", gTimeFilterMethods, NELEM(gTimeFilterMethods)) != JNI_OK) { ALOGE("Failed to register time filter native methods"); return false; } if (AndroidRuntime::registerNativeMethods( env, "android/media/tv/tuner/Descrambler", gDescramblerMethods, NELEM(gDescramblerMethods)) != JNI_OK) { ALOGE("Failed to register descrambler native methods"); return false; } if (AndroidRuntime::registerNativeMethods( env, "android/media/tv/tuner/dvr/DvrRecorder", gDvrRecorderMethods, NELEM(gDvrRecorderMethods)) != JNI_OK) { ALOGE("Failed to register dvr recorder native methods"); return false; } if (AndroidRuntime::registerNativeMethods( env, "android/media/tv/tuner/dvr/DvrPlayback", gDvrPlaybackMethods, NELEM(gDvrPlaybackMethods)) != JNI_OK) { ALOGE("Failed to register dvr playback native methods"); return false; } if (AndroidRuntime::registerNativeMethods( env, "android/media/tv/tuner/Lnb", gLnbMethods, NELEM(gLnbMethods)) != JNI_OK) { ALOGE("Failed to register lnb native methods"); return false; } if (AndroidRuntime::registerNativeMethods( env, "android/media/tv/tuner/filter/MediaEvent", gMediaEventMethods, NELEM(gMediaEventMethods)) != JNI_OK) { ALOGE("Failed to register MediaEvent native methods"); return false; } return true; } jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("ERROR: GetEnv failed\n"); return result; } assert(env != NULL); if (!register_android_media_tv_Tuner(env)) { ALOGE("ERROR: Tuner native registration failed\n"); return result; } return JNI_VERSION_1_4; }