• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "AudioVolumeGroups-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 <media/AudioSystem.h>
30 #include <media/AudioPolicy.h>
31 
32 #include <nativehelper/ScopedUtfChars.h>
33 
34 #include "android_media_AudioAttributes.h"
35 #include "android_media_AudioErrors.h"
36 
37 // ----------------------------------------------------------------------------
38 
39 using namespace android;
40 
41 // ----------------------------------------------------------------------------
42 static const char* const kClassPathName = "android/media/audiopolicy/AudioVolumeGroup";
43 static const char* const kAudioVolumeGroupClassPathName =
44         "android/media/audiopolicy/AudioVolumeGroup";
45 
46 static jclass gAudioVolumeGroupClass;
47 static jmethodID gAudioVolumeGroupCstor;
48 static struct {
49     jfieldID    mName;
50     jfieldID    mId;
51 } gAudioVolumeGroupFields;
52 
53 static jclass gArrayListClass;
54 static jmethodID gArrayListCstor;
55 static struct {
56     jmethodID    add;
57     jmethodID    toArray;
58 } gArrayListMethods;
59 
60 
convertAudioVolumeGroupsFromNative(JNIEnv * env,jobject * jGroup,const AudioVolumeGroup & group)61 static jint convertAudioVolumeGroupsFromNative(
62         JNIEnv *env, jobject *jGroup, const AudioVolumeGroup &group)
63 {
64     jint jStatus = (jint)AUDIO_JAVA_SUCCESS;
65     jstring jName = NULL;
66     jint Id = NULL;
67 
68     jintArray jLegacyStreamTypes = NULL;
69     jobjectArray jAudioAttributes = NULL;
70     jint numAttributes;
71     jobject jAudioAttribute = NULL;
72 
73     jName = env->NewStringUTF(group.getName().c_str());
74     Id = static_cast<jint>(group.getId());
75 
76     // Legacy stream types array
77     jLegacyStreamTypes = env->NewIntArray(group.getStreamTypes().size());
78     if (jLegacyStreamTypes == NULL) {
79         jStatus = (jint)AUDIO_JAVA_ERROR;
80         goto exit;
81     }
82     for (size_t streamIndex = 0; streamIndex < group.getStreamTypes().size(); streamIndex++) {
83         jint jStream = group.getStreamTypes()[streamIndex];
84         env->SetIntArrayRegion(jLegacyStreamTypes, streamIndex, 1, &jStream);
85     }
86 
87     // Audio Attributes array
88     numAttributes = group.getAudioAttributes().size();
89     jStatus = JNIAudioAttributeHelper::getJavaArray(env, &jAudioAttributes, numAttributes);
90     if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
91         goto exit;
92     }
93 
94     for (size_t j = 0; j < static_cast<size_t>(numAttributes); j++) {
95         auto attributes = group.getAudioAttributes()[j];
96 
97         // Native & Java audio attributes default initializers are not aligned for the source.
98         // Given the volume group class concerns only playback, this field must be equal to the
99         // default java initializer.
100         attributes.source = AUDIO_SOURCE_INVALID;
101 
102         jStatus = JNIAudioAttributeHelper::nativeToJava(env, &jAudioAttribute, attributes);
103         if (jStatus != AUDIO_JAVA_SUCCESS) {
104             goto exit;
105         }
106         env->SetObjectArrayElement(jAudioAttributes, j, jAudioAttribute);
107     }
108 
109     *jGroup = env->NewObject(gAudioVolumeGroupClass, gAudioVolumeGroupCstor,
110                              jName, Id, jAudioAttributes, jLegacyStreamTypes);
111 exit:
112     if (jName != NULL) {
113         env->DeleteLocalRef(jName);
114     }
115     return jStatus;
116 }
117 
118 static jint
android_media_AudioSystem_listAudioVolumeGroups(JNIEnv * env,jobject clazz,jobject jVolumeGroups)119 android_media_AudioSystem_listAudioVolumeGroups(JNIEnv *env, jobject clazz, jobject jVolumeGroups)
120 {
121     if (env == NULL) {
122         return AUDIO_JAVA_DEAD_OBJECT;
123     }
124     if (jVolumeGroups == NULL) {
125         ALOGE("listAudioVolumeGroups NULL AudioVolumeGroups");
126         return (jint)AUDIO_JAVA_BAD_VALUE;
127     }
128     if (!env->IsInstanceOf(jVolumeGroups, gArrayListClass)) {
129         ALOGE("listAudioVolumeGroups not an arraylist");
130         return (jint)AUDIO_JAVA_BAD_VALUE;
131     }
132 
133     status_t status;
134     AudioVolumeGroupVector groups;
135     jint jStatus;
136     jobject jGroup = NULL;
137 
138     status = AudioSystem::listAudioVolumeGroups(groups);
139     if (status != NO_ERROR) {
140         ALOGE("AudioSystem::listAudioVolumeGroups error %d", status);
141         return nativeToJavaStatus(status);
142     }
143     for (const auto &group : groups) {
144         jStatus = convertAudioVolumeGroupsFromNative(env, &jGroup, group);
145         if (jStatus != AUDIO_JAVA_SUCCESS) {
146             goto exit;
147         }
148         env->CallBooleanMethod(jVolumeGroups, gArrayListMethods.add, jGroup);
149     }
150 exit:
151     if (jGroup != NULL) {
152         env->DeleteLocalRef(jGroup);
153     }
154     return jStatus;
155 }
156 
157 /*
158  * JNI registration.
159  */
160 static const JNINativeMethod gMethods[] = {
161     {"native_list_audio_volume_groups", "(Ljava/util/ArrayList;)I",
162                         (void *)android_media_AudioSystem_listAudioVolumeGroups},
163 };
164 
register_android_media_AudioVolumeGroups(JNIEnv * env)165 int register_android_media_AudioVolumeGroups(JNIEnv *env)
166 {
167     jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList");
168     gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass);
169     gArrayListCstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V");
170     gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z");
171     gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass,
172                                                  "toArray", "()[Ljava/lang/Object;");
173 
174     jclass audioVolumeGroupClass = FindClassOrDie(env, kAudioVolumeGroupClassPathName);
175     gAudioVolumeGroupClass = MakeGlobalRefOrDie(env, audioVolumeGroupClass);
176     gAudioVolumeGroupCstor = GetMethodIDOrDie(
177                 env, audioVolumeGroupClass, "<init>",
178                 "(Ljava/lang/String;I[Landroid/media/AudioAttributes;[I)V");
179 
180     gAudioVolumeGroupFields.mName = GetFieldIDOrDie(
181                 env, audioVolumeGroupClass, "mName", "Ljava/lang/String;");
182     gAudioVolumeGroupFields.mId = GetFieldIDOrDie(
183                 env, audioVolumeGroupClass, "mId", "I");
184 
185     env->DeleteLocalRef(audioVolumeGroupClass);
186 
187     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
188 }
189