Add Tuner framework AudioPresentation support
DVB MPEG-2 transport streams can include audio preselection descriptors
for next-generation audio (NGA) as specified in ETSI EN 300 468. The
tuner framework audio preselection is mapped to media framework audio
presentations and made available via MediaEvent.
Bug: 264812332
Test: CtsTvTestCases:TunerTest#testAudioFilterStreamTypeConfig
on aosp_cf_x86_tv with android.hardware.tv.tuner-service.example
Change-Id: I57ff6fd29da0744f622aec64c1344abf4cfb0d91
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index a0304bb..ed1072c 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -88,6 +88,7 @@
"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 a3adddd..0c83ddf 100644
--- a/media/jni/android_media_AudioPresentation.h
+++ b/media/jni/android_media_AudioPresentation.h
@@ -19,10 +19,14 @@
#include "jni.h"
+#include <aidl/android/hardware/tv/tuner/AudioPresentation.h>
#include <media/stagefright/foundation/ADebug.h> // CHECK
#include <media/stagefright/foundation/AudioPresentationInfo.h>
#include <nativehelper/ScopedLocalRef.h>
+using ::aidl::android::hardware::tv::tuner::AudioPreselectionRenderingIndicationType;
+using TunerAudioPresentation = ::aidl::android::hardware::tv::tuner::AudioPresentation;
+
namespace android {
struct JAudioPresentationInfo {
@@ -97,6 +101,38 @@
}
static void addPresentations(JNIEnv *env, const fields_t& fields,
+ const std::vector<TunerAudioPresentation>& tunerAudioPresentations,
+ jobject presentationsJObj) {
+ AudioPresentationCollection apc = {};
+ static const std::map<AudioPreselectionRenderingIndicationType, MasteringIndication> 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) {
ScopedLocalRef<jobject> jLabelObject = convertLabelsToMap(env, fields, ap.mLabels);
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index aacea3d..0147406 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 <aidl/android/hardware/tv/tuner/AudioExtraMetaData.h>
+#include <aidl/android/hardware/tv/tuner/AudioPresentation.h>
#include <aidl/android/hardware/tv/tuner/AudioStreamType.h>
#include <aidl/android/hardware/tv/tuner/AvStreamType.h>
#include <aidl/android/hardware/tv/tuner/Constant.h>
@@ -155,12 +156,14 @@
#include <nativehelper/ScopedLocalRef.h>
#include <utils/Log.h>
+#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;
@@ -350,6 +353,9 @@
}
namespace android {
+
+static JAudioPresentationInfo::fields_t gAudioPresentationFields;
+
/////////////// LnbClientCallbackImpl ///////////////////////
void LnbClientCallbackImpl::onEvent(const LnbEventType lnbEventType) {
ALOGV("LnbClientCallbackImpl::onEvent, type=%d", lnbEventType);
@@ -620,27 +626,45 @@
eventClazz,
"<init>",
"(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<DemuxFilterEvent::Tag::media>();
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, "<init>", "(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, "<init>", "(BBCBBB)V");
- const AudioExtraMetaData &ad =
- mediaEvent.extraMetaData.get<DemuxFilterMediaEventExtraMetaData::Tag::audio>();
- 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<DemuxFilterMediaEventExtraMetaData::Tag::audio>();
+ 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<DemuxFilterMediaEventExtraMetaData::Tag::audioPresentations>(),
+ presentationsJObj);
+ break;
+ }
+ default: {
+ ALOGE("FilterClientCallbackImpl::getMediaEvent: unknown extraMetaData");
+ break;
+ }
}
jlong dataLength = mediaEvent.dataLength;
@@ -669,7 +693,8 @@
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 ||
@@ -688,6 +713,7 @@
}
env->DeleteLocalRef(obj);
env->DeleteLocalRef(eventClazz);
+ env->DeleteLocalRef(presentationsJObj);
}
void FilterClientCallbackImpl::getPesEvent(jobjectArray &arr, const int size,