[vlc-devel] [PATCH 4/6] audiotrack: refactor Write
Thomas Guillem
thomas at gllm.fr
Wed Mar 11 15:00:48 CET 2015
Don't change p_buffer internal values, but use a local offset to know the
position.
The main advantage is that we can use this offset with the Android write method
in order to avoid a Java copy when you call Write several time for the same
p_buffer.
---
modules/audio_output/audiotrack.c | 161 +++++++++++++++++++++++++-------------
1 file changed, 106 insertions(+), 55 deletions(-)
diff --git a/modules/audio_output/audiotrack.c b/modules/audio_output/audiotrack.c
index d388d1a..3bcb216 100644
--- a/modules/audio_output/audiotrack.c
+++ b/modules/audio_output/audiotrack.c
@@ -69,6 +69,10 @@ struct aout_sys_t {
int i_audiotrack_stuck_count;
uint8_t i_chans_to_reorder; /* do we need channel reordering */
uint8_t p_chan_table[AOUT_CHAN_MAX];
+ enum {
+ WRITE,
+ WRITE_V21
+ } i_write_type;
/* JNIThread control */
vlc_mutex_t mutex;
@@ -793,6 +797,17 @@ JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
}
#endif
+ if( jfields.AudioTrack.writeV21 )
+ {
+ msg_Dbg( p_aout, "using WRITE_V21");
+ p_sys->i_write_type = WRITE_V21;
+ }
+ else
+ {
+ msg_Dbg( p_aout, "using WRITE");
+ p_sys->i_write_type = WRITE;
+ }
+
JNI_AT_CALL_VOID( play );
CHECK_AT_EXCEPTION( "play" );
p_sys->i_play_time = mdate();
@@ -833,15 +848,16 @@ JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
* that we won't wait in AudioTrack.write() method
*/
static int
-JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
+JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
+ size_t i_buffer_offset )
{
aout_sys_t *p_sys = p_aout->sys;
- uint8_t *p_data = p_buffer->p_buffer;
size_t i_data;
uint32_t i_samples;
uint32_t i_audiotrack_pos;
uint32_t i_samples_pending;
+ i_data = p_buffer->i_buffer - i_buffer_offset;
i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
if( i_audiotrack_pos > p_sys->i_samples_written )
{
@@ -873,37 +889,12 @@ JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
} else
p_sys->i_audiotrack_stuck_count = 0;
i_samples = __MIN( p_sys->i_max_audiotrack_samples - i_samples_pending,
- p_buffer->i_nb_samples );
+ BYTES_TO_FRAMES( i_data ) );
i_data = i_samples * p_sys->i_bytes_per_frame;
- /* check if we need to realloc a ByteArray */
- if( i_data > p_sys->i_bytearray_size )
- {
- jbyteArray p_bytearray;
-
- if( p_sys->p_bytearray )
- {
- (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
- p_sys->p_bytearray = NULL;
- }
-
- p_bytearray = (*env)->NewByteArray( env, i_data );
- if( p_bytearray )
- {
- p_sys->p_bytearray = (*env)->NewGlobalRef( env, p_bytearray );
- (*env)->DeleteLocalRef( env, p_bytearray );
- }
- p_sys->i_bytearray_size = i_data;
- }
- if( !p_sys->p_bytearray )
- return jfields.AudioTrack.ERROR_BAD_VALUE;
-
- /* copy p_buffer in to ByteArray */
- (*env)->SetByteArrayRegion( env, p_sys->p_bytearray, 0, i_data,
- (jbyte *)p_data);
-
- return JNI_AT_CALL_INT( write, p_sys->p_bytearray, 0, i_data );
+ return JNI_AT_CALL_INT( write, p_sys->p_bytearray,
+ i_buffer_offset, i_data );
}
/**
@@ -911,17 +902,19 @@ JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
* It calls a new write method with WRITE_NON_BLOCKING flags.
*/
static int
-JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
+JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
+ size_t i_buffer_offset )
{
aout_sys_t *p_sys = p_aout->sys;
int i_ret;
+ size_t i_data = p_buffer->i_buffer - i_buffer_offset;
+ uint8_t *p_data = p_buffer->p_buffer + i_buffer_offset;
if( !p_sys->p_bytebuffer )
{
jobject p_bytebuffer;
- p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_buffer->p_buffer,
- p_buffer->i_buffer );
+ p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_data, i_data );
if( !p_bytebuffer )
return jfields.AudioTrack.ERROR_BAD_VALUE;
@@ -936,7 +929,7 @@ JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
}
}
- i_ret = JNI_AT_CALL_INT( writeV21, p_sys->p_bytebuffer, p_buffer->i_buffer,
+ i_ret = JNI_AT_CALL_INT( writeV21, p_sys->p_bytebuffer, i_data,
jfields.AudioTrack.WRITE_NON_BLOCKING );
if( i_ret > 0 )
{
@@ -949,17 +942,71 @@ JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
}
static int
+JNIThread_PreparePlay( JNIEnv *env, audio_output_t *p_aout,
+ block_t *p_buffer )
+{
+ aout_sys_t *p_sys = p_aout->sys;
+
+ if( p_sys->i_chans_to_reorder )
+ aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer,
+ p_sys->i_chans_to_reorder, p_sys->p_chan_table,
+ p_sys->fmt.i_format );
+
+ switch( p_sys->i_write_type )
+ {
+ case WRITE:
+ /* check if we need to realloc a ByteArray */
+ if( p_buffer->i_buffer > p_sys->i_bytearray_size )
+ {
+ jbyteArray p_bytearray;
+
+ if( p_sys->p_bytearray )
+ {
+ (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
+ p_sys->p_bytearray = NULL;
+ }
+
+ p_bytearray = (*env)->NewByteArray( env, p_buffer->i_buffer );
+ if( p_bytearray )
+ {
+ p_sys->p_bytearray = (*env)->NewGlobalRef( env, p_bytearray );
+ (*env)->DeleteLocalRef( env, p_bytearray );
+ }
+ p_sys->i_bytearray_size = p_buffer->i_buffer;
+ }
+ if( !p_sys->p_bytearray )
+ return VLC_EGENERIC;
+
+ /* copy p_buffer in to ByteArray */
+ (*env)->SetByteArrayRegion( env, p_sys->p_bytearray, 0,
+ p_buffer->i_buffer,
+ (jbyte *)p_buffer->p_buffer);
+ break;
+ case WRITE_V21:
+ break;
+ }
+
+ return VLC_SUCCESS;
+}
+
+static int
JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
- block_t **pp_buffer, mtime_t *p_wait )
+ block_t *p_buffer, size_t *p_buffer_offset, mtime_t *p_wait )
{
aout_sys_t *p_sys = p_aout->sys;
- block_t *p_buffer = *pp_buffer;
int i_ret;
- if( jfields.AudioTrack.writeV21 )
- i_ret = JNIThread_WriteV21( env, p_aout, p_buffer );
- else
- i_ret = JNIThread_Write( env, p_aout, p_buffer );
+ switch( p_sys->i_write_type )
+ {
+ case WRITE_V21:
+ i_ret = JNIThread_WriteV21( env, p_aout, p_buffer, *p_buffer_offset );
+ break;
+ case WRITE:
+ i_ret = JNIThread_Write( env, p_aout, p_buffer, *p_buffer_offset );
+ break;
+ default:
+ vlc_assert_unreachable();
+ }
if( i_ret < 0 ) {
if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
@@ -991,11 +1038,7 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
p_sys->i_samples_queued -= i_samples;
p_sys->i_samples_written += i_samples;
- p_buffer->p_buffer += i_ret;
- p_buffer->i_buffer -= i_ret;
- p_buffer->i_nb_samples -= i_samples;
- if( p_buffer->i_buffer == 0 )
- *pp_buffer = NULL;
+ *p_buffer_offset += i_ret;
/* HACK: There is a known issue in audiotrack, "due to an internal
* timeout within the AudioTrackThread". It happens after android
@@ -1004,7 +1047,7 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
* write. This hack is done only for API 19 (AudioTimestamp was added
* in API 19). */
- if( jfields.AudioTimestamp.clazz && !jfields.AudioTrack.writeV21 )
+ if( p_sys->i_write_type == WRITE && jfields.AudioTimestamp.clazz )
*p_wait = FRAMES_TO_US( i_samples ) / 2;
}
return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
@@ -1078,6 +1121,7 @@ JNIThread( void *data )
bool b_error = false;
bool b_paused = false;
block_t *p_buffer = NULL;
+ size_t i_buffer_offset = 0;
mtime_t i_play_deadline = 0;
JNIEnv* env;
@@ -1155,18 +1199,25 @@ JNIThread( void *data )
if( p_buffer == NULL )
{
p_buffer = p_cmd->in.play.p_buffer;
- if( p_sys->i_chans_to_reorder )
- aout_ChannelReorder( p_buffer->p_buffer,
- p_buffer->i_buffer,
- p_sys->i_chans_to_reorder,
- p_sys->p_chan_table,
- p_sys->fmt.i_format );
-
+ b_error = JNIThread_PreparePlay( env, p_aout, p_buffer )
+ != VLC_SUCCESS;
}
- b_error = JNIThread_Play( env, p_aout, &p_buffer,
+ if( b_error )
+ break;
+ b_error = JNIThread_Play( env, p_aout, p_buffer,
+ &i_buffer_offset,
&i_play_wait ) != VLC_SUCCESS;
- if( p_buffer != NULL )
+ if( i_buffer_offset < p_buffer->i_buffer )
+ {
+ /* buffer is not fully processed, try again with the
+ * same cmd and buffer */
b_remove_cmd = false;
+ }
+ else
+ {
+ p_buffer = NULL;
+ i_buffer_offset = 0;
+ }
if( i_play_wait > 0 )
i_play_deadline = mdate() + i_play_wait;
break;
--
2.1.3
More information about the vlc-devel
mailing list