| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| //#define LOG_NDEBUG 0 |
| |
| #define LOG_TAG "AudioVolumeGroups-JNI" |
| |
| #include <inttypes.h> |
| #include <jni.h> |
| #include <nativehelper/JNIHelp.h> |
| #include "core_jni_helpers.h" |
| |
| #include <utils/Log.h> |
| #include <vector> |
| |
| #include <media/AudioSystem.h> |
| #include <media/AudioPolicy.h> |
| |
| #include <nativehelper/ScopedUtfChars.h> |
| |
| #include "android_media_AudioAttributes.h" |
| #include "android_media_AudioErrors.h" |
| |
| // ---------------------------------------------------------------------------- |
| |
| using namespace android; |
| |
| // ---------------------------------------------------------------------------- |
| static const char* const kClassPathName = "android/media/audiopolicy/AudioVolumeGroup"; |
| static const char* const kAudioVolumeGroupClassPathName = |
| "android/media/audiopolicy/AudioVolumeGroup"; |
| |
| static jclass gAudioVolumeGroupClass; |
| static jmethodID gAudioVolumeGroupCstor; |
| static struct { |
| jfieldID mName; |
| jfieldID mId; |
| } gAudioVolumeGroupFields; |
| |
| static jclass gArrayListClass; |
| static jmethodID gArrayListCstor; |
| static struct { |
| jmethodID add; |
| jmethodID toArray; |
| } gArrayListMethods; |
| |
| |
| static jint convertAudioVolumeGroupsFromNative( |
| JNIEnv *env, jobject *jGroup, const AudioVolumeGroup &group) |
| { |
| jint jStatus = (jint)AUDIO_JAVA_SUCCESS; |
| jstring jName = NULL; |
| jint Id = NULL; |
| |
| jintArray jLegacyStreamTypes = NULL; |
| jobjectArray jAudioAttributes = NULL; |
| jint numAttributes; |
| jobject jAudioAttribute = NULL; |
| |
| jName = env->NewStringUTF(group.getName().c_str()); |
| Id = static_cast<jint>(group.getId()); |
| |
| // Legacy stream types array |
| jLegacyStreamTypes = env->NewIntArray(group.getStreamTypes().size()); |
| if (jLegacyStreamTypes == NULL) { |
| jStatus = (jint)AUDIO_JAVA_ERROR; |
| goto exit; |
| } |
| for (size_t streamIndex = 0; streamIndex < group.getStreamTypes().size(); streamIndex++) { |
| jint jStream = group.getStreamTypes()[streamIndex]; |
| env->SetIntArrayRegion(jLegacyStreamTypes, streamIndex, 1, &jStream); |
| } |
| |
| // Audio Attributes array |
| numAttributes = group.getAudioAttributes().size(); |
| jStatus = JNIAudioAttributeHelper::getJavaArray(env, &jAudioAttributes, numAttributes); |
| if (jStatus != (jint)AUDIO_JAVA_SUCCESS) { |
| goto exit; |
| } |
| |
| for (size_t j = 0; j < static_cast<size_t>(numAttributes); j++) { |
| auto attributes = group.getAudioAttributes()[j]; |
| |
| jStatus = JNIAudioAttributeHelper::nativeToJava(env, &jAudioAttribute, attributes); |
| if (jStatus != AUDIO_JAVA_SUCCESS) { |
| goto exit; |
| } |
| env->SetObjectArrayElement(jAudioAttributes, j, jAudioAttribute); |
| } |
| |
| *jGroup = env->NewObject(gAudioVolumeGroupClass, gAudioVolumeGroupCstor, |
| jName, Id, jAudioAttributes, jLegacyStreamTypes); |
| exit: |
| if (jName != NULL) { |
| env->DeleteLocalRef(jName); |
| } |
| return jStatus; |
| } |
| |
| static jint |
| android_media_AudioSystem_listAudioVolumeGroups(JNIEnv *env, jobject clazz, jobject jVolumeGroups) |
| { |
| if (env == NULL) { |
| return AUDIO_JAVA_DEAD_OBJECT; |
| } |
| if (jVolumeGroups == NULL) { |
| ALOGE("listAudioVolumeGroups NULL AudioVolumeGroups"); |
| return (jint)AUDIO_JAVA_BAD_VALUE; |
| } |
| if (!env->IsInstanceOf(jVolumeGroups, gArrayListClass)) { |
| ALOGE("listAudioVolumeGroups not an arraylist"); |
| return (jint)AUDIO_JAVA_BAD_VALUE; |
| } |
| |
| status_t status; |
| AudioVolumeGroupVector groups; |
| jint jStatus; |
| jobject jGroup = NULL; |
| |
| status = AudioSystem::listAudioVolumeGroups(groups); |
| if (status != NO_ERROR) { |
| ALOGE("AudioSystem::listAudioVolumeGroups error %d", status); |
| return nativeToJavaStatus(status); |
| } |
| for (const auto &group : groups) { |
| jStatus = convertAudioVolumeGroupsFromNative(env, &jGroup, group); |
| if (jStatus != AUDIO_JAVA_SUCCESS) { |
| goto exit; |
| } |
| env->CallBooleanMethod(jVolumeGroups, gArrayListMethods.add, jGroup); |
| } |
| exit: |
| if (jGroup != NULL) { |
| env->DeleteLocalRef(jGroup); |
| } |
| return jStatus; |
| } |
| |
| /* |
| * JNI registration. |
| */ |
| static const JNINativeMethod gMethods[] = { |
| {"native_list_audio_volume_groups", "(Ljava/util/ArrayList;)I", |
| (void *)android_media_AudioSystem_listAudioVolumeGroups}, |
| }; |
| |
| int register_android_media_AudioVolumeGroups(JNIEnv *env) |
| { |
| jclass arrayListClass = FindClassOrDie(env, "java/util/ArrayList"); |
| gArrayListClass = MakeGlobalRefOrDie(env, arrayListClass); |
| gArrayListCstor = GetMethodIDOrDie(env, arrayListClass, "<init>", "()V"); |
| gArrayListMethods.add = GetMethodIDOrDie(env, arrayListClass, "add", "(Ljava/lang/Object;)Z"); |
| gArrayListMethods.toArray = GetMethodIDOrDie(env, arrayListClass, |
| "toArray", "()[Ljava/lang/Object;"); |
| |
| jclass audioVolumeGroupClass = FindClassOrDie(env, kAudioVolumeGroupClassPathName); |
| gAudioVolumeGroupClass = MakeGlobalRefOrDie(env, audioVolumeGroupClass); |
| gAudioVolumeGroupCstor = GetMethodIDOrDie( |
| env, audioVolumeGroupClass, "<init>", |
| "(Ljava/lang/String;I[Landroid/media/AudioAttributes;[I)V"); |
| |
| gAudioVolumeGroupFields.mName = GetFieldIDOrDie( |
| env, audioVolumeGroupClass, "mName", "Ljava/lang/String;"); |
| gAudioVolumeGroupFields.mId = GetFieldIDOrDie( |
| env, audioVolumeGroupClass, "mId", "I"); |
| |
| env->DeleteLocalRef(audioVolumeGroupClass); |
| |
| return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); |
| } |