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

Commit a31667c1 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "AudioMix: add option for silence injection on injection starvation" into main

parents 442d78a1 9efb10a9
Loading
Loading
Loading
Loading
+5 −3
Original line number Original line Diff line number Diff line
@@ -8146,6 +8146,7 @@ package android.media.audiopolicy {
  public class AudioMix implements android.os.Parcelable {
  public class AudioMix implements android.os.Parcelable {
    method public int describeContents();
    method public int describeContents();
    method public int getMixState();
    method public int getMixState();
    method @FlaggedApi("android.media.audio.dap_injection_starve_management") public boolean isInjectingSilenceOnStarvation();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioMix> CREATOR;
    field @NonNull public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioMix> CREATOR;
    field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff
    field public static final int MIX_STATE_DISABLED = -1; // 0xffffffff
@@ -8158,9 +8159,10 @@ package android.media.audiopolicy {
  public static class AudioMix.Builder {
  public static class AudioMix.Builder {
    ctor public AudioMix.Builder(@NonNull android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
    ctor public AudioMix.Builder(@NonNull android.media.audiopolicy.AudioMixingRule) throws java.lang.IllegalArgumentException;
    method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException;
    method public android.media.audiopolicy.AudioMix build() throws java.lang.IllegalArgumentException;
    method public android.media.audiopolicy.AudioMix.Builder setDevice(@NonNull android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
    method @NonNull public android.media.audiopolicy.AudioMix.Builder setDevice(@NonNull android.media.AudioDeviceInfo) throws java.lang.IllegalArgumentException;
    method public android.media.audiopolicy.AudioMix.Builder setFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
    method @NonNull public android.media.audiopolicy.AudioMix.Builder setFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
    method public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException;
    method @FlaggedApi("android.media.audio.dap_injection_starve_management") @NonNull public android.media.audiopolicy.AudioMix.Builder setInjectSilenceOnStarvation(boolean);
    method @NonNull public android.media.audiopolicy.AudioMix.Builder setRouteFlags(int) throws java.lang.IllegalArgumentException;
  }
  }
  public class AudioMixingRule implements android.os.Parcelable {
  public class AudioMixingRule implements android.os.Parcelable {
+81 −11
Original line number Original line Diff line number Diff line
@@ -16,9 +16,12 @@


package android.media.audiopolicy;
package android.media.audiopolicy;


import static android.media.audio.Flags.FLAG_DAP_INJECTION_STARVE_MANAGEMENT;
import static android.media.audio.Flags.dapInjectionStarveManagement;
import static android.media.AudioSystem.getDeviceName;
import static android.media.AudioSystem.getDeviceName;
import static android.media.AudioSystem.isRemoteSubmixDevice;
import static android.media.AudioSystem.isRemoteSubmixDevice;


import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
@@ -74,6 +77,11 @@ public class AudioMix implements Parcelable {
    // audio routing for this device ID.
    // audio routing for this device ID.
    private int mVirtualDeviceId;
    private int mVirtualDeviceId;


    // When this mix is used for injecting audio into recordings, indicates whether silence
    // should be injected when the injection is failing to provide enough audio data in time
    // False by default or when not applicable
    private boolean mInjectSilenceOnStarve = false;

    /**
    /**
     * All parameters are guaranteed valid through the Builder.
     * All parameters are guaranteed valid through the Builder.
     */
     */
@@ -90,6 +98,23 @@ public class AudioMix implements Parcelable {
        mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress;
        mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress;
        mToken = token;
        mToken = token;
        mVirtualDeviceId = virtualDeviceId;
        mVirtualDeviceId = virtualDeviceId;
        mInjectSilenceOnStarve = false;
    }

    private AudioMix(@NonNull AudioMixingRule rule, @NonNull AudioFormat format,
            int routeFlags, int callbackFlags,
            int deviceType, @Nullable String deviceAddress, IBinder token,
            int virtualDeviceId, boolean injectSilenceOnStarve) {
        mRule = Objects.requireNonNull(rule);
        mFormat = Objects.requireNonNull(format);
        mRouteFlags = routeFlags;
        mMixType = rule.getTargetMixType();
        mCallbackFlags = callbackFlags;
        mDeviceSystemType = deviceType;
        mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress;
        mToken = token;
        mVirtualDeviceId = virtualDeviceId;
        mInjectSilenceOnStarve = injectSilenceOnStarve;
    }
    }


    // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
    // CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
@@ -272,6 +297,20 @@ public class AudioMix implements Parcelable {
        return null;
        return null;
    }
    }


    /**
     * Returns whether this mix was configured to inject silence audio into recordings
     * when the injection is failing to provide enough audio data in time.
     * @return <code>false</code> if the mix is not an injection mix, or how it was configured
     *         {@link Builder#setInjectSilenceOnStarvation(boolean)}.
     */
    @FlaggedApi(FLAG_DAP_INJECTION_STARVE_MANAGEMENT)
    public boolean isInjectingSilenceOnStarvation() {
        if (!dapInjectionStarveManagement()) {
            return false;
        }
        return mInjectSilenceOnStarve;
    }

    /** @hide */
    /** @hide */
    public boolean isForCallRedirection() {
    public boolean isForCallRedirection() {
        return mRule.isForCallRedirection();
        return mRule.isForCallRedirection();
@@ -321,6 +360,9 @@ public class AudioMix implements Parcelable {
        mRule.writeToParcel(dest, flags);
        mRule.writeToParcel(dest, flags);
        dest.writeStrongBinder(mToken);
        dest.writeStrongBinder(mToken);
        dest.writeInt(mVirtualDeviceId);
        dest.writeInt(mVirtualDeviceId);
        if (dapInjectionStarveManagement()) {
            dest.writeBoolean(mInjectSilenceOnStarve);
        }
    }
    }


    public static final @NonNull Parcelable.Creator<AudioMix> CREATOR = new Parcelable.Creator<>() {
    public static final @NonNull Parcelable.Creator<AudioMix> CREATOR = new Parcelable.Creator<>() {
@@ -342,6 +384,9 @@ public class AudioMix implements Parcelable {
            mixBuilder.setMixingRule(AudioMixingRule.CREATOR.createFromParcel(p));
            mixBuilder.setMixingRule(AudioMixingRule.CREATOR.createFromParcel(p));
            mixBuilder.setToken(p.readStrongBinder());
            mixBuilder.setToken(p.readStrongBinder());
            mixBuilder.setVirtualDeviceId(p.readInt());
            mixBuilder.setVirtualDeviceId(p.readInt());
            if (dapInjectionStarveManagement()) {
                mixBuilder.setInjectSilenceOnStarvation(p.readBoolean());
            }
            return mixBuilder.build();
            return mixBuilder.build();
        }
        }


@@ -378,6 +423,7 @@ public class AudioMix implements Parcelable {
        // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
        // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
        private int mDeviceSystemType = AudioSystem.DEVICE_NONE;
        private int mDeviceSystemType = AudioSystem.DEVICE_NONE;
        private String mDeviceAddress = null;
        private String mDeviceAddress = null;
        private boolean mInjectSilenceOnStarve = false;


        /**
        /**
         * @hide
         * @hide
@@ -405,7 +451,7 @@ public class AudioMix implements Parcelable {
         * @return the same Builder instance.
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         * @throws IllegalArgumentException
         */
         */
        Builder setMixingRule(@NonNull AudioMixingRule rule)
        @NonNull Builder setMixingRule(@NonNull AudioMixingRule rule)
                throws IllegalArgumentException {
                throws IllegalArgumentException {
            if (rule == null) {
            if (rule == null) {
                throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
                throw new IllegalArgumentException("Illegal null AudioMixingRule argument");
@@ -418,7 +464,7 @@ public class AudioMix implements Parcelable {
         * @hide
         * @hide
         * Only used by AudioMix internally.
         * Only used by AudioMix internally.
         */
         */
        Builder setToken(IBinder token) {
        @NonNull Builder setToken(IBinder token) {
            mToken = token;
            mToken = token;
            return this;
            return this;
        }
        }
@@ -427,7 +473,7 @@ public class AudioMix implements Parcelable {
         * @hide
         * @hide
         * Only used by AudioMix internally.
         * Only used by AudioMix internally.
         */
         */
        Builder setVirtualDeviceId(int virtualDeviceId) {
        @NonNull Builder setVirtualDeviceId(int virtualDeviceId) {
            mVirtualDeviceId = virtualDeviceId;
            mVirtualDeviceId = virtualDeviceId;
            return this;
            return this;
        }
        }
@@ -435,11 +481,11 @@ public class AudioMix implements Parcelable {
        /**
        /**
         * @hide
         * @hide
         * Only used by AudioPolicyConfig, not a public API.
         * Only used by AudioPolicyConfig, not a public API.
         * @param callbackFlags which callbacks are called from native
         * @param flags which callbacks are called from native
         * @return the same Builder instance.
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         * @throws IllegalArgumentException
         */
         */
        Builder setCallbackFlags(int flags) throws IllegalArgumentException {
        @NonNull Builder setCallbackFlags(int flags) throws IllegalArgumentException {
            if ((flags != 0) && ((flags & CALLBACK_FLAGS_ALL) == 0)) {
            if ((flags != 0) && ((flags & CALLBACK_FLAGS_ALL) == 0)) {
                throw new IllegalArgumentException("Illegal callback flags 0x"
                throw new IllegalArgumentException("Illegal callback flags 0x"
                        + Integer.toHexString(flags).toUpperCase());
                        + Integer.toHexString(flags).toUpperCase());
@@ -456,7 +502,7 @@ public class AudioMix implements Parcelable {
         * @return the same Builder instance.
         * @return the same Builder instance.
         */
         */
        @VisibleForTesting
        @VisibleForTesting
        public Builder setDevice(int deviceType, String address) {
        public @NonNull Builder setDevice(int deviceType, String address) {
            mDeviceSystemType = deviceType;
            mDeviceSystemType = deviceType;
            mDeviceAddress = address;
            mDeviceAddress = address;
            return this;
            return this;
@@ -468,7 +514,7 @@ public class AudioMix implements Parcelable {
         * @return the same Builder instance.
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         * @throws IllegalArgumentException
         */
         */
        public Builder setFormat(@NonNull AudioFormat format)
        public @NonNull Builder setFormat(@NonNull AudioFormat format)
                throws IllegalArgumentException {
                throws IllegalArgumentException {
            if (format == null) {
            if (format == null) {
                throw new IllegalArgumentException("Illegal null AudioFormat argument");
                throw new IllegalArgumentException("Illegal null AudioFormat argument");
@@ -485,7 +531,7 @@ public class AudioMix implements Parcelable {
         * @return the same Builder instance.
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         * @throws IllegalArgumentException
         */
         */
        public Builder setRouteFlags(@RouteFlags int routeFlags)
        public @NonNull Builder setRouteFlags(@RouteFlags int routeFlags)
                throws IllegalArgumentException {
                throws IllegalArgumentException {
            if (routeFlags == 0) {
            if (routeFlags == 0) {
                throw new IllegalArgumentException("Illegal empty route flags");
                throw new IllegalArgumentException("Illegal empty route flags");
@@ -511,7 +557,8 @@ public class AudioMix implements Parcelable {
         * @return the same Builder instance
         * @return the same Builder instance
         * @throws IllegalArgumentException
         * @throws IllegalArgumentException
         */
         */
        public Builder setDevice(@NonNull AudioDeviceInfo device) throws IllegalArgumentException {
        public @NonNull Builder setDevice(@NonNull AudioDeviceInfo device)
                throws IllegalArgumentException {
            if (device == null) {
            if (device == null) {
                throw new IllegalArgumentException("Illegal null AudioDeviceInfo argument");
                throw new IllegalArgumentException("Illegal null AudioDeviceInfo argument");
            }
            }
@@ -523,10 +570,24 @@ public class AudioMix implements Parcelable {
            return this;
            return this;
        }
        }


        /**
         * When this mix is used for injecting audio into recordings, configure whether silence
         * should be injected when the injection is failing to provide enough audio data in time
         * @param injectSilence indicates if silence is injected into recordings when
         * @return the same Builder instance
         */
        @FlaggedApi(FLAG_DAP_INJECTION_STARVE_MANAGEMENT)
        public @NonNull Builder setInjectSilenceOnStarvation(boolean injectSilence) {
            mInjectSilenceOnStarve = injectSilence;
            return this;
        }

        /**
        /**
         * Combines all of the settings and return a new {@link AudioMix} object.
         * Combines all of the settings and return a new {@link AudioMix} object.
         * @return a new {@link AudioMix} object
         * @return a new {@link AudioMix} object
         * @throws IllegalArgumentException if no {@link AudioMixingRule} has been set.
         * @throws IllegalArgumentException if no {@link AudioMixingRule} has been set
         *     or if {@link #setInjectSilenceOnStarvation(boolean)} was set to <code>true</code> on
         *     a mix not used for injection
         */
         */
        public AudioMix build() throws IllegalArgumentException {
        public AudioMix build() throws IllegalArgumentException {
            if (mRule == null) {
            if (mRule == null) {
@@ -588,6 +649,15 @@ public class AudioMix implements Parcelable {
                }
                }
            }
            }


            if (dapInjectionStarveManagement()
                    && ((mRouteFlags & ROUTE_FLAG_LOOP_BACK) == ROUTE_FLAG_LOOP_BACK)
                    && (mRule.getTargetMixType() != MIX_TYPE_RECORDERS)
                    && (mInjectSilenceOnStarve)) {
                throw new IllegalArgumentException(
                        "AudioMix.Builder.setInjectSilenceOnStarvation(true) called "
                        + "on a non-injection AudioMix");
            }

            if (mRule.allowPrivilegedMediaPlaybackCapture()) {
            if (mRule.allowPrivilegedMediaPlaybackCapture()) {
                String error = AudioMix.canBeUsedForPrivilegedMediaCapture(mFormat);
                String error = AudioMix.canBeUsedForPrivilegedMediaCapture(mFormat);
                if (error != null) {
                if (error != null) {
@@ -600,7 +670,7 @@ public class AudioMix implements Parcelable {
            }
            }


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


        private int getLoopbackDeviceSystemTypeForAudioMixingRule(AudioMixingRule rule) {
        private int getLoopbackDeviceSystemTypeForAudioMixingRule(AudioMixingRule rule) {
+3 −0
Original line number Original line Diff line number Diff line
@@ -53,6 +53,7 @@ import static android.media.audio.Flags.autoPublicVolumeApiHardening;
import static android.media.audio.Flags.cacheGetStreamMinMaxVolume;
import static android.media.audio.Flags.cacheGetStreamMinMaxVolume;
import static android.media.audio.Flags.cacheGetStreamVolume;
import static android.media.audio.Flags.cacheGetStreamVolume;
import static android.media.audio.Flags.concurrentAudioRecordBypassPermission;
import static android.media.audio.Flags.concurrentAudioRecordBypassPermission;
import static android.media.audio.Flags.dapInjectionStarveManagement;
import static android.media.audio.Flags.deviceVolumeApis;
import static android.media.audio.Flags.deviceVolumeApis;
import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency;
import static android.media.audio.Flags.featureSpatialAudioHeadtrackingLowLatency;
import static android.media.audio.Flags.focusFreezeTestApi;
import static android.media.audio.Flags.focusFreezeTestApi;
@@ -5442,6 +5443,8 @@ public class AudioService extends IAudioService.Stub
        pw.println("\tandroid.media.audio.autoPublicVolumeApiHardening:"
        pw.println("\tandroid.media.audio.autoPublicVolumeApiHardening:"
                + autoPublicVolumeApiHardening());
                + autoPublicVolumeApiHardening());
        pw.println("\tandroid.media.audio.automaticBtDeviceType - EOL");
        pw.println("\tandroid.media.audio.automaticBtDeviceType - EOL");
        pw.println("\tandroid.media.audio.dapInjectionStarveManagement:"
                + dapInjectionStarveManagement());
        pw.println("\tandroid.media.audio.featureSpatialAudioHeadtrackingLowLatency:"
        pw.println("\tandroid.media.audio.featureSpatialAudioHeadtrackingLowLatency:"
                + featureSpatialAudioHeadtrackingLowLatency());
                + featureSpatialAudioHeadtrackingLowLatency());
        pw.println("\tandroid.media.audio.focusFreezeTestApi:"
        pw.println("\tandroid.media.audio.focusFreezeTestApi:"