[vlc-devel] [PATCH 3/4] audiotrack: add WriteV21 (for Lollipop)
Thomas Guillem
thomas at gllm.fr
Tue Mar 3 18:05:39 CET 2015
There is a new write method that can be non blocking and that can use a direct
ByteBuffer (no memcpy between java and jni).
---
modules/audio_output/audiotrack.c | 71 +++++++++++++++++++++++++++++++++++++--
1 file changed, 68 insertions(+), 3 deletions(-)
diff --git a/modules/audio_output/audiotrack.c b/modules/audio_output/audiotrack.c
index f4a4d03..0d5cb81 100644
--- a/modules/audio_output/audiotrack.c
+++ b/modules/audio_output/audiotrack.c
@@ -55,8 +55,9 @@ struct aout_sys_t {
/* Owned by JNIThread */
jobject p_audiotrack; /* AudioTrack ref */
jobject p_audioTimestamp; /* AudioTimestamp ref */
- jbyteArray p_bytearray; /* ByteArray ref */
+ jbyteArray p_bytearray; /* ByteArray ref (for Write) */
size_t i_bytearray_size; /* size of the ByteArray */
+ jobject p_bytebuffer; /* ByteBuffer ref (for WriteV21) */
audio_sample_format_t fmt; /* fmt setup by Start */
uint32_t i_pos_initial; /* initial position set by getPlaybackHeadPosition */
uint32_t i_samples_written; /* number of samples written since last flush */
@@ -150,6 +151,7 @@ static struct
jmethodID flush;
jmethodID pause;
jmethodID write;
+ jmethodID writeV21;
jmethodID getPlaybackHeadPosition;
jmethodID getTimestamp;
jmethodID getMinBufferSize;
@@ -158,6 +160,7 @@ static struct
jint ERROR;
jint ERROR_BAD_VALUE;
jint ERROR_INVALID_OPERATION;
+ jint WRITE_NON_BLOCKING;
} AudioTrack;
struct {
jint ENCODING_PCM_8BIT;
@@ -251,7 +254,14 @@ InitJNIFields( audio_output_t *p_aout )
GET_ID( GetMethodID, AudioTrack.stop, "stop", "()V", true );
GET_ID( GetMethodID, AudioTrack.flush, "flush", "()V", true );
GET_ID( GetMethodID, AudioTrack.pause, "pause", "()V", true );
- GET_ID( GetMethodID, AudioTrack.write, "write", "([BII)I", true );
+
+ GET_ID( GetMethodID, AudioTrack.writeV21, "write", "(Ljava/nio/ByteBuffer;II)I", false );
+ if( jfields.AudioTrack.writeV21 )
+ {
+ jfields.AudioTrack.write = NULL;
+ GET_CONST_INT( AudioTrack.WRITE_NON_BLOCKING, "WRITE_NON_BLOCKING", true );
+ } else
+ GET_ID( GetMethodID, AudioTrack.write, "write", "([BII)I", true );
GET_ID( GetMethodID, AudioTrack.getTimestamp,
"getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
@@ -717,6 +727,50 @@ JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
return JNI_AT_CALL_INT( write, p_sys->p_bytearray, 0, i_data );
}
+/**
+ * JNIThread_Write doesn't always work on Lollipop. Probably because audiotrack
+ * buffer size is bigger than the one we pass in ctor arguments (and there is
+ * no way to know it). It's not an issue since there is a new write method that
+ * is non blocking.
+ */
+static int
+JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
+{
+ aout_sys_t *p_sys = p_aout->sys;
+ int i_ret;
+
+ if( !p_sys->p_bytebuffer )
+ {
+ jobject p_bytebuffer;
+
+ p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_buffer->p_buffer,
+ p_buffer->i_buffer );
+ if( !p_bytebuffer )
+ return jfields.AudioTrack.ERROR_BAD_VALUE;
+
+ p_sys->p_bytebuffer = (*env)->NewGlobalRef( env, p_bytebuffer );
+ (*env)->DeleteLocalRef( env, p_bytebuffer );
+
+ if( !p_sys->p_bytebuffer || (*env)->ExceptionOccurred( env ) )
+ {
+ p_sys->p_bytebuffer = NULL;
+ (*env)->ExceptionClear( env );
+ return jfields.AudioTrack.ERROR_BAD_VALUE;
+ }
+ }
+
+ i_ret = JNI_AT_CALL_INT( writeV21, p_sys->p_bytebuffer, p_buffer->i_buffer,
+ jfields.AudioTrack.WRITE_NON_BLOCKING );
+ if( i_ret > 0 )
+ {
+ /* don't delete the bytebuffer if we wrote nothing, keep it for next
+ * call */
+ (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
+ p_sys->p_bytebuffer = NULL;
+ }
+ return i_ret;
+}
+
static int
JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
block_t **pp_buffer, mtime_t *p_wait )
@@ -725,7 +779,10 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
block_t *p_buffer = *pp_buffer;
int i_ret;
- i_ret = JNIThread_Write( env, p_aout, p_buffer );
+ if( jfields.AudioTrack.writeV21 )
+ i_ret = JNIThread_WriteV21( env, p_aout, p_buffer );
+ else
+ i_ret = JNIThread_Write( env, p_aout, p_buffer );
if( i_ret < 0 ) {
if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
@@ -816,6 +873,12 @@ JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
JNI_AT_CALL_VOID( play );
CHECK_AT_EXCEPTION( "play" );
p_sys->i_play_time = mdate();
+
+ if( p_sys->p_bytebuffer )
+ {
+ (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
+ p_sys->p_bytebuffer = NULL;
+ }
}
static void *
@@ -951,6 +1014,8 @@ end:
{
if( p_sys->p_bytearray )
(*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
+ if( p_sys->p_bytebuffer )
+ (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
jni_detach_thread();
}
vlc_mutex_unlock( &p_sys->mutex );
--
2.1.3
More information about the vlc-devel
mailing list