1 /*
2  * Copyright (C) 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 //#define LOG_NDEBUG 0
18 
19 #define LOG_TAG "AudioAttributes-JNI"
20 
21 #include <inttypes.h>
22 #include <jni.h>
23 #include <nativehelper/JNIHelp.h>
24 #include "core_jni_helpers.h"
25 
26 #include <utils/Log.h>
27 #include <vector>
28 
29 #include <nativehelper/ScopedLocalRef.h>
30 #include <nativehelper/ScopedUtfChars.h>
31 
32 #include "android_media_AudioAttributes.h"
33 #include "android_media_AudioErrors.h"
34 
35 // ----------------------------------------------------------------------------
36 
37 using namespace android;
38 
39 // ----------------------------------------------------------------------------
40 static const char* const kClassPathName = "android/media/AudioAttributes";
41 
42 static jclass gAudioAttributesClass;
43 static struct {
44     jfieldID    mUsage;         // AudioAttributes.mUsage
45     jfieldID    mSource;        // AudioAttributes.mSource
46     jfieldID    mContentType;   // AudioAttributes.mContentType
47     jfieldID    mFlags;         // AudioAttributes.mFlags
48     jfieldID    mFormattedTags; // AudioAttributes.mFormattedTags
49 } gAudioAttributesFields;
50 
51 static struct { jmethodID isSystemUsage; } gAudioAttributesClassMethods;
52 
53 static jclass gAudioAttributesBuilderClass;
54 static jmethodID gAudioAttributesBuilderCstor;
55 static struct {
56     jmethodID build;
57     jmethodID setUsage;
58     jmethodID setSystemUsage;
59     jmethodID setInternalCapturePreset;
60     jmethodID setInternalContentType;
61     jmethodID replaceFlags;
62     jmethodID addTag;
63 } gAudioAttributesBuilderMethods;
64 
65 
nativeAudioAttributesFromJavaAudioAttributes(JNIEnv * env,jobject jAudioAttributes,audio_attributes_t * aa)66 static jint nativeAudioAttributesFromJavaAudioAttributes(
67         JNIEnv* env, jobject jAudioAttributes, audio_attributes_t *aa)
68 {
69     if (env == nullptr) {
70         return AUDIO_JAVA_DEAD_OBJECT;
71     }
72     if (jAudioAttributes == nullptr) {
73         ALOGE("Invalid AudioAttributes java object");
74         return (jint)AUDIO_JAVA_BAD_VALUE;
75     }
76     if (!env->IsInstanceOf(jAudioAttributes, gAudioAttributesClass)) {
77         return (jint)AUDIO_JAVA_BAD_VALUE;
78     }
79     const jstring jtags =
80             (jstring) env->GetObjectField(jAudioAttributes, gAudioAttributesFields.mFormattedTags);
81     if (jtags == nullptr) {
82         return AUDIO_JAVA_NO_INIT;
83     }
84     const char* tags = env->GetStringUTFChars(jtags, NULL);
85     // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it
86     strncpy(aa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
87     env->ReleaseStringUTFChars(jtags, tags);
88 
89     // Record ?
90     aa->source = (audio_source_t) env->GetIntField(jAudioAttributes,
91                                                     gAudioAttributesFields.mSource);
92     // Track ?
93     aa->usage = (audio_usage_t) env->GetIntField(jAudioAttributes, gAudioAttributesFields.mUsage);
94 
95     aa->content_type =
96             (audio_content_type_t) env->GetIntField(jAudioAttributes,
97                                                     gAudioAttributesFields.mContentType);
98 
99     aa->flags = (audio_flags_mask_t)env->GetIntField(jAudioAttributes,
100                                                       gAudioAttributesFields.mFlags);
101 
102     ALOGV("AudioAttributes for usage=%d content=%d source=%d tags=%s flags=%08x tags=%s",
103           aa->usage, aa->content_type, aa->source, aa->tags, aa->flags, aa->tags);
104     return (jint)AUDIO_JAVA_SUCCESS;
105 }
106 
nativeAudioAttributesToJavaAudioAttributes(JNIEnv * env,jobject * jAudioAttributes,const audio_attributes_t & attributes)107 static jint nativeAudioAttributesToJavaAudioAttributes(
108         JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes)
109 {
110     ScopedLocalRef<jobject> jAttributeBuilder(env, env->NewObject(gAudioAttributesBuilderClass,
111                                                                   gAudioAttributesBuilderCstor));
112     if (jAttributeBuilder.get() == nullptr) {
113         return (jint)AUDIO_JAVA_ERROR;
114     }
115 
116     const bool isSystemUsage = env->CallStaticBooleanMethod(gAudioAttributesClass,
117                                                       gAudioAttributesClassMethods.isSystemUsage,
118                                                       attributes.usage);
119     if (isSystemUsage) {
120         env->CallObjectMethod(jAttributeBuilder.get(),
121                               gAudioAttributesBuilderMethods.setSystemUsage, attributes.usage);
122     } else {
123         env->CallObjectMethod(jAttributeBuilder.get(), gAudioAttributesBuilderMethods.setUsage,
124                               attributes.usage);
125     }
126     env->CallObjectMethod(jAttributeBuilder.get(),
127                           gAudioAttributesBuilderMethods.setInternalCapturePreset,
128                           attributes.source);
129     env->CallObjectMethod(jAttributeBuilder.get(),
130                           gAudioAttributesBuilderMethods.setInternalContentType,
131                           attributes.content_type);
132     env->CallObjectMethod(jAttributeBuilder.get(),
133                           gAudioAttributesBuilderMethods.replaceFlags,
134                           attributes.flags);
135     env->CallObjectMethod(jAttributeBuilder.get(),
136                           gAudioAttributesBuilderMethods.addTag,
137                           env->NewStringUTF(attributes.tags));
138 
139     *jAudioAttributes = env->CallObjectMethod(jAttributeBuilder.get(),
140                                               gAudioAttributesBuilderMethods.build);
141     return (jint)AUDIO_JAVA_SUCCESS;
142 }
143 
144 // ----------------------------------------------------------------------------
makeUnique()145 JNIAudioAttributeHelper::UniqueAaPtr JNIAudioAttributeHelper::makeUnique()
146 {
147     audio_attributes_t *aa = new (calloc(1, sizeof(audio_attributes_t)))
148                 audio_attributes_t{AUDIO_ATTRIBUTES_INITIALIZER};
149     return UniqueAaPtr{aa};
150 }
151 
nativeFromJava(JNIEnv * env,jobject jAudioAttributes,audio_attributes_t * paa)152 jint JNIAudioAttributeHelper::nativeFromJava(JNIEnv* env, jobject jAudioAttributes,
153                                              audio_attributes_t *paa)
154 {
155     return nativeAudioAttributesFromJavaAudioAttributes(env, jAudioAttributes, paa);
156 }
157 
nativeToJava(JNIEnv * env,jobject * jAudioAttributes,const audio_attributes_t & attributes)158 jint JNIAudioAttributeHelper::nativeToJava(
159         JNIEnv* env, jobject *jAudioAttributes, const audio_attributes_t &attributes)
160 {
161     return nativeAudioAttributesToJavaAudioAttributes(env, jAudioAttributes, attributes);
162 }
163 
getJavaArray(JNIEnv * env,jobjectArray * jAudioAttributeArray,jint numAudioAttributes)164 jint JNIAudioAttributeHelper::getJavaArray(
165         JNIEnv* env, jobjectArray *jAudioAttributeArray, jint numAudioAttributes)
166 {
167     *jAudioAttributeArray = env->NewObjectArray(numAudioAttributes, gAudioAttributesClass, NULL);
168     return *jAudioAttributeArray == NULL? (jint)AUDIO_JAVA_ERROR : (jint)AUDIO_JAVA_SUCCESS;
169 }
170 
171 /*
172  * JNI registration.
173  */
register_android_media_AudioAttributes(JNIEnv * env)174 int register_android_media_AudioAttributes(JNIEnv *env)
175 {
176     jclass audioAttributesClass = FindClassOrDie(env, kClassPathName);
177     gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
178     gAudioAttributesClassMethods.isSystemUsage =
179             GetStaticMethodIDOrDie(env, gAudioAttributesClass, "isSystemUsage", "(I)Z");
180 
181     gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, audioAttributesClass, "mUsage", "I");
182     gAudioAttributesFields.mSource = GetFieldIDOrDie(env, audioAttributesClass, "mSource", "I");
183     gAudioAttributesFields.mContentType =
184             GetFieldIDOrDie(env, audioAttributesClass, "mContentType", "I");
185     gAudioAttributesFields.mFlags = GetFieldIDOrDie(env, audioAttributesClass, "mFlags", "I");
186     gAudioAttributesFields.mFormattedTags =
187             GetFieldIDOrDie(env, audioAttributesClass, "mFormattedTags", "Ljava/lang/String;");
188 
189     jclass audioAttributesBuilderClass = FindClassOrDie(
190                 env, "android/media/AudioAttributes$Builder");
191     gAudioAttributesBuilderClass = MakeGlobalRefOrDie(env, audioAttributesBuilderClass);
192     gAudioAttributesBuilderCstor = GetMethodIDOrDie(
193                 env, audioAttributesBuilderClass, "<init>", "()V");
194     gAudioAttributesBuilderMethods.build = GetMethodIDOrDie(
195                 env, audioAttributesBuilderClass, "build", "()Landroid/media/AudioAttributes;");
196     gAudioAttributesBuilderMethods.setUsage = GetMethodIDOrDie(
197                 env, audioAttributesBuilderClass, "setUsage",
198                 "(I)Landroid/media/AudioAttributes$Builder;");
199     gAudioAttributesBuilderMethods.setSystemUsage =
200             GetMethodIDOrDie(env, audioAttributesBuilderClass, "setSystemUsage",
201                              "(I)Landroid/media/AudioAttributes$Builder;");
202     gAudioAttributesBuilderMethods.setInternalCapturePreset = GetMethodIDOrDie(
203                 env, audioAttributesBuilderClass, "setInternalCapturePreset",
204                 "(I)Landroid/media/AudioAttributes$Builder;");
205     gAudioAttributesBuilderMethods.setInternalContentType =
206             GetMethodIDOrDie(env, audioAttributesBuilderClass, "setInternalContentType",
207                              "(I)Landroid/media/AudioAttributes$Builder;");
208     gAudioAttributesBuilderMethods.replaceFlags = GetMethodIDOrDie(
209                 env, audioAttributesBuilderClass, "replaceFlags",
210                 "(I)Landroid/media/AudioAttributes$Builder;");
211     gAudioAttributesBuilderMethods.addTag = GetMethodIDOrDie(
212                 env, audioAttributesBuilderClass, "addTag",
213                 "(Ljava/lang/String;)Landroid/media/AudioAttributes$Builder;");
214 
215     env->DeleteLocalRef(audioAttributesClass);
216 
217     return 0;
218 }
219