summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2014-12-01 19:36:30 -0800
committerEric Laurent <elaurent@google.com>2014-12-08 09:37:30 -0800
commit7f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02 (patch)
tree9b9147714ecdbbb8acd6a2fe059d4b686ba39b55
parent2ea3650d18ab0ce4dba2cee101d639400b411452 (diff)
downloadframeworks_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.cpp199
-rw-r--r--media/java/android/media/AudioService.java27
-rw-r--r--media/java/android/media/AudioSystem.java3
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);
}