Merge "Add floating point AudioRecord read"
This commit is contained in:
@@ -14669,6 +14669,7 @@ package android.media {
|
||||
method public int getState();
|
||||
method public int read(byte[], int, int);
|
||||
method public int read(short[], int, int);
|
||||
method public int read(float[], int, int, int);
|
||||
method public int read(java.nio.ByteBuffer, int);
|
||||
method public void release();
|
||||
method public int setNotificationMarkerPosition(int);
|
||||
@@ -14681,6 +14682,8 @@ package android.media {
|
||||
field public static final int ERROR = -1; // 0xffffffff
|
||||
field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
|
||||
field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
|
||||
field public static final int READ_BLOCKING = 0; // 0x0
|
||||
field public static final int READ_NON_BLOCKING = 1; // 0x1
|
||||
field public static final int RECORDSTATE_RECORDING = 3; // 0x3
|
||||
field public static final int RECORDSTATE_STOPPED = 1; // 0x1
|
||||
field public static final int STATE_INITIALIZED = 1; // 0x1
|
||||
|
||||
@@ -15876,6 +15876,7 @@ package android.media {
|
||||
method public int getState();
|
||||
method public int read(byte[], int, int);
|
||||
method public int read(short[], int, int);
|
||||
method public int read(float[], int, int, int);
|
||||
method public int read(java.nio.ByteBuffer, int);
|
||||
method public void release();
|
||||
method public int setNotificationMarkerPosition(int);
|
||||
@@ -15888,6 +15889,8 @@ package android.media {
|
||||
field public static final int ERROR = -1; // 0xffffffff
|
||||
field public static final int ERROR_BAD_VALUE = -2; // 0xfffffffe
|
||||
field public static final int ERROR_INVALID_OPERATION = -3; // 0xfffffffd
|
||||
field public static final int READ_BLOCKING = 0; // 0x0
|
||||
field public static final int READ_NON_BLOCKING = 1; // 0x1
|
||||
field public static final int RECORDSTATE_RECORDING = 3; // 0x3
|
||||
field public static final int RECORDSTATE_STOPPED = 1; // 0x1
|
||||
field public static final int STATE_INITIALIZED = 1; // 0x1
|
||||
|
||||
@@ -440,6 +440,57 @@ static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thi
|
||||
return (jint) readSize;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioRecord_readInFloatArray(JNIEnv *env, jobject thiz,
|
||||
jfloatArray javaAudioData,
|
||||
jint offsetInFloats, jint sizeInFloats,
|
||||
jboolean isReadBlocking) {
|
||||
// get the audio recorder from which we'll read new audio samples
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder == NULL) {
|
||||
ALOGE("Unable to retrieve AudioRecord object");
|
||||
return (jint)AUDIO_JAVA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (javaAudioData == NULL) {
|
||||
ALOGE("Invalid Java array to store recorded audio");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
|
||||
// get the pointer to where we'll record the audio
|
||||
// NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
|
||||
// a way that it becomes much more efficient. When doing so, we will have to prevent the
|
||||
// AudioSystem callback to be called while in critical section (in case of media server
|
||||
// process crash for instance)
|
||||
jfloat *recordBuff = (jfloat *)env->GetFloatArrayElements(javaAudioData, NULL);
|
||||
if (recordBuff == NULL) {
|
||||
ALOGE("Error retrieving destination for recorded audio data");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
|
||||
// read the new audio data from the native AudioRecord object
|
||||
const size_t sizeInBytes = sizeInFloats * sizeof(float);
|
||||
ssize_t readSize = lpRecorder->read(recordBuff + offsetInFloats, sizeInBytes);
|
||||
|
||||
env->ReleaseFloatArrayElements(javaAudioData, recordBuff, 0);
|
||||
|
||||
if (readSize < 0) {
|
||||
ALOGE_IF(readSize != WOULD_BLOCK, "Error %zd during AudioRecord native read", readSize);
|
||||
switch (readSize) {
|
||||
case WOULD_BLOCK:
|
||||
return (jint)0;
|
||||
case BAD_VALUE:
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
default:
|
||||
// may be possible for other errors such as
|
||||
// NO_INIT to happen if restoreRecord_l fails.
|
||||
case INVALID_OPERATION:
|
||||
return (jint)AUDIO_JAVA_INVALID_OPERATION;
|
||||
}
|
||||
}
|
||||
return (jint)(readSize / sizeof(float));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz,
|
||||
jobject jBuffer, jint sizeInBytes) {
|
||||
@@ -574,6 +625,8 @@ static JNINativeMethod gMethods[] = {
|
||||
"([BII)I", (void *)android_media_AudioRecord_readInByteArray},
|
||||
{"native_read_in_short_array",
|
||||
"([SII)I", (void *)android_media_AudioRecord_readInShortArray},
|
||||
{"native_read_in_float_array",
|
||||
"([FIIZ)I", (void *)android_media_AudioRecord_readInFloatArray},
|
||||
{"native_read_in_direct_buffer","(Ljava/lang/Object;I)I",
|
||||
(void *)android_media_AudioRecord_readInDirectBuffer},
|
||||
{"native_set_marker_pos","(I)I", (void *)android_media_AudioRecord_set_marker_pos},
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package android.media;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.os.Binder;
|
||||
@@ -109,6 +112,26 @@ public class AudioRecord
|
||||
/** @hide */
|
||||
public final static String SUBMIX_FIXED_VOLUME = "fixedVolume";
|
||||
|
||||
/** @hide */
|
||||
@IntDef({
|
||||
READ_BLOCKING,
|
||||
READ_NON_BLOCKING
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface ReadMode {}
|
||||
|
||||
/**
|
||||
* The read mode indicating the read operation will block until all data
|
||||
* requested has been read.
|
||||
*/
|
||||
public final static int READ_BLOCKING = 0;
|
||||
|
||||
/**
|
||||
* The read mode indicating the read operation will return immediately after
|
||||
* reading as much audio data as possible without blocking.
|
||||
*/
|
||||
public final static int READ_NON_BLOCKING = 1;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Used exclusively by native code
|
||||
//--------------------
|
||||
@@ -144,6 +167,7 @@ public class AudioRecord
|
||||
* The encoding of the audio samples.
|
||||
* @see AudioFormat#ENCODING_PCM_8BIT
|
||||
* @see AudioFormat#ENCODING_PCM_16BIT
|
||||
* @see AudioFormat#ENCODING_PCM_FLOAT
|
||||
*/
|
||||
private int mAudioFormat;
|
||||
/**
|
||||
@@ -212,9 +236,9 @@ public class AudioRecord
|
||||
* See {@link AudioFormat#CHANNEL_IN_MONO} and
|
||||
* {@link AudioFormat#CHANNEL_IN_STEREO}. {@link AudioFormat#CHANNEL_IN_MONO} is guaranteed
|
||||
* to work on all devices.
|
||||
* @param audioFormat the format in which the audio data is represented.
|
||||
* See {@link AudioFormat#ENCODING_PCM_16BIT} and
|
||||
* {@link AudioFormat#ENCODING_PCM_8BIT}
|
||||
* @param audioFormat the format in which the audio data is to be returned.
|
||||
* See {@link AudioFormat#ENCODING_PCM_8BIT}, {@link AudioFormat#ENCODING_PCM_16BIT},
|
||||
* and {@link AudioFormat#ENCODING_PCM_FLOAT}.
|
||||
* @param bufferSizeInBytes the total size (in bytes) of the buffer where audio data is written
|
||||
* to 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
|
||||
@@ -559,13 +583,14 @@ public class AudioRecord
|
||||
case AudioFormat.ENCODING_DEFAULT:
|
||||
mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
|
||||
break;
|
||||
case AudioFormat.ENCODING_PCM_FLOAT:
|
||||
case AudioFormat.ENCODING_PCM_16BIT:
|
||||
case AudioFormat.ENCODING_PCM_8BIT:
|
||||
mAudioFormat = audioFormat;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported sample encoding."
|
||||
+ " Should be ENCODING_PCM_8BIT or ENCODING_PCM_16BIT.");
|
||||
+ " Should be ENCODING_PCM_8BIT, ENCODING_PCM_16BIT, or ENCODING_PCM_FLOAT.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,7 +598,8 @@ public class AudioRecord
|
||||
// Convenience method for the contructor's audio buffer size check.
|
||||
// preconditions:
|
||||
// mChannelCount is valid
|
||||
// mAudioFormat is AudioFormat.ENCODING_PCM_8BIT OR AudioFormat.ENCODING_PCM_16BIT
|
||||
// mAudioFormat is AudioFormat.ENCODING_PCM_8BIT, AudioFormat.ENCODING_PCM_16BIT,
|
||||
// or AudioFormat.ENCODING_PCM_FLOAT
|
||||
// postcondition:
|
||||
// mNativeBufferSizeInBytes is valid (multiple of frame size, positive)
|
||||
private void audioBuffSizeCheck(int audioBufferSize) throws IllegalArgumentException {
|
||||
@@ -632,8 +658,8 @@ public class AudioRecord
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
|
||||
* and {@link AudioFormat#ENCODING_PCM_8BIT}.
|
||||
* Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_8BIT},
|
||||
* {@link AudioFormat#ENCODING_PCM_16BIT}, and {@link AudioFormat#ENCODING_PCM_FLOAT}.
|
||||
*/
|
||||
public int getAudioFormat() {
|
||||
return mAudioFormat;
|
||||
@@ -732,12 +758,6 @@ public class AudioRecord
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
// PCM_8BIT is not supported at the moment
|
||||
if (audioFormat != AudioFormat.ENCODING_PCM_16BIT) {
|
||||
loge("getMinBufferSize(): Invalid audio format.");
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
|
||||
if (size == 0) {
|
||||
return ERROR_BAD_VALUE;
|
||||
@@ -841,11 +861,13 @@ public class AudioRecord
|
||||
// Audio data supply
|
||||
//--------------------
|
||||
/**
|
||||
* Reads audio data from the audio hardware for recording into a buffer.
|
||||
* Reads audio data from the audio hardware for recording into a byte array.
|
||||
* The format specified in the AudioRecord constructor should be
|
||||
* {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
|
||||
* @param audioData the array to which the recorded audio data is written.
|
||||
* @param offsetInBytes index in audioData from which the data is written expressed in bytes.
|
||||
* @param sizeInBytes the number of requested bytes.
|
||||
* @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
|
||||
* @return the number of bytes that were read 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.
|
||||
* The number of bytes will not exceed sizeInBytes.
|
||||
@@ -866,11 +888,13 @@ public class AudioRecord
|
||||
|
||||
|
||||
/**
|
||||
* Reads audio data from the audio hardware for recording into a buffer.
|
||||
* Reads audio data from the audio hardware for recording into a short array.
|
||||
* The format specified in the AudioRecord constructor should be
|
||||
* {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
|
||||
* @param audioData the array to which the recorded audio data is written.
|
||||
* @param offsetInShorts index in audioData from which the data is written expressed in shorts.
|
||||
* @param sizeInShorts the number of requested shorts.
|
||||
* @return the number of shorts that were read or or {@link #ERROR_INVALID_OPERATION}
|
||||
* @return the number of shorts that were read 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.
|
||||
* The number of shorts will not exceed sizeInShorts.
|
||||
@@ -889,18 +913,55 @@ public class AudioRecord
|
||||
return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads audio data from the audio hardware for recording into a float array.
|
||||
* The format specified in the AudioRecord constructor should be
|
||||
* {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
|
||||
* @param audioData the array to which the recorded audio data is written.
|
||||
* @param offsetInFloats index in audioData from which the data is written.
|
||||
* @param sizeInFloats the number of requested floats.
|
||||
* @param readMode one of {@link #READ_BLOCKING}, {@link #READ_NON_BLOCKING}.
|
||||
* <BR>With {@link #READ_BLOCKING}, the read will block until all the requested data
|
||||
* is read.
|
||||
* <BR>With {@link #READ_NON_BLOCKING}, the read will return immediately after
|
||||
* reading as much audio data as possible without blocking.
|
||||
* @return the number of floats that were read 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.
|
||||
* The number of floats will not exceed sizeInFloats.
|
||||
*/
|
||||
public int read(float[] audioData, int offsetInFloats, int sizeInFloats,
|
||||
@ReadMode int readMode) {
|
||||
if (mState != STATE_INITIALIZED) {
|
||||
return ERROR_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0)
|
||||
|| (offsetInFloats + sizeInFloats < 0) // detect integer overflow
|
||||
|| (offsetInFloats + sizeInFloats > audioData.length)) {
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
return native_read_in_float_array(audioData, offsetInFloats, sizeInFloats,
|
||||
readMode == READ_BLOCKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads audio data from the audio hardware for recording into a direct buffer. If this buffer
|
||||
* is not a direct buffer, this method will always return 0.
|
||||
* Note that the value returned by {@link java.nio.Buffer#position()} on this buffer is
|
||||
* unchanged after a call to this method.
|
||||
* The representation of the data in the buffer will depend on the format specified in
|
||||
* the AudioRecord constructor, and will be native endian.
|
||||
* @param audioBuffer the direct buffer to which the recorded audio data is written.
|
||||
* @param sizeInBytes the number of requested bytes.
|
||||
* @return the number of bytes that were read or or {@link #ERROR_INVALID_OPERATION}
|
||||
* @param sizeInBytes the number of requested bytes. It is recommended but not enforced
|
||||
* that the number of bytes requested be a multiple of the frame size (sample size in
|
||||
* bytes multiplied by the channel count).
|
||||
* @return the number of bytes that were read 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.
|
||||
* The number of bytes will not exceed sizeInBytes.
|
||||
* The number of bytes read will truncated to be a multiple of the frame size.
|
||||
*/
|
||||
public int read(ByteBuffer audioBuffer, int sizeInBytes) {
|
||||
if (mState != STATE_INITIALIZED) {
|
||||
@@ -1101,6 +1162,9 @@ public class AudioRecord
|
||||
private native final int native_read_in_short_array(short[] audioData,
|
||||
int offsetInShorts, int sizeInShorts);
|
||||
|
||||
private native final int native_read_in_float_array(float[] audioData,
|
||||
int offsetInFloats, int sizeInFloats, boolean isBlocking);
|
||||
|
||||
private native final int native_read_in_direct_buffer(Object jBuffer, int sizeInBytes);
|
||||
|
||||
private native final int native_set_marker_pos(int marker);
|
||||
|
||||
Reference in New Issue
Block a user