diff --git a/core/api/system-current.txt b/core/api/system-current.txt index fc7b9d4f081a9..2eb99efc4bed6 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7961,6 +7961,7 @@ package android.media.tv.tuner.filter { public class MediaEvent extends android.media.tv.tuner.filter.FilterEvent { method public long getAudioHandle(); + method @NonNull public java.util.List getAudioPresentations(); method public long getAvDataId(); method public long getDataLength(); method public long getDts(); diff --git a/media/java/android/media/tv/tuner/filter/MediaEvent.java b/media/java/android/media/tv/tuner/filter/MediaEvent.java index d958db102f190..8f2e7b573b092 100644 --- a/media/java/android/media/tv/tuner/filter/MediaEvent.java +++ b/media/java/android/media/tv/tuner/filter/MediaEvent.java @@ -18,10 +18,15 @@ package android.media.tv.tuner.filter; import android.annotation.BytesLong; import android.annotation.IntRange; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.media.AudioPresentation; import android.media.MediaCodec.LinearBlock; +import java.util.Collections; +import java.util.List; + /** * Filter event sent from {@link Filter} objects with media type. * @@ -51,12 +56,13 @@ public class MediaEvent extends FilterEvent { private final boolean mIsPrivateData; private final int mScIndexMask; private final AudioDescriptor mExtraMetaData; + private final List mAudioPresentations; // This constructor is used by JNI code only private MediaEvent(int streamId, boolean isPtsPresent, long pts, boolean isDtsPresent, long dts, long dataLength, long offset, LinearBlock buffer, boolean isSecureMemory, long dataId, int mpuSequenceNumber, boolean isPrivateData, int scIndexMask, - AudioDescriptor extraMetaData) { + AudioDescriptor extraMetaData, List audioPresentations) { mStreamId = streamId; mIsPtsPresent = isPtsPresent; mPts = pts; @@ -71,6 +77,7 @@ public class MediaEvent extends FilterEvent { mIsPrivateData = isPrivateData; mScIndexMask = scIndexMask; mExtraMetaData = extraMetaData; + mAudioPresentations = audioPresentations; } /** @@ -215,6 +222,13 @@ public class MediaEvent extends FilterEvent { return mExtraMetaData; } + /** + * Gets audio presentations. + */ + @NonNull + public List getAudioPresentations() { + return mAudioPresentations == null ? Collections.emptyList() : mAudioPresentations; + } /** * Finalize the MediaEvent object. diff --git a/media/jni/Android.bp b/media/jni/Android.bp index a0304bb5c04bd..ed1072cf409f2 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -88,6 +88,7 @@ cc_library_shared { "android.hidl.memory@1.0", "android.hidl.token@1.0-utils", "android.hardware.drm-V1-ndk", + "android.hardware.tv.tuner-V2-ndk", ], header_libs: [ diff --git a/media/jni/android_media_AudioPresentation.h b/media/jni/android_media_AudioPresentation.h index a3adddd21fd6e..0c83ddf36b189 100644 --- a/media/jni/android_media_AudioPresentation.h +++ b/media/jni/android_media_AudioPresentation.h @@ -19,10 +19,14 @@ #include "jni.h" +#include #include // CHECK #include #include +using ::aidl::android::hardware::tv::tuner::AudioPreselectionRenderingIndicationType; +using TunerAudioPresentation = ::aidl::android::hardware::tv::tuner::AudioPresentation; + namespace android { struct JAudioPresentationInfo { @@ -96,6 +100,38 @@ struct JAudioPresentationInfo { return env->NewObject(fields.listClazz, fields.listConstructId); } + static void addPresentations(JNIEnv *env, const fields_t& fields, + const std::vector& tunerAudioPresentations, + jobject presentationsJObj) { + AudioPresentationCollection apc = {}; + static const std::map mMap { + { AudioPreselectionRenderingIndicationType::NOT_INDICATED, MASTERING_NOT_INDICATED }, + { AudioPreselectionRenderingIndicationType::STEREO, MASTERED_FOR_STEREO }, + { AudioPreselectionRenderingIndicationType::TWO_DIMENSIONAL, MASTERED_FOR_SURROUND }, + { AudioPreselectionRenderingIndicationType::THREE_DIMENSIONAL, MASTERED_FOR_3D }, + { AudioPreselectionRenderingIndicationType::HEADPHONE, MASTERED_FOR_HEADPHONE }, + }; + for (const auto& tap : tunerAudioPresentations) { + AudioPresentationV1 ap; + ap.mPresentationId = tap.preselection.preselectionId; + ap.mProgramId = tap.ac4ShortProgramId; + for (const auto& md : tap.preselection.labels) { + ap.mLabels.insert(std::pair(md.language, md.text)); + } + ap.mLanguage = tap.preselection.language; + ap.mMasteringIndication = MASTERING_NOT_INDICATED; + auto masteringSearch = mMap.find(tap.preselection.renderingIndication); + if (masteringSearch != mMap.end()) { + ap.mMasteringIndication = masteringSearch->second; + } + ap.mAudioDescriptionAvailable = tap.preselection.hasAudioDescription; + ap.mSpokenSubtitlesAvailable = tap.preselection.hasSpokenSubtitles; + ap.mDialogueEnhancementAvailable = tap.preselection.hasDialogueEnhancement; + apc.push_back(ap); + } + addPresentations(env, fields, apc, presentationsJObj); + } + static void addPresentations(JNIEnv *env, const fields_t& fields, const AudioPresentationCollection& presentations, jobject presentationsJObj) { for (const auto& ap : presentations) { diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 625e842a2db91..f56e236f5a37c 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -20,6 +20,7 @@ #include "android_media_tv_Tuner.h" #include +#include #include #include #include @@ -161,12 +162,14 @@ #include #include +#include "android_media_AudioPresentation.h" #include "android_media_MediaCodecLinearBlock.h" #include "android_runtime/AndroidRuntime.h" #pragma GCC diagnostic ignored "-Wunused-function" using ::aidl::android::hardware::tv::tuner::AudioExtraMetaData; +using ::aidl::android::hardware::tv::tuner::AudioPreselection; using ::aidl::android::hardware::tv::tuner::AudioStreamType; using ::aidl::android::hardware::tv::tuner::AvStreamType; using ::aidl::android::hardware::tv::tuner::Constant; @@ -362,6 +365,9 @@ void DestroyCallback(const C2Buffer * buf, void *arg) { } namespace android { + +static JAudioPresentationInfo::fields_t gAudioPresentationFields; + /////////////// LnbClientCallbackImpl /////////////////////// void LnbClientCallbackImpl::onEvent(const LnbEventType lnbEventType) { ALOGV("LnbClientCallbackImpl::onEvent, type=%d", lnbEventType); @@ -634,27 +640,45 @@ void FilterClientCallbackImpl::getMediaEvent(jobjectArray &arr, const int size, eventClazz, "", "(IZJZJJJLandroid/media/MediaCodec$LinearBlock;" - "ZJIZILandroid/media/tv/tuner/filter/AudioDescriptor;)V"); + "ZJIZILandroid/media/tv/tuner/filter/AudioDescriptor;" + "Ljava/util/List;)V"); jfieldID eventContext = env->GetFieldID(eventClazz, "mNativeContext", "J"); const DemuxFilterMediaEvent &mediaEvent = event.get(); jobject audioDescriptor = nullptr; - if (mediaEvent.extraMetaData.getTag() == DemuxFilterMediaEventExtraMetaData::Tag::audio) { - jclass adClazz = env->FindClass("android/media/tv/tuner/filter/AudioDescriptor"); - jmethodID adInit = env->GetMethodID(adClazz, "", "(BBCBBB)V"); + gAudioPresentationFields.init(env); + jobject presentationsJObj = JAudioPresentationInfo::asJobject(env, gAudioPresentationFields); + switch (mediaEvent.extraMetaData.getTag()) { + case DemuxFilterMediaEventExtraMetaData::Tag::audio: { + jclass adClazz = env->FindClass("android/media/tv/tuner/filter/AudioDescriptor"); + jmethodID adInit = env->GetMethodID(adClazz, "", "(BBCBBB)V"); - const AudioExtraMetaData &ad = - mediaEvent.extraMetaData.get(); - jbyte adFade = ad.adFade; - jbyte adPan = ad.adPan; - jchar versionTextTag = ad.versionTextTag; - jbyte adGainCenter = ad.adGainCenter; - jbyte adGainFront = ad.adGainFront; - jbyte adGainSurround = ad.adGainSurround; + const AudioExtraMetaData &ad = + mediaEvent.extraMetaData.get(); + jbyte adFade = ad.adFade; + jbyte adPan = ad.adPan; + jchar versionTextTag = ad.versionTextTag; + jbyte adGainCenter = ad.adGainCenter; + jbyte adGainFront = ad.adGainFront; + jbyte adGainSurround = ad.adGainSurround; - audioDescriptor = env->NewObject(adClazz, adInit, adFade, adPan, versionTextTag, - adGainCenter, adGainFront, adGainSurround); - env->DeleteLocalRef(adClazz); + audioDescriptor = env->NewObject(adClazz, adInit, adFade, adPan, versionTextTag, + adGainCenter, adGainFront, adGainSurround); + env->DeleteLocalRef(adClazz); + break; + } + case DemuxFilterMediaEventExtraMetaData::Tag::audioPresentations: { + JAudioPresentationInfo::addPresentations( + env, gAudioPresentationFields, + mediaEvent.extraMetaData + .get(), + presentationsJObj); + break; + } + default: { + ALOGE("FilterClientCallbackImpl::getMediaEvent: unknown extraMetaData"); + break; + } } jlong dataLength = mediaEvent.dataLength; @@ -683,7 +707,8 @@ void FilterClientCallbackImpl::getMediaEvent(jobjectArray &arr, const int size, jobject obj = env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, isDtsPresent, dts, dataLength, offset, nullptr, isSecureMemory, avDataId, - mpuSequenceNumber, isPesPrivateData, sc, audioDescriptor); + mpuSequenceNumber, isPesPrivateData, sc, audioDescriptor, + presentationsJObj); uint64_t avSharedMemSize = mFilterClient->getAvSharedHandleInfo().size; if (mediaEvent.avMemory.fds.size() > 0 || mediaEvent.avDataId != 0 || @@ -702,6 +727,7 @@ void FilterClientCallbackImpl::getMediaEvent(jobjectArray &arr, const int size, } env->DeleteLocalRef(obj); env->DeleteLocalRef(eventClazz); + env->DeleteLocalRef(presentationsJObj); } void FilterClientCallbackImpl::getPesEvent(jobjectArray &arr, const int size,