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 <media/stagefright/foundation/ADebug.h>  // CHECK
23 #include <media/stagefright/foundation/AudioPresentationInfo.h>
24 #include <nativehelper/ScopedLocalRef.h>
25 
26 namespace android {
27 
28 struct JAudioPresentationInfo {
29     struct fields_t {
30         jclass      clazz = NULL;
31         jmethodID   constructID;
32 
33         // list parameters
34         jclass listClazz = NULL;
35         jmethodID listConstructId;
36         jmethodID listAddId;
37 
38         // hashmap parameters
39         jclass hashMapClazz = NULL;
40         jmethodID hashMapConstructID;
41         jmethodID hashMapPutID;
42 
43         // ulocale parameters
44         jclass ulocaleClazz = NULL;
45         jmethodID ulocaleConstructID;
46 
initJAudioPresentationInfo::fields_t47         void init(JNIEnv *env) {
48             jclass lclazz = env->FindClass("android/media/AudioPresentation");
49             CHECK(lclazz != NULL);
50             clazz = (jclass)env->NewGlobalRef(lclazz);
51             CHECK(clazz != NULL);
52             constructID = env->GetMethodID(clazz, "<init>",
53                     "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V");
54             CHECK(constructID != NULL);
55 
56             // list objects
57             jclass llistClazz = env->FindClass("java/util/ArrayList");
58             CHECK(llistClazz != NULL);
59             listClazz = static_cast<jclass>(env->NewGlobalRef(llistClazz));
60             CHECK(listClazz != NULL);
61             listConstructId = env->GetMethodID(listClazz, "<init>", "()V");
62             CHECK(listConstructId != NULL);
63             listAddId = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z");
64             CHECK(listAddId != NULL);
65 
66             // hashmap objects
67             jclass lhashMapClazz = env->FindClass("java/util/HashMap");
68             CHECK(lhashMapClazz != NULL);
69             hashMapClazz = (jclass)env->NewGlobalRef(lhashMapClazz);
70             CHECK(hashMapClazz != NULL);
71             hashMapConstructID = env->GetMethodID(hashMapClazz, "<init>", "()V");
72             CHECK(hashMapConstructID != NULL);
73             hashMapPutID = env->GetMethodID(
74                     hashMapClazz,
75                     "put",
76                     "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
77             CHECK(hashMapPutID != NULL);
78 
79             jclass lulocaleClazz = env->FindClass("android/icu/util/ULocale");
80             CHECK(lulocaleClazz != NULL);
81             ulocaleClazz = (jclass)env->NewGlobalRef(lulocaleClazz);
82             CHECK(ulocaleClazz != NULL);
83             ulocaleConstructID = env->GetMethodID(ulocaleClazz, "<init>", "(Ljava/lang/String;)V");
84             CHECK(ulocaleConstructID != NULL);
85         }
86 
exitJAudioPresentationInfo::fields_t87         void exit(JNIEnv *env) {
88             env->DeleteGlobalRef(clazz); clazz = NULL;
89             env->DeleteGlobalRef(listClazz); listClazz = NULL;
90             env->DeleteGlobalRef(hashMapClazz); hashMapClazz = NULL;
91             env->DeleteGlobalRef(ulocaleClazz); ulocaleClazz = NULL;
92         }
93     };
94 
asJobjectJAudioPresentationInfo95     static jobject asJobject(JNIEnv *env, const fields_t& fields) {
96         return env->NewObject(fields.listClazz, fields.listConstructId);
97     }
98 
addPresentationsJAudioPresentationInfo99     static void addPresentations(JNIEnv *env, const fields_t& fields,
100                     const AudioPresentationCollection& presentations, jobject presentationsJObj) {
101         for (const auto& ap : presentations) {
102             ScopedLocalRef<jobject> jLabelObject = convertLabelsToMap(env, fields, ap.mLabels);
103             if (jLabelObject == nullptr) return;
104             ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(ap.mLanguage.c_str()));
105             if (jLanguage == nullptr) return;
106             ScopedLocalRef<jobject> jLocale(env, env->NewObject(
107                             fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get()));
108             ScopedLocalRef<jobject> jValueObj(env, env->NewObject(fields.clazz, fields.constructID,
109                             static_cast<jint>(ap.mPresentationId),
110                             static_cast<jint>(ap.mProgramId),
111                             jLocale.get(),
112                             static_cast<jint>(ap.mMasteringIndication),
113                             static_cast<jboolean>((ap.mAudioDescriptionAvailable == 1) ? 1 : 0),
114                             static_cast<jboolean>((ap.mSpokenSubtitlesAvailable == 1) ? 1 : 0),
115                             static_cast<jboolean>((ap.mDialogueEnhancementAvailable == 1) ? 1 : 0),
116                             jLabelObject.get()));
117             if (jValueObj != nullptr) {
118                 env->CallBooleanMethod(presentationsJObj, fields.listAddId, jValueObj.get());
119             }
120         }
121     }
122 
123   private:
convertLabelsToMapJAudioPresentationInfo124     static ScopedLocalRef<jobject> convertLabelsToMap(
125             JNIEnv *env, const fields_t& fields, const std::map<std::string, std::string> &labels) {
126         ScopedLocalRef<jobject> nullMap(env, nullptr);
127         ScopedLocalRef<jobject> hashMap(env, env->NewObject(
128                         fields.hashMapClazz, fields.hashMapConstructID));
129         if (hashMap == nullptr) {
130             return nullMap;
131         }
132 
133         for (const auto& label : labels) {
134             ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(label.first.c_str()));
135             if (jLanguage == nullptr) return nullMap;
136             ScopedLocalRef<jobject> jLocale(env, env->NewObject(
137                             fields.ulocaleClazz,
138                             fields.ulocaleConstructID,
139                             jLanguage.get()));
140             if (jLocale == nullptr) return nullMap;
141             ScopedLocalRef<jobject> jValue(env, env->NewStringUTF(label.second.c_str()));
142             if (jValue == nullptr) return nullMap;
143             env->CallObjectMethod(hashMap.get(), fields.hashMapPutID, jLocale.get(), jValue.get());
144         }
145         return hashMap;
146     }
147 };
148 }  // namespace android
149 
150 #endif  // _ANDROID_MEDIA_AUDIO_PRESENTATION_H_
151