diff options
author | Glenn Kasten <gkasten@google.com> | 2014-04-30 18:03:15 -0700 |
---|---|---|
committer | Glenn Kasten <gkasten@google.com> | 2014-05-08 16:11:42 -0700 |
commit | 54955e33c8612a737a76177408f3e7c8482cfcf4 (patch) | |
tree | c6a5d800c9b91d5a5222c95d252fbaa02a705d75 /media/java | |
parent | ed32c842c6d0cc31587256bfbfc2693588ee556c (diff) | |
download | frameworks_base-54955e33c8612a737a76177408f3e7c8482cfcf4.zip frameworks_base-54955e33c8612a737a76177408f3e7c8482cfcf4.tar.gz frameworks_base-54955e33c8612a737a76177408f3e7c8482cfcf4.tar.bz2 |
Add hidden support for ENCODING_PCM_FLOAT to AudioTrack
Change-Id: I15e6d6ab34846366e7f5cbf948fd3cb327e72632
Diffstat (limited to 'media/java')
-rw-r--r-- | media/java/android/media/AudioTrack.java | 104 |
1 files changed, 98 insertions, 6 deletions
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 007eb40..dab6eed 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -72,6 +72,7 @@ import com.android.internal.app.IAppOpsService; * * AudioTrack is not final and thus permits subclasses, but such use is not recommended. */ +// add {@link #write(float[], int, int)} when @hide removed public class AudioTrack { //--------------------------------------------------------- @@ -245,6 +246,7 @@ public class AudioTrack * @see AudioFormat#ENCODING_PCM_8BIT * @see AudioFormat#ENCODING_PCM_16BIT */ + // add @see AudioFormat#ENCODING_PCM_FLOAT when @hide removed private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT; /** * Audio session ID @@ -300,6 +302,7 @@ public class AudioTrack * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM} * @throws java.lang.IllegalArgumentException */ + // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode) throws IllegalArgumentException { @@ -341,6 +344,7 @@ public class AudioTrack * @param sessionId Id of audio session the AudioTrack must be attached to * @throws java.lang.IllegalArgumentException */ + // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode, int sessionId) throws IllegalArgumentException { @@ -459,11 +463,14 @@ public class AudioTrack break; case AudioFormat.ENCODING_PCM_16BIT: case AudioFormat.ENCODING_PCM_8BIT: + case AudioFormat.ENCODING_PCM_FLOAT: mAudioFormat = audioFormat; break; default: throw new IllegalArgumentException("Unsupported sample encoding." - + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT."); + + " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT" + // + " or ENCODING_PCM_FLOAT" when @hide removed + + "."); } //-------------- @@ -728,6 +735,7 @@ public class AudioTrack * or {@link #ERROR} if unable to query for output properties, * or the minimum buffer size expressed in bytes. */ + // add {@link AudioFormat#ENCODING_PCM_FLOAT} to audioFormat section above, when @hide removed static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { int channelCount = 0; switch(channelConfig) { @@ -750,7 +758,8 @@ public class AudioTrack } if ((audioFormat != AudioFormat.ENCODING_PCM_16BIT) - && (audioFormat != AudioFormat.ENCODING_PCM_8BIT)) { + && (audioFormat != AudioFormat.ENCODING_PCM_8BIT) + && (audioFormat != AudioFormat.ENCODING_PCM_FLOAT)) { loge("getMinBufferSize(): Invalid audio format."); return ERROR_BAD_VALUE; } @@ -1150,7 +1159,7 @@ public class AudioTrack public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) { - if (mState == STATE_UNINITIALIZED) { + if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { return ERROR_INVALID_OPERATION; } @@ -1188,13 +1197,13 @@ public class AudioTrack * starts. * @param sizeInShorts the number of shorts to read in audioData after the offset. * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION} - * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if - * the parameters don't resolve to valid data and indexes. + * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * the parameters don't resolve to valid data and indexes. */ public int write(short[] audioData, int offsetInShorts, int sizeInShorts) { - if (mState == STATE_UNINITIALIZED) { + if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { return ERROR_INVALID_OPERATION; } @@ -1220,6 +1229,80 @@ public class AudioTrack /** * Writes the audio data to the audio sink for playback (streaming mode), * or copies audio data for later playback (static buffer mode). + * In static buffer mode, copies the data to the buffer starting at offset 0, + * and the write mode is ignored. + * In streaming mode, the blocking behavior will depend on the write mode. + * <p> + * Note that the actual playback of this data might occur after this function + * returns. This function is thread safe with respect to {@link #stop} calls, + * in which case all of the specified data might not be written to the audio sink. + * <p> + * @param audioData the array that holds the data to play. + * The implementation does not clip for sample values within the nominal range + * [-1.0f, 1.0f], provided that all gains in the audio pipeline are + * less than or equal to unity (1.0f), and in the absence of post-processing effects + * that could add energy, such as reverb. For the convenience of applications + * that compute samples using filters with non-unity gain, + * sample values +3 dB beyond the nominal range are permitted. + * However such values may eventually be limited or clipped, depending on various gains + * and later processing in the audio path. Therefore applications are encouraged + * to provide samples values within the nominal range. + * @param offsetInFloats the offset, expressed as a number of floats, + * in audioData where the data to play starts. + * @param sizeInFloats the number of floats to read in audioData after the offset. + * @param writeMode one of {@link #WRITE_BLOCKING}, {@link #WRITE_NON_BLOCKING}. It has no + * effect in static mode. + * <BR>With {@link #WRITE_BLOCKING}, the write will block until all data has been written + * to the audio sink. + * <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after + * queuing as much audio data for playback as possible without blocking. + * @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION} + * if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if + * the parameters don't resolve to valid data and indexes. + * @hide candidate for public API + */ + public int write(float[] audioData, int offsetInFloats, int sizeInFloats, + @WriteMode int writeMode) { + + if (mState == STATE_UNINITIALIZED) { + Log.e(TAG, "AudioTrack.write() called in invalid state STATE_UNINITIALIZED"); + return ERROR_INVALID_OPERATION; + } + + if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) { + Log.e(TAG, "AudioTrack.write(float[] ...) requires format ENCODING_PCM_FLOAT"); + return ERROR_INVALID_OPERATION; + } + + if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) { + Log.e(TAG, "AudioTrack.write() called with invalid blocking mode"); + return ERROR_BAD_VALUE; + } + + if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0) + || (offsetInFloats + sizeInFloats < 0) // detect integer overflow + || (offsetInFloats + sizeInFloats > audioData.length)) { + Log.e(TAG, "AudioTrack.write() called with invalid array, offset, or size"); + return ERROR_BAD_VALUE; + } + + int ret = native_write_float(audioData, offsetInFloats, sizeInFloats, mAudioFormat, + writeMode == WRITE_BLOCKING); + + if ((mDataLoadMode == MODE_STATIC) + && (mState == STATE_NO_STATIC_DATA) + && (ret > 0)) { + // benign race with respect to other APIs that read mState + mState = STATE_INITIALIZED; + } + + return ret; + } + + + /** + * Writes the audio data to the audio sink for playback (streaming mode), + * or copies audio data for later playback (static buffer mode). * In static buffer mode, copies the data to the buffer starting at its 0 offset, and the write * mode is ignored. * In streaming mode, the blocking behavior will depend on the write mode. @@ -1247,6 +1330,11 @@ public class AudioTrack return ERROR_INVALID_OPERATION; } + if (mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) { + Log.e(TAG, "AudioTrack.write(ByteBuffer ...) not yet supported for ENCODING_PCM_FLOAT"); + return ERROR_INVALID_OPERATION; + } + if ((writeMode != WRITE_BLOCKING) && (writeMode != WRITE_NON_BLOCKING)) { Log.e(TAG, "AudioTrack.write() called with invalid blocking mode"); return ERROR_BAD_VALUE; @@ -1487,6 +1575,10 @@ public class AudioTrack private native final int native_write_short(short[] audioData, int offsetInShorts, int sizeInShorts, int format); + private native final int native_write_float(float[] audioData, + int offsetInFloats, int sizeInFloats, int format, + boolean isBlocking); + private native final int native_write_native_bytes(Object audioData, int positionInBytes, int sizeInBytes, int format, boolean blocking); |