1 /* 2 * Copyright 2018, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef _ANDROID_MEDIA_AUDIOPRESENTATION_H_ 18 #define _ANDROID_MEDIA_AUDIOPRESENTATION_H_ 19 20 #include "jni.h" 21 22 #include <aidl/android/hardware/tv/tuner/AudioPresentation.h> 23 #include <media/stagefright/foundation/ADebug.h> // CHECK 24 #include <media/stagefright/foundation/AudioPresentationInfo.h> 25 #include <nativehelper/ScopedLocalRef.h> 26 27 using ::aidl::android::hardware::tv::tuner::AudioPreselectionRenderingIndicationType; 28 using TunerAudioPresentation = ::aidl::android::hardware::tv::tuner::AudioPresentation; 29 30 namespace android { 31 32 struct JAudioPresentationInfo { 33 struct fields_t { 34 jclass clazz = NULL; 35 jmethodID constructID; 36 37 // list parameters 38 jclass listClazz = NULL; 39 jmethodID listConstructId; 40 jmethodID listAddId; 41 42 // hashmap parameters 43 jclass hashMapClazz = NULL; 44 jmethodID hashMapConstructID; 45 jmethodID hashMapPutID; 46 47 // ulocale parameters 48 jclass ulocaleClazz = NULL; 49 jmethodID ulocaleConstructID; 50 initJAudioPresentationInfo::fields_t51 void init(JNIEnv *env) { 52 jclass lclazz = env->FindClass("android/media/AudioPresentation"); 53 CHECK(lclazz != NULL); 54 clazz = (jclass)env->NewGlobalRef(lclazz); 55 CHECK(clazz != NULL); 56 constructID = env->GetMethodID(clazz, "<init>", 57 "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V"); 58 CHECK(constructID != NULL); 59 60 // list objects 61 jclass llistClazz = env->FindClass("java/util/ArrayList"); 62 CHECK(llistClazz != NULL); 63 listClazz = static_cast<jclass>(env->NewGlobalRef(llistClazz)); 64 CHECK(listClazz != NULL); 65 listConstructId = env->GetMethodID(listClazz, "<init>", "()V"); 66 CHECK(listConstructId != NULL); 67 listAddId = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z"); 68 CHECK(listAddId != NULL); 69 70 // hashmap objects 71 jclass lhashMapClazz = env->FindClass("java/util/HashMap"); 72 CHECK(lhashMapClazz != NULL); 73 hashMapClazz = (jclass)env->NewGlobalRef(lhashMapClazz); 74 CHECK(hashMapClazz != NULL); 75 hashMapConstructID = env->GetMethodID(hashMapClazz, "<init>", "()V"); 76 CHECK(hashMapConstructID != NULL); 77 hashMapPutID = env->GetMethodID( 78 hashMapClazz, 79 "put", 80 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 81 CHECK(hashMapPutID != NULL); 82 83 jclass lulocaleClazz = env->FindClass("android/icu/util/ULocale"); 84 CHECK(lulocaleClazz != NULL); 85 ulocaleClazz = (jclass)env->NewGlobalRef(lulocaleClazz); 86 CHECK(ulocaleClazz != NULL); 87 ulocaleConstructID = env->GetMethodID(ulocaleClazz, "<init>", "(Ljava/lang/String;)V"); 88 CHECK(ulocaleConstructID != NULL); 89 } 90 exitJAudioPresentationInfo::fields_t91 void exit(JNIEnv *env) { 92 env->DeleteGlobalRef(clazz); clazz = NULL; 93 env->DeleteGlobalRef(listClazz); listClazz = NULL; 94 env->DeleteGlobalRef(hashMapClazz); hashMapClazz = NULL; 95 env->DeleteGlobalRef(ulocaleClazz); ulocaleClazz = NULL; 96 } 97 }; 98 asJobjectJAudioPresentationInfo99 static jobject asJobject(JNIEnv *env, const fields_t& fields) { 100 return env->NewObject(fields.listClazz, fields.listConstructId); 101 } 102 addPresentationsJAudioPresentationInfo103 static void addPresentations(JNIEnv *env, const fields_t& fields, 104 const std::vector<TunerAudioPresentation>& tunerAudioPresentations, 105 jobject presentationsJObj) { 106 AudioPresentationCollection apc = {}; 107 static const std::map<AudioPreselectionRenderingIndicationType, MasteringIndication> mMap { 108 { AudioPreselectionRenderingIndicationType::NOT_INDICATED, MASTERING_NOT_INDICATED }, 109 { AudioPreselectionRenderingIndicationType::STEREO, MASTERED_FOR_STEREO }, 110 { AudioPreselectionRenderingIndicationType::TWO_DIMENSIONAL, MASTERED_FOR_SURROUND }, 111 { AudioPreselectionRenderingIndicationType::THREE_DIMENSIONAL, MASTERED_FOR_3D }, 112 { AudioPreselectionRenderingIndicationType::HEADPHONE, MASTERED_FOR_HEADPHONE }, 113 }; 114 for (const auto& tap : tunerAudioPresentations) { 115 AudioPresentationV1 ap; 116 ap.mPresentationId = tap.preselection.preselectionId; 117 ap.mProgramId = tap.ac4ShortProgramId; 118 for (const auto& md : tap.preselection.labels) { 119 ap.mLabels.insert(std::pair(md.language, md.text)); 120 } 121 ap.mLanguage = tap.preselection.language; 122 ap.mMasteringIndication = MASTERING_NOT_INDICATED; 123 auto masteringSearch = mMap.find(tap.preselection.renderingIndication); 124 if (masteringSearch != mMap.end()) { 125 ap.mMasteringIndication = masteringSearch->second; 126 } 127 ap.mAudioDescriptionAvailable = tap.preselection.hasAudioDescription; 128 ap.mSpokenSubtitlesAvailable = tap.preselection.hasSpokenSubtitles; 129 ap.mDialogueEnhancementAvailable = tap.preselection.hasDialogueEnhancement; 130 apc.push_back(ap); 131 } 132 addPresentations(env, fields, apc, presentationsJObj); 133 } 134 addPresentationsJAudioPresentationInfo135 static void addPresentations(JNIEnv *env, const fields_t& fields, 136 const AudioPresentationCollection& presentations, jobject presentationsJObj) { 137 for (const auto& ap : presentations) { 138 ScopedLocalRef<jobject> jLabelObject = convertLabelsToMap(env, fields, ap.mLabels); 139 if (jLabelObject == nullptr) return; 140 ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(ap.mLanguage.c_str())); 141 if (jLanguage == nullptr) return; 142 ScopedLocalRef<jobject> jLocale(env, env->NewObject( 143 fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get())); 144 ScopedLocalRef<jobject> jValueObj(env, env->NewObject(fields.clazz, fields.constructID, 145 static_cast<jint>(ap.mPresentationId), 146 static_cast<jint>(ap.mProgramId), 147 jLocale.get(), 148 static_cast<jint>(ap.mMasteringIndication), 149 static_cast<jboolean>((ap.mAudioDescriptionAvailable == 1) ? 1 : 0), 150 static_cast<jboolean>((ap.mSpokenSubtitlesAvailable == 1) ? 1 : 0), 151 static_cast<jboolean>((ap.mDialogueEnhancementAvailable == 1) ? 1 : 0), 152 jLabelObject.get())); 153 if (jValueObj != nullptr) { 154 env->CallBooleanMethod(presentationsJObj, fields.listAddId, jValueObj.get()); 155 } 156 } 157 } 158 159 private: convertLabelsToMapJAudioPresentationInfo160 static ScopedLocalRef<jobject> convertLabelsToMap( 161 JNIEnv *env, const fields_t& fields, const std::map<std::string, std::string> &labels) { 162 ScopedLocalRef<jobject> nullMap(env, nullptr); 163 ScopedLocalRef<jobject> hashMap(env, env->NewObject( 164 fields.hashMapClazz, fields.hashMapConstructID)); 165 if (hashMap == nullptr) { 166 return nullMap; 167 } 168 169 for (const auto& label : labels) { 170 ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(label.first.c_str())); 171 if (jLanguage == nullptr) return nullMap; 172 ScopedLocalRef<jobject> jLocale(env, env->NewObject( 173 fields.ulocaleClazz, 174 fields.ulocaleConstructID, 175 jLanguage.get())); 176 if (jLocale == nullptr) return nullMap; 177 ScopedLocalRef<jobject> jValue(env, env->NewStringUTF(label.second.c_str())); 178 if (jValue == nullptr) return nullMap; 179 env->CallObjectMethod(hashMap.get(), fields.hashMapPutID, jLocale.get(), jValue.get()); 180 } 181 return hashMap; 182 } 183 }; 184 } // namespace android 185 186 #endif // _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ 187