diff options
| -rw-r--r-- | api/current.txt | 10 | ||||
| -rw-r--r-- | api/system-current.txt | 10 | ||||
| -rw-r--r-- | media/java/android/media/AudioTrack.java | 185 |
3 files changed, 204 insertions, 1 deletions
diff --git a/api/current.txt b/api/current.txt index 202139cc757b..34a632060211 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14726,6 +14726,16 @@ package android.media { field public static final int WRITE_NON_BLOCKING = 1; // 0x1 } + public static class AudioTrack.Builder { + ctor public AudioTrack.Builder(); + method public android.media.AudioTrack build() throws java.lang.UnsupportedOperationException; + method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException; + } + public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener { method public abstract void onMarkerReached(android.media.AudioTrack); method public abstract void onPeriodicNotification(android.media.AudioTrack); diff --git a/api/system-current.txt b/api/system-current.txt index 8d8e0c3b517f..1ea3842ec186 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -15931,6 +15931,16 @@ package android.media { field public static final int WRITE_NON_BLOCKING = 1; // 0x1 } + public static class AudioTrack.Builder { + ctor public AudioTrack.Builder(); + method public android.media.AudioTrack build() throws java.lang.UnsupportedOperationException; + method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException; + method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException; + } + public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener { method public abstract void onMarkerReached(android.media.AudioTrack); method public abstract void onPeriodicNotification(android.media.AudioTrack); diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 93e2cbecb465..98bfaffbd9bc 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -21,7 +21,10 @@ import java.lang.annotation.RetentionPolicy; import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.NioUtils; + import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.app.ActivityThread; import android.app.AppOpsManager; import android.content.Context; @@ -113,6 +116,14 @@ public class AudioTrack */ public static final int MODE_STREAM = 1; + /** @hide */ + @IntDef({ + MODE_STATIC, + MODE_STREAM + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TransferMode {} + /** * State of an AudioTrack that was not successfully initialized upon creation. */ @@ -457,6 +468,179 @@ public class AudioTrack } } + /** + * Builder class for {@link AudioTrack} objects. + * Use this class to configure and create an <code>AudioTrack</code> instance. By setting audio + * attributes 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>AudioTrack</code> instance: + * + * <pre class="prettyprint"> + * AudioTrack player = new AudioTrack.Builder() + * .setAudioAttributes(new AudioAttributes.Builder() + * .setUsage(AudioAttributes.USAGE_ALARM) + * .setContentType(CONTENT_TYPE_MUSIC) + * .build()) + * .setAudioFormat(new AudioFormat.Builder() + * .setEncoding(AudioFormat.ENCODING_PCM_16BIT) + * .setSampleRate(441000) + * .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) + * .build()) + * .setBufferSize(minBuffSize) + * .build(); + * </pre> + * <p> + * If the audio attributes are not set with {@link #setAudioAttributes(AudioAttributes)}, + * attributes comprising {@link AudioAttributes#USAGE_MEDIA} will be 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_OUT_STEREO} and the encoding will be + * {@link AudioFormat#ENCODING_PCM_16BIT}. + * <br>If the transfer mode is not specified with {@link #setTransferMode(int)}, + * {@link AudioTrack#MODE_STREAM} will be used. + * <br>If the session ID is not specified with {@link #setSessionId(int)}, a new one will + * be generated. + */ + public static class Builder { + private AudioAttributes mAttributes; + private AudioFormat mFormat; + private int mBufferSizeInBytes; + private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE; + private int mMode = MODE_STREAM; + + /** + * Constructs a new Builder with the default values as described above. + */ + public Builder() { + } + + /** + * Sets the {@link AudioAttributes}. + * @param attributes a non-null {@link AudioAttributes} instance that describes the audio + * data to be played. + * @return the same Builder instance. + * @throws IllegalArgumentException + */ + public @NonNull Builder setAudioAttributes(@NonNull AudioAttributes attributes) + throws IllegalArgumentException { + if (attributes == null) { + throw new IllegalArgumentException("Illegal null AudioAttributes argument"); + } + // keep reference, we only copy the data when building + mAttributes = attributes; + return this; + } + + /** + * Sets the format of the audio data to be played by the {@link AudioTrack}. + * See {@link AudioFormat.Builder} for configuring the audio format parameters such + * as encoding, channel mask and sample rate. + * @param format a non-null {@link AudioFormat} instance. + * @return the same Builder instance. + * @throws IllegalArgumentException + */ + public @NonNull 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 read from for playback. + * If using the {@link AudioTrack} in streaming mode + * (see {@link AudioTrack#MODE_STREAM}, you can write data into 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 AudioTrack instance + * in streaming mode. Using values smaller than <code>getMinBufferSize()</code> will result + * in an exception when trying to build the <code>AudioTrack</code>. + * <br>If using the <code>AudioTrack</code> in static mode (see + * {@link AudioTrack#MODE_STATIC}), this is the maximum size of the sound that will be + * played by this instance. + * @param bufferSizeInBytes + * @return the same Builder instance. + * @throws IllegalArgumentException + */ + public @NonNull Builder setBufferSizeInBytes(int bufferSizeInBytes) + throws IllegalArgumentException { + if (bufferSizeInBytes <= 0) { + throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes); + } + mBufferSizeInBytes = bufferSizeInBytes; + return this; + } + + /** + * Sets the mode under which buffers of audio data are transferred from the + * {@link AudioTrack} to the framework. + * @param mode one of {@link AudioTrack#MODE_STREAM}, {@link AudioTrack#MODE_STATIC}. + * @return the same Builder instance. + * @throws IllegalArgumentException + */ + public @NonNull Builder setTransferMode(@TransferMode int mode) + throws IllegalArgumentException { + switch(mode) { + case MODE_STREAM: + case MODE_STATIC: + mMode = mode; + break; + default: + throw new IllegalArgumentException("Invalid transfer mode " + mode); + } + return this; + } + + /** + * Sets the session ID the {@link AudioTrack} will be attached to. + * @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 + * {@link AudioManager#AUDIO_SESSION_ID_GENERATE}. + * @return the same Builder instance. + * @throws IllegalArgumentException + */ + public @NonNull Builder setSessionId(int sessionId) + throws IllegalArgumentException { + if ((sessionId != AudioManager.AUDIO_SESSION_ID_GENERATE) && (sessionId < 1)) { + throw new IllegalArgumentException("Invalid audio session ID " + sessionId); + } + mSessionId = sessionId; + return this; + } + + /** + * Builds an {@link AudioTrack} instance initialized with all the parameters set + * on this <code>Builder</code>. + * @return a new {@link AudioTrack} instance. + * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code> + * were incompatible, or if they are not supported by the device. + */ + public @NonNull AudioTrack build() throws UnsupportedOperationException { + if (mAttributes == null) { + mAttributes = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .build(); + } + if (mFormat == null) { + mFormat = new AudioFormat.Builder() + .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO) + .setSampleRate(AudioSystem.getPrimaryOutputSamplingRate()) + .setEncoding(AudioFormat.ENCODING_DEFAULT) + .build(); + } + try { + return new AudioTrack(mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId); + } catch (IllegalArgumentException e) { + throw new UnsupportedOperationException(e.getMessage()); + } + } + } + // mask of all the channels supported by this implementation private static final int SUPPORTED_OUT_CHANNELS = AudioFormat.CHANNEL_OUT_FRONT_LEFT | @@ -1749,5 +1933,4 @@ public class AudioTrack private static void loge(String msg) { Log.e(TAG, msg); } - } |