blob: 0c83ddf36b1895abafa11461869dc8fe4fa3a1ed [file] [log] [blame]
/*
* Copyright 2018, 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.
*/
#ifndef _ANDROID_MEDIA_AUDIOPRESENTATION_H_
#define _ANDROID_MEDIA_AUDIOPRESENTATION_H_
#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 {
struct fields_t {
jclass clazz = NULL;
jmethodID constructID;
// list parameters
jclass listClazz = NULL;
jmethodID listConstructId;
jmethodID listAddId;
// hashmap parameters
jclass hashMapClazz = NULL;
jmethodID hashMapConstructID;
jmethodID hashMapPutID;
// ulocale parameters
jclass ulocaleClazz = NULL;
jmethodID ulocaleConstructID;
void init(JNIEnv *env) {
jclass lclazz = env->FindClass("android/media/AudioPresentation");
CHECK(lclazz != NULL);
clazz = (jclass)env->NewGlobalRef(lclazz);
CHECK(clazz != NULL);
constructID = env->GetMethodID(clazz, "<init>",
"(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V");
CHECK(constructID != NULL);
// list objects
jclass llistClazz = env->FindClass("java/util/ArrayList");
CHECK(llistClazz != NULL);
listClazz = static_cast<jclass>(env->NewGlobalRef(llistClazz));
CHECK(listClazz != NULL);
listConstructId = env->GetMethodID(listClazz, "<init>", "()V");
CHECK(listConstructId != NULL);
listAddId = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z");
CHECK(listAddId != NULL);
// hashmap objects
jclass lhashMapClazz = env->FindClass("java/util/HashMap");
CHECK(lhashMapClazz != NULL);
hashMapClazz = (jclass)env->NewGlobalRef(lhashMapClazz);
CHECK(hashMapClazz != NULL);
hashMapConstructID = env->GetMethodID(hashMapClazz, "<init>", "()V");
CHECK(hashMapConstructID != NULL);
hashMapPutID = env->GetMethodID(
hashMapClazz,
"put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
CHECK(hashMapPutID != NULL);
jclass lulocaleClazz = env->FindClass("android/icu/util/ULocale");
CHECK(lulocaleClazz != NULL);
ulocaleClazz = (jclass)env->NewGlobalRef(lulocaleClazz);
CHECK(ulocaleClazz != NULL);
ulocaleConstructID = env->GetMethodID(ulocaleClazz, "<init>", "(Ljava/lang/String;)V");
CHECK(ulocaleConstructID != NULL);
}
void exit(JNIEnv *env) {
env->DeleteGlobalRef(clazz); clazz = NULL;
env->DeleteGlobalRef(listClazz); listClazz = NULL;
env->DeleteGlobalRef(hashMapClazz); hashMapClazz = NULL;
env->DeleteGlobalRef(ulocaleClazz); ulocaleClazz = NULL;
}
};
static jobject asJobject(JNIEnv *env, const fields_t& fields) {
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) {
ScopedLocalRef<jobject> jLabelObject = convertLabelsToMap(env, fields, ap.mLabels);
if (jLabelObject == nullptr) return;
ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(ap.mLanguage.c_str()));
if (jLanguage == nullptr) return;
ScopedLocalRef<jobject> jLocale(env, env->NewObject(
fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get()));
ScopedLocalRef<jobject> jValueObj(env, env->NewObject(fields.clazz, fields.constructID,
static_cast<jint>(ap.mPresentationId),
static_cast<jint>(ap.mProgramId),
jLocale.get(),
static_cast<jint>(ap.mMasteringIndication),
static_cast<jboolean>((ap.mAudioDescriptionAvailable == 1) ? 1 : 0),
static_cast<jboolean>((ap.mSpokenSubtitlesAvailable == 1) ? 1 : 0),
static_cast<jboolean>((ap.mDialogueEnhancementAvailable == 1) ? 1 : 0),
jLabelObject.get()));
if (jValueObj != nullptr) {
env->CallBooleanMethod(presentationsJObj, fields.listAddId, jValueObj.get());
}
}
}
private:
static ScopedLocalRef<jobject> convertLabelsToMap(
JNIEnv *env, const fields_t& fields, const std::map<std::string, std::string> &labels) {
ScopedLocalRef<jobject> nullMap(env, nullptr);
ScopedLocalRef<jobject> hashMap(env, env->NewObject(
fields.hashMapClazz, fields.hashMapConstructID));
if (hashMap == nullptr) {
return nullMap;
}
for (const auto& label : labels) {
ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(label.first.c_str()));
if (jLanguage == nullptr) return nullMap;
ScopedLocalRef<jobject> jLocale(env, env->NewObject(
fields.ulocaleClazz,
fields.ulocaleConstructID,
jLanguage.get()));
if (jLocale == nullptr) return nullMap;
ScopedLocalRef<jobject> jValue(env, env->NewStringUTF(label.second.c_str()));
if (jValue == nullptr) return nullMap;
env->CallObjectMethod(hashMap.get(), fields.hashMapPutID, jLocale.get(), jValue.get());
}
return hashMap;
}
};
} // namespace android
#endif // _ANDROID_MEDIA_AUDIO_PRESENTATION_H_