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 #include "android_media_MicrophoneInfo.h"
18 
19 #include <media/AidlConversion.h>
20 
21 #include "android_media_AudioErrors.h"
22 #include "core_jni_helpers.h"
23 
24 using namespace android;
25 
26 static jclass gArrayListClass;
27 static jmethodID gArrayListCstor;
28 static struct {
29     jmethodID add;
30 } gArrayListMethods;
31 
32 static jclass gFloatClass;
33 static jmethodID gFloatCstor;
34 
35 static jclass gFloatArrayClass;
36 
37 static jclass gIntegerClass;
38 static jmethodID gIntegerCstor;
39 
40 static jclass gMicrophoneInfoClass;
41 static jmethodID gMicrophoneInfoCstor;
42 
43 static jclass gMicrophoneInfoCoordinateClass;
44 static jmethodID gMicrophoneInfoCoordinateCstor;
45 
46 static jclass gPairClass;
47 static jmethodID gPairCstor;
48 
49 namespace android {
50 
convertMicrophoneInfoFromNative(JNIEnv * env,jobject * jMicrophoneInfo,const media::MicrophoneInfoFw * microphoneInfo)51 jint convertMicrophoneInfoFromNative(JNIEnv *env, jobject *jMicrophoneInfo,
52                                      const media::MicrophoneInfoFw *microphoneInfo) {
53     // The Java object uses the same enum values as the C enum values, which are
54     // generated from HIDL. Thus, we can use the legacy structure as the source for
55     // creating the Java object. Once we start removing legacy types, we can add
56     // direct converters between Java and AIDL, this will eliminate the need
57     // to have JNI code like this one.
58     auto conv = aidl2legacy_MicrophoneInfoFw_audio_microphone_characteristic_t(*microphoneInfo);
59     if (!conv.ok()) {
60         return nativeToJavaStatus(conv.error());
61     }
62 
63     jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
64     jstring jDeviceId = NULL;
65     jstring jAddress = NULL;
66     jobject jGeometricLocation = NULL;
67     jobject jOrientation = NULL;
68     jobject jFrequencyResponses = NULL;
69     jobject jChannelMappings = NULL;
70 
71     const auto &micInfo = conv.value();
72     jDeviceId = env->NewStringUTF(micInfo.device_id);
73     jAddress = env->NewStringUTF(micInfo.address);
74     jGeometricLocation =
75             env->NewObject(gMicrophoneInfoCoordinateClass, gMicrophoneInfoCoordinateCstor,
76                            micInfo.geometric_location.x, micInfo.geometric_location.y,
77                            micInfo.geometric_location.z);
78     jOrientation =
79             env->NewObject(gMicrophoneInfoCoordinateClass, gMicrophoneInfoCoordinateCstor,
80                            micInfo.orientation.x, micInfo.orientation.y, micInfo.orientation.z);
81     // Create a list of Pair for frequency response.
82     jFrequencyResponses = env->NewObject(gArrayListClass, gArrayListCstor);
83     for (size_t i = 0; i < micInfo.num_frequency_responses; i++) {
84         jobject jFrequency =
85                 env->NewObject(gFloatClass, gFloatCstor, micInfo.frequency_responses[0][i]);
86         jobject jResponse =
87                 env->NewObject(gFloatClass, gFloatCstor, micInfo.frequency_responses[1][i]);
88         jobject jFrequencyResponse = env->NewObject(gPairClass, gPairCstor, jFrequency, jResponse);
89         env->CallBooleanMethod(jFrequencyResponses, gArrayListMethods.add, jFrequencyResponse);
90         env->DeleteLocalRef(jFrequency);
91         env->DeleteLocalRef(jResponse);
92         env->DeleteLocalRef(jFrequencyResponse);
93     }
94     // Create a list of Pair for channel mapping.
95     jChannelMappings = env->NewObject(gArrayListClass, gArrayListCstor);
96     const auto &channelMapping = micInfo.channel_mapping;
97     for (size_t i = 0; i < std::size(channelMapping); i++) {
98         int channelMappingType = channelMapping[i];
99         if (channelMappingType != AUDIO_MICROPHONE_CHANNEL_MAPPING_UNUSED) {
100             jobject jChannelIndex = env->NewObject(gIntegerClass, gIntegerCstor, i);
101             jobject jChannelMappingType = env->NewObject(gIntegerClass, gIntegerCstor,
102                                                          channelMappingType);
103             jobject jChannelMapping = env->NewObject(gPairClass, gPairCstor,
104                                                      jChannelIndex, jChannelMappingType);
105             env->CallBooleanMethod(jChannelMappings, gArrayListMethods.add, jChannelMapping);
106             env->DeleteLocalRef(jChannelIndex);
107             env->DeleteLocalRef(jChannelMappingType);
108             env->DeleteLocalRef(jChannelMapping);
109         }
110     }
111     *jMicrophoneInfo = env->NewObject(gMicrophoneInfoClass, gMicrophoneInfoCstor, jDeviceId,
112                                       micInfo.device, jAddress, micInfo.location, micInfo.group,
113                                       micInfo.index_in_the_group, jGeometricLocation, jOrientation,
114                                       jFrequencyResponses, jChannelMappings, micInfo.sensitivity,
115                                       micInfo.max_spl, micInfo.min_spl, micInfo.directionality);
116 
117     if (jDeviceId != NULL) {
118         env->DeleteLocalRef(jDeviceId);
119     }
120     if (jAddress != NULL) {
121         env->DeleteLocalRef(jAddress);
122     }
123     if (jFrequencyResponses != NULL) {
124         env->DeleteLocalRef(jFrequencyResponses);
125     }
126     if (jChannelMappings != NULL) {
127         env->DeleteLocalRef(jChannelMappings);
128     }
129     if (jGeometricLocation != NULL) {
130         env->DeleteLocalRef(jGeometricLocation);
131     }
132     if (jOrientation != NULL) {
133         env->DeleteLocalRef(jOrientation);
134     }
135     return jStatus;
136 }
137 }
138 
register_android_media_MicrophoneInfo(JNIEnv * env)139 int register_android_media_MicrophoneInfo(JNIEnv *env)
140 {
141     jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
142     gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
143     gArrayListCstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
144     gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
145 
146     jclass floatClass = FindClassOrDie(env, "java/lang/Float");
147     gFloatClass = MakeGlobalRefOrDie(env, floatClass);
148     gFloatCstor = GetMethodIDOrDie(env, floatClass, "<init>", "(F)V");
149 
150     jclass floatArrayClass = FindClassOrDie(env, "[F");
151     gFloatArrayClass = MakeGlobalRefOrDie(env, floatArrayClass);
152 
153     jclass integerClass = FindClassOrDie(env, "java/lang/Integer");
154     gIntegerClass = MakeGlobalRefOrDie(env, integerClass);
155     gIntegerCstor = GetMethodIDOrDie(env, integerClass, "<init>", "(I)V");
156 
157     jclass microphoneInfoClass = FindClassOrDie(env, "android/media/MicrophoneInfo");
158     gMicrophoneInfoClass = MakeGlobalRefOrDie(env, microphoneInfoClass);
159     gMicrophoneInfoCstor = GetMethodIDOrDie(env, microphoneInfoClass, "<init>",
160             "(Ljava/lang/String;ILjava/lang/String;IIILandroid/media/MicrophoneInfo$Coordinate3F;Landroid/media/MicrophoneInfo$Coordinate3F;Ljava/util/List;Ljava/util/List;FFFI)V");
161 
162     jclass microphoneInfoCoordinateClass = FindClassOrDie(
163             env, "android/media/MicrophoneInfo$Coordinate3F");
164     gMicrophoneInfoCoordinateClass = MakeGlobalRefOrDie(env, microphoneInfoCoordinateClass);
165     gMicrophoneInfoCoordinateCstor = GetMethodIDOrDie(env, microphoneInfoCoordinateClass, "<init>",
166            "(FFF)V");
167 
168     jclass pairClass = FindClassOrDie(env, "android/util/Pair");
169     gPairClass = MakeGlobalRefOrDie(env, pairClass);
170     gPairCstor = GetMethodIDOrDie(env, pairClass, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
171 
172     return 0;
173 }
174