Loading media/java/android/media/tv/tuner/FilterSettings.java 0 → 100644 +383 −0 Original line number Diff line number Diff line /* * 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. */ package android.media.tv.tuner; import android.annotation.Nullable; import android.hardware.tv.tuner.V1_0.Constants; import android.media.tv.tuner.TunerConstants.FilterSettingsType; import java.util.List; /** * Demux Filter settings. * * @hide */ public abstract class FilterSettings { @Nullable protected final Settings mSettings; protected FilterSettings(Settings settings) { mSettings = settings; } /** * Gets filter settings type */ @FilterSettingsType public abstract int getType(); // TODO: more builders and getters /** * Filter Settings for a TS filter. */ public static class TsFilterSettings extends FilterSettings { private int mTpid; private TsFilterSettings(Settings settings, int tpid) { super(settings); mTpid = tpid; } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_TS; } /** * Creates a new builder. */ public static Builder newBuilder() { return new Builder(); } /** * Builder for TsFilterSettings. */ public static class Builder { private Settings mSettings; private int mTpid; /** * Sets settings. */ public Builder setSettings(Settings settings) { mSettings = settings; return this; } /** * Sets TPID. */ public Builder setTpid(int tpid) { mTpid = tpid; return this; } /** * Builds a TsFilterSettings instance. */ public TsFilterSettings build() { return new TsFilterSettings(mSettings, mTpid); } } } /** * Filter Settings for a MMTP filter. */ public static class MmtpFilterSettings extends FilterSettings { private int mMmtpPid; public MmtpFilterSettings(Settings settings) { super(settings); } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_MMTP; } } /** * Filter Settings for a IP filter. */ public static class IpFilterSettings extends FilterSettings { private byte[] mSrcIpAddress; private byte[] mDstIpAddress; private int mSrcPort; private int mDstPort; private boolean mPassthrough; public IpFilterSettings(Settings settings) { super(settings); } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_IP; } } /** * Filter Settings for a TLV filter. */ public static class TlvFilterSettings extends FilterSettings { private int mPacketType; private boolean mIsCompressedIpPacket; private boolean mPassthrough; public TlvFilterSettings(Settings settings) { super(settings); } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_TLV; } } /** * Filter Settings for a ALP filter. */ public static class AlpFilterSettings extends FilterSettings { private int mPacketType; private int mLengthType; public AlpFilterSettings(Settings settings) { super(settings); } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_ALP; } } /** * Settings for filters of different subtypes. */ public abstract static class Settings { protected final int mType; protected Settings(int type) { mType = type; } /** * Gets filter settings type. * @return */ int getType() { return mType; } } /** * Filter Settings for Section data according to ISO/IEC 13818-1. */ public static class SectionSettings extends Settings { private SectionSettings(int mainType) { super(SectionSettings.findType(mainType)); } private static int findType(int mainType) { switch (mainType) { case TunerConstants.FILTER_SETTINGS_TS: return Constants.DemuxTsFilterType.SECTION; case TunerConstants.FILTER_SETTINGS_MMTP: return Constants.DemuxMmtpFilterType.SECTION; case TunerConstants.FILTER_SETTINGS_IP: return Constants.DemuxIpFilterType.SECTION; case TunerConstants.FILTER_SETTINGS_TLV: return Constants.DemuxTlvFilterType.SECTION; case TunerConstants.FILTER_SETTINGS_ALP: return Constants.DemuxAlpFilterType.SECTION; } // UNDEFINED return 0; } } /** * Bits Settings for Section Filter. */ public static class SectionSettingsWithSectionBits extends SectionSettings { private List<Byte> mFilter; private List<Byte> mMask; private List<Byte> mMode; private SectionSettingsWithSectionBits(int mainType) { super(mainType); } } /** * Table information for Section Filter. */ public static class SectionSettingsWithTableInfo extends SectionSettings { private int mTableId; private int mVersion; private SectionSettingsWithTableInfo(int mainType) { super(mainType); } } /** * Filter Settings for a PES Data. */ public static class PesSettings extends Settings { private int mStreamId; private boolean mIsRaw; private PesSettings(int mainType, int streamId, boolean isRaw) { super(PesSettings.findType(mainType)); mStreamId = streamId; mIsRaw = isRaw; } private static int findType(int mainType) { switch (mainType) { case TunerConstants.FILTER_SETTINGS_TS: return Constants.DemuxTsFilterType.PES; case TunerConstants.FILTER_SETTINGS_MMTP: return Constants.DemuxMmtpFilterType.PES; } // UNDEFINED return 0; } /** * Creates a builder for PesSettings. */ public static Builder newBuilder(int mainType) { return new Builder(mainType); } /** * Builder for PesSettings. */ public static class Builder { private final int mMainType; private int mStreamId; private boolean mIsRaw; public Builder(int mainType) { mMainType = mainType; } /** * Sets stream ID. */ public Builder setStreamId(int streamId) { mStreamId = streamId; return this; } /** * Sets whether it's raw. * true if the filter send onFilterStatus instead of onFilterEvent. */ public Builder setIsRaw(boolean isRaw) { mIsRaw = isRaw; return this; } /** * Builds a PesSettings instance. */ public PesSettings build() { return new PesSettings(mMainType, mStreamId, mIsRaw); } } } /** * Filter Settings for a Video and Audio. */ public static class AvSettings extends Settings { private boolean mIsPassthrough; private AvSettings(int mainType, boolean isAudio) { super(AvSettings.findType(mainType, isAudio)); } private static int findType(int mainType, boolean isAudio) { switch (mainType) { case TunerConstants.FILTER_SETTINGS_TS: return isAudio ? Constants.DemuxTsFilterType.AUDIO : Constants.DemuxTsFilterType.VIDEO; case TunerConstants.FILTER_SETTINGS_MMTP: return isAudio ? Constants.DemuxMmtpFilterType.AUDIO : Constants.DemuxMmtpFilterType.VIDEO; } // UNDEFINED return 0; } } /** * Filter Settings for a Download. */ public static class DownloadSettings extends Settings { private int mDownloadId; public DownloadSettings(int mainType) { super(DownloadSettings.findType(mainType)); } private static int findType(int mainType) { if (mainType == TunerConstants.FILTER_SETTINGS_MMTP) { return Constants.DemuxMmtpFilterType.DOWNLOAD; } // UNDEFINED return 0; } } /** * The Settings for the record in DVR. */ public static class RecordSettings extends Settings { private int mIndexType; private int mIndexMask; public RecordSettings(int mainType) { super(RecordSettings.findType(mainType)); } private static int findType(int mainType) { switch (mainType) { case TunerConstants.FILTER_SETTINGS_TS: return Constants.DemuxTsFilterType.RECORD; case TunerConstants.FILTER_SETTINGS_MMTP: return Constants.DemuxMmtpFilterType.RECORD; } // UNDEFINED return 0; } } } media/java/android/media/tv/tuner/Tuner.java +15 −0 Original line number Diff line number Diff line Loading @@ -243,9 +243,11 @@ public final class Tuner implements AutoCloseable { private FilterCallback mCallback; int mId; private native int nativeConfigureFilter(int type, int subType, FilterSettings settings); private native boolean nativeStartFilter(); private native boolean nativeStopFilter(); private native boolean nativeFlushFilter(); private native int nativeRead(byte[] buffer, int offset, int size); private Filter(int id) { mId = id; Loading @@ -258,6 +260,14 @@ public final class Tuner implements AutoCloseable { } } public int configure(FilterSettings settings) { int subType = -1; if (settings.mSettings != null) { subType = settings.mSettings.getType(); } return nativeConfigureFilter(settings.getType(), subType, settings); } public boolean start() { return nativeStartFilter(); } Loading @@ -269,6 +279,11 @@ public final class Tuner implements AutoCloseable { public boolean flush() { return nativeFlushFilter(); } public int read(@NonNull byte[] buffer, int offset, int size) { size = Math.min(size, buffer.length - offset); return nativeRead(buffer, offset, size); } } private Filter openFilter(int type, int subType, int bufferSize, FilterCallback cb) { Loading media/java/android/media/tv/tuner/TunerConstants.java +11 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,17 @@ final class TunerConstants { public static final int FRONTEND_SETTINGS_ISDBS3 = 8; public static final int FRONTEND_SETTINGS_ISDBT = 9; @Retention(RetentionPolicy.SOURCE) @IntDef({FILTER_SETTINGS_TS, FILTER_SETTINGS_MMTP, FILTER_SETTINGS_IP, FILTER_SETTINGS_TLV, FILTER_SETTINGS_ALP}) public @interface FilterSettingsType {} public static final int FILTER_SETTINGS_TS = Constants.DemuxFilterMainType.TS; public static final int FILTER_SETTINGS_MMTP = Constants.DemuxFilterMainType.MMTP; public static final int FILTER_SETTINGS_IP = Constants.DemuxFilterMainType.IP; public static final int FILTER_SETTINGS_TLV = Constants.DemuxFilterMainType.TLV; public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP; private TunerConstants() { } } media/jni/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,8 @@ cc_library_shared { shared_libs: [ "android.hardware.tv.tuner@1.0", "libandroid_runtime", "libcutils", "libfmq", "libhidlbase", "liblog", "libutils", Loading media/jni/android_media_tv_Tuner.cpp +145 −14 Original line number Diff line number Diff line Loading @@ -28,8 +28,12 @@ using ::android::hardware::Void; using ::android::hardware::hidl_vec; using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType; using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid; using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; 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::FrontendAnalogSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard; Loading Loading @@ -112,6 +116,26 @@ void FilterCallback::setFilter(const jobject filter) { mFilter = env->NewWeakGlobalRef(filter); } /////////////// Filter /////////////////////// Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {} Filter::~Filter() { EventFlag::deleteEventFlag(&mFilterMQEventFlag); } int Filter::close() { Result r = mFilterSp->close(); if (r == Result::SUCCESS) { EventFlag::deleteEventFlag(&mFilterMQEventFlag); } return (int)r; } sp<IFilter> Filter::getIFilter() { return mFilterSp; } /////////////// FrontendCallback /////////////////////// FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {} Loading Loading @@ -211,6 +235,7 @@ jobject JTuner::openFrontendById(int id) { fe->setCallback(feCb); jint jId = (jint) id; JNIEnv *env = AndroidRuntime::getJNIEnv(); // TODO: add more fields to frontend return env->NewObject( Loading Loading @@ -327,18 +352,18 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { } } sp<IFilter> filterSp; sp<IFilter> iFilterSp; sp<FilterCallback> callback = new FilterCallback(); mDemux->openFilter(type, bufferSize, callback, [&](Result, const sp<IFilter>& filter) { filterSp = filter; iFilterSp = filter; }); if (filterSp == NULL) { if (iFilterSp == NULL) { ALOGD("Failed to open filter, type = %d", type.mainType); return NULL; } int fId; filterSp->getId([&](Result, uint32_t filterId) { iFilterSp->getId([&](Result, uint32_t filterId) { fId = filterId; }); Loading @@ -350,6 +375,7 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { mObject, (jint) fId); sp<Filter> filterSp = new Filter(iFilterSp, filterObj); filterSp->incStrong(filterObj); env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get()); Loading Loading @@ -432,7 +458,7 @@ static DemuxPid getDemuxPid(int pidType, int pid) { static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) { FrontendSettings frontendSettings; jclass clazz = env->FindClass("android/media/tv/tuner/FrontendSettings"); jfieldID freqField = env->GetFieldID(clazz, "frequency", "I"); jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I"); uint32_t freq = static_cast<uint32_t>(env->GetIntField(clazz, freqField)); // TODO: handle the other 8 types of settings Loading @@ -455,8 +481,8 @@ static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject setti return frontendSettings; } static sp<IFilter> getFilter(JNIEnv *env, jobject filter) { return (IFilter *)env->GetLongField(filter, gFields.filterContext); static sp<Filter> getFilter(JNIEnv *env, jobject filter) { return (Filter *)env->GetLongField(filter, gFields.filterContext); } static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) { Loading Loading @@ -542,8 +568,100 @@ static jobject android_media_tv_Tuner_open_filter( return tuner->openFilter(filterType, bufferSize); } static DemuxFilterSettings getFilterSettings( JNIEnv *env, int type, int subtype, jobject filterSettingsObj) { DemuxFilterSettings filterSettings; // TODO: more setting types jobject settingsObj = env->GetObjectField( filterSettingsObj, env->GetFieldID( env->FindClass("android/media/tv/tuner/FilterSettings"), "mSettings", "Landroid/media/tv/tuner/FilterSettings$Settings;")); if (type == (int)DemuxFilterMainType::TS) { // DemuxTsFilterSettings jclass clazz = env->FindClass("android/media/tv/tuner/FilterSettings$TsFilterSettings"); int tpid = env->GetIntField(filterSettingsObj, env->GetFieldID(clazz, "mTpid", "I")); if (subtype == (int)DemuxTsFilterType::PES) { // DemuxFilterPesDataSettings jclass settingClazz = env->FindClass("android/media/tv/tuner/FilterSettings$PesSettings"); int streamId = env->GetIntField( settingsObj, env->GetFieldID(settingClazz, "mStreamId", "I")); bool isRaw = (bool)env->GetBooleanField( settingsObj, env->GetFieldID(settingClazz, "mIsRaw", "Z")); DemuxFilterPesDataSettings filterPesDataSettings { .streamId = static_cast<uint16_t>(streamId), .isRaw = isRaw, }; DemuxTsFilterSettings tsFilterSettings { .tpid = static_cast<uint16_t>(tpid), }; tsFilterSettings.filterSettings.pesData(filterPesDataSettings); filterSettings.ts(tsFilterSettings); } } return filterSettings; } static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offset, int size) { ALOGD("copyData, size=%d, offset=%d", size, offset); int available = filter->mFilterMQ->availableToRead(); ALOGD("copyData, available=%d", available); size = std::min(size, available); jboolean isCopy; jbyte *dst = env->GetByteArrayElements(buffer, &isCopy); ALOGD("copyData, isCopy=%d", isCopy); if (dst == nullptr) { ALOGD("Failed to GetByteArrayElements"); return 0; } if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) { env->ReleaseByteArrayElements(buffer, dst, 0); filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); } else { ALOGD("Failed to read FMQ"); env->ReleaseByteArrayElements(buffer, dst, 0); return 0; } return size; } static int 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<Filter> filterSp = getFilter(env, filter); sp<IFilter> iFilterSp = filterSp->getIFilter(); if (iFilterSp == NULL) { ALOGD("Failed to configure filter: filter not found"); return (int)Result::INVALID_STATE; } DemuxFilterSettings filterSettings = getFilterSettings(env, type, subtype, settings); Result res = iFilterSp->configure(filterSettings); MQDescriptorSync<uint8_t> filterMQDesc; if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) { Result getQueueDescResult = Result::UNKNOWN_ERROR; iFilterSp->getQueueDesc( [&](Result r, const MQDescriptorSync<uint8_t>& desc) { filterMQDesc = desc; getQueueDescResult = r; ALOGD("getFilterQueueDesc"); }); if (getQueueDescResult == Result::SUCCESS) { filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true); EventFlag::createEventFlag( filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); } } return (int)res; } static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to start filter: filter not found"); return false; Loading @@ -552,7 +670,7 @@ static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { } static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to stop filter: filter not found"); return false; Loading @@ -561,7 +679,7 @@ static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { } static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to flush filter: filter not found"); return false; Loading @@ -569,6 +687,16 @@ static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { return filterSp->flush() == Result::SUCCESS; } static int android_media_tv_Tuner_read_filter_fmq( JNIEnv *env, jobject filter, jbyteArray buffer, jint offset, jint size) { sp<Filter> filterSp = getFilter(env, filter); if (filterSp == NULL) { ALOGD("Failed to read filter FMQ: filter not found"); return 0; } return copyData(env, filterSp, buffer, offset, size); } static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) { sp<JTuner> tuner = getTuner(env, thiz); return tuner->openDescrambler(); Loading @@ -580,7 +708,7 @@ static bool android_media_tv_Tuner_add_pid( if (descramblerSp == NULL) { return false; } sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp); return result == Result::SUCCESS; } Loading @@ -591,7 +719,7 @@ static bool android_media_tv_Tuner_remove_pid( if (descramblerSp == NULL) { return false; } sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp); return result == Result::SUCCESS; } Loading @@ -603,7 +731,7 @@ static jobject android_media_tv_Tuner_open_dvr(JNIEnv *env, jobject thiz, jint t static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr); sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL || filterSp == NULL) { return false; } Loading @@ -613,7 +741,7 @@ static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobje static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr); sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL || filterSp == NULL) { return false; } Loading Loading @@ -670,9 +798,12 @@ static const JNINativeMethod gTunerMethods[] = { }; static const JNINativeMethod gFilterMethods[] = { { "nativeConfigureFilter", "(IILandroid/media/tv/tuner/FilterSettings;)I", (void *)android_media_tv_Tuner_configure_filter }, { "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter }, { "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter }, { "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter }, { "nativeRead", "([BII)I", (void *)android_media_tv_Tuner_read_filter_fmq }, }; static const JNINativeMethod gDescramblerMethods[] = { Loading Loading
media/java/android/media/tv/tuner/FilterSettings.java 0 → 100644 +383 −0 Original line number Diff line number Diff line /* * 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. */ package android.media.tv.tuner; import android.annotation.Nullable; import android.hardware.tv.tuner.V1_0.Constants; import android.media.tv.tuner.TunerConstants.FilterSettingsType; import java.util.List; /** * Demux Filter settings. * * @hide */ public abstract class FilterSettings { @Nullable protected final Settings mSettings; protected FilterSettings(Settings settings) { mSettings = settings; } /** * Gets filter settings type */ @FilterSettingsType public abstract int getType(); // TODO: more builders and getters /** * Filter Settings for a TS filter. */ public static class TsFilterSettings extends FilterSettings { private int mTpid; private TsFilterSettings(Settings settings, int tpid) { super(settings); mTpid = tpid; } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_TS; } /** * Creates a new builder. */ public static Builder newBuilder() { return new Builder(); } /** * Builder for TsFilterSettings. */ public static class Builder { private Settings mSettings; private int mTpid; /** * Sets settings. */ public Builder setSettings(Settings settings) { mSettings = settings; return this; } /** * Sets TPID. */ public Builder setTpid(int tpid) { mTpid = tpid; return this; } /** * Builds a TsFilterSettings instance. */ public TsFilterSettings build() { return new TsFilterSettings(mSettings, mTpid); } } } /** * Filter Settings for a MMTP filter. */ public static class MmtpFilterSettings extends FilterSettings { private int mMmtpPid; public MmtpFilterSettings(Settings settings) { super(settings); } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_MMTP; } } /** * Filter Settings for a IP filter. */ public static class IpFilterSettings extends FilterSettings { private byte[] mSrcIpAddress; private byte[] mDstIpAddress; private int mSrcPort; private int mDstPort; private boolean mPassthrough; public IpFilterSettings(Settings settings) { super(settings); } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_IP; } } /** * Filter Settings for a TLV filter. */ public static class TlvFilterSettings extends FilterSettings { private int mPacketType; private boolean mIsCompressedIpPacket; private boolean mPassthrough; public TlvFilterSettings(Settings settings) { super(settings); } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_TLV; } } /** * Filter Settings for a ALP filter. */ public static class AlpFilterSettings extends FilterSettings { private int mPacketType; private int mLengthType; public AlpFilterSettings(Settings settings) { super(settings); } @Override public int getType() { return TunerConstants.FILTER_SETTINGS_ALP; } } /** * Settings for filters of different subtypes. */ public abstract static class Settings { protected final int mType; protected Settings(int type) { mType = type; } /** * Gets filter settings type. * @return */ int getType() { return mType; } } /** * Filter Settings for Section data according to ISO/IEC 13818-1. */ public static class SectionSettings extends Settings { private SectionSettings(int mainType) { super(SectionSettings.findType(mainType)); } private static int findType(int mainType) { switch (mainType) { case TunerConstants.FILTER_SETTINGS_TS: return Constants.DemuxTsFilterType.SECTION; case TunerConstants.FILTER_SETTINGS_MMTP: return Constants.DemuxMmtpFilterType.SECTION; case TunerConstants.FILTER_SETTINGS_IP: return Constants.DemuxIpFilterType.SECTION; case TunerConstants.FILTER_SETTINGS_TLV: return Constants.DemuxTlvFilterType.SECTION; case TunerConstants.FILTER_SETTINGS_ALP: return Constants.DemuxAlpFilterType.SECTION; } // UNDEFINED return 0; } } /** * Bits Settings for Section Filter. */ public static class SectionSettingsWithSectionBits extends SectionSettings { private List<Byte> mFilter; private List<Byte> mMask; private List<Byte> mMode; private SectionSettingsWithSectionBits(int mainType) { super(mainType); } } /** * Table information for Section Filter. */ public static class SectionSettingsWithTableInfo extends SectionSettings { private int mTableId; private int mVersion; private SectionSettingsWithTableInfo(int mainType) { super(mainType); } } /** * Filter Settings for a PES Data. */ public static class PesSettings extends Settings { private int mStreamId; private boolean mIsRaw; private PesSettings(int mainType, int streamId, boolean isRaw) { super(PesSettings.findType(mainType)); mStreamId = streamId; mIsRaw = isRaw; } private static int findType(int mainType) { switch (mainType) { case TunerConstants.FILTER_SETTINGS_TS: return Constants.DemuxTsFilterType.PES; case TunerConstants.FILTER_SETTINGS_MMTP: return Constants.DemuxMmtpFilterType.PES; } // UNDEFINED return 0; } /** * Creates a builder for PesSettings. */ public static Builder newBuilder(int mainType) { return new Builder(mainType); } /** * Builder for PesSettings. */ public static class Builder { private final int mMainType; private int mStreamId; private boolean mIsRaw; public Builder(int mainType) { mMainType = mainType; } /** * Sets stream ID. */ public Builder setStreamId(int streamId) { mStreamId = streamId; return this; } /** * Sets whether it's raw. * true if the filter send onFilterStatus instead of onFilterEvent. */ public Builder setIsRaw(boolean isRaw) { mIsRaw = isRaw; return this; } /** * Builds a PesSettings instance. */ public PesSettings build() { return new PesSettings(mMainType, mStreamId, mIsRaw); } } } /** * Filter Settings for a Video and Audio. */ public static class AvSettings extends Settings { private boolean mIsPassthrough; private AvSettings(int mainType, boolean isAudio) { super(AvSettings.findType(mainType, isAudio)); } private static int findType(int mainType, boolean isAudio) { switch (mainType) { case TunerConstants.FILTER_SETTINGS_TS: return isAudio ? Constants.DemuxTsFilterType.AUDIO : Constants.DemuxTsFilterType.VIDEO; case TunerConstants.FILTER_SETTINGS_MMTP: return isAudio ? Constants.DemuxMmtpFilterType.AUDIO : Constants.DemuxMmtpFilterType.VIDEO; } // UNDEFINED return 0; } } /** * Filter Settings for a Download. */ public static class DownloadSettings extends Settings { private int mDownloadId; public DownloadSettings(int mainType) { super(DownloadSettings.findType(mainType)); } private static int findType(int mainType) { if (mainType == TunerConstants.FILTER_SETTINGS_MMTP) { return Constants.DemuxMmtpFilterType.DOWNLOAD; } // UNDEFINED return 0; } } /** * The Settings for the record in DVR. */ public static class RecordSettings extends Settings { private int mIndexType; private int mIndexMask; public RecordSettings(int mainType) { super(RecordSettings.findType(mainType)); } private static int findType(int mainType) { switch (mainType) { case TunerConstants.FILTER_SETTINGS_TS: return Constants.DemuxTsFilterType.RECORD; case TunerConstants.FILTER_SETTINGS_MMTP: return Constants.DemuxMmtpFilterType.RECORD; } // UNDEFINED return 0; } } }
media/java/android/media/tv/tuner/Tuner.java +15 −0 Original line number Diff line number Diff line Loading @@ -243,9 +243,11 @@ public final class Tuner implements AutoCloseable { private FilterCallback mCallback; int mId; private native int nativeConfigureFilter(int type, int subType, FilterSettings settings); private native boolean nativeStartFilter(); private native boolean nativeStopFilter(); private native boolean nativeFlushFilter(); private native int nativeRead(byte[] buffer, int offset, int size); private Filter(int id) { mId = id; Loading @@ -258,6 +260,14 @@ public final class Tuner implements AutoCloseable { } } public int configure(FilterSettings settings) { int subType = -1; if (settings.mSettings != null) { subType = settings.mSettings.getType(); } return nativeConfigureFilter(settings.getType(), subType, settings); } public boolean start() { return nativeStartFilter(); } Loading @@ -269,6 +279,11 @@ public final class Tuner implements AutoCloseable { public boolean flush() { return nativeFlushFilter(); } public int read(@NonNull byte[] buffer, int offset, int size) { size = Math.min(size, buffer.length - offset); return nativeRead(buffer, offset, size); } } private Filter openFilter(int type, int subType, int bufferSize, FilterCallback cb) { Loading
media/java/android/media/tv/tuner/TunerConstants.java +11 −0 Original line number Diff line number Diff line Loading @@ -90,6 +90,17 @@ final class TunerConstants { public static final int FRONTEND_SETTINGS_ISDBS3 = 8; public static final int FRONTEND_SETTINGS_ISDBT = 9; @Retention(RetentionPolicy.SOURCE) @IntDef({FILTER_SETTINGS_TS, FILTER_SETTINGS_MMTP, FILTER_SETTINGS_IP, FILTER_SETTINGS_TLV, FILTER_SETTINGS_ALP}) public @interface FilterSettingsType {} public static final int FILTER_SETTINGS_TS = Constants.DemuxFilterMainType.TS; public static final int FILTER_SETTINGS_MMTP = Constants.DemuxFilterMainType.MMTP; public static final int FILTER_SETTINGS_IP = Constants.DemuxFilterMainType.IP; public static final int FILTER_SETTINGS_TLV = Constants.DemuxFilterMainType.TLV; public static final int FILTER_SETTINGS_ALP = Constants.DemuxFilterMainType.ALP; private TunerConstants() { } }
media/jni/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,8 @@ cc_library_shared { shared_libs: [ "android.hardware.tv.tuner@1.0", "libandroid_runtime", "libcutils", "libfmq", "libhidlbase", "liblog", "libutils", Loading
media/jni/android_media_tv_Tuner.cpp +145 −14 Original line number Diff line number Diff line Loading @@ -28,8 +28,12 @@ using ::android::hardware::Void; using ::android::hardware::hidl_vec; using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType; using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings; using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings; using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid; using ::android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits; 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::FrontendAnalogSettings; using ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard; Loading Loading @@ -112,6 +116,26 @@ void FilterCallback::setFilter(const jobject filter) { mFilter = env->NewWeakGlobalRef(filter); } /////////////// Filter /////////////////////// Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {} Filter::~Filter() { EventFlag::deleteEventFlag(&mFilterMQEventFlag); } int Filter::close() { Result r = mFilterSp->close(); if (r == Result::SUCCESS) { EventFlag::deleteEventFlag(&mFilterMQEventFlag); } return (int)r; } sp<IFilter> Filter::getIFilter() { return mFilterSp; } /////////////// FrontendCallback /////////////////////// FrontendCallback::FrontendCallback(jweak tunerObj, FrontendId id) : mObject(tunerObj), mId(id) {} Loading Loading @@ -211,6 +235,7 @@ jobject JTuner::openFrontendById(int id) { fe->setCallback(feCb); jint jId = (jint) id; JNIEnv *env = AndroidRuntime::getJNIEnv(); // TODO: add more fields to frontend return env->NewObject( Loading Loading @@ -327,18 +352,18 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { } } sp<IFilter> filterSp; sp<IFilter> iFilterSp; sp<FilterCallback> callback = new FilterCallback(); mDemux->openFilter(type, bufferSize, callback, [&](Result, const sp<IFilter>& filter) { filterSp = filter; iFilterSp = filter; }); if (filterSp == NULL) { if (iFilterSp == NULL) { ALOGD("Failed to open filter, type = %d", type.mainType); return NULL; } int fId; filterSp->getId([&](Result, uint32_t filterId) { iFilterSp->getId([&](Result, uint32_t filterId) { fId = filterId; }); Loading @@ -350,6 +375,7 @@ jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) { mObject, (jint) fId); sp<Filter> filterSp = new Filter(iFilterSp, filterObj); filterSp->incStrong(filterObj); env->SetLongField(filterObj, gFields.filterContext, (jlong)filterSp.get()); Loading Loading @@ -432,7 +458,7 @@ static DemuxPid getDemuxPid(int pidType, int pid) { static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject settings) { FrontendSettings frontendSettings; jclass clazz = env->FindClass("android/media/tv/tuner/FrontendSettings"); jfieldID freqField = env->GetFieldID(clazz, "frequency", "I"); jfieldID freqField = env->GetFieldID(clazz, "mFrequency", "I"); uint32_t freq = static_cast<uint32_t>(env->GetIntField(clazz, freqField)); // TODO: handle the other 8 types of settings Loading @@ -455,8 +481,8 @@ static FrontendSettings getFrontendSettings(JNIEnv *env, int type, jobject setti return frontendSettings; } static sp<IFilter> getFilter(JNIEnv *env, jobject filter) { return (IFilter *)env->GetLongField(filter, gFields.filterContext); static sp<Filter> getFilter(JNIEnv *env, jobject filter) { return (Filter *)env->GetLongField(filter, gFields.filterContext); } static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) { Loading Loading @@ -542,8 +568,100 @@ static jobject android_media_tv_Tuner_open_filter( return tuner->openFilter(filterType, bufferSize); } static DemuxFilterSettings getFilterSettings( JNIEnv *env, int type, int subtype, jobject filterSettingsObj) { DemuxFilterSettings filterSettings; // TODO: more setting types jobject settingsObj = env->GetObjectField( filterSettingsObj, env->GetFieldID( env->FindClass("android/media/tv/tuner/FilterSettings"), "mSettings", "Landroid/media/tv/tuner/FilterSettings$Settings;")); if (type == (int)DemuxFilterMainType::TS) { // DemuxTsFilterSettings jclass clazz = env->FindClass("android/media/tv/tuner/FilterSettings$TsFilterSettings"); int tpid = env->GetIntField(filterSettingsObj, env->GetFieldID(clazz, "mTpid", "I")); if (subtype == (int)DemuxTsFilterType::PES) { // DemuxFilterPesDataSettings jclass settingClazz = env->FindClass("android/media/tv/tuner/FilterSettings$PesSettings"); int streamId = env->GetIntField( settingsObj, env->GetFieldID(settingClazz, "mStreamId", "I")); bool isRaw = (bool)env->GetBooleanField( settingsObj, env->GetFieldID(settingClazz, "mIsRaw", "Z")); DemuxFilterPesDataSettings filterPesDataSettings { .streamId = static_cast<uint16_t>(streamId), .isRaw = isRaw, }; DemuxTsFilterSettings tsFilterSettings { .tpid = static_cast<uint16_t>(tpid), }; tsFilterSettings.filterSettings.pesData(filterPesDataSettings); filterSettings.ts(tsFilterSettings); } } return filterSettings; } static int copyData(JNIEnv *env, sp<Filter> filter, jbyteArray buffer, jint offset, int size) { ALOGD("copyData, size=%d, offset=%d", size, offset); int available = filter->mFilterMQ->availableToRead(); ALOGD("copyData, available=%d", available); size = std::min(size, available); jboolean isCopy; jbyte *dst = env->GetByteArrayElements(buffer, &isCopy); ALOGD("copyData, isCopy=%d", isCopy); if (dst == nullptr) { ALOGD("Failed to GetByteArrayElements"); return 0; } if (filter->mFilterMQ->read(reinterpret_cast<unsigned char*>(dst) + offset, size)) { env->ReleaseByteArrayElements(buffer, dst, 0); filter->mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); } else { ALOGD("Failed to read FMQ"); env->ReleaseByteArrayElements(buffer, dst, 0); return 0; } return size; } static int 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<Filter> filterSp = getFilter(env, filter); sp<IFilter> iFilterSp = filterSp->getIFilter(); if (iFilterSp == NULL) { ALOGD("Failed to configure filter: filter not found"); return (int)Result::INVALID_STATE; } DemuxFilterSettings filterSettings = getFilterSettings(env, type, subtype, settings); Result res = iFilterSp->configure(filterSettings); MQDescriptorSync<uint8_t> filterMQDesc; if (res == Result::SUCCESS && filterSp->mFilterMQ == NULL) { Result getQueueDescResult = Result::UNKNOWN_ERROR; iFilterSp->getQueueDesc( [&](Result r, const MQDescriptorSync<uint8_t>& desc) { filterMQDesc = desc; getQueueDescResult = r; ALOGD("getFilterQueueDesc"); }); if (getQueueDescResult == Result::SUCCESS) { filterSp->mFilterMQ = std::make_unique<FilterMQ>(filterMQDesc, true); EventFlag::createEventFlag( filterSp->mFilterMQ->getEventFlagWord(), &(filterSp->mFilterMQEventFlag)); } } return (int)res; } static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to start filter: filter not found"); return false; Loading @@ -552,7 +670,7 @@ static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) { } static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to stop filter: filter not found"); return false; Loading @@ -561,7 +679,7 @@ static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) { } static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (filterSp == NULL) { ALOGD("Failed to flush filter: filter not found"); return false; Loading @@ -569,6 +687,16 @@ static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) { return filterSp->flush() == Result::SUCCESS; } static int android_media_tv_Tuner_read_filter_fmq( JNIEnv *env, jobject filter, jbyteArray buffer, jint offset, jint size) { sp<Filter> filterSp = getFilter(env, filter); if (filterSp == NULL) { ALOGD("Failed to read filter FMQ: filter not found"); return 0; } return copyData(env, filterSp, buffer, offset, size); } static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) { sp<JTuner> tuner = getTuner(env, thiz); return tuner->openDescrambler(); Loading @@ -580,7 +708,7 @@ static bool android_media_tv_Tuner_add_pid( if (descramblerSp == NULL) { return false; } sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp); return result == Result::SUCCESS; } Loading @@ -591,7 +719,7 @@ static bool android_media_tv_Tuner_remove_pid( if (descramblerSp == NULL) { return false; } sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp); return result == Result::SUCCESS; } Loading @@ -603,7 +731,7 @@ static jobject android_media_tv_Tuner_open_dvr(JNIEnv *env, jobject thiz, jint t static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr); sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL || filterSp == NULL) { return false; } Loading @@ -613,7 +741,7 @@ static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobje static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<IDvr> dvrSp = getDvr(env, dvr); sp<IFilter> filterSp = getFilter(env, filter); sp<IFilter> filterSp = getFilter(env, filter)->getIFilter(); if (dvrSp == NULL || filterSp == NULL) { return false; } Loading Loading @@ -670,9 +798,12 @@ static const JNINativeMethod gTunerMethods[] = { }; static const JNINativeMethod gFilterMethods[] = { { "nativeConfigureFilter", "(IILandroid/media/tv/tuner/FilterSettings;)I", (void *)android_media_tv_Tuner_configure_filter }, { "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter }, { "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter }, { "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter }, { "nativeRead", "([BII)I", (void *)android_media_tv_Tuner_read_filter_fmq }, }; static const JNINativeMethod gDescramblerMethods[] = { Loading