Merge "Add non-blocking writes to AudioTrack"
This commit is contained in:
@@ -15001,7 +15001,9 @@ package android.media {
|
||||
method public int setVolume(float);
|
||||
method public void stop() throws java.lang.IllegalStateException;
|
||||
method public int write(byte[], int, int);
|
||||
method public int write(byte[], int, int, int);
|
||||
method public int write(short[], int, int);
|
||||
method public int write(short[], int, int, int);
|
||||
method public int write(float[], int, int, int);
|
||||
method public int write(java.nio.ByteBuffer, int, int);
|
||||
field public static final int ERROR = -1; // 0xffffffff
|
||||
|
||||
@@ -16213,7 +16213,9 @@ package android.media {
|
||||
method public int setVolume(float);
|
||||
method public void stop() throws java.lang.IllegalStateException;
|
||||
method public int write(byte[], int, int);
|
||||
method public int write(byte[], int, int, int);
|
||||
method public int write(short[], int, int);
|
||||
method public int write(short[], int, int, int);
|
||||
method public int write(float[], int, int, int);
|
||||
method public int write(java.nio.ByteBuffer, int, int);
|
||||
field public static final int ERROR = -1; // 0xffffffff
|
||||
|
||||
@@ -510,14 +510,47 @@ static void android_media_AudioTrack_finalize(JNIEnv *env, jobject thiz) {
|
||||
android_media_AudioTrack_release(env, thiz);
|
||||
}
|
||||
|
||||
// overloaded JNI array helper functions (same as in android_media_AudioRecord)
|
||||
static inline
|
||||
jbyte *envGetArrayElements(JNIEnv *env, jbyteArray array, jboolean *isCopy) {
|
||||
return env->GetByteArrayElements(array, isCopy);
|
||||
}
|
||||
|
||||
static inline
|
||||
void envReleaseArrayElements(JNIEnv *env, jbyteArray array, jbyte *elems, jint mode) {
|
||||
env->ReleaseByteArrayElements(array, elems, mode);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const jbyte* data,
|
||||
jint offsetInBytes, jint sizeInBytes, bool blocking = true) {
|
||||
template <typename T>
|
||||
static jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const T *data,
|
||||
jint offsetInSamples, jint sizeInSamples, bool blocking) {
|
||||
// give the data to the native AudioTrack object (the data starts at the offset)
|
||||
ssize_t written = 0;
|
||||
// regular write() or copy the data to the AudioTrack's shared memory?
|
||||
size_t sizeInBytes = sizeInSamples * sizeof(T);
|
||||
if (track->sharedBuffer() == 0) {
|
||||
written = track->write(data + offsetInBytes, sizeInBytes, blocking);
|
||||
written = track->write(data + offsetInSamples, sizeInBytes, blocking);
|
||||
// for compatibility with earlier behavior of write(), return 0 in this case
|
||||
if (written == (ssize_t) WOULD_BLOCK) {
|
||||
written = 0;
|
||||
@@ -527,55 +560,59 @@ jint writeToTrack(const sp<AudioTrack>& track, jint audioFormat, const jbyte* da
|
||||
if ((size_t)sizeInBytes > track->sharedBuffer()->size()) {
|
||||
sizeInBytes = track->sharedBuffer()->size();
|
||||
}
|
||||
memcpy(track->sharedBuffer()->pointer(), data + offsetInBytes, sizeInBytes);
|
||||
memcpy(track->sharedBuffer()->pointer(), data + offsetInSamples, sizeInBytes);
|
||||
written = sizeInBytes;
|
||||
}
|
||||
if (written > 0) {
|
||||
return written / sizeof(T);
|
||||
}
|
||||
// for compatibility, error codes pass through unchanged
|
||||
return written;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioTrack_write_byte(JNIEnv *env, jobject thiz,
|
||||
jbyteArray javaAudioData,
|
||||
jint offsetInBytes, jint sizeInBytes,
|
||||
jint javaAudioFormat,
|
||||
jboolean isWriteBlocking) {
|
||||
//ALOGV("android_media_AudioTrack_write_byte(offset=%d, sizeInBytes=%d) called",
|
||||
// offsetInBytes, sizeInBytes);
|
||||
template <typename T>
|
||||
static jint android_media_AudioTrack_writeArray(JNIEnv *env, jobject thiz,
|
||||
T javaAudioData,
|
||||
jint offsetInSamples, jint sizeInSamples,
|
||||
jint javaAudioFormat,
|
||||
jboolean isWriteBlocking) {
|
||||
//ALOGV("android_media_AudioTrack_writeArray(offset=%d, sizeInSamples=%d) called",
|
||||
// offsetInSamples, sizeInSamples);
|
||||
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
|
||||
if (lpTrack == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Unable to retrieve AudioTrack pointer for write()");
|
||||
return 0;
|
||||
return (jint)AUDIO_JAVA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
if (javaAudioData == NULL) {
|
||||
ALOGE("NULL java array of audio data to play");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE;
|
||||
}
|
||||
|
||||
// get the pointer for the audio data from the java array
|
||||
// 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)
|
||||
jbyte* cAudioData = NULL;
|
||||
if (javaAudioData) {
|
||||
cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
|
||||
if (cAudioData == NULL) {
|
||||
ALOGE("Error retrieving source of audio data to play, can't play");
|
||||
return 0; // out of memory or no data to load
|
||||
}
|
||||
} else {
|
||||
ALOGE("NULL java array of audio data to play, can't play");
|
||||
return 0;
|
||||
|
||||
// get the pointer for the audio data from the java array
|
||||
auto cAudioData = envGetArrayElements(env, javaAudioData, NULL);
|
||||
if (cAudioData == NULL) {
|
||||
ALOGE("Error retrieving source of audio data to play");
|
||||
return (jint)AUDIO_JAVA_BAD_VALUE; // out of memory or no data to load
|
||||
}
|
||||
|
||||
jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes,
|
||||
isWriteBlocking == JNI_TRUE /* blocking */);
|
||||
jint samplesWritten = writeToTrack(lpTrack, javaAudioFormat, cAudioData,
|
||||
offsetInSamples, sizeInSamples, isWriteBlocking == JNI_TRUE /* blocking */);
|
||||
|
||||
env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
|
||||
envReleaseArrayElements(env, javaAudioData, cAudioData, 0);
|
||||
|
||||
//ALOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
|
||||
// (int)written, (int)(sizeInBytes), (int)offsetInBytes);
|
||||
return written;
|
||||
//ALOGV("write wrote %d (tried %d) samples in the native AudioTrack with offset %d",
|
||||
// (int)samplesWritten, (int)(sizeInSamples), (int)offsetInSamples);
|
||||
return samplesWritten;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject thiz,
|
||||
jbyteArray javaBytes, jint byteOffset, jint sizeInBytes,
|
||||
@@ -586,7 +623,7 @@ static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject th
|
||||
if (lpTrack == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Unable to retrieve AudioTrack pointer for write()");
|
||||
return 0;
|
||||
return (jint)AUDIO_JAVA_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
ScopedBytesRO bytes(env, javaBytes);
|
||||
@@ -601,90 +638,6 @@ static jint android_media_AudioTrack_write_native_bytes(JNIEnv *env, jobject th
|
||||
return written;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioTrack_write_short(JNIEnv *env, jobject thiz,
|
||||
jshortArray javaAudioData,
|
||||
jint offsetInShorts, jint sizeInShorts,
|
||||
jint javaAudioFormat) {
|
||||
|
||||
//ALOGV("android_media_AudioTrack_write_short(offset=%d, sizeInShorts=%d) called",
|
||||
// offsetInShorts, sizeInShorts);
|
||||
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
|
||||
if (lpTrack == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Unable to retrieve AudioTrack pointer for write()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get the pointer for the audio data from the java array
|
||||
// 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)
|
||||
jshort* cAudioData = NULL;
|
||||
if (javaAudioData) {
|
||||
cAudioData = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
|
||||
if (cAudioData == NULL) {
|
||||
ALOGE("Error retrieving source of audio data to play, can't play");
|
||||
return 0; // out of memory or no data to load
|
||||
}
|
||||
} else {
|
||||
ALOGE("NULL java array of audio data to play, can't play");
|
||||
return 0;
|
||||
}
|
||||
jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
|
||||
offsetInShorts * sizeof(short), sizeInShorts * sizeof(short),
|
||||
true /*blocking write, legacy behavior*/);
|
||||
env->ReleaseShortArrayElements(javaAudioData, cAudioData, 0);
|
||||
|
||||
if (written > 0) {
|
||||
written /= sizeof(short);
|
||||
}
|
||||
//ALOGV("write wrote %d (tried %d) shorts in the native AudioTrack with offset %d",
|
||||
// (int)written, (int)(sizeInShorts), (int)offsetInShorts);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioTrack_write_float(JNIEnv *env, jobject thiz,
|
||||
jfloatArray javaAudioData,
|
||||
jint offsetInFloats, jint sizeInFloats,
|
||||
jint javaAudioFormat,
|
||||
jboolean isWriteBlocking) {
|
||||
|
||||
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
|
||||
if (lpTrack == NULL) {
|
||||
jniThrowException(env, "java/lang/IllegalStateException",
|
||||
"Unable to retrieve AudioTrack pointer for write()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
jfloat* cAudioData = NULL;
|
||||
if (javaAudioData) {
|
||||
cAudioData = (jfloat *)env->GetFloatArrayElements(javaAudioData, NULL);
|
||||
if (cAudioData == NULL) {
|
||||
ALOGE("Error retrieving source of audio data to play, can't play");
|
||||
return 0; // out of memory or no data to load
|
||||
}
|
||||
} else {
|
||||
ALOGE("NULL java array of audio data to play, can't play");
|
||||
return 0;
|
||||
}
|
||||
jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
|
||||
offsetInFloats * sizeof(float), sizeInFloats * sizeof(float),
|
||||
isWriteBlocking == JNI_TRUE /* blocking */);
|
||||
env->ReleaseFloatArrayElements(javaAudioData, cAudioData, 0);
|
||||
|
||||
if (written > 0) {
|
||||
written /= sizeof(float);
|
||||
}
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
static jint android_media_AudioTrack_get_native_frame_count(JNIEnv *env, jobject thiz) {
|
||||
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
|
||||
@@ -976,12 +929,12 @@ static JNINativeMethod gMethods[] = {
|
||||
(void *)android_media_AudioTrack_setup},
|
||||
{"native_finalize", "()V", (void *)android_media_AudioTrack_finalize},
|
||||
{"native_release", "()V", (void *)android_media_AudioTrack_release},
|
||||
{"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_write_byte},
|
||||
{"native_write_byte", "([BIIIZ)I",(void *)android_media_AudioTrack_writeArray<jbyteArray>},
|
||||
{"native_write_native_bytes",
|
||||
"(Ljava/lang/Object;IIIZ)I",
|
||||
(void *)android_media_AudioTrack_write_native_bytes},
|
||||
{"native_write_short", "([SIII)I", (void *)android_media_AudioTrack_write_short},
|
||||
{"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_write_float},
|
||||
{"native_write_short", "([SIIIZ)I",(void *)android_media_AudioTrack_writeArray<jshortArray>},
|
||||
{"native_write_float", "([FIIIZ)I",(void *)android_media_AudioTrack_writeArray<jfloatArray>},
|
||||
{"native_setVolume", "(FF)V", (void *)android_media_AudioTrack_set_volume},
|
||||
{"native_get_native_frame_count",
|
||||
"()I", (void *)android_media_AudioTrack_get_native_frame_count},
|
||||
|
||||
@@ -1540,6 +1540,8 @@ 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).
|
||||
* The format specified in the AudioTrack constructor should be
|
||||
* {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
|
||||
* In streaming mode, will block until all data has been written to the audio sink.
|
||||
* In static buffer mode, copies the data to the buffer starting at offset 0.
|
||||
* Note that the actual playback of this data might occur after this function
|
||||
@@ -1556,13 +1558,49 @@ public class AudioTrack
|
||||
* {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
|
||||
* needs to be recreated.
|
||||
*/
|
||||
public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes) {
|
||||
return write(audioData, offsetInBytes, sizeInBytes, WRITE_BLOCKING);
|
||||
}
|
||||
|
||||
public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) {
|
||||
/**
|
||||
* Writes the audio data to the audio sink for playback (streaming mode),
|
||||
* or copies audio data for later playback (static buffer mode).
|
||||
* The format specified in the AudioTrack constructor should be
|
||||
* {@link AudioFormat#ENCODING_PCM_8BIT} to correspond to the data in the array.
|
||||
* In streaming mode, will block until all data has been written to the audio sink.
|
||||
* In static buffer mode, copies the data to the buffer starting at offset 0.
|
||||
* 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.
|
||||
*
|
||||
* @param audioData the array that holds the data to play.
|
||||
* @param offsetInBytes the offset expressed in bytes in audioData where the data to play
|
||||
* starts.
|
||||
* @param sizeInBytes the number of bytes 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 bytes 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, or
|
||||
* {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
|
||||
* needs to be recreated.
|
||||
*/
|
||||
public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,
|
||||
@WriteMode int writeMode) {
|
||||
|
||||
if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.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) || (offsetInBytes < 0 ) || (sizeInBytes < 0)
|
||||
|| (offsetInBytes + sizeInBytes < 0) // detect integer overflow
|
||||
|| (offsetInBytes + sizeInBytes > audioData.length)) {
|
||||
@@ -1570,7 +1608,7 @@ public class AudioTrack
|
||||
}
|
||||
|
||||
int ret = native_write_byte(audioData, offsetInBytes, sizeInBytes, mAudioFormat,
|
||||
true /*isBlocking*/);
|
||||
writeMode == WRITE_BLOCKING);
|
||||
|
||||
if ((mDataLoadMode == MODE_STATIC)
|
||||
&& (mState == STATE_NO_STATIC_DATA)
|
||||
@@ -1582,10 +1620,11 @@ public class AudioTrack
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the audio data to the audio sink for playback (streaming mode),
|
||||
* or copies audio data for later playback (static buffer mode).
|
||||
* The format specified in the AudioTrack constructor should be
|
||||
* {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
|
||||
* In streaming mode, will block until all data has been written to the audio sink.
|
||||
* In static buffer mode, copies the data to the buffer starting at offset 0.
|
||||
* Note that the actual playback of this data might occur after this function
|
||||
@@ -1602,20 +1641,57 @@ public class AudioTrack
|
||||
* {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
|
||||
* needs to be recreated.
|
||||
*/
|
||||
public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts) {
|
||||
return write(audioData, offsetInShorts, sizeInShorts, WRITE_BLOCKING);
|
||||
}
|
||||
|
||||
public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
|
||||
/**
|
||||
* Writes the audio data to the audio sink for playback (streaming mode),
|
||||
* or copies audio data for later playback (static buffer mode).
|
||||
* The format specified in the AudioTrack constructor should be
|
||||
* {@link AudioFormat#ENCODING_PCM_16BIT} to correspond to the data in the array.
|
||||
* In streaming mode, will block until all data has been written to the audio sink.
|
||||
* In static buffer mode, copies the data to the buffer starting at offset 0.
|
||||
* 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.
|
||||
*
|
||||
* @param audioData the array that holds the data to play.
|
||||
* @param offsetInShorts the offset expressed in shorts in audioData where the data to play
|
||||
* starts.
|
||||
* @param sizeInShorts the number of shorts 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 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, or
|
||||
* {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
|
||||
* needs to be recreated.
|
||||
*/
|
||||
public int write(@NonNull short[] audioData, int offsetInShorts, int sizeInShorts,
|
||||
@WriteMode int writeMode) {
|
||||
|
||||
if (mState == STATE_UNINITIALIZED || mAudioFormat == AudioFormat.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) || (offsetInShorts < 0 ) || (sizeInShorts < 0)
|
||||
|| (offsetInShorts + sizeInShorts < 0) // detect integer overflow
|
||||
|| (offsetInShorts + sizeInShorts > audioData.length)) {
|
||||
return ERROR_BAD_VALUE;
|
||||
}
|
||||
|
||||
int ret = native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat);
|
||||
int ret = native_write_short(audioData, offsetInShorts, sizeInShorts, mAudioFormat,
|
||||
writeMode == WRITE_BLOCKING);
|
||||
|
||||
if ((mDataLoadMode == MODE_STATIC)
|
||||
&& (mState == STATE_NO_STATIC_DATA)
|
||||
@@ -1627,10 +1703,11 @@ public class AudioTrack
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes the audio data to the audio sink for playback (streaming mode),
|
||||
* or copies audio data for later playback (static buffer mode).
|
||||
* The format specified in the AudioTrack constructor should be
|
||||
* {@link AudioFormat#ENCODING_PCM_FLOAT} to correspond to the data in the array.
|
||||
* 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.
|
||||
@@ -1654,9 +1731,9 @@ public class AudioTrack
|
||||
* @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
|
||||
* <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
|
||||
* <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
|
||||
@@ -1664,7 +1741,7 @@ public class AudioTrack
|
||||
* {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
|
||||
* needs to be recreated.
|
||||
*/
|
||||
public int write(float[] audioData, int offsetInFloats, int sizeInFloats,
|
||||
public int write(@NonNull float[] audioData, int offsetInFloats, int sizeInFloats,
|
||||
@WriteMode int writeMode) {
|
||||
|
||||
if (mState == STATE_UNINITIALIZED) {
|
||||
@@ -1727,7 +1804,7 @@ public class AudioTrack
|
||||
* {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
|
||||
* needs to be recreated.
|
||||
*/
|
||||
public int write(ByteBuffer audioData, int sizeInBytes,
|
||||
public int write(@NonNull ByteBuffer audioData, int sizeInBytes,
|
||||
@WriteMode int writeMode) {
|
||||
|
||||
if (mState == STATE_UNINITIALIZED) {
|
||||
@@ -2017,7 +2094,8 @@ public class AudioTrack
|
||||
boolean isBlocking);
|
||||
|
||||
private native final int native_write_short(short[] audioData,
|
||||
int offsetInShorts, int sizeInShorts, int format);
|
||||
int offsetInShorts, int sizeInShorts, int format,
|
||||
boolean isBlocking);
|
||||
|
||||
private native final int native_write_float(float[] audioData,
|
||||
int offsetInFloats, int sizeInFloats, int format,
|
||||
|
||||
Reference in New Issue
Block a user