Merge "AudioSystem JNI: Add audio policy custom mixes registration" into lmp-mr1-dev

This commit is contained in:
Eric Laurent
2014-12-10 01:33:07 +00:00
committed by Android (Google) Code Review
3 changed files with 213 additions and 16 deletions

View File

@@ -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,

View File

@@ -4299,6 +4299,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;
@@ -5939,7 +5946,7 @@ public class AudioService extends IAudioService.Stub {
if (mHasFocusListener) {
mMediaFocusControl.addFocusFollower(mPolicyToken);
}
updateMixes(AudioSystem.DEVICE_STATE_AVAILABLE);
connectMixes();
}
public void binderDied() {
@@ -5961,23 +5968,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);
}
};

View File

@@ -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);
}