Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f764d219 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi Committed by Android (Google) Code Review
Browse files

Merge "AudioService receives callback for dynamic policy mix state changes" into mnc-dev

parents ed375f26 5a56109d
Loading
Loading
Loading
Loading
+40 −3
Original line number Diff line number Diff line
@@ -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);
+47 −0
Original line number Diff line number Diff line
@@ -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;

+31 −4
Original line number Diff line number Diff line
@@ -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
@@ -198,6 +209,22 @@ public class AudioMix {
            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.
         * @param format a non-null {@link AudioFormat} 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);
        }
    }
}
+24 −0
Original line number Diff line number Diff line
@@ -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);
            }
+8 −0
Original line number Diff line number Diff line
@@ -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();
Loading