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
This commit is contained in:
Dean Wheatley
2022-12-20 09:33:23 +11:00
committed by Ray Chin
parent eaa21fd5e6
commit c7762b4a93
5 changed files with 95 additions and 17 deletions

View File

@@ -7876,6 +7876,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<android.media.AudioPresentation> getAudioPresentations();
method public long getAvDataId();
method public long getDataLength();
method public long getDts();

View File

@@ -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<AudioPresentation> 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<AudioPresentation> 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<AudioPresentation> getAudioPresentations() {
return mAudioPresentations == null ? Collections.emptyList() : mAudioPresentations;
}
/**
* Finalize the MediaEvent object.

View File

@@ -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: [

View File

@@ -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 {
@@ -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<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) {

View File

@@ -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 @@ 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);
@@ -620,27 +626,45 @@ void FilterClientCallbackImpl::getMediaEvent(jobjectArray &arr, const int size,
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 @@ 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 ||
@@ -688,6 +713,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,