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:
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user