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

Commit 0eb290d6 authored by Marvin Ramin's avatar Marvin Ramin Committed by Android (Google) Code Review
Browse files

Merge "Improve ownership model of AudioMixes in AudioPolicies" into main

parents 3eb4fe9f 70850403
Loading
Loading
Loading
Loading
+27 −11
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
//#define LOG_NDEBUG 0

#define LOG_TAG "AudioSystem-JNI"
#include <android/binder_ibinder_jni.h>
#include <android/binder_libbinder.h>
#include <android/media/AudioVibratorInfo.h>
#include <android/media/INativeSpatializerCallback.h>
#include <android/media/ISpatializer.h>
@@ -25,6 +27,7 @@
#include <android_media_audiopolicy.h>
#include <android_os_Parcel.h>
#include <audiomanager/AudioManager.h>
#include <binder/IBinder.h>
#include <jni.h>
#include <media/AidlConversion.h>
#include <media/AudioContainers.h>
@@ -157,6 +160,7 @@ static struct {
    jfieldID mDeviceAddress;
    jfieldID mMixType;
    jfieldID mCallbackFlags;
    jfieldID mToken;
} gAudioMixFields;

static jclass gAudioFormatClass;
@@ -2300,11 +2304,15 @@ static jint convertAudioMixFromNative(JNIEnv *env, jobject *jAudioMix, const Aud
    if (status != AUDIO_JAVA_SUCCESS) {
        return status;
    }
    std::unique_ptr<AIBinder, decltype(&AIBinder_decStrong)> aiBinder(AIBinder_fromPlatformBinder(
                                                                              nAudioMix.mToken),
                                                                      &AIBinder_decStrong);
    jobject jBinderToken = AIBinder_toJavaBinder(env, aiBinder.get());

    jstring deviceAddress = env->NewStringUTF(nAudioMix.mDeviceAddress.c_str());
    *jAudioMix = env->NewObject(gAudioMixClass, gAudioMixCstor, jAudioMixingRule, jAudioFormat,
                                nAudioMix.mRouteFlags, nAudioMix.mCbFlags, nAudioMix.mDeviceType,
                                deviceAddress);
                                deviceAddress, jBinderToken);
    return AUDIO_JAVA_SUCCESS;
}

@@ -2333,6 +2341,12 @@ static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, const jobj
    nAudioMix->mVoiceCommunicationCaptureAllowed =
            env->GetBooleanField(jRule, gAudioMixingRuleFields.mVoiceCommunicationCaptureAllowed);

    jobject jToken = env->GetObjectField(jAudioMix, gAudioMixFields.mToken);

    std::unique_ptr<AIBinder, decltype(&AIBinder_decStrong)>
            aiBinder(AIBinder_fromJavaBinder(env, jToken), &AIBinder_decStrong);
    nAudioMix->mToken = AIBinder_toPlatformBinder(aiBinder.get());

    jint status = convertAudioMixingRuleToNative(env, jRule, &(nAudioMix->mCriteria));

    env->DeleteLocalRef(jRule);
@@ -3659,9 +3673,10 @@ int register_android_media_AudioSystem(JNIEnv *env)
    jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
    gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
    if (audio_flags::audio_mix_test_api()) {
        gAudioMixCstor = GetMethodIDOrDie(env, audioMixClass, "<init>",
        gAudioMixCstor =
                GetMethodIDOrDie(env, audioMixClass, "<init>",
                                 "(Landroid/media/audiopolicy/AudioMixingRule;Landroid/"
                                          "media/AudioFormat;IIILjava/lang/String;)V");
                                 "media/AudioFormat;IIILjava/lang/String;Landroid/os/IBinder;)V");
    }
    gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
                                                "Landroid/media/audiopolicy/AudioMixingRule;");
@@ -3673,6 +3688,7 @@ int register_android_media_AudioSystem(JNIEnv *env)
                                                      "Ljava/lang/String;");
    gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
    gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
    gAudioMixFields.mToken = GetFieldIDOrDie(env, audioMixClass, "mToken", "Landroid/os/IBinder;");

    jclass audioFormatClass = FindClassOrDie(env, "android/media/AudioFormat");
    gAudioFormatClass = MakeGlobalRefOrDie(env, audioFormatClass);
+27 −4
Original line number Diff line number Diff line
@@ -27,7 +27,9 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
import android.media.AudioSystem;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;

@@ -52,6 +54,8 @@ public class AudioMix implements Parcelable {
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private int mMixType = MIX_TYPE_INVALID;

    private final IBinder mToken;

    // written by AudioPolicy
    int mMixState = MIX_STATE_DISABLED;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -68,7 +72,7 @@ public class AudioMix implements Parcelable {
     */
    private AudioMix(@NonNull AudioMixingRule rule, @NonNull AudioFormat format,
            int routeFlags, int callbackFlags,
            int deviceType, @Nullable String deviceAddress) {
            int deviceType, @Nullable String deviceAddress, IBinder token) {
        mRule = Objects.requireNonNull(rule);
        mFormat = Objects.requireNonNull(format);
        mRouteFlags = routeFlags;
@@ -76,6 +80,7 @@ public class AudioMix implements Parcelable {
        mCallbackFlags = callbackFlags;
        mDeviceSystemType = deviceType;
        mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress;
        mToken = token;
    }

    // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
@@ -273,13 +278,14 @@ public class AudioMix implements Parcelable {
        return Objects.equals(this.mRouteFlags, that.mRouteFlags)
            && Objects.equals(this.mRule, that.mRule)
            && Objects.equals(this.mMixType, that.mMixType)
            && Objects.equals(this.mFormat, that.mFormat);
            && Objects.equals(this.mFormat, that.mFormat)
            && Objects.equals(this.mToken, that.mToken);
    }

    /** @hide */
    @Override
    public int hashCode() {
        return Objects.hash(mRouteFlags, mRule, mMixType, mFormat);
        return Objects.hash(mRouteFlags, mRule, mMixType, mFormat, mToken);
    }

    @Override
@@ -298,6 +304,7 @@ public class AudioMix implements Parcelable {
        dest.writeString8(mDeviceAddress);
        mFormat.writeToParcel(dest, flags);
        mRule.writeToParcel(dest, flags);
        dest.writeStrongBinder(mToken);
    }

    public static final @NonNull Parcelable.Creator<AudioMix> CREATOR = new Parcelable.Creator<>() {
@@ -317,6 +324,7 @@ public class AudioMix implements Parcelable {
            mixBuilder.setDevice(p.readInt(), p.readString8());
            mixBuilder.setFormat(AudioFormat.CREATOR.createFromParcel(p));
            mixBuilder.setMixingRule(AudioMixingRule.CREATOR.createFromParcel(p));
            mixBuilder.setToken(p.readStrongBinder());
            return mixBuilder.build();
        }

@@ -339,6 +347,7 @@ public class AudioMix implements Parcelable {
        private AudioFormat mFormat = null;
        private int mRouteFlags = 0;
        private int mCallbackFlags = 0;
        private IBinder mToken = null;
        // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
        private int mDeviceSystemType = AudioSystem.DEVICE_NONE;
        private String mDeviceAddress = null;
@@ -378,6 +387,15 @@ public class AudioMix implements Parcelable {
            return this;
        }

        /**
         * @hide
         * Only used by AudioMix internally.
         */
        Builder setToken(IBinder token) {
            mToken = token;
            return this;
        }

        /**
         * @hide
         * Only used by AudioPolicyConfig, not a public API.
@@ -540,8 +558,13 @@ public class AudioMix implements Parcelable {
                    throw new IllegalArgumentException(error);
                }
            }

            if (mToken == null) {
                mToken = new Binder();
            }

            return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceSystemType,
                    mDeviceAddress);
                    mDeviceAddress, mToken);
        }

        private int getLoopbackDeviceSystemTypeForAudioMixingRule(AudioMixingRule rule) {
+10 −6
Original line number Diff line number Diff line
@@ -337,7 +337,9 @@ public class AudioPolicy {

    /**
     * Update the current configuration of the set of audio mixes by adding new ones, while
     * keeping the policy registered.
     * keeping the policy registered. If any of the provided audio mixes is invalid then none of
     * the passed mixes will be registered.
     *
     * This method can only be called on a registered policy.
     * @param mixes the list of {@link AudioMix} to add
     * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
@@ -375,12 +377,15 @@ public class AudioPolicy {
    }

    /**
     * Update the current configuration of the set of audio mixes by removing some, while
     * keeping the policy registered.
     * This method can only be called on a registered policy.
     * Update the current configuration of the set of audio mixes for this audio policy by
     * removing some, while keeping the policy registered. Will unregister all provided audio
     * mixes, if possible.
     *
     * This method can only be called on a registered policy and only affects this current policy.
     * @param mixes the list of {@link AudioMix} to remove
     * @return {@link AudioManager#SUCCESS} if the change was successful, {@link AudioManager#ERROR}
     *    otherwise.
     *    otherwise. If only some of the provided audio mixes were detached but any one mix
     *    failed to be detached, this method returns {@link AudioManager#ERROR}.
     */
    public int detachMixes(@NonNull List<AudioMix> mixes) {
        if (mixes == null) {
@@ -394,7 +399,6 @@ public class AudioPolicy {
            for (AudioMix mix : mixes) {
                if (mix == null) {
                    throw new IllegalArgumentException("Illegal null AudioMix in detachMixes");
                    // TODO also check mix is currently contained in list of mixes
                } else {
                    zeMixes.add(mix);
                }
+4 −2
Original line number Diff line number Diff line
@@ -228,7 +228,7 @@ public class AudioPolicyConfig implements Parcelable {
        }
    }

    private void setMixRegistration(@NonNull final AudioMix mix) {
    protected void setMixRegistration(@NonNull final AudioMix mix) {
        if (!mRegistrationId.isEmpty()) {
            if ((mix.getRouteFlags() & AudioMix.ROUTE_FLAG_LOOP_BACK) ==
                    AudioMix.ROUTE_FLAG_LOOP_BACK) {
@@ -246,7 +246,9 @@ public class AudioPolicyConfig implements Parcelable {
    @GuardedBy("mMixes")
    protected void add(@NonNull ArrayList<AudioMix> mixes) {
        for (AudioMix mix : mixes) {
            if (mix.getRegistration() == null || mix.getRegistration().isEmpty()) {
                setMixRegistration(mix);
            }
            mMixes.add(mix);
        }
    }
+28 −1
Original line number Diff line number Diff line
@@ -12528,6 +12528,16 @@ public class AudioService extends IAudioService.Stub
            if (app == null) {
                return AudioManager.ERROR;
            }
            if (android.media.audiopolicy.Flags.audioMixOwnership()) {
                for (AudioMix mix : policyConfig.getMixes()) {
                    if (!app.getMixes().contains(mix)) {
                        Slog.e(TAG,
                                "removeMixForPolicy attempted to unregister AudioMix(es) not "
                                        + "belonging to the AudioPolicy");
                        return AudioManager.ERROR;
                    }
                }
            }
            return app.removeMixes(policyConfig.getMixes()) == AudioSystem.SUCCESS
                ? AudioManager.SUCCESS : AudioManager.ERROR;
        }
@@ -13306,7 +13316,13 @@ public class AudioService extends IAudioService.Stub
            }
            final long identity = Binder.clearCallingIdentity();
            try {
                if (android.media.audiopolicy.Flags.audioMixOwnership()) {
                    synchronized (mMixes) {
                        removeMixes(new ArrayList(mMixes));
                    }
                } else {
                    mAudioSystem.registerPolicyMixes(mMixes, false);
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
@@ -13350,6 +13366,17 @@ public class AudioService extends IAudioService.Stub
        int addMixes(@NonNull ArrayList<AudioMix> mixes) {
            synchronized (mMixes) {
                if (android.media.audiopolicy.Flags.audioMixOwnership()) {
                    for (AudioMix mix : mixes) {
                        setMixRegistration(mix);
                    }
                    int result = mAudioSystem.registerPolicyMixes(mixes, true);
                    if (result == AudioSystem.SUCCESS) {
                        this.add(mixes);
                    }
                    return result;
                }
                this.add(mixes);
                return mAudioSystem.registerPolicyMixes(mixes, true);
            }