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_AUDIO_PRESENTATION_H_ 18 #define _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ 19 20 #include "jni.h" 21 22 #include <media/AudioPresentationInfo.h> 23 #include <media/stagefright/foundation/ADebug.h> 24 #include <media/stagefright/foundation/AMessage.h> 25 26 #include <nativehelper/ScopedLocalRef.h> 27 28 namespace android { 29 30 struct JAudioPresentationInfo { 31 struct fields_t { 32 jclass clazz; 33 jmethodID constructID; 34 35 // list parameters 36 jclass listclazz; 37 jmethodID listConstructId; 38 jmethodID listAddId; 39 40 void init(JNIEnv *env) { 41 jclass lclazz = env->FindClass("android/media/AudioPresentation"); 42 if (lclazz == NULL) { 43 return; 44 } 45 46 clazz = (jclass)env->NewGlobalRef(lclazz); 47 if (clazz == NULL) { 48 return; 49 } 50 51 constructID = env->GetMethodID(clazz, "<init>", 52 "(IILjava/util/Map;Ljava/lang/String;IZZZ)V"); 53 env->DeleteLocalRef(lclazz); 54 55 // list objects 56 jclass llistclazz = env->FindClass("java/util/ArrayList"); 57 CHECK(llistclazz != NULL); 58 listclazz = static_cast<jclass>(env->NewGlobalRef(llistclazz)); 59 CHECK(listclazz != NULL); 60 listConstructId = env->GetMethodID(listclazz, "<init>", "()V"); 61 CHECK(listConstructId != NULL); 62 listAddId = env->GetMethodID(listclazz, "add", "(Ljava/lang/Object;)Z"); 63 CHECK(listAddId != NULL); 64 env->DeleteLocalRef(llistclazz); 65 } 66 67 void exit(JNIEnv *env) { 68 env->DeleteGlobalRef(clazz); 69 clazz = NULL; 70 env->DeleteGlobalRef(listclazz); 71 listclazz = NULL; 72 } 73 }; 74 75 static status_t ConvertMessageToMap(JNIEnv *env, const sp<AMessage> &msg, jobject *map) { 76 ScopedLocalRef<jclass> hashMapClazz(env, env->FindClass("java/util/HashMap")); 77 78 if (hashMapClazz.get() == NULL) { 79 return -EINVAL; 80 } 81 jmethodID hashMapConstructID = 82 env->GetMethodID(hashMapClazz.get(), "<init>", "()V"); 83 84 if (hashMapConstructID == NULL) { 85 return -EINVAL; 86 } 87 jmethodID hashMapPutID = 88 env->GetMethodID( 89 hashMapClazz.get(), 90 "put", 91 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 92 93 if (hashMapPutID == NULL) { 94 return -EINVAL; 95 } 96 97 jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID); 98 99 for (size_t i = 0; i < msg->countEntries(); ++i) { 100 AMessage::Type valueType; 101 const char *key = msg->getEntryNameAt(i, &valueType); 102 103 if (!strncmp(key, "android._", 9)) { 104 // don't expose private keys (starting with android._) 105 continue; 106 } 107 108 jobject valueObj = NULL; 109 110 AString val; 111 CHECK(msg->findString(key, &val)); 112 113 valueObj = env->NewStringUTF(val.c_str()); 114 115 if (valueObj != NULL) { 116 jstring keyObj = env->NewStringUTF(key); 117 118 env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj); 119 120 env->DeleteLocalRef(keyObj); keyObj = NULL; 121 env->DeleteLocalRef(valueObj); valueObj = NULL; 122 } 123 } 124 125 *map = hashMap; 126 127 return OK; 128 } 129 130 jobject asJobject(JNIEnv *env, const fields_t& fields, const AudioPresentationInfo &info) { 131 jobject list = env->NewObject(fields.listclazz, fields.listConstructId); 132 133 for (size_t i = 0; i < info.countPresentations(); ++i) { 134 const sp<AudioPresentation> &ap = info.getPresentation(i); 135 jobject jLabelObject; 136 137 sp<AMessage> labelMessage = new AMessage(); 138 for (size_t i = 0; i < ap->mLabels.size(); ++i) { 139 labelMessage->setString(ap->mLabels.keyAt(i).string(), 140 ap->mLabels.valueAt(i).string()); 141 } 142 if (ConvertMessageToMap(env, labelMessage, &jLabelObject) != OK) { 143 return NULL; 144 } 145 jstring jLanguage = env->NewStringUTF(ap->mLanguage.string()); 146 147 jobject jValueObj = env->NewObject(fields.clazz, fields.constructID, 148 static_cast<jint>(ap->mPresentationId), 149 static_cast<jint>(ap->mProgramId), 150 jLabelObject, 151 jLanguage, 152 static_cast<jint>(ap->mMasteringIndication), 153 static_cast<jboolean>((ap->mAudioDescriptionAvailable == 1) ? 154 1 : 0), 155 static_cast<jboolean>((ap->mSpokenSubtitlesAvailable == 1) ? 156 1 : 0), 157 static_cast<jboolean>((ap->mDialogueEnhancementAvailable == 1) ? 158 1 : 0)); 159 if (jValueObj == NULL) { 160 env->DeleteLocalRef(jLanguage); jLanguage = NULL; 161 return NULL; 162 } 163 164 env->CallBooleanMethod(list, fields.listAddId, jValueObj); 165 env->DeleteLocalRef(jValueObj); jValueObj = NULL; 166 env->DeleteLocalRef(jLanguage); jLanguage = NULL; 167 } 168 return list; 169 } 170 }; 171 } // namespace android 172 173 #endif // _ANDROID_MEDIA_AUDIO_PRESENTATION_H_ 174