Commit 4ea3c307 authored by Thomas Guillem's avatar Thomas Guillem Committed by Jean-Baptiste Kempf

audiotrack: add WriteV21 (for Lollipop)

There is a new write method that can be non blocking and that can use a direct
ByteBuffer (no memcpy between java and jni).
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent a0107422
...@@ -55,8 +55,9 @@ struct aout_sys_t { ...@@ -55,8 +55,9 @@ struct aout_sys_t {
/* Owned by JNIThread */ /* Owned by JNIThread */
jobject p_audiotrack; /* AudioTrack ref */ jobject p_audiotrack; /* AudioTrack ref */
jobject p_audioTimestamp; /* AudioTimestamp 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 */ 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 */ audio_sample_format_t fmt; /* fmt setup by Start */
uint32_t i_pos_initial; /* initial position set by getPlaybackHeadPosition */ uint32_t i_pos_initial; /* initial position set by getPlaybackHeadPosition */
uint32_t i_samples_written; /* number of samples written since last flush */ uint32_t i_samples_written; /* number of samples written since last flush */
...@@ -150,6 +151,7 @@ static struct ...@@ -150,6 +151,7 @@ static struct
jmethodID flush; jmethodID flush;
jmethodID pause; jmethodID pause;
jmethodID write; jmethodID write;
jmethodID writeV21;
jmethodID getPlaybackHeadPosition; jmethodID getPlaybackHeadPosition;
jmethodID getTimestamp; jmethodID getTimestamp;
jmethodID getMinBufferSize; jmethodID getMinBufferSize;
...@@ -158,6 +160,7 @@ static struct ...@@ -158,6 +160,7 @@ static struct
jint ERROR; jint ERROR;
jint ERROR_BAD_VALUE; jint ERROR_BAD_VALUE;
jint ERROR_INVALID_OPERATION; jint ERROR_INVALID_OPERATION;
jint WRITE_NON_BLOCKING;
} AudioTrack; } AudioTrack;
struct { struct {
jint ENCODING_PCM_8BIT; jint ENCODING_PCM_8BIT;
...@@ -251,7 +254,14 @@ InitJNIFields( audio_output_t *p_aout ) ...@@ -251,7 +254,14 @@ InitJNIFields( audio_output_t *p_aout )
GET_ID( GetMethodID, AudioTrack.stop, "stop", "()V", true ); GET_ID( GetMethodID, AudioTrack.stop, "stop", "()V", true );
GET_ID( GetMethodID, AudioTrack.flush, "flush", "()V", true ); GET_ID( GetMethodID, AudioTrack.flush, "flush", "()V", true );
GET_ID( GetMethodID, AudioTrack.pause, "pause", "()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, GET_ID( GetMethodID, AudioTrack.getTimestamp,
"getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false ); "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
...@@ -717,6 +727,50 @@ JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer ) ...@@ -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 ); 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 static int
JNIThread_Play( JNIEnv *env, audio_output_t *p_aout, JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
block_t **pp_buffer, mtime_t *p_wait ) block_t **pp_buffer, mtime_t *p_wait )
...@@ -725,7 +779,10 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout, ...@@ -725,7 +779,10 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
block_t *p_buffer = *pp_buffer; block_t *p_buffer = *pp_buffer;
int i_ret; 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( i_ret < 0 ) {
if( jfields.AudioManager.has_ERROR_DEAD_OBJECT if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
...@@ -816,6 +873,12 @@ JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout, ...@@ -816,6 +873,12 @@ JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
JNI_AT_CALL_VOID( play ); JNI_AT_CALL_VOID( play );
CHECK_AT_EXCEPTION( "play" ); CHECK_AT_EXCEPTION( "play" );
p_sys->i_play_time = mdate(); 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 * static void *
...@@ -951,6 +1014,8 @@ end: ...@@ -951,6 +1014,8 @@ end:
{ {
if( p_sys->p_bytearray ) if( p_sys->p_bytearray )
(*env)->DeleteGlobalRef( env, 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(); jni_detach_thread();
} }
vlc_mutex_unlock( &p_sys->mutex ); vlc_mutex_unlock( &p_sys->mutex );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment