diff options
author | Jean-Michel Trivi <jmtrivi@google.com> | 2015-04-30 17:26:29 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-04-30 17:26:29 +0000 |
commit | e36846cbf1d1d2f349289ed4764875c3ee9087be (patch) | |
tree | 79e74c283c1831c7471b58508cfd36209e11fa48 | |
parent | 662f9df99e2f1fdda79da7eda43a13c52ff5b5d0 (diff) | |
parent | c8efc4490df6fb58bf333540cf746c68070345f5 (diff) | |
download | frameworks_base-e36846cbf1d1d2f349289ed4764875c3ee9087be.zip frameworks_base-e36846cbf1d1d2f349289ed4764875c3ee9087be.tar.gz frameworks_base-e36846cbf1d1d2f349289ed4764875c3ee9087be.tar.bz2 |
am c8efc449: am 3d42d238: am f764d219: Merge "AudioService receives callback for dynamic policy mix state changes" into mnc-dev
* commit 'c8efc4490df6fb58bf333540cf746c68070345f5':
AudioService receives callback for dynamic policy mix state changes
7 files changed, 199 insertions, 14 deletions
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index fc05a6d..3655adc 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -111,6 +111,7 @@ static struct { jfieldID mRouteFlags; jfieldID mRegistrationId; jfieldID mMixType; + jfieldID mCallbackFlags; } gAudioMixFields; static jclass gAudioFormatClass; @@ -149,6 +150,10 @@ static struct { jmethodID postEventFromNative; } gAudioPortEventHandlerMethods; +static struct { + jmethodID postDynPolicyEventFromNative; +} gDynPolicyEventHandlerMethods; + static Mutex gLock; enum AudioError { @@ -166,7 +171,7 @@ enum { #define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5 // ---------------------------------------------------------------------------- -// ref-counted object for callbacks +// ref-counted object for audio port callbacks class JNIAudioPortCallback: public AudioSystem::AudioPortCallback { public: @@ -361,6 +366,26 @@ android_media_AudioSystem_error_callback(status_t err) env->DeleteLocalRef(clazz); } +static void +android_media_AudioSystem_dyn_policy_callback(int event, String8 regId, int val) +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (env == NULL) { + return; + } + + jclass clazz = env->FindClass(kClassPathName); + const char* zechars = regId.string(); + jstring zestring = env->NewStringUTF(zechars); + + env->CallStaticVoidMethod(clazz, gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative, + event, zestring, val); + + env->ReleaseStringUTFChars(zestring, zechars); + env->DeleteLocalRef(clazz); + +} + static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name) { @@ -1402,7 +1427,11 @@ android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, ji return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId); } - +static void +android_media_AudioSystem_registerDynPolicyCallback(JNIEnv *env, jobject thiz) +{ + AudioSystem::setDynPolicyCallback(android_media_AudioSystem_dyn_policy_callback); +} static jint convertAudioMixToNative(JNIEnv *env, @@ -1419,6 +1448,8 @@ static jint convertAudioMixToNative(JNIEnv *env, env->ReleaseStringUTFChars(jRegistrationId, nRegistrationId); env->DeleteLocalRef(jRegistrationId); + nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags); + jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat); nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat, gAudioFormatFields.mSampleRate); @@ -1567,7 +1598,8 @@ static JNINativeMethod gMethods[] = { (void *)android_media_AudioSystem_getAudioHwSyncForSession}, {"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I", (void *)android_media_AudioSystem_registerPolicyMixes}, - + {"native_register_dynamic_policy_callback", "()V", + (void *)android_media_AudioSystem_registerDynPolicyCallback}, }; @@ -1670,6 +1702,10 @@ int register_android_media_AudioSystem(JNIEnv *env) gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env, eventHandlerClass, "mJniCallback", "J"); + gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative = + GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName), + "dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V"); + jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix"); gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass); gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule", @@ -1680,6 +1716,7 @@ int register_android_media_AudioSystem(JNIEnv *env) gAudioMixFields.mRegistrationId = GetFieldIDOrDie(env, audioMixClass, "mRegistrationId", "Ljava/lang/String;"); gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I"); + gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I"); jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat"); gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass); diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 25e6594..3dae543 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -19,6 +19,7 @@ package android.media; import android.content.Context; import android.content.pm.PackageManager; import android.media.audiopolicy.AudioMix; +import android.util.Log; import java.util.ArrayList; @@ -32,6 +33,7 @@ import java.util.ArrayList; */ public class AudioSystem { + private static final String TAG = "AudioSystem"; /* These values must be kept in sync with system/audio.h */ /* * If these are modified, please also update Settings.System.VOLUME_SETTINGS @@ -224,6 +226,48 @@ public class AudioSystem } } + /** + * Handles events for the audio policy manager about dynamic audio policies + * @see android.media.audiopolicy.AudioPolicy + */ + public interface DynamicPolicyCallback + { + void onDynamicPolicyMixStateUpdate(String regId, int state); + } + + //keep in sync with include/media/AudioPolicy.h + private final static int DYNAMIC_POLICY_EVENT_MIX_STATE_UPDATE = 0; + + private static DynamicPolicyCallback sDynPolicyCallback; + + public static void setDynamicPolicyCallback(DynamicPolicyCallback cb) + { + synchronized (AudioSystem.class) { + sDynPolicyCallback = cb; + native_register_dynamic_policy_callback(); + } + } + + private static void dynamicPolicyCallbackFromNative(int event, String regId, int val) + { + DynamicPolicyCallback cb = null; + synchronized (AudioSystem.class) { + if (sDynPolicyCallback != null) { + cb = sDynPolicyCallback; + } + } + if (cb != null) { + switch(event) { + case DYNAMIC_POLICY_EVENT_MIX_STATE_UPDATE: + cb.onDynamicPolicyMixStateUpdate(regId, val); + break; + default: + Log.e(TAG, "dynamicPolicyCallbackFromNative: unknown event " + event); + } + } + } + + /* * Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...) * Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h @@ -580,6 +624,9 @@ public class AudioSystem public static native int listAudioPatches(ArrayList<AudioPatch> patches, int[] generation); public static native int setAudioPortConfig(AudioPortConfig config); + // declare this instance as having a dynamic policy callback handler + private static native final void native_register_dynamic_policy_callback(); + // must be kept in sync with value in include/system/audio.h public static final int AUDIO_HW_SYNC_INVALID = 0; diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java index 6aa4d8a..4ffac6d 100644 --- a/media/java/android/media/audiopolicy/AudioMix.java +++ b/media/java/android/media/audiopolicy/AudioMix.java @@ -36,20 +36,30 @@ public class AudioMix { private int mRouteFlags; private String mRegistrationId; private int mMixType = MIX_TYPE_INVALID; - private int mMixState = MIX_STATE_DISABLED; + int mMixState = MIX_STATE_DISABLED; + int mCallbackFlags; /** * All parameters are guaranteed valid through the Builder. */ - private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags) { + private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags) { mRule = rule; mFormat = format; mRouteFlags = routeFlags; mRegistrationId = null; mMixType = rule.getTargetMixType(); + mCallbackFlags = callbackFlags; } - // ROUTE_FLAG_* values to keep in sync with frameworks/av/include/media/AudioPolicy.h + // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined + // in frameworks/av/include/media/AudioPolicy.h + /** @hide */ + public final static int CALLBACK_FLAG_NOTIFY_ACTIVITY = 0x1; + // when adding new MIX_FLAG_* flags, add them to this mask of authorized masks: + private final static int CALLBACK_FLAGS_ALL = CALLBACK_FLAG_NOTIFY_ACTIVITY; + + // ROUTE_FLAG_* values: keep in sync with MIX_ROUTE_FLAG_* values defined + // in frameworks/av/include/media/AudioPolicy.h /** * An audio mix behavior where the output of the mix is sent to the original destination of * the audio signal, i.e. an output device for an output mix, or a recording for an input mix. @@ -161,6 +171,7 @@ public class AudioMix { private AudioMixingRule mRule = null; private AudioFormat mFormat = null; private int mRouteFlags = 0; + private int mCallbackFlags = 0; /** * @hide @@ -199,6 +210,22 @@ public class AudioMix { } /** + * @hide + * Only used by AudioPolicyConfig, not a public API. + * @param callbackFlags which callbacks are called from native + * @return the same Builder instance. + * @throws IllegalArgumentException + */ + public Builder setCallbackFlags(int flags) throws IllegalArgumentException { + if ((flags != 0) && ((flags & CALLBACK_FLAGS_ALL) == 0)) { + throw new IllegalArgumentException("Illegal callback flags 0x" + + Integer.toHexString(flags).toUpperCase()); + } + mCallbackFlags = flags; + return this; + } + + /** * Sets the {@link AudioFormat} for the mix. * @param format a non-null {@link AudioFormat} instance. * @return the same Builder instance. @@ -256,7 +283,7 @@ public class AudioMix { } mFormat = new AudioFormat.Builder().setSampleRate(rate).build(); } - return new AudioMix(mRule, mFormat, mRouteFlags); + return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags); } } } diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java index f128044..423b467 100644 --- a/media/java/android/media/audiopolicy/AudioPolicy.java +++ b/media/java/android/media/audiopolicy/AudioPolicy.java @@ -189,6 +189,12 @@ public class AudioPolicy { @SystemApi public AudioPolicy build() { + if (mStatusListener != null) { + // the AudioPolicy status listener includes updates on each mix activity state + for (AudioMix mix : mMixes) { + mix.mCallbackFlags |= AudioMix.CALLBACK_FLAG_NOTIFY_ACTIVITY; + } + } return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper, mFocusListener, mStatusListener); } @@ -432,6 +438,18 @@ public class AudioPolicy { + afi.getClientId() + "wasNotified=" + wasNotified); } } + + public void notifyMixStateUpdate(String regId, int state) { + for (AudioMix mix : mConfig.getMixes()) { + if (mix.getRegistration().equals(regId)) { + mix.mMixState = state; + sendMsg(MSG_MIX_STATE_UPDATE, mix, 0/*ignored*/); + if (DEBUG) { + Log.v(TAG, "notifyMixStateUpdate: regId=" + regId + " state=" + state); + } + } + } + } }; //================================================== @@ -440,6 +458,7 @@ public class AudioPolicy { private final static int MSG_POLICY_STATUS_CHANGE = 0; private final static int MSG_FOCUS_GRANT = 1; private final static int MSG_FOCUS_LOSS = 2; + private final static int MSG_MIX_STATE_UPDATE = 3; private class EventHandler extends Handler { public EventHandler(AudioPolicy ap, Looper looper) { @@ -464,6 +483,11 @@ public class AudioPolicy { (AudioFocusInfo) msg.obj, msg.arg1 != 0); } break; + case MSG_MIX_STATE_UPDATE: + if (mStatusListener != null) { + mStatusListener.onMixStateUpdate((AudioMix) msg.obj); + } + break; default: Log.e(TAG, "Unknown event " + msg.what); } diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java index 917e07b..252f5f4 100644 --- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java +++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java @@ -59,6 +59,10 @@ public class AudioPolicyConfig implements Parcelable { mMixes.add(mix); } + public ArrayList<AudioMix> getMixes() { + return mMixes; + } + @Override public int hashCode() { return Objects.hash(mMixes); @@ -75,6 +79,8 @@ public class AudioPolicyConfig implements Parcelable { for (AudioMix mix : mMixes) { // write mix route flags dest.writeInt(mix.getRouteFlags()); + // write callback flags + dest.writeInt(mix.mCallbackFlags); // write mix format dest.writeInt(mix.getFormat().getSampleRate()); dest.writeInt(mix.getFormat().getEncoding()); @@ -96,6 +102,8 @@ public class AudioPolicyConfig implements Parcelable { // read mix route flags int routeFlags = in.readInt(); mixBuilder.setRouteFlags(routeFlags); + // read callback flags + mixBuilder.setCallbackFlags(in.readInt()); // read mix format int sampleRate = in.readInt(); int encoding = in.readInt(); diff --git a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl index c777c58..ad8af15 100644 --- a/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl +++ b/media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl @@ -25,4 +25,7 @@ oneway interface IAudioPolicyCallback { // callbacks for audio focus void notifyAudioFocusGrant(in AudioFocusInfo afi, int requestResult); void notifyAudioFocusLoss(in AudioFocusInfo afi, boolean wasNotified); + + // callback for mix activity status update + void notifyMixStateUpdate(in String regId, int state); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index eb28ed0..06fba34 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -65,6 +65,7 @@ import android.media.SoundPool; import android.media.VolumePolicy; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaPlayer.OnErrorListener; +import android.media.audiopolicy.AudioMix; import android.media.audiopolicy.AudioPolicy; import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.IAudioPolicyCallback; @@ -206,6 +207,7 @@ public class AudioService extends IAudioService.Stub { private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22; private static final int MSG_PERSIST_MICROPHONE_MUTE = 23; private static final int MSG_UNMUTE_STREAM = 24; + private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) @@ -4337,6 +4339,9 @@ public class AudioService extends IAudioService.Stub { case MSG_UNMUTE_STREAM: onUnmuteStream(msg.arg1, msg.arg2); break; + case MSG_DYN_POLICY_MIX_STATE_UPDATE: + onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1); + break; } } } @@ -5758,6 +5763,8 @@ public class AudioService extends IAudioService.Stub { //========================================================================================== public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb, boolean hasFocusListener) { + AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback); + if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder() + " with config:" + policyConfig); String regId = null; @@ -5853,6 +5860,39 @@ public class AudioService extends IAudioService.Stub { } //====================== + // Audio policy callback from AudioSystem + //====================== + private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback = + new AudioSystem.DynamicPolicyCallback() { + public void onDynamicPolicyMixStateUpdate(String regId, int state) { + if (!TextUtils.isEmpty(regId)) { + sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE, + state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/); + } + } + }; + + private void onDynPolicyMixStateUpdate(String regId, int state) { + if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")"); + synchronized (mAudioPolicies) { + for (AudioPolicyProxy policy : mAudioPolicies.values()) { + for (AudioMix mix : policy.getMixes()) { + if (mix.getRegistration().equals(regId)) { + try { + policy.mPolicyCallback.notifyMixStateUpdate(regId, state); + } catch (RemoteException e) { + Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback " + + policy.mPolicyCallback.asBinder(), e); + } + return; + } + } + } + } + + } + + //====================== // Audio policy proxy //====================== /** @@ -5861,8 +5901,7 @@ public class AudioService extends IAudioService.Stub { */ public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient { private static final String TAG = "AudioPolicyProxy"; - AudioPolicyConfig mConfig; - IAudioPolicyCallback mPolicyToken; + IAudioPolicyCallback mPolicyCallback; boolean mHasFocusListener; /** * Audio focus ducking behavior for an audio policy. @@ -5877,19 +5916,19 @@ public class AudioService extends IAudioService.Stub { boolean hasFocusListener) { super(config); setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++)); - mPolicyToken = token; + mPolicyCallback = token; mHasFocusListener = hasFocusListener; if (mHasFocusListener) { - mMediaFocusControl.addFocusFollower(mPolicyToken); + mMediaFocusControl.addFocusFollower(mPolicyCallback); } connectMixes(); } public void binderDied() { synchronized (mAudioPolicies) { - Log.i(TAG, "audio policy " + mPolicyToken + " died"); + Log.i(TAG, "audio policy " + mPolicyCallback + " died"); release(); - mAudioPolicies.remove(mPolicyToken.asBinder()); + mAudioPolicies.remove(mPolicyCallback.asBinder()); } } @@ -5902,7 +5941,7 @@ public class AudioService extends IAudioService.Stub { mMediaFocusControl.setDuckingInExtPolicyAvailable(false); } if (mHasFocusListener) { - mMediaFocusControl.removeFocusFollower(mPolicyToken); + mMediaFocusControl.removeFocusFollower(mPolicyCallback); } AudioSystem.registerPolicyMixes(mMixes, false); } |