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

Commit 7af0d66c authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

AudioRecord builder

Add public and system APIs for building an AudioRecord instance.
The validity of the combination of parameters is verified at
  "build" time.

Bug 19699343

Change-Id: If959f0f35208fb81a902364aaeefc1ebef1a4d23
parent 73484d8b
Loading
Loading
Loading
Loading
+8 −0
Original line number Original line Diff line number Diff line
@@ -14610,6 +14610,14 @@ package android.media {
    field public static final int SUCCESS = 0; // 0x0
    field public static final int SUCCESS = 0; // 0x0
  }
  }
  public static class AudioRecord.Builder {
    ctor public AudioRecord.Builder();
    method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
    method public android.media.AudioRecord.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
    method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
    method public android.media.AudioRecord.Builder setCapturePreset(int) throws java.lang.IllegalArgumentException;
  }
  public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
  public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
    method public abstract void onMarkerReached(android.media.AudioRecord);
    method public abstract void onMarkerReached(android.media.AudioRecord);
    method public abstract void onPeriodicNotification(android.media.AudioRecord);
    method public abstract void onPeriodicNotification(android.media.AudioRecord);
+10 −0
Original line number Original line Diff line number Diff line
@@ -15808,6 +15808,16 @@ package android.media {
    field public static final int SUCCESS = 0; // 0x0
    field public static final int SUCCESS = 0; // 0x0
  }
  }
  public static class AudioRecord.Builder {
    ctor public AudioRecord.Builder();
    method public android.media.AudioRecord build() throws java.lang.UnsupportedOperationException;
    method public android.media.AudioRecord.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
    method public android.media.AudioRecord.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
    method public android.media.AudioRecord.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
    method public android.media.AudioRecord.Builder setCapturePreset(int) throws java.lang.IllegalArgumentException;
    method public android.media.AudioRecord.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
  }
  public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
  public static abstract interface AudioRecord.OnRecordPositionUpdateListener {
    method public abstract void onMarkerReached(android.media.AudioRecord);
    method public abstract void onMarkerReached(android.media.AudioRecord);
    method public abstract void onPeriodicNotification(android.media.AudioRecord);
    method public abstract void onPeriodicNotification(android.media.AudioRecord);
+164 −2
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import java.lang.ref.WeakReference;
import java.nio.ByteBuffer;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.Iterator;


import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.Binder;
import android.os.Handler;
import android.os.Handler;
@@ -313,8 +314,14 @@ public class AudioRecord


        audioParamCheck(attributes.getCapturePreset(), rate, encoding);
        audioParamCheck(attributes.getCapturePreset(), rate, encoding);


        mChannelCount = AudioFormat.channelCountFromInChannelMask(format.getChannelMask());
        int channelMask = AudioFormat.CHANNEL_IN_DEFAULT;
        mChannelMask = getChannelMaskFromLegacyConfig(format.getChannelMask(), false);
        if ((format.getPropertySetMask()
                & AudioFormat.AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK) != 0)
        {
            channelMask = format.getChannelMask();
        }
        mChannelCount = AudioFormat.channelCountFromInChannelMask(channelMask);
        mChannelMask = getChannelMaskFromLegacyConfig(channelMask, false);


        audioBuffSizeCheck(bufferSizeInBytes);
        audioBuffSizeCheck(bufferSizeInBytes);


@@ -335,6 +342,161 @@ public class AudioRecord
        mState = STATE_INITIALIZED;
        mState = STATE_INITIALIZED;
    }
    }


    /**
     * Builder class for {@link AudioRecord} objects.
     * Use this class to configure and create an <code>AudioRecord</code> instance. By setting the
     * recording preset (a.k.a. recording source) and audio format parameters, you indicate which of
     *  those vary from the default behavior on the device.
     * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat}
     * parameters, to be used by a new <code>AudioRecord</code> instance:
     *
     * <pre class="prettyprint">
     * AudioRecord recorder = new AudioRecord.Builder()
     *         .setCapturePreset(MediaRecorder.AudioSource.VOICE_COMMUNICATION)
     *         .setAudioFormat(new AudioFormat.Builder()
     *                 .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
     *                 .setSampleRate(32000)
     *                 .setChannelMask(AudioFormat.CHANNEL_IN_MONO)
     *                 .build())
     *         .setBufferSize(2*minBuffSize)
     *         .build();
     * </pre>
     * <p>
     * If the capture preset is not set with {@link #setCapturePreset(int)},
     * {@link MediaRecorder.AudioSource#DEFAULT} is used.
     * <br>If the audio format is not specified or is incomplete, its sample rate will be the
     * default output sample rate of the device (see
     * {@link AudioManager#PROPERTY_OUTPUT_SAMPLE_RATE}), its channel configuration will be
     * {@link AudioFormat#CHANNEL_IN_DEFAULT}.
     * <br>Failing to set an adequate buffer size with {@link #setBufferSizeInBytes(int)} will
     * prevent the successful creation of an <code>AudioRecord</code> instance.
     */
    public static class Builder {
        private AudioAttributes mAttributes;
        private AudioFormat mFormat;
        private int mBufferSizeInBytes;
        private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;

        /**
         * Constructs a new Builder with the default values as described above.
         */
        public Builder() {
        }

        /**
         * @param preset the capture preset (also referred to as the recording source).
         * See {@link MediaRecorder.AudioSource} for the supported capture preset definitions.
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         */
        public Builder setCapturePreset(int preset) throws IllegalArgumentException {
            if ( (preset < MediaRecorder.AudioSource.DEFAULT) ||
                    (preset > MediaRecorder.getAudioSourceMax()) ) {
                throw new IllegalArgumentException("Invalid audio source " + preset);
            }
            mAttributes = new AudioAttributes.Builder()
                    .setInternalCapturePreset(preset)
                    .build();
            return this;
        }

        /**
         * @hide
         * To be only used by system components. Allows specifying non-public capture presets
         * @param attributes a non-null {@link AudioAttributes} instance that contains the capture
         *     preset to be used.
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         */
        @SystemApi
        public Builder setAudioAttributes(@NonNull AudioAttributes attributes)
                throws IllegalArgumentException {
            if (attributes == null) {
                throw new IllegalArgumentException("Illegal null AudioAttributes argument");
            }
            if (attributes.getCapturePreset() == MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID) {
                throw new IllegalArgumentException(
                        "No valid capture preset in AudioAttributes argument");
            }
            // keep reference, we only copy the data when building
            mAttributes = attributes;
            return this;
        }

        /**
         * Sets the format of the audio data to be captured.
         * @param format a non-null {@link AudioFormat} instance
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         */
        public Builder setAudioFormat(@NonNull AudioFormat format) throws IllegalArgumentException {
            if (format == null) {
                throw new IllegalArgumentException("Illegal null AudioFormat argument");
            }
            // keep reference, we only copy the data when building
            mFormat = format;
            return this;
        }

        /**
         * Sets the total size (in bytes) of the buffer where audio data is written
         * during the recording. New audio data can be read from this buffer in smaller chunks
         * than this size. See {@link #getMinBufferSize(int, int, int)} to determine the minimum
         * required buffer size for the successful creation of an AudioRecord instance.
         * Using values smaller than getMinBufferSize() will result in an initialization failure.
         * @param bufferSizeInBytes a value strictly greater than 0
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         */
        public Builder setBufferSizeInBytes(int bufferSizeInBytes) throws IllegalArgumentException {
            if (bufferSizeInBytes <= 0) {
                throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes);
            }
            mBufferSizeInBytes = bufferSizeInBytes;
            return this;
        }

        /**
         * @hide
         * To be only used by system components.
         * @param sessionId ID of audio session the AudioRecord must be attached to, or
         *     {@link AudioManager#AUDIO_SESSION_ID_GENERATE} if the session isn't known at
         *     construction time.
         * @return the same Builder instance.
         * @throws IllegalArgumentException
         */
        @SystemApi
        public Builder setSessionId(int sessionId) throws IllegalArgumentException {
            if (sessionId < 0) {
                throw new IllegalArgumentException("Invalid session ID " + sessionId);
            }
            mSessionId = sessionId;
            return this;
        }

        /**
         * @return a new {@link AudioRecord} instance initialized with all the parameters set
         *     on this <code>Builder</code>
         * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code>
         *     were incompatible, or if they are not supported by the device.
         */
        public AudioRecord build() throws UnsupportedOperationException {
            if (mFormat == null) {
                mFormat = new AudioFormat.Builder().build();
            }
            if (mAttributes == null) {
                mAttributes = new AudioAttributes.Builder()
                        .setInternalCapturePreset(MediaRecorder.AudioSource.DEFAULT)
                        .build();
            }
            try {
                return new AudioRecord(mAttributes, mFormat, mBufferSizeInBytes, mSessionId);
            } catch (IllegalArgumentException e) {
                throw new UnsupportedOperationException(e.getMessage());
            }
        }
    }

    // Convenience method for the constructor's parameter checks.
    // Convenience method for the constructor's parameter checks.
    // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor
    // This, getChannelMaskFromLegacyConfig and audioBuffSizeCheck are where constructor
    // IllegalArgumentException-s are thrown
    // IllegalArgumentException-s are thrown
+5 −2
Original line number Original line Diff line number Diff line
@@ -157,8 +157,11 @@ public class MediaRecorder
    }
    }


    /**
    /**
     * Defines the audio source. These constants are used with
     * Defines the audio source.
     * {@link MediaRecorder#setAudioSource(int)}.
     * An audio source defines both a default physical source of audio signal, and a recording
     * configuration; it's also known as a capture preset. These constants are for instance used
     * in {@link MediaRecorder#setAudioSource(int)} or
     * {@link AudioRecord.Builder#setCapturePreset(int)}.
     */
     */
    public final class AudioSource {
    public final class AudioSource {