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

Commit 0691dd15 authored by Ján Sebechlebský's avatar Ján Sebechlebský Committed by Android (Google) Code Review
Browse files

Merge "Add context-aware AudioTrack construction APIs."

parents 4516134e 5789bf94
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -21197,6 +21197,7 @@ package android.media {
    method @NonNull public android.media.AudioTrack.Builder setAudioAttributes(@NonNull android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
    method @NonNull public android.media.AudioTrack.Builder setAudioFormat(@NonNull android.media.AudioFormat) throws java.lang.IllegalArgumentException;
    method @NonNull public android.media.AudioTrack.Builder setBufferSizeInBytes(@IntRange(from=0) int) throws java.lang.IllegalArgumentException;
    method @NonNull public android.media.AudioTrack.Builder setContext(@NonNull android.content.Context);
    method @NonNull public android.media.AudioTrack.Builder setEncapsulationMode(int);
    method @NonNull public android.media.AudioTrack.Builder setOffloadedPlayback(boolean);
    method @NonNull public android.media.AudioTrack.Builder setPerformanceMode(int);
+1 −0
Original line number Diff line number Diff line
@@ -3043,6 +3043,7 @@ package android.companion.virtual {
    field public static final int LOCK_STATE_DEFAULT = 0; // 0x0
    field public static final int NAVIGATION_POLICY_DEFAULT_ALLOWED = 0; // 0x0
    field public static final int NAVIGATION_POLICY_DEFAULT_BLOCKED = 1; // 0x1
    field public static final int POLICY_TYPE_AUDIO = 1; // 0x1
    field public static final int POLICY_TYPE_SENSORS = 0; // 0x0
    field public static final int RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS = 1; // 0x1
  }
+38 −0
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.companion.virtual;

import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -254,6 +256,42 @@ public final class VirtualDeviceManager {
        }
    }

    /**
     * Returns device-specific audio session id for audio playback.
     *
     * @param deviceId - id of the virtual audio device
     * @return Device specific session id to be used for audio playback (see
     *     {@link android.media.AudioManager.generateAudioSessionId}) if virtual device has
     *     {@link VirtualDeviceParams.POLICY_TYPE_AUDIO} set to
     *     {@link VirtualDeviceParams.DEVICE_POLICY_CUSTOM} and Virtual Audio Device
     *     is configured in context-aware mode.
     *     Otherwise {@link AUDIO_SESSION_ID_GENERATE} constant is returned.
     * @hide
     */
    public int getAudioPlaybackSessionId(int deviceId) {
        //TODO - Return session id rerouted to VirtualAudioDevice if the VirtualAudioDevice
        //is configured to operate in context-aware mode.
        return AUDIO_SESSION_ID_GENERATE;
    }

    /**
     * Returns device-specific audio session id for audio recording.
     *
     * @param deviceId - id of the virtual audio device
     * @return Device specific session id to be used for audio recording (see
     *     {@link android.media.AudioManager.generateAudioSessionId}) if virtual device has
     *     {@link VirtualDeviceParams.POLICY_TYPE_AUDIO} set to
     *     {@link VirtualDeviceParams.DEVICE_POLICY_CUSTOM} and Virtual Audio Device
     *     is configured in context-aware mode.
     *     Otherwise {@link AUDIO_SESSION_ID_GENERATE} constant is returned.
     * @hide
     */
    public int getAudioRecordingSessionId(int deviceId) {
        //TODO - Return session id corresponding to VirtualAudioDevice injection if the
        // VirtualAudioDevice is configured to operate in context-aware mode.
        return AUDIO_SESSION_ID_GENERATE;
    }

    /**
     * A virtual device has its own virtual display, audio output, microphone, and camera etc. The
     * creator of a virtual device can take the output from the virtual display and stream it over
+16 −1
Original line number Diff line number Diff line
@@ -129,7 +129,7 @@ public final class VirtualDeviceParams implements Parcelable {
     * a given policy type.
     * @hide
     */
    @IntDef(prefix = "POLICY_TYPE_",  value = {POLICY_TYPE_SENSORS})
    @IntDef(prefix = "POLICY_TYPE_",  value = {POLICY_TYPE_SENSORS, POLICY_TYPE_AUDIO})
    @Retention(RetentionPolicy.SOURCE)
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    public @interface PolicyType {}
@@ -147,6 +147,21 @@ public final class VirtualDeviceParams implements Parcelable {
     */
    public static final int POLICY_TYPE_SENSORS = 0;

    /**
     * Tells the audio framework whether to configure the players ({@link android.media.AudioTrack},
     * {@link android.media.MediaPlayer}, {@link android.media.SoundPool} and recorders
     * {@link android.media.AudioRecord}) to use specific session ids re-routed to
     * VirtualAudioDevice.
     *
     * <ul>
     *     <li>{@link #DEVICE_POLICY_DEFAULT}: fall back to default session id handling.
     *     <li>{@link #DEVICE_POLICY_CUSTOM}: audio framework will assign device specific session
     *     ids to players and recorders constructed within device context. The session ids are
     *     used to re-route corresponding audio streams to VirtualAudioDevice.
     * <ul/>
     */
    public static final int POLICY_TYPE_AUDIO = 1;

    /** @hide */
    @IntDef(flag = true, prefix = "RECENTS_POLICY_",
            value = {RECENTS_POLICY_ALLOW_IN_HOST_DEVICE_RECENTS})
+68 −11
Original line number Diff line number Diff line
@@ -16,6 +16,11 @@

package android.media;

import static android.companion.virtual.VirtualDeviceManager.DEVICE_ID_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO;
import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE;

import android.annotation.CallbackExecutor;
import android.annotation.FloatRange;
import android.annotation.IntDef;
@@ -25,7 +30,9 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.companion.virtual.VirtualDeviceManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.media.audiopolicy.AudioMix;
import android.media.audiopolicy.AudioMixingRule;
import android.media.audiopolicy.AudioPolicy;
@@ -545,7 +552,7 @@ public class AudioTrack extends PlayerBase
    /**
     * Audio session ID
     */
    private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
    private int mSessionId = AUDIO_SESSION_ID_GENERATE;
    /**
     * HW_AV_SYNC track AV Sync Header
     */
@@ -645,7 +652,7 @@ public class AudioTrack extends PlayerBase
            int bufferSizeInBytes, int mode)
    throws IllegalArgumentException {
        this(streamType, sampleRateInHz, channelConfig, audioFormat,
                bufferSizeInBytes, mode, AudioManager.AUDIO_SESSION_ID_GENERATE);
                bufferSizeInBytes, mode, AUDIO_SESSION_ID_GENERATE);
    }

    /**
@@ -749,12 +756,12 @@ public class AudioTrack extends PlayerBase
    public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
            int mode, int sessionId)
                    throws IllegalArgumentException {
        this(attributes, format, bufferSizeInBytes, mode, sessionId, false /*offload*/,
                ENCAPSULATION_MODE_NONE, null /* tunerConfiguration */);
        this(null /* context */, attributes, format, bufferSizeInBytes, mode, sessionId,
                false /*offload*/, ENCAPSULATION_MODE_NONE, null /* tunerConfiguration */);
    }

    private AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
            int mode, int sessionId, boolean offload, int encapsulationMode,
    private AudioTrack(@Nullable Context context, AudioAttributes attributes, AudioFormat format,
            int bufferSizeInBytes, int mode, int sessionId, boolean offload, int encapsulationMode,
            @Nullable TunerConfiguration tunerConfiguration)
                    throws IllegalArgumentException {
        super(attributes, AudioPlaybackConfiguration.PLAYER_TYPE_JAM_AUDIOTRACK);
@@ -817,7 +824,13 @@ public class AudioTrack extends PlayerBase

        int[] sampleRate = new int[] {mSampleRate};
        int[] session = new int[1];
        if (sessionId == AUDIO_SESSION_ID_GENERATE) {
            // If there's no specific session id requested, try to get one from context.
            session[0] = getSessionIdForContext(context);
        } else {
            session[0] = sessionId;
        }

        // native initialization
        int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
                sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
@@ -1028,11 +1041,12 @@ public class AudioTrack extends PlayerBase
     * <br>Offload is false by default.
     */
    public static class Builder {
        private Context mContext;
        private AudioAttributes mAttributes;
        private AudioFormat mFormat;
        private int mBufferSizeInBytes;
        private int mEncapsulationMode = ENCAPSULATION_MODE_NONE;
        private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
        private int mSessionId = AUDIO_SESSION_ID_GENERATE;
        private int mMode = MODE_STREAM;
        private int mPerformanceMode = PERFORMANCE_MODE_NONE;
        private boolean mOffload = false;
@@ -1045,6 +1059,19 @@ public class AudioTrack extends PlayerBase
        public Builder() {
        }

        /**
         * Sets the context the track belongs to. This context will be used to pull information,
         * such as {@link android.content.AttributionSource} and device specific audio session ids,
         * which will be associated with the {@link AudioTrack}. However, the context itself will
         * not be retained by the {@link AudioTrack}.
         * @param context a non-null {@link Context} instance
         * @return the same Builder instance.
         */
        public @NonNull Builder setContext(@NonNull Context context) {
            mContext = Objects.requireNonNull(context);
            return this;
        }

        /**
         * Sets the {@link AudioAttributes}.
         * @param attributes a non-null {@link AudioAttributes} instance that describes the audio
@@ -1152,6 +1179,10 @@ public class AudioTrack extends PlayerBase

        /**
         * Sets the session ID the {@link AudioTrack} will be attached to.
         *
         * Note, that if there's a device specific session id asociated with the context, explicitly
         * setting a session id using this method will override it
         * (see {@link Builder#setContext(Context)}).
         * @param sessionId a strictly positive ID number retrieved from another
         *     <code>AudioTrack</code> via {@link AudioTrack#getAudioSessionId()} or allocated by
         *     {@link AudioManager} via {@link AudioManager#generateAudioSessionId()}, or
@@ -1161,7 +1192,7 @@ public class AudioTrack extends PlayerBase
         */
        public @NonNull Builder setSessionId(@IntRange(from = 1) int sessionId)
                throws IllegalArgumentException {
            if ((sessionId != AudioManager.AUDIO_SESSION_ID_GENERATE) && (sessionId < 1)) {
            if ((sessionId != AUDIO_SESSION_ID_GENERATE) && (sessionId < 1)) {
                throw new IllegalArgumentException("Invalid audio session ID " + sessionId);
            }
            mSessionId = sessionId;
@@ -1371,8 +1402,8 @@ public class AudioTrack extends PlayerBase

            try {
                final AudioTrack track = new AudioTrack(
                        mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId, mOffload,
                        mEncapsulationMode, mTunerConfiguration);
                        mContext, mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId,
                        mOffload, mEncapsulationMode, mTunerConfiguration);
                if (track.getState() == STATE_UNINITIALIZED) {
                    // release is not necessary
                    throw new UnsupportedOperationException("Cannot create AudioTrack");
@@ -1384,6 +1415,32 @@ public class AudioTrack extends PlayerBase
        }
    }

    /**
     * Helper method to extract device specific audio session id from Context.
     *
     * @param context {@link Context} to use for extraction of device specific session id.
     * @return device specific session id. If context is null or doesn't have specific audio
     *   session id associated, this method returns {@link AUDIO_SESSION_ID_GENERATE}.
     */
    private static int getSessionIdForContext(@Nullable Context context) {
        if (context == null) {
            return AUDIO_SESSION_ID_GENERATE;
        }

        int deviceId = context.getDeviceId();
        if (deviceId == DEVICE_ID_DEFAULT) {
            return AUDIO_SESSION_ID_GENERATE;
        }

        VirtualDeviceManager vdm = context.getSystemService(VirtualDeviceManager.class);
        if (vdm == null || vdm.getDevicePolicy(deviceId, POLICY_TYPE_AUDIO)
                == DEVICE_POLICY_DEFAULT) {
            return AUDIO_SESSION_ID_GENERATE;
        }

        return vdm.getAudioPlaybackSessionId(deviceId);
    }

    /**
     * Sets an {@link AudioPolicy} to automatically unregister when the track is released.
     *
Loading