diff options
author | Eric Laurent <elaurent@google.com> | 2014-12-01 19:36:30 -0800 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2014-12-08 09:37:30 -0800 |
commit | 7f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02 (patch) | |
tree | 9b9147714ecdbbb8acd6a2fe059d4b686ba39b55 | |
parent | 2ea3650d18ab0ce4dba2cee101d639400b411452 (diff) | |
download | frameworks_base-7f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02.zip frameworks_base-7f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02.tar.gz frameworks_base-7f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02.tar.bz2 |
AudioSystem JNI: Add audio policy custom mixes registration
Bug: 16009464.
Change-Id: I3763e79f4fa0331acb56d1d6f575c7a36e0bebd5
-rw-r--r-- | core/jni/android_media_AudioSystem.cpp | 199 | ||||
-rw-r--r-- | media/java/android/media/AudioService.java | 27 | ||||
-rw-r--r-- | media/java/android/media/AudioSystem.java | 3 |
3 files changed, 213 insertions, 16 deletions
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index cabe200..fee1ead 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -25,6 +25,7 @@ #include <android_runtime/AndroidRuntime.h> #include <media/AudioSystem.h> +#include <media/AudioPolicy.h> #include <system/audio.h> #include <system/audio_policy.h> @@ -40,6 +41,7 @@ static const char* const kClassPathName = "android/media/AudioSystem"; static jclass gArrayListClass; static struct { jmethodID add; + jmethodID toArray; } gArrayListMethods; static jclass gAudioHandleClass; @@ -102,6 +104,42 @@ static struct { // other fields unused by JNI } gAudioPatchFields; +static jclass gAudioMixClass; +static struct { + jfieldID mRule; + jfieldID mFormat; + jfieldID mRouteFlags; + jfieldID mRegistrationId; + jfieldID mMixType; +} gAudioMixFields; + +static jclass gAudioFormatClass; +static struct { + jfieldID mEncoding; + jfieldID mSampleRate; + jfieldID mChannelMask; + // other fields unused by JNI +} gAudioFormatFields; + +static jclass gAudioMixingRuleClass; +static struct { + jfieldID mCriteria; + // other fields unused by JNI +} gAudioMixingRuleFields; + +static jclass gAttributeMatchCriterionClass; +static struct { + jfieldID mAttr; + jfieldID mRule; +} gAttributeMatchCriterionFields; + +static jclass gAudioAttributesClass; +static struct { + jfieldID mUsage; + jfieldID mSource; +} gAudioAttributesFields; + + static const char* const kEventHandlerClassPathName = "android/media/AudioPortEventHandler"; static jmethodID gPostEventFromNative; @@ -1322,6 +1360,128 @@ android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, ji return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId); } + + + +static jint convertAudioMixToNative(JNIEnv *env, + AudioMix *nAudioMix, + const jobject jAudioMix) +{ + nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType); + nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags); + + jstring jRegistrationId = (jstring)env->GetObjectField(jAudioMix, + gAudioMixFields.mRegistrationId); + const char *nRegistrationId = env->GetStringUTFChars(jRegistrationId, NULL); + nAudioMix->mRegistrationId = String8(nRegistrationId); + env->ReleaseStringUTFChars(jRegistrationId, nRegistrationId); + env->DeleteLocalRef(jRegistrationId); + + jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat); + nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat, + gAudioFormatFields.mSampleRate); + nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat, + gAudioFormatFields.mChannelMask)); + nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat, + gAudioFormatFields.mEncoding)); + env->DeleteLocalRef(jFormat); + + jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule); + jobject jRuleCriteria = env->GetObjectField(jRule, gAudioMixingRuleFields.mCriteria); + env->DeleteLocalRef(jRule); + jobjectArray jCriteria = (jobjectArray)env->CallObjectMethod(jRuleCriteria, + gArrayListMethods.toArray); + env->DeleteLocalRef(jRuleCriteria); + + jint numCriteria = env->GetArrayLength(jCriteria); + if (numCriteria > MAX_CRITERIA_PER_MIX) { + numCriteria = MAX_CRITERIA_PER_MIX; + } + + for (jint i = 0; i < numCriteria; i++) { + AttributeMatchCriterion nCriterion; + + jobject jCriterion = env->GetObjectArrayElement(jCriteria, i); + + nCriterion.mRule = env->GetIntField(jCriterion, gAttributeMatchCriterionFields.mRule); + + jobject jAttributes = env->GetObjectField(jCriterion, gAttributeMatchCriterionFields.mAttr); + if (nCriterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE || + nCriterion.mRule == RULE_EXCLUDE_ATTRIBUTE_USAGE) { + nCriterion.mAttr.mUsage = (audio_usage_t)env->GetIntField(jAttributes, + gAudioAttributesFields.mUsage); + } else { + nCriterion.mAttr.mSource = (audio_source_t)env->GetIntField(jAttributes, + gAudioAttributesFields.mSource); + } + env->DeleteLocalRef(jAttributes); + + nAudioMix->mCriteria.add(nCriterion); + env->DeleteLocalRef(jCriterion); + } + + env->DeleteLocalRef(jCriteria); + + return (jint)AUDIO_JAVA_SUCCESS; +} + +static jint +android_media_AudioSystem_registerPolicyMixes(JNIEnv *env, jobject clazz, + jobject jMixesList, jboolean registration) +{ + ALOGV("registerPolicyMixes"); + + if (jMixesList == NULL) { + return (jint)AUDIO_JAVA_BAD_VALUE; + } + if (!env->IsInstanceOf(jMixesList, gArrayListClass)) { + return (jint)AUDIO_JAVA_BAD_VALUE; + } + jobjectArray jMixes = (jobjectArray)env->CallObjectMethod(jMixesList, + gArrayListMethods.toArray); + jint numMixes = env->GetArrayLength(jMixes); + if (numMixes > MAX_MIXES_PER_POLICY) { + numMixes = MAX_MIXES_PER_POLICY; + } + + status_t status; + jint jStatus; + jobject jAudioMix = NULL; + Vector <AudioMix> mixes; + for (jint i = 0; i < numMixes; i++) { + jAudioMix = env->GetObjectArrayElement(jMixes, i); + if (!env->IsInstanceOf(jAudioMix, gAudioMixClass)) { + jStatus = (jint)AUDIO_JAVA_BAD_VALUE; + goto exit; + } + AudioMix mix; + jStatus = convertAudioMixToNative(env, &mix, jAudioMix); + env->DeleteLocalRef(jAudioMix); + jAudioMix = NULL; + if (jStatus != AUDIO_JAVA_SUCCESS) { + goto exit; + } + mixes.add(mix); + } + + ALOGV("AudioSystem::registerPolicyMixes numMixes %d registration %d", numMixes, registration); + status = AudioSystem::registerPolicyMixes(mixes, registration); + ALOGV("AudioSystem::registerPolicyMixes() returned %d", status); + + jStatus = nativeToJavaStatus(status); + if (jStatus != AUDIO_JAVA_SUCCESS) { + goto exit; + } + +exit: + if (jAudioMix != NULL) { + env->DeleteLocalRef(jAudioMix); + } + return jStatus; +} + + + // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { @@ -1363,6 +1523,9 @@ static JNINativeMethod gMethods[] = { (void *)android_media_AudioSystem_setAudioPortConfig}, {"getAudioHwSyncForSession", "(I)I", (void *)android_media_AudioSystem_getAudioHwSyncForSession}, + {"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I", + (void *)android_media_AudioSystem_registerPolicyMixes}, + }; @@ -1381,6 +1544,7 @@ int register_android_media_AudioSystem(JNIEnv *env) jclass arrayListClass = env->FindClass("java/util/ArrayList"); gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass); gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z"); + gArrayListMethods.toArray = env->GetMethodID(arrayListClass, "toArray", "()[Ljava/lang/Object;"); jclass audioHandleClass = env->FindClass("android/media/AudioHandle"); gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass); @@ -1462,6 +1626,41 @@ int register_android_media_AudioSystem(JNIEnv *env) "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + jclass audioMixClass = env->FindClass("android/media/audiopolicy/AudioMix"); + gAudioMixClass = (jclass) env->NewGlobalRef(audioMixClass); + gAudioMixFields.mRule = env->GetFieldID(audioMixClass, "mRule", + "Landroid/media/audiopolicy/AudioMixingRule;"); + gAudioMixFields.mFormat = env->GetFieldID(audioMixClass, "mFormat", + "Landroid/media/AudioFormat;"); + gAudioMixFields.mRouteFlags = env->GetFieldID(audioMixClass, "mRouteFlags", "I"); + gAudioMixFields.mRegistrationId = env->GetFieldID(audioMixClass, "mRegistrationId", + "Ljava/lang/String;"); + gAudioMixFields.mMixType = env->GetFieldID(audioMixClass, "mMixType", "I"); + + jclass audioFormatClass = env->FindClass("android/media/AudioFormat"); + gAudioFormatClass = (jclass) env->NewGlobalRef(audioFormatClass); + gAudioFormatFields.mEncoding = env->GetFieldID(audioFormatClass, "mEncoding", "I"); + gAudioFormatFields.mSampleRate = env->GetFieldID(audioFormatClass, "mSampleRate", "I"); + gAudioFormatFields.mChannelMask = env->GetFieldID(audioFormatClass, "mChannelMask", "I"); + + jclass audioMixingRuleClass = env->FindClass("android/media/audiopolicy/AudioMixingRule"); + gAudioMixingRuleClass = (jclass) env->NewGlobalRef(audioMixingRuleClass); + gAudioMixingRuleFields.mCriteria = env->GetFieldID(audioMixingRuleClass, "mCriteria", + "Ljava/util/ArrayList;"); + + jclass attributeMatchCriterionClass = + env->FindClass("android/media/audiopolicy/AudioMixingRule$AttributeMatchCriterion"); + gAttributeMatchCriterionClass = (jclass) env->NewGlobalRef(attributeMatchCriterionClass); + gAttributeMatchCriterionFields.mAttr = env->GetFieldID(attributeMatchCriterionClass, "mAttr", + "Landroid/media/AudioAttributes;"); + gAttributeMatchCriterionFields.mRule = env->GetFieldID(attributeMatchCriterionClass, "mRule", + "I"); + + jclass audioAttributesClass = env->FindClass("android/media/AudioAttributes"); + gAudioAttributesClass = (jclass) env->NewGlobalRef(audioAttributesClass); + gAudioAttributesFields.mUsage = env->GetFieldID(audioAttributesClass, "mUsage", "I"); + gAudioAttributesFields.mSource = env->GetFieldID(audioAttributesClass, "mSource", "I"); + AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback); int status = AndroidRuntime::registerNativeMethods(env, diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 03ecad2..ebb7380 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -4298,6 +4298,13 @@ public class AudioService extends IAudioService.Stub { } } } + + synchronized (mAudioPolicies) { + for(AudioPolicyProxy policy : mAudioPolicies.values()) { + policy.connectMixes(); + } + } + // indicate the end of reconfiguration phase to audio HAL AudioSystem.setParameters("restarting=false"); break; @@ -5938,7 +5945,7 @@ public class AudioService extends IAudioService.Stub { if (mHasFocusListener) { mMediaFocusControl.addFocusFollower(mPolicyToken); } - updateMixes(AudioSystem.DEVICE_STATE_AVAILABLE); + connectMixes(); } public void binderDied() { @@ -5960,23 +5967,11 @@ public class AudioService extends IAudioService.Stub { if (mHasFocusListener) { mMediaFocusControl.removeFocusFollower(mPolicyToken); } - updateMixes(AudioSystem.DEVICE_STATE_UNAVAILABLE); + AudioSystem.registerPolicyMixes(mMixes, false); } - void updateMixes(int connectionState) { - for (AudioMix mix : mMixes) { - // TODO implement sending the mix attribute matching info to native audio policy - if (DEBUG_AP) { - Log.v(TAG, "AudioPolicyProxy mix new connection state=" + connectionState - + " addr=" + mix.getRegistration()); - } - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX, - connectionState, - mix.getRegistration()); - AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX, - connectionState, - mix.getRegistration()); - } + void connectMixes() { + AudioSystem.registerPolicyMixes(mMixes, true); } }; diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index e795fa7..46ab7e0 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -16,6 +16,7 @@ package android.media; +import android.media.audiopolicy.AudioMix; import java.util.ArrayList; /* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET @@ -566,5 +567,7 @@ public class AudioSystem public static final int AUDIO_HW_SYNC_INVALID = 0; public static native int getAudioHwSyncForSession(int sessionId); + + public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register); } |