am 3d42d238: am f764d219: Merge "AudioService receives callback for dynamic policy mix state changes" into mnc-dev
* commit '3d42d2380f5af53ce299610e27f40a8d88930c89': AudioService receives callback for dynamic policy mix state changes
This commit is contained in:
@@ -111,6 +111,7 @@ static struct {
|
|||||||
jfieldID mRouteFlags;
|
jfieldID mRouteFlags;
|
||||||
jfieldID mRegistrationId;
|
jfieldID mRegistrationId;
|
||||||
jfieldID mMixType;
|
jfieldID mMixType;
|
||||||
|
jfieldID mCallbackFlags;
|
||||||
} gAudioMixFields;
|
} gAudioMixFields;
|
||||||
|
|
||||||
static jclass gAudioFormatClass;
|
static jclass gAudioFormatClass;
|
||||||
@@ -149,6 +150,10 @@ static struct {
|
|||||||
jmethodID postEventFromNative;
|
jmethodID postEventFromNative;
|
||||||
} gAudioPortEventHandlerMethods;
|
} gAudioPortEventHandlerMethods;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
jmethodID postDynPolicyEventFromNative;
|
||||||
|
} gDynPolicyEventHandlerMethods;
|
||||||
|
|
||||||
static Mutex gLock;
|
static Mutex gLock;
|
||||||
|
|
||||||
enum AudioError {
|
enum AudioError {
|
||||||
@@ -166,7 +171,7 @@ enum {
|
|||||||
#define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
|
#define MAX_PORT_GENERATION_SYNC_ATTEMPTS 5
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// ref-counted object for callbacks
|
// ref-counted object for audio port callbacks
|
||||||
class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
|
class JNIAudioPortCallback: public AudioSystem::AudioPortCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -361,6 +366,26 @@ android_media_AudioSystem_error_callback(status_t err)
|
|||||||
env->DeleteLocalRef(clazz);
|
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
|
static jint
|
||||||
android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
|
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);
|
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,
|
static jint convertAudioMixToNative(JNIEnv *env,
|
||||||
@@ -1419,6 +1448,8 @@ static jint convertAudioMixToNative(JNIEnv *env,
|
|||||||
env->ReleaseStringUTFChars(jRegistrationId, nRegistrationId);
|
env->ReleaseStringUTFChars(jRegistrationId, nRegistrationId);
|
||||||
env->DeleteLocalRef(jRegistrationId);
|
env->DeleteLocalRef(jRegistrationId);
|
||||||
|
|
||||||
|
nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
|
||||||
|
|
||||||
jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
|
jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
|
||||||
nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
|
nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
|
||||||
gAudioFormatFields.mSampleRate);
|
gAudioFormatFields.mSampleRate);
|
||||||
@@ -1567,7 +1598,8 @@ static JNINativeMethod gMethods[] = {
|
|||||||
(void *)android_media_AudioSystem_getAudioHwSyncForSession},
|
(void *)android_media_AudioSystem_getAudioHwSyncForSession},
|
||||||
{"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
|
{"registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
|
||||||
(void *)android_media_AudioSystem_registerPolicyMixes},
|
(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,
|
gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
|
||||||
eventHandlerClass, "mJniCallback", "J");
|
eventHandlerClass, "mJniCallback", "J");
|
||||||
|
|
||||||
|
gDynPolicyEventHandlerMethods.postDynPolicyEventFromNative =
|
||||||
|
GetStaticMethodIDOrDie(env, env->FindClass(kClassPathName),
|
||||||
|
"dynamicPolicyCallbackFromNative", "(ILjava/lang/String;I)V");
|
||||||
|
|
||||||
jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
|
jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
|
||||||
gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
|
gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
|
||||||
gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
|
gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
|
||||||
@@ -1680,6 +1716,7 @@ int register_android_media_AudioSystem(JNIEnv *env)
|
|||||||
gAudioMixFields.mRegistrationId = GetFieldIDOrDie(env, audioMixClass, "mRegistrationId",
|
gAudioMixFields.mRegistrationId = GetFieldIDOrDie(env, audioMixClass, "mRegistrationId",
|
||||||
"Ljava/lang/String;");
|
"Ljava/lang/String;");
|
||||||
gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
|
gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
|
||||||
|
gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
|
||||||
|
|
||||||
jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
|
jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
|
||||||
gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
|
gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package android.media;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.media.audiopolicy.AudioMix;
|
import android.media.audiopolicy.AudioMix;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ import java.util.ArrayList;
|
|||||||
*/
|
*/
|
||||||
public class AudioSystem
|
public class AudioSystem
|
||||||
{
|
{
|
||||||
|
private static final String TAG = "AudioSystem";
|
||||||
/* These values must be kept in sync with system/audio.h */
|
/* These values must be kept in sync with system/audio.h */
|
||||||
/*
|
/*
|
||||||
* If these are modified, please also update Settings.System.VOLUME_SETTINGS
|
* 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 ...)
|
* Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
|
||||||
* Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h
|
* 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 listAudioPatches(ArrayList<AudioPatch> patches, int[] generation);
|
||||||
public static native int setAudioPortConfig(AudioPortConfig config);
|
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
|
// must be kept in sync with value in include/system/audio.h
|
||||||
public static final int AUDIO_HW_SYNC_INVALID = 0;
|
public static final int AUDIO_HW_SYNC_INVALID = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -36,20 +36,30 @@ public class AudioMix {
|
|||||||
private int mRouteFlags;
|
private int mRouteFlags;
|
||||||
private String mRegistrationId;
|
private String mRegistrationId;
|
||||||
private int mMixType = MIX_TYPE_INVALID;
|
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.
|
* 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;
|
mRule = rule;
|
||||||
mFormat = format;
|
mFormat = format;
|
||||||
mRouteFlags = routeFlags;
|
mRouteFlags = routeFlags;
|
||||||
mRegistrationId = null;
|
mRegistrationId = null;
|
||||||
mMixType = rule.getTargetMixType();
|
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
|
* 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.
|
* 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 AudioMixingRule mRule = null;
|
||||||
private AudioFormat mFormat = null;
|
private AudioFormat mFormat = null;
|
||||||
private int mRouteFlags = 0;
|
private int mRouteFlags = 0;
|
||||||
|
private int mCallbackFlags = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
@@ -198,6 +209,22 @@ public class AudioMix {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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.
|
* Sets the {@link AudioFormat} for the mix.
|
||||||
* @param format a non-null {@link AudioFormat} instance.
|
* @param format a non-null {@link AudioFormat} instance.
|
||||||
@@ -256,7 +283,7 @@ public class AudioMix {
|
|||||||
}
|
}
|
||||||
mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
|
mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
|
||||||
}
|
}
|
||||||
return new AudioMix(mRule, mFormat, mRouteFlags);
|
return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,6 +189,12 @@ public class AudioPolicy {
|
|||||||
|
|
||||||
@SystemApi
|
@SystemApi
|
||||||
public AudioPolicy build() {
|
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,
|
return new AudioPolicy(new AudioPolicyConfig(mMixes), mContext, mLooper,
|
||||||
mFocusListener, mStatusListener);
|
mFocusListener, mStatusListener);
|
||||||
}
|
}
|
||||||
@@ -432,6 +438,18 @@ public class AudioPolicy {
|
|||||||
+ afi.getClientId() + "wasNotified=" + wasNotified);
|
+ 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_POLICY_STATUS_CHANGE = 0;
|
||||||
private final static int MSG_FOCUS_GRANT = 1;
|
private final static int MSG_FOCUS_GRANT = 1;
|
||||||
private final static int MSG_FOCUS_LOSS = 2;
|
private final static int MSG_FOCUS_LOSS = 2;
|
||||||
|
private final static int MSG_MIX_STATE_UPDATE = 3;
|
||||||
|
|
||||||
private class EventHandler extends Handler {
|
private class EventHandler extends Handler {
|
||||||
public EventHandler(AudioPolicy ap, Looper looper) {
|
public EventHandler(AudioPolicy ap, Looper looper) {
|
||||||
@@ -464,6 +483,11 @@ public class AudioPolicy {
|
|||||||
(AudioFocusInfo) msg.obj, msg.arg1 != 0);
|
(AudioFocusInfo) msg.obj, msg.arg1 != 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MSG_MIX_STATE_UPDATE:
|
||||||
|
if (mStatusListener != null) {
|
||||||
|
mStatusListener.onMixStateUpdate((AudioMix) msg.obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Log.e(TAG, "Unknown event " + msg.what);
|
Log.e(TAG, "Unknown event " + msg.what);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ public class AudioPolicyConfig implements Parcelable {
|
|||||||
mMixes.add(mix);
|
mMixes.add(mix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ArrayList<AudioMix> getMixes() {
|
||||||
|
return mMixes;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(mMixes);
|
return Objects.hash(mMixes);
|
||||||
@@ -75,6 +79,8 @@ public class AudioPolicyConfig implements Parcelable {
|
|||||||
for (AudioMix mix : mMixes) {
|
for (AudioMix mix : mMixes) {
|
||||||
// write mix route flags
|
// write mix route flags
|
||||||
dest.writeInt(mix.getRouteFlags());
|
dest.writeInt(mix.getRouteFlags());
|
||||||
|
// write callback flags
|
||||||
|
dest.writeInt(mix.mCallbackFlags);
|
||||||
// write mix format
|
// write mix format
|
||||||
dest.writeInt(mix.getFormat().getSampleRate());
|
dest.writeInt(mix.getFormat().getSampleRate());
|
||||||
dest.writeInt(mix.getFormat().getEncoding());
|
dest.writeInt(mix.getFormat().getEncoding());
|
||||||
@@ -96,6 +102,8 @@ public class AudioPolicyConfig implements Parcelable {
|
|||||||
// read mix route flags
|
// read mix route flags
|
||||||
int routeFlags = in.readInt();
|
int routeFlags = in.readInt();
|
||||||
mixBuilder.setRouteFlags(routeFlags);
|
mixBuilder.setRouteFlags(routeFlags);
|
||||||
|
// read callback flags
|
||||||
|
mixBuilder.setCallbackFlags(in.readInt());
|
||||||
// read mix format
|
// read mix format
|
||||||
int sampleRate = in.readInt();
|
int sampleRate = in.readInt();
|
||||||
int encoding = in.readInt();
|
int encoding = in.readInt();
|
||||||
|
|||||||
@@ -25,4 +25,7 @@ oneway interface IAudioPolicyCallback {
|
|||||||
// callbacks for audio focus
|
// callbacks for audio focus
|
||||||
void notifyAudioFocusGrant(in AudioFocusInfo afi, int requestResult);
|
void notifyAudioFocusGrant(in AudioFocusInfo afi, int requestResult);
|
||||||
void notifyAudioFocusLoss(in AudioFocusInfo afi, boolean wasNotified);
|
void notifyAudioFocusLoss(in AudioFocusInfo afi, boolean wasNotified);
|
||||||
|
|
||||||
|
// callback for mix activity status update
|
||||||
|
void notifyMixStateUpdate(in String regId, int state);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import android.media.SoundPool;
|
|||||||
import android.media.VolumePolicy;
|
import android.media.VolumePolicy;
|
||||||
import android.media.MediaPlayer.OnCompletionListener;
|
import android.media.MediaPlayer.OnCompletionListener;
|
||||||
import android.media.MediaPlayer.OnErrorListener;
|
import android.media.MediaPlayer.OnErrorListener;
|
||||||
|
import android.media.audiopolicy.AudioMix;
|
||||||
import android.media.audiopolicy.AudioPolicy;
|
import android.media.audiopolicy.AudioPolicy;
|
||||||
import android.media.audiopolicy.AudioPolicyConfig;
|
import android.media.audiopolicy.AudioPolicyConfig;
|
||||||
import android.media.audiopolicy.IAudioPolicyCallback;
|
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_MUSIC_ACTIVE_MS = 22;
|
||||||
private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
|
private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
|
||||||
private static final int MSG_UNMUTE_STREAM = 24;
|
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
|
// start of messages handled under wakelock
|
||||||
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
|
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
|
||||||
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
|
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
|
||||||
@@ -4337,6 +4339,9 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
case MSG_UNMUTE_STREAM:
|
case MSG_UNMUTE_STREAM:
|
||||||
onUnmuteStream(msg.arg1, msg.arg2);
|
onUnmuteStream(msg.arg1, msg.arg2);
|
||||||
break;
|
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,
|
public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
|
||||||
boolean hasFocusListener) {
|
boolean hasFocusListener) {
|
||||||
|
AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
|
||||||
|
|
||||||
if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
|
if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
|
||||||
+ " with config:" + policyConfig);
|
+ " with config:" + policyConfig);
|
||||||
String regId = null;
|
String regId = null;
|
||||||
@@ -5852,6 +5859,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
|
// Audio policy proxy
|
||||||
//======================
|
//======================
|
||||||
@@ -5861,8 +5901,7 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
*/
|
*/
|
||||||
public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
|
public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
|
||||||
private static final String TAG = "AudioPolicyProxy";
|
private static final String TAG = "AudioPolicyProxy";
|
||||||
AudioPolicyConfig mConfig;
|
IAudioPolicyCallback mPolicyCallback;
|
||||||
IAudioPolicyCallback mPolicyToken;
|
|
||||||
boolean mHasFocusListener;
|
boolean mHasFocusListener;
|
||||||
/**
|
/**
|
||||||
* Audio focus ducking behavior for an audio policy.
|
* Audio focus ducking behavior for an audio policy.
|
||||||
@@ -5877,19 +5916,19 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
boolean hasFocusListener) {
|
boolean hasFocusListener) {
|
||||||
super(config);
|
super(config);
|
||||||
setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
|
setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
|
||||||
mPolicyToken = token;
|
mPolicyCallback = token;
|
||||||
mHasFocusListener = hasFocusListener;
|
mHasFocusListener = hasFocusListener;
|
||||||
if (mHasFocusListener) {
|
if (mHasFocusListener) {
|
||||||
mMediaFocusControl.addFocusFollower(mPolicyToken);
|
mMediaFocusControl.addFocusFollower(mPolicyCallback);
|
||||||
}
|
}
|
||||||
connectMixes();
|
connectMixes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void binderDied() {
|
public void binderDied() {
|
||||||
synchronized (mAudioPolicies) {
|
synchronized (mAudioPolicies) {
|
||||||
Log.i(TAG, "audio policy " + mPolicyToken + " died");
|
Log.i(TAG, "audio policy " + mPolicyCallback + " died");
|
||||||
release();
|
release();
|
||||||
mAudioPolicies.remove(mPolicyToken.asBinder());
|
mAudioPolicies.remove(mPolicyCallback.asBinder());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5902,7 +5941,7 @@ public class AudioService extends IAudioService.Stub {
|
|||||||
mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
|
mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
|
||||||
}
|
}
|
||||||
if (mHasFocusListener) {
|
if (mHasFocusListener) {
|
||||||
mMediaFocusControl.removeFocusFollower(mPolicyToken);
|
mMediaFocusControl.removeFocusFollower(mPolicyCallback);
|
||||||
}
|
}
|
||||||
AudioSystem.registerPolicyMixes(mMixes, false);
|
AudioSystem.registerPolicyMixes(mMixes, false);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user