Merge "AudioSystem JNI: Add audio policy custom mixes registration" into lmp-mr1-dev
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
#include <android_runtime/AndroidRuntime.h>
|
#include <android_runtime/AndroidRuntime.h>
|
||||||
|
|
||||||
#include <media/AudioSystem.h>
|
#include <media/AudioSystem.h>
|
||||||
|
#include <media/AudioPolicy.h>
|
||||||
|
|
||||||
#include <system/audio.h>
|
#include <system/audio.h>
|
||||||
#include <system/audio_policy.h>
|
#include <system/audio_policy.h>
|
||||||
@@ -40,6 +41,7 @@ static const char* const kClassPathName = "android/media/AudioSystem";
|
|||||||
static jclass gArrayListClass;
|
static jclass gArrayListClass;
|
||||||
static struct {
|
static struct {
|
||||||
jmethodID add;
|
jmethodID add;
|
||||||
|
jmethodID toArray;
|
||||||
} gArrayListMethods;
|
} gArrayListMethods;
|
||||||
|
|
||||||
static jclass gAudioHandleClass;
|
static jclass gAudioHandleClass;
|
||||||
@@ -102,6 +104,42 @@ static struct {
|
|||||||
// other fields unused by JNI
|
// other fields unused by JNI
|
||||||
} gAudioPatchFields;
|
} 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 =
|
static const char* const kEventHandlerClassPathName =
|
||||||
"android/media/AudioPortEventHandler";
|
"android/media/AudioPortEventHandler";
|
||||||
static jmethodID gPostEventFromNative;
|
static jmethodID gPostEventFromNative;
|
||||||
@@ -1322,6 +1360,128 @@ android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, ji
|
|||||||
return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId);
|
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[] = {
|
static JNINativeMethod gMethods[] = {
|
||||||
@@ -1363,6 +1523,9 @@ static JNINativeMethod gMethods[] = {
|
|||||||
(void *)android_media_AudioSystem_setAudioPortConfig},
|
(void *)android_media_AudioSystem_setAudioPortConfig},
|
||||||
{"getAudioHwSyncForSession", "(I)I",
|
{"getAudioHwSyncForSession", "(I)I",
|
||||||
(void *)android_media_AudioSystem_getAudioHwSyncForSession},
|
(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");
|
jclass arrayListClass = env->FindClass("java/util/ArrayList");
|
||||||
gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
|
gArrayListClass = (jclass) env->NewGlobalRef(arrayListClass);
|
||||||
gArrayListMethods.add = env->GetMethodID(arrayListClass, "add", "(Ljava/lang/Object;)Z");
|
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");
|
jclass audioHandleClass = env->FindClass("android/media/AudioHandle");
|
||||||
gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass);
|
gAudioHandleClass = (jclass) env->NewGlobalRef(audioHandleClass);
|
||||||
@@ -1462,6 +1626,41 @@ int register_android_media_AudioSystem(JNIEnv *env)
|
|||||||
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
|
"(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);
|
AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
|
||||||
|
|
||||||
int status = AndroidRuntime::registerNativeMethods(env,
|
int status = AndroidRuntime::registerNativeMethods(env,
|
||||||
|
|||||||
@@ -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
|
// indicate the end of reconfiguration phase to audio HAL
|
||||||
AudioSystem.setParameters("restarting=false");
|
AudioSystem.setParameters("restarting=false");
|
||||||
break;
|
break;
|
||||||
@@ -5939,7 +5946,7 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
if (mHasFocusListener) {
|
if (mHasFocusListener) {
|
||||||
mMediaFocusControl.addFocusFollower(mPolicyToken);
|
mMediaFocusControl.addFocusFollower(mPolicyToken);
|
||||||
}
|
}
|
||||||
updateMixes(AudioSystem.DEVICE_STATE_AVAILABLE);
|
connectMixes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
@@ -5961,23 +5968,11 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
if (mHasFocusListener) {
|
if (mHasFocusListener) {
|
||||||
mMediaFocusControl.removeFocusFollower(mPolicyToken);
|
mMediaFocusControl.removeFocusFollower(mPolicyToken);
|
||||||
}
|
}
|
||||||
updateMixes(AudioSystem.DEVICE_STATE_UNAVAILABLE);
|
AudioSystem.registerPolicyMixes(mMixes, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateMixes(int connectionState) {
|
void connectMixes() {
|
||||||
for (AudioMix mix : mMixes) {
|
AudioSystem.registerPolicyMixes(mMixes, true);
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package android.media;
|
package android.media;
|
||||||
|
|
||||||
|
import android.media.audiopolicy.AudioMix;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET
|
/* 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 final int AUDIO_HW_SYNC_INVALID = 0;
|
||||||
|
|
||||||
public static native int getAudioHwSyncForSession(int sessionId);
|
public static native int getAudioHwSyncForSession(int sessionId);
|
||||||
|
|
||||||
|
public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user