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

audiotrack: refactor Write

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.
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 3bf78587
...@@ -69,6 +69,10 @@ struct aout_sys_t { ...@@ -69,6 +69,10 @@ struct aout_sys_t {
int i_audiotrack_stuck_count; int i_audiotrack_stuck_count;
uint8_t i_chans_to_reorder; /* do we need channel reordering */ uint8_t i_chans_to_reorder; /* do we need channel reordering */
uint8_t p_chan_table[AOUT_CHAN_MAX]; uint8_t p_chan_table[AOUT_CHAN_MAX];
enum {
WRITE,
WRITE_V21
} i_write_type;
/* JNIThread control */ /* JNIThread control */
vlc_mutex_t mutex; vlc_mutex_t mutex;
...@@ -793,6 +797,17 @@ JNIThread_Start( JNIEnv *env, audio_output_t *p_aout ) ...@@ -793,6 +797,17 @@ JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
} }
#endif #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 ); 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();
...@@ -833,15 +848,16 @@ JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout ) ...@@ -833,15 +848,16 @@ JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
* that we won't wait in AudioTrack.write() method * that we won't wait in AudioTrack.write() method
*/ */
static int 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; aout_sys_t *p_sys = p_aout->sys;
uint8_t *p_data = p_buffer->p_buffer;
size_t i_data; size_t i_data;
uint32_t i_samples; uint32_t i_samples;
uint32_t i_audiotrack_pos; uint32_t i_audiotrack_pos;
uint32_t i_samples_pending; uint32_t i_samples_pending;
i_data = p_buffer->i_buffer - i_buffer_offset;
i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout ); i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
if( i_audiotrack_pos > p_sys->i_samples_written ) 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 ) ...@@ -873,37 +889,12 @@ JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
} else } else
p_sys->i_audiotrack_stuck_count = 0; p_sys->i_audiotrack_stuck_count = 0;
i_samples = __MIN( p_sys->i_max_audiotrack_samples - i_samples_pending, 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; i_data = i_samples * p_sys->i_bytes_per_frame;
/* check if we need to realloc a ByteArray */ return JNI_AT_CALL_INT( write, p_sys->p_bytearray,
if( i_data > p_sys->i_bytearray_size ) i_buffer_offset, i_data );
{
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 );
} }
/** /**
...@@ -911,17 +902,19 @@ JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer ) ...@@ -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. * It calls a new write method with WRITE_NON_BLOCKING flags.
*/ */
static int 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; aout_sys_t *p_sys = p_aout->sys;
int i_ret; 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 ) if( !p_sys->p_bytebuffer )
{ {
jobject p_bytebuffer; jobject p_bytebuffer;
p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_buffer->p_buffer, p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_data, i_data );
p_buffer->i_buffer );
if( !p_bytebuffer ) if( !p_bytebuffer )
return jfields.AudioTrack.ERROR_BAD_VALUE; return jfields.AudioTrack.ERROR_BAD_VALUE;
...@@ -936,7 +929,7 @@ JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer ) ...@@ -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 ); jfields.AudioTrack.WRITE_NON_BLOCKING );
if( i_ret > 0 ) if( i_ret > 0 )
{ {
...@@ -948,18 +941,72 @@ JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer ) ...@@ -948,18 +941,72 @@ JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
return i_ret; return i_ret;
} }
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 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 *p_buffer, size_t *p_buffer_offset, mtime_t *p_wait )
{ {
aout_sys_t *p_sys = p_aout->sys; aout_sys_t *p_sys = p_aout->sys;
block_t *p_buffer = *pp_buffer;
int i_ret; int i_ret;
if( jfields.AudioTrack.writeV21 ) switch( p_sys->i_write_type )
i_ret = JNIThread_WriteV21( env, p_aout, p_buffer ); {
else case WRITE_V21:
i_ret = JNIThread_Write( env, p_aout, p_buffer ); 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( i_ret < 0 ) {
if( jfields.AudioManager.has_ERROR_DEAD_OBJECT if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
...@@ -991,11 +1038,7 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout, ...@@ -991,11 +1038,7 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
p_sys->i_samples_queued -= i_samples; p_sys->i_samples_queued -= i_samples;
p_sys->i_samples_written += i_samples; p_sys->i_samples_written += i_samples;
p_buffer->p_buffer += i_ret; *p_buffer_offset += i_ret;
p_buffer->i_buffer -= i_ret;
p_buffer->i_nb_samples -= i_samples;
if( p_buffer->i_buffer == 0 )
*pp_buffer = NULL;
/* HACK: There is a known issue in audiotrack, "due to an internal /* HACK: There is a known issue in audiotrack, "due to an internal
* timeout within the AudioTrackThread". It happens after android * timeout within the AudioTrackThread". It happens after android
...@@ -1004,7 +1047,7 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout, ...@@ -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 * write. This hack is done only for API 19 (AudioTimestamp was added
* in API 19). */ * 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; *p_wait = FRAMES_TO_US( i_samples ) / 2;
} }
return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC; return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
...@@ -1078,6 +1121,7 @@ JNIThread( void *data ) ...@@ -1078,6 +1121,7 @@ JNIThread( void *data )
bool b_error = false; bool b_error = false;
bool b_paused = false; bool b_paused = false;
block_t *p_buffer = NULL; block_t *p_buffer = NULL;
size_t i_buffer_offset = 0;
mtime_t i_play_deadline = 0; mtime_t i_play_deadline = 0;
JNIEnv* env; JNIEnv* env;
...@@ -1155,18 +1199,25 @@ JNIThread( void *data ) ...@@ -1155,18 +1199,25 @@ JNIThread( void *data )
if( p_buffer == NULL ) if( p_buffer == NULL )
{ {
p_buffer = p_cmd->in.play.p_buffer; p_buffer = p_cmd->in.play.p_buffer;
if( p_sys->i_chans_to_reorder ) b_error = JNIThread_PreparePlay( env, p_aout, p_buffer )
aout_ChannelReorder( p_buffer->p_buffer, != VLC_SUCCESS;
p_buffer->i_buffer,
p_sys->i_chans_to_reorder,
p_sys->p_chan_table,
p_sys->fmt.i_format );
} }
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; &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; b_remove_cmd = false;
}
else
{
p_buffer = NULL;
i_buffer_offset = 0;
}
if( i_play_wait > 0 ) if( i_play_wait > 0 )
i_play_deadline = mdate() + i_play_wait; i_play_deadline = mdate() + i_play_wait;
break; break;
......
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