Add non-blocking reads to AudioRecord
Change-Id: I63d5345129f197f96f9a13696996071c96551efe
This commit is contained in:
@@ -14910,9 +14910,12 @@ package android.media {
|
||||
method public int getSampleRate();
|
||||
method public int getState();
|
||||
method public int read(byte[], int, int);
|
||||
method public int read(byte[], int, int, int);
|
||||
method public int read(short[], int, int);
|
||||
method public int read(short[], int, int, int);
|
||||
method public int read(float[], int, int, int);
|
||||
method public int read(java.nio.ByteBuffer, int);
|
||||
method public int read(java.nio.ByteBuffer, int, int);
|
||||
method public void release();
|
||||
method public int setNotificationMarkerPosition(int);
|
||||
method public int setPositionNotificationPeriod(int);
|
||||
|
||||
@@ -16120,9 +16120,12 @@ package android.media {
|
||||
method public int getSampleRate();
|
||||
method public int getState();
|
||||
method public int read(byte[], int, int);
|
||||
method public int read(byte[], int, int, int);
|
||||
method public int read(short[], int, int);
|
||||
method public int read(short[], int, int, int);
|
||||
method public int read(float[], int, int, int);
|
||||
method public int read(java.nio.ByteBuffer, int);
|
||||
method public int read(java.nio.ByteBuffer, int, int);
|
||||
method public void release();
|
||||
method public int setNotificationMarkerPosition(int);
|
||||
method public int setPositionNotificationPeriod(int);
|
||||
|
||||
@@ -356,95 +356,58 @@ static void android_media_AudioRecord_finalize(JNIEnv *env, jobject thiz) {
|
||||
android_media_AudioRecord_release(env, thiz);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioRecord_readInByteArray(JNIEnv *env, jobject thiz,
|
||||
jbyteArray javaAudioData,
|
||||
jint offsetInBytes, jint sizeInBytes) {
|
||||
jbyte* recordBuff = NULL;
|
||||
// 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, can't record");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!javaAudioData) {
|
||||
ALOGE("Invalid Java array to store recorded audio, can't record");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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)
|
||||
recordBuff = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
|
||||
|
||||
if (recordBuff == NULL) {
|
||||
ALOGE("Error retrieving destination for recorded audio data, can't record");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read the new audio data from the native AudioRecord object
|
||||
ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes, sizeInBytes);
|
||||
env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
|
||||
|
||||
if (readSize < 0) {
|
||||
readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
|
||||
}
|
||||
return (jint) readSize;
|
||||
// overloaded JNI array helper functions
|
||||
static inline
|
||||
jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
|
||||
return env->GetByteArrayElements(array, isCopy);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioRecord_readInShortArray(JNIEnv *env, jobject thiz,
|
||||
jshortArray javaAudioData,
|
||||
jint offsetInShorts, jint sizeInShorts) {
|
||||
|
||||
jshort* recordBuff = NULL;
|
||||
// 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, can't record");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!javaAudioData) {
|
||||
ALOGE("Invalid Java array to store recorded audio, can't record");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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)
|
||||
recordBuff = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
|
||||
|
||||
if (recordBuff == NULL) {
|
||||
ALOGE("Error retrieving destination for recorded audio data, can't record");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// read the new audio data from the native AudioRecord object
|
||||
const size_t sizeInBytes = sizeInShorts * sizeof(short);
|
||||
ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts, sizeInBytes);
|
||||
|
||||
env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
|
||||
|
||||
if (readSize < 0) {
|
||||
readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
|
||||
} else {
|
||||
readSize /= sizeof(short);
|
||||
}
|
||||
return (jint) readSize;
|
||||
static inline
|
||||
void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
|
||||
env->ReleaseByteArrayElements(array, elems, mode);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioRecord_readInFloatArray(JNIEnv *env, jobject thiz,
|
||||
jfloatArray javaAudioData,
|
||||
jint offsetInFloats, jint sizeInFloats,
|
||||
jboolean isReadBlocking) {
|
||||
static inline
|
||||
jshort *envGetArrayElements(JNIEnv *env, jshortArray array, jboolean *isCopy) {
|
||||
return env->GetShortArrayElements(array, isCopy);
|
||||
}
|
||||
|
||||
static inline
|
||||
void envReleaseArrayElements(JNIEnv *env, jshortArray array, jshort *elems, jint mode) {
|
||||
env->ReleaseShortArrayElements(array, elems, mode);
|
||||
}
|
||||
|
||||
static inline
|
||||
jfloat *envGetArrayElements(JNIEnv *env, jfloatArray array, jboolean *isCopy) {
|
||||
return env->GetFloatArrayElements(array, isCopy);
|
||||
}
|
||||
|
||||
static inline
|
||||
void envReleaseArrayElements(JNIEnv *env, jfloatArray array, jfloat *elems, jint mode) {
|
||||
env->ReleaseFloatArrayElements(array, elems, mode);
|
||||
}
|
||||
|
||||
static inline
|
||||
jint interpretReadSizeError(ssize_t readSize) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static jint android_media_AudioRecord_readInArray(JNIEnv *env, jobject thiz,
|
||||
T javaAudioData,
|
||||
jint offsetInSamples, jint sizeInSamples,
|
||||
jboolean isReadBlocking) {
|
||||
// get the audio recorder from which we'll read new audio samples
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder == NULL) {
|
||||
@@ -453,76 +416,68 @@ static jint android_media_AudioRecord_readInFloatArray(JNIEnv *env, jobject thi
|
||||
}
|
||||
|
||||
if (javaAudioData == NULL) {
|
||||
ALOGE("Invalid Java array to store recorded audio");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
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);
|
||||
|
||||
// get the pointer to where we'll record the audio
|
||||
auto *recordBuff = envGetArrayElements(env, 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);
|
||||
const size_t sizeInBytes = sizeInSamples * sizeof(*recordBuff);
|
||||
ssize_t readSize = lpRecorder->read(
|
||||
recordBuff + offsetInSamples, sizeInBytes, isReadBlocking == JNI_TRUE /* blocking */);
|
||||
|
||||
env->ReleaseFloatArrayElements(javaAudioData, recordBuff, 0);
|
||||
envReleaseArrayElements(env, 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 interpretReadSizeError(readSize);
|
||||
}
|
||||
return (jint)(readSize / sizeof(float));
|
||||
return (jint)(readSize / sizeof(*recordBuff));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioRecord_readInDirectBuffer(JNIEnv *env, jobject thiz,
|
||||
jobject jBuffer, jint sizeInBytes) {
|
||||
jobject jBuffer, jint sizeInBytes,
|
||||
jboolean isReadBlocking) {
|
||||
// get the audio recorder from which we'll read new audio samples
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
if (lpRecorder==NULL)
|
||||
return 0;
|
||||
return (jint)AUDIO_JAVA_INVALID_OPERATION;
|
||||
|
||||
// direct buffer and direct access supported?
|
||||
long capacity = env->GetDirectBufferCapacity(jBuffer);
|
||||
if (capacity == -1) {
|
||||
// buffer direct access is not supported
|
||||
ALOGE("Buffer direct access is not supported, can't record");
|
||||
return 0;
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
//ALOGV("capacity = %ld", capacity);
|
||||
jbyte* nativeFromJavaBuf = (jbyte*) env->GetDirectBufferAddress(jBuffer);
|
||||
if (nativeFromJavaBuf==NULL) {
|
||||
ALOGE("Buffer direct access is not supported, can't record");
|
||||
return 0;
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
|
||||
// read new data from the recorder
|
||||
ssize_t readSize = lpRecorder->read(nativeFromJavaBuf,
|
||||
capacity < sizeInBytes ? capacity : sizeInBytes);
|
||||
capacity < sizeInBytes ? capacity : sizeInBytes,
|
||||
isReadBlocking == JNI_TRUE /* blocking */);
|
||||
if (readSize < 0) {
|
||||
readSize = (jint)AUDIO_JAVA_INVALID_OPERATION;
|
||||
return interpretReadSizeError(readSize);
|
||||
}
|
||||
return (jint)readSize;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioRecord_get_native_frame_count(JNIEnv *env, jobject thiz) {
|
||||
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
|
||||
@@ -633,12 +588,15 @@ static JNINativeMethod gMethods[] = {
|
||||
{"native_finalize", "()V", (void *)android_media_AudioRecord_finalize},
|
||||
{"native_release", "()V", (void *)android_media_AudioRecord_release},
|
||||
{"native_read_in_byte_array",
|
||||
"([BII)I", (void *)android_media_AudioRecord_readInByteArray},
|
||||
"([BIIZ)I",
|
||||
(void *)android_media_AudioRecord_readInArray<jbyteArray>},
|
||||
{"native_read_in_short_array",
|
||||
"([SII)I", (void *)android_media_AudioRecord_readInShortArray},
|
||||
"([SIIZ)I",
|
||||
(void *)android_media_AudioRecord_readInArray<jshortArray>},
|
||||
{"native_read_in_float_array",
|
||||
"([FIIZ)I", (void *)android_media_AudioRecord_readInFloatArray},
|
||||
{"native_read_in_direct_buffer","(Ljava/lang/Object;I)I",
|
||||
"([FIIZ)I",
|
||||
(void *)android_media_AudioRecord_readInArray<jfloatArray>},
|
||||
{"native_read_in_direct_buffer","(Ljava/lang/Object;IZ)I",
|
||||
(void *)android_media_AudioRecord_readInDirectBuffer},
|
||||
{"native_get_native_frame_count",
|
||||
"()I", (void *)android_media_AudioRecord_get_native_frame_count},
|
||||
|
||||
@@ -901,21 +901,48 @@ public class AudioRecord
|
||||
* the parameters don't resolve to valid data and indexes.
|
||||
* The number of bytes will not exceed sizeInBytes.
|
||||
*/
|
||||
public int read(byte[] audioData, int offsetInBytes, int sizeInBytes) {
|
||||
if (mState != STATE_INITIALIZED) {
|
||||
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
|
||||
return read(audioData, offsetInBytes, sizeInBytes, READ_BLOCKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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 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.
|
||||
*/
|
||||
public int read(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
|
||||
@ReadMode int readMode) {
|
||||
if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
|
||||
return ERROR_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
|
||||
Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
if ( (audioData == null) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
|
||||
|| (offsetInBytes + sizeInBytes < 0) // detect integer overflow
|
||||
|| (offsetInBytes + sizeInBytes > audioData.length)) {
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes);
|
||||
return native_read_in_byte_array(audioData, offsetInBytes, sizeInBytes,
|
||||
readMode == READ_BLOCKING);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads audio data from the audio hardware for recording into a short array.
|
||||
* The format specified in the AudioRecord constructor should be
|
||||
@@ -928,18 +955,46 @@ public class AudioRecord
|
||||
* the parameters don't resolve to valid data and indexes.
|
||||
* The number of shorts will not exceed sizeInShorts.
|
||||
*/
|
||||
public int read(short[] audioData, int offsetInShorts, int sizeInShorts) {
|
||||
if (mState != STATE_INITIALIZED) {
|
||||
public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
|
||||
return read(audioData, offsetInShorts, sizeInShorts, READ_BLOCKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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 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.
|
||||
*/
|
||||
public int read(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
|
||||
@ReadMode int readMode) {
|
||||
if (mState != STATE_INITIALIZED || mAudioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
|
||||
return ERROR_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
|
||||
Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
if ( (audioData == null) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
|
||||
|| (offsetInShorts + sizeInShorts < 0) // detect integer overflow
|
||||
|| (offsetInShorts + sizeInShorts > audioData.length)) {
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts);
|
||||
return native_read_in_short_array(audioData, offsetInShorts, sizeInShorts,
|
||||
readMode == READ_BLOCKING);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -950,22 +1005,33 @@ public class AudioRecord
|
||||
* @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
|
||||
* <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
|
||||
* <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,
|
||||
public int read(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
|
||||
@ReadMode int readMode) {
|
||||
if (mState != STATE_INITIALIZED) {
|
||||
if (mState == STATE_UNINITIALIZED) {
|
||||
Log.e(TAG, "AudioRecord.read() called in invalid state STATE_UNINITIALIZED");
|
||||
return ERROR_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if ( (audioData == null) || (offsetInFloats < 0 ) || (sizeInFloats < 0)
|
||||
if (mAudioFormat != AudioFormat.ENCODING_PCM_FLOAT) {
|
||||
Log.e(TAG, "AudioRecord.read(float[] ...) requires format ENCODING_PCM_FLOAT");
|
||||
return ERROR_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
|
||||
Log.e(TAG, "AudioRecord.read() 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)) {
|
||||
return ERROR_BAD_VALUE;
|
||||
@@ -992,19 +1058,49 @@ public class AudioRecord
|
||||
* 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) {
|
||||
public int read(@NonNull ByteBuffer audioBuffer, int sizeInBytes) {
|
||||
return read(audioBuffer, sizeInBytes, 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. 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).
|
||||
* @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 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(@NonNull ByteBuffer audioBuffer, int sizeInBytes, @ReadMode int readMode) {
|
||||
if (mState != STATE_INITIALIZED) {
|
||||
return ERROR_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if ((readMode != READ_BLOCKING) && (readMode != READ_NON_BLOCKING)) {
|
||||
Log.e(TAG, "AudioRecord.read() called with invalid blocking mode");
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
if ( (audioBuffer == null) || (sizeInBytes < 0) ) {
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
return native_read_in_direct_buffer(audioBuffer, sizeInBytes);
|
||||
return native_read_in_direct_buffer(audioBuffer, sizeInBytes, readMode == READ_BLOCKING);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Initialization / configuration
|
||||
//--------------------
|
||||
@@ -1186,15 +1282,16 @@ public class AudioRecord
|
||||
private native final void native_stop();
|
||||
|
||||
private native final int native_read_in_byte_array(byte[] audioData,
|
||||
int offsetInBytes, int sizeInBytes);
|
||||
int offsetInBytes, int sizeInBytes, boolean isBlocking);
|
||||
|
||||
private native final int native_read_in_short_array(short[] audioData,
|
||||
int offsetInShorts, int sizeInShorts);
|
||||
int offsetInShorts, int sizeInShorts, boolean isBlocking);
|
||||
|
||||
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_read_in_direct_buffer(Object jBuffer,
|
||||
int sizeInBytes, boolean isBlocking);
|
||||
|
||||
private native final int native_get_native_frame_count();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user