[vlc-devel] [PATCH 1/2] audiotrack: get rid of the thread and the queue
Thomas Guillem
thomas at gllm.fr
Thu Apr 2 18:46:41 CEST 2015
No need to have a queue inside VLC since we can control the size of the
AudioTrack buffer. There is now only one delay to handle, the AudioTrack one.
---
modules/audio_output/audiotrack.c | 652 +++++++-------------------------------
1 file changed, 115 insertions(+), 537 deletions(-)
diff --git a/modules/audio_output/audiotrack.c b/modules/audio_output/audiotrack.c
index 813fd6b..b925e26 100644
--- a/modules/audio_output/audiotrack.c
+++ b/modules/audio_output/audiotrack.c
@@ -29,31 +29,21 @@
#include <jni.h>
#include <dlfcn.h>
#include <stdbool.h>
-#include <sys/queue.h>
-#include <vlc_atomic.h>
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_aout.h>
-#include <vlc_threads.h>
-
-/* Maximum VLC buffers queued by the internal queue in microseconds. This delay
- * doesn't include audiotrack delay */
-#define MAX_QUEUE_US INT64_C(1000000) // 1000ms
static int Open( vlc_object_t * );
static void Close( vlc_object_t * );
-static void JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout );
-
-struct thread_cmd;
-typedef TAILQ_HEAD(, thread_cmd) THREAD_CMD_QUEUE;
+static void Stop( audio_output_t * );
+static int Start( audio_output_t *, audio_sample_format_t * );
struct aout_sys_t {
/* sw gain */
float soft_gain;
bool soft_mute;
- /* Owned by JNIThread */
jobject p_audiotrack; /* AudioTrack ref */
jobject p_audioTimestamp; /* AudioTimestamp ref */
jbyteArray p_bytearray; /* ByteArray ref (for Write) */
@@ -68,6 +58,7 @@ struct aout_sys_t {
uint32_t i_max_audiotrack_samples;
mtime_t i_play_time; /* time when play was called */
bool b_audiotrack_exception; /* true if audiotrack throwed an exception */
+ bool b_error; /* generic error */
int i_audiotrack_stuck_count;
bool b_spdif;
uint8_t i_chans_to_reorder; /* do we need channel reordering */
@@ -77,16 +68,6 @@ struct aout_sys_t {
WRITE_V21,
WRITE_FLOAT
} i_write_type;
-
- /* JNIThread control */
- vlc_mutex_t mutex;
- vlc_cond_t cond;
- vlc_thread_t thread;
-
- /* Shared between two threads, must be locked */
- bool b_thread_run; /* is thread alive */
- THREAD_CMD_QUEUE thread_cmd_queue; /* thread cmd queue */
- uint32_t i_samples_queued; /* number of samples queued */
};
/* Soft volume helper */
@@ -108,46 +89,6 @@ vlc_module_begin ()
set_callbacks( Open, Close )
vlc_module_end ()
-struct thread_cmd
-{
- TAILQ_ENTRY(thread_cmd) next;
- enum {
- CMD_START,
- CMD_STOP,
- CMD_PLAY,
- CMD_PAUSE,
- CMD_TIME_GET,
- CMD_FLUSH,
- CMD_DONE,
- } id;
- union {
- struct {
- audio_sample_format_t *p_fmt;
- } start;
- struct {
- block_t *p_buffer;
- } play;
- struct {
- bool b_pause;
- mtime_t i_date;
- } pause;
- struct {
- bool b_wait;
- } flush;
- } in;
- union {
- struct {
- int i_ret;
- audio_sample_format_t *p_fmt;
- } start;
- struct {
- int i_ret;
- mtime_t i_delay;
- } time_get;
- } out;
- void ( *pf_destroy )( struct thread_cmd * );
-};
-
#define THREAD_NAME "android_audiotrack"
extern JNIEnv *jni_get_env(const char *name);
@@ -383,6 +324,7 @@ check_exception( JNIEnv *env, audio_output_t *p_aout,
aout_sys_t *p_sys = p_aout->sys;
p_sys->b_audiotrack_exception = true;
+ p_sys->b_error = true;
(*env)->ExceptionClear( env );
msg_Err( p_aout, "AudioTrack.%s triggered an exception !", method );
return true;
@@ -433,57 +375,8 @@ frames_to_bytes( aout_sys_t *p_sys, uint32_t i_frames )
}
#define FRAMES_TO_BYTES(x) frames_to_bytes( p_sys, (x) )
-static struct thread_cmd *
-ThreadCmd_New( int id )
-{
- struct thread_cmd *p_cmd = calloc( 1, sizeof(struct thread_cmd) );
-
- if( p_cmd )
- p_cmd->id = id;
-
- return p_cmd;
-}
-
static void
-ThreadCmd_InsertHead( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
-{
- TAILQ_INSERT_HEAD( &p_sys->thread_cmd_queue, p_cmd, next);
- vlc_cond_signal( &p_sys->cond );
-}
-
-static void
-ThreadCmd_InsertTail( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
-{
- TAILQ_INSERT_TAIL( &p_sys->thread_cmd_queue, p_cmd, next);
- vlc_cond_signal( &p_sys->cond );
-}
-
-static bool
-ThreadCmd_Wait( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
-{
- while( p_cmd->id != CMD_DONE )
- vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
-
- return p_cmd->id == CMD_DONE;
-}
-
-static void
-ThreadCmd_FlushQueue( aout_sys_t *p_sys )
-{
- struct thread_cmd *p_cmd, *p_cmd_next;
-
- for ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue );
- p_cmd != NULL; p_cmd = p_cmd_next )
- {
- p_cmd_next = TAILQ_NEXT( p_cmd, next );
- TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
- if( p_cmd->pf_destroy )
- p_cmd->pf_destroy( p_cmd );
- }
-}
-
-static void
-JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout )
+AudioTrack_InitDelay( JNIEnv *env, audio_output_t *p_aout )
{
aout_sys_t *p_sys = p_aout->sys;
@@ -504,11 +397,10 @@ JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout )
} while( p_sys->i_pos_initial != i_last_pos );
}
p_sys->i_samples_written = 0;
- p_sys->i_samples_queued = 0;
}
static uint32_t
-JNIThread_GetAudioTrackPos( JNIEnv *env, audio_output_t *p_aout )
+AudioTrack_GetPos( JNIEnv *env, audio_output_t *p_aout )
{
aout_sys_t *p_sys = p_aout->sys;
@@ -526,13 +418,17 @@ JNIThread_GetAudioTrackPos( JNIEnv *env, audio_output_t *p_aout )
}
static int
-JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
+TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
{
aout_sys_t *p_sys = p_aout->sys;
jlong i_frame_pos;
uint32_t i_audiotrack_delay = 0;
+ JNIEnv *env;
+
+ if( p_sys->b_error || !( env = jni_get_env( THREAD_NAME ) ) )
+ return -1;
- if( p_sys->i_samples_queued == 0 || p_sys->b_spdif )
+ if( p_sys->b_spdif )
return -1;
if( p_sys->p_audioTimestamp )
{
@@ -575,7 +471,7 @@ JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
}
if( i_audiotrack_delay == 0 )
{
- uint32_t i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
+ uint32_t i_audiotrack_pos = AudioTrack_GetPos( env, p_aout );
if( p_sys->i_samples_written > i_audiotrack_pos )
i_audiotrack_delay = p_sys->i_samples_written - i_audiotrack_pos;
@@ -583,7 +479,7 @@ JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
if( i_audiotrack_delay > 0 )
{
- *p_delay = FRAMES_TO_US( p_sys->i_samples_queued + i_audiotrack_delay );
+ *p_delay = FRAMES_TO_US( i_audiotrack_delay );
return 0;
} else
return -1;
@@ -629,11 +525,11 @@ AudioTrack_GetChanOrder( uint16_t i_physical_channels, uint32_t p_chans_out[] )
* returns NULL on configuration error
*/
static jobject
-JNIThread_NewAudioTrack( JNIEnv *env, audio_output_t *p_aout,
- unsigned int i_rate,
- vlc_fourcc_t i_vlc_format,
- uint16_t i_physical_channels,
- int *p_audiotrack_size )
+AudioTrack_New( JNIEnv *env, audio_output_t *p_aout,
+ unsigned int i_rate,
+ vlc_fourcc_t i_vlc_format,
+ uint16_t i_physical_channels,
+ int *p_audiotrack_size )
{
int i_size, i_min_buffer_size, i_channel_config, i_format;
jobject p_audiotrack;
@@ -712,12 +608,18 @@ JNIThread_NewAudioTrack( JNIEnv *env, audio_output_t *p_aout,
}
static int
-JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
+Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
{
aout_sys_t *p_sys = p_aout->sys;
+ JNIEnv *env;
jobject p_audiotrack = NULL;
int i_nb_channels, i_audiotrack_size;
+ if( !( env = jni_get_env( THREAD_NAME ) ) )
+ return VLC_EGENERIC;
+
+ p_sys->fmt = *p_fmt;
+
aout_FormatPrint( p_aout, "VLC is looking for:", &p_sys->fmt );
p_sys->fmt.i_original_channels = p_sys->fmt.i_physical_channels;
@@ -772,13 +674,13 @@ JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
do
{
/* Try to create an AudioTrack with the most advanced channel and
- * format configuration. If NewAudioTrack fails, try again with a less
+ * format configuration. If AudioTrack_New fails, try again with a less
* advanced format (PCM S16N). If it fails again, try again with Stereo
* channels. */
- p_audiotrack = JNIThread_NewAudioTrack( env, p_aout, p_sys->fmt.i_rate,
- p_sys->fmt.i_format,
- p_sys->fmt.i_physical_channels,
- &i_audiotrack_size );
+ p_audiotrack = AudioTrack_New( env, p_aout, p_sys->fmt.i_rate,
+ p_sys->fmt.i_format,
+ p_sys->fmt.i_physical_channels,
+ &i_audiotrack_size );
if( !p_audiotrack )
{
if( p_sys->fmt.i_format == VLC_CODEC_SPDIFB )
@@ -846,16 +748,14 @@ JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
jobject p_audioTimestamp = JNI_CALL( NewObject,
jfields.AudioTimestamp.clazz,
jfields.AudioTimestamp.ctor );
- if( !p_audioTimestamp )
+ if( p_audioTimestamp )
{
- JNIThread_Stop( env, p_aout );
- return VLC_EGENERIC;
+ p_sys->p_audioTimestamp = (*env)->NewGlobalRef( env, p_audioTimestamp );
+ (*env)->DeleteLocalRef( env, p_audioTimestamp );
}
- p_sys->p_audioTimestamp = (*env)->NewGlobalRef( env, p_audioTimestamp );
- (*env)->DeleteLocalRef( env, p_audioTimestamp );
if( !p_sys->p_audioTimestamp )
{
- JNIThread_Stop( env, p_aout );
+ Stop( p_aout );
return VLC_EGENERIC;
}
}
@@ -881,15 +781,23 @@ JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
CHECK_AT_EXCEPTION( "play" );
p_sys->i_play_time = mdate();
+ AudioTrack_InitDelay( env, p_aout );
+ *p_fmt = p_sys->fmt;
+ aout_SoftVolumeStart( p_aout );
+
aout_FormatPrint( p_aout, "VLC will output:", &p_sys->fmt );
return VLC_SUCCESS;
}
static void
-JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
+Stop( audio_output_t *p_aout )
{
aout_sys_t *p_sys = p_aout->sys;
+ JNIEnv *env;
+
+ if( !( env = jni_get_env( THREAD_NAME ) ) )
+ return;
if( p_sys->p_audiotrack )
{
@@ -902,13 +810,14 @@ JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
(*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
p_sys->p_audiotrack = NULL;
}
- p_sys->b_audiotrack_exception = false;
-
if( p_sys->p_audioTimestamp )
{
(*env)->DeleteGlobalRef( env, p_sys->p_audioTimestamp );
p_sys->p_audioTimestamp = NULL;
}
+
+ p_sys->b_audiotrack_exception = false;
+ p_sys->b_error = false;
}
/**
@@ -917,8 +826,8 @@ 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,
- size_t i_buffer_offset )
+AudioTrack_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;
size_t i_data;
@@ -927,11 +836,11 @@ JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
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 = AudioTrack_GetPos( env, p_aout );
if( i_audiotrack_pos > p_sys->i_samples_written )
{
msg_Warn( p_aout, "audiotrack position is ahead. Should NOT happen" );
- JNIThread_InitDelay( env, p_aout );
+ AudioTrack_InitDelay( env, p_aout );
return 0;
}
i_samples_pending = p_sys->i_samples_written - i_audiotrack_pos;
@@ -955,6 +864,10 @@ JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
i_samples_pending = 0;
p_sys->i_audiotrack_stuck_count = 0;
}
+ else
+ {
+ return 0;
+ }
} else
p_sys->i_audiotrack_stuck_count = 0;
i_samples = __MIN( p_sys->i_max_audiotrack_samples - i_samples_pending,
@@ -971,8 +884,8 @@ 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,
- size_t i_buffer_offset )
+AudioTrack_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;
@@ -1015,8 +928,8 @@ JNIThread_WriteV21( 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_WriteFloat( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
- size_t i_buffer_offset )
+AudioTrack_WriteFloat( 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;
@@ -1035,8 +948,8 @@ JNIThread_WriteFloat( 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 )
+AudioTrack_PreparePlay( JNIEnv *env, audio_output_t *p_aout,
+ block_t *p_buffer )
{
aout_sys_t *p_sys = p_aout->sys;
@@ -1115,8 +1028,8 @@ JNIThread_PreparePlay( JNIEnv *env, audio_output_t *p_aout,
}
static int
-JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
- block_t *p_buffer, size_t *p_buffer_offset, mtime_t *p_wait )
+AudioTrack_Play( JNIEnv *env, audio_output_t *p_aout,
+ block_t *p_buffer, size_t *p_buffer_offset, mtime_t *p_wait )
{
aout_sys_t *p_sys = p_aout->sys;
int i_ret;
@@ -1124,13 +1037,13 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
switch( p_sys->i_write_type )
{
case WRITE_V21:
- i_ret = JNIThread_WriteV21( env, p_aout, p_buffer, *p_buffer_offset );
+ i_ret = AudioTrack_WriteV21( env, p_aout, p_buffer, *p_buffer_offset );
break;
case WRITE:
- i_ret = JNIThread_Write( env, p_aout, p_buffer, *p_buffer_offset );
+ i_ret = AudioTrack_Write( env, p_aout, p_buffer, *p_buffer_offset );
break;
case WRITE_FLOAT:
- i_ret = JNIThread_WriteFloat( env, p_aout, p_buffer, *p_buffer_offset );
+ i_ret = AudioTrack_WriteFloat( env, p_aout, p_buffer, *p_buffer_offset );
break;
default:
vlc_assert_unreachable();
@@ -1142,8 +1055,8 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
{
msg_Warn( p_aout, "ERROR_DEAD_OBJECT: "
"try recreating AudioTrack" );
- JNIThread_Stop( env, p_aout );
- i_ret = JNIThread_Start( env, p_aout );
+ Stop( p_aout );
+ i_ret = Start( p_aout, &p_sys->fmt );
} else
{
const char *str;
@@ -1164,31 +1077,50 @@ JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
{
uint32_t i_samples = BYTES_TO_FRAMES( i_ret );
- p_sys->i_samples_queued -= i_samples;
p_sys->i_samples_written += i_samples;
*p_buffer_offset += i_ret;
+ }
+ return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
+}
- /* HACK: There is a known issue in audiotrack, "due to an internal
- * timeout within the AudioTrackThread". It happens after android
- * 4.4.2, it's not a problem for Android 5.0 since we use an other way
- * to write samples. A working hack is to wait a little between each
- * write. This hack is done only for API 19 (AudioTimestamp was added
- * in API 19). */
+static void
+Play( audio_output_t *p_aout, block_t *p_buffer )
+{
+ JNIEnv *env;
+ size_t i_buffer_offset = 0;
+ mtime_t i_play_wait = 0;
+ aout_sys_t *p_sys = p_aout->sys;
+
+ if( p_sys->b_error || !( env = jni_get_env( THREAD_NAME ) ) )
+ goto bailout;
+
+ p_sys->b_error = AudioTrack_PreparePlay( env, p_aout, p_buffer )
+ != VLC_SUCCESS;
+
+ while( i_buffer_offset < p_buffer->i_buffer && !p_sys->b_error )
+ {
+ if( i_play_wait != 0 )
+ msleep( i_play_wait );
- if( p_sys->i_write_type == WRITE && jfields.AudioTimestamp.clazz )
- *p_wait = FRAMES_TO_US( i_samples ) / 2;
+ i_play_wait = 0;
+ p_sys->b_error = AudioTrack_Play( env, p_aout, p_buffer,
+ &i_buffer_offset,
+ &i_play_wait ) != VLC_SUCCESS;
}
- return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
+bailout:
+ block_Release( p_buffer );
}
static void
-JNIThread_Pause( JNIEnv *env, audio_output_t *p_aout,
- bool b_pause, mtime_t i_date )
+Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
{
+ aout_sys_t *p_sys = p_aout->sys;
+ JNIEnv *env;
VLC_UNUSED( i_date );
- aout_sys_t *p_sys = p_aout->sys;
+ if( p_sys->b_error || !( env = jni_get_env( THREAD_NAME ) ) )
+ return;
if( b_pause )
{
@@ -1203,10 +1135,13 @@ JNIThread_Pause( JNIEnv *env, audio_output_t *p_aout,
}
static void
-JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
- bool b_wait )
+Flush( audio_output_t *p_aout, bool b_wait )
{
aout_sys_t *p_sys = p_aout->sys;
+ JNIEnv *env;
+
+ if( p_sys->b_error || !( env = jni_get_env( THREAD_NAME ) ) )
+ return;
/* Android doc:
* stop(): Stops playing the audio data. When used on an instance created
@@ -1240,349 +1175,10 @@ JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
(*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
p_sys->p_bytebuffer = NULL;
}
-}
-
-static void *
-JNIThread( void *data )
-{
- audio_output_t *p_aout = data;
- aout_sys_t *p_sys = p_aout->sys;
- 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;
-
- env = jni_get_env(THREAD_NAME);
-
- vlc_mutex_lock( &p_sys->mutex );
- if( !env )
- goto end;
-
- while( p_sys->b_thread_run )
- {
- struct thread_cmd *p_cmd;
- bool b_remove_cmd = true;
-
- /* wait to process a command */
- while( ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue ) ) == NULL
- && p_sys->b_thread_run )
- vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
-
- if( !p_sys->b_thread_run || p_cmd == NULL )
- break;
-
- if( b_paused && p_cmd->id == CMD_PLAY )
- {
- vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
- continue;
- }
-
- if( p_cmd->id == CMD_PLAY && i_play_deadline > 0 )
- {
- if( mdate() > i_play_deadline )
- i_play_deadline = 0;
- else
- {
- int i_ret = 0;
- while( p_cmd == TAILQ_FIRST( &p_sys->thread_cmd_queue )
- && i_ret != ETIMEDOUT && p_sys->b_thread_run )
- i_ret = vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex,
- i_play_deadline );
- continue;
- }
- }
-
- /* process a command */
- switch( p_cmd->id )
- {
- case CMD_START:
- assert( !p_sys->p_audiotrack );
- if( b_error ) {
- p_cmd->out.start.i_ret = -1;
- break;
- }
- p_sys->fmt = *p_cmd->in.start.p_fmt;
- p_cmd->out.start.i_ret =
- JNIThread_Start( env, p_aout );
- JNIThread_InitDelay( env, p_aout );
- p_cmd->out.start.p_fmt = &p_sys->fmt;
- b_paused = false;
- break;
- case CMD_STOP:
- assert( p_sys->p_audiotrack );
- JNIThread_Stop( env, p_aout );
- JNIThread_InitDelay( env, p_aout );
- b_paused = false;
- b_error = false;
- p_buffer = NULL;
- break;
- case CMD_PLAY:
- {
- mtime_t i_play_wait = 0;
-
- assert( p_sys->p_audiotrack );
- if( b_error )
- break;
- if( p_buffer == NULL )
- {
- if( !p_cmd->in.play.p_buffer->i_buffer )
- break;
- p_buffer = p_cmd->in.play.p_buffer;
- i_buffer_offset = 0;
- b_error = JNIThread_PreparePlay( env, p_aout, p_buffer )
- != VLC_SUCCESS;
- if( b_error )
- break;
- }
- b_error = JNIThread_Play( env, p_aout, p_buffer,
- &i_buffer_offset,
- &i_play_wait ) != VLC_SUCCESS;
- 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;
- }
- if( i_play_wait > 0 )
- i_play_deadline = mdate() + i_play_wait;
- break;
- }
- case CMD_PAUSE:
- assert( p_sys->p_audiotrack );
- if( b_error )
- break;
- JNIThread_Pause( env, p_aout,
- p_cmd->in.pause.b_pause,
- p_cmd->in.pause.i_date );
- b_paused = p_cmd->in.pause.b_pause;
- break;
- case CMD_TIME_GET:
- assert( p_sys->p_audiotrack );
- if( b_error )
- {
- p_cmd->out.time_get.i_ret = -1;
- break;
- }
- p_cmd->out.time_get.i_ret =
- JNIThread_TimeGet( env, p_aout,
- &p_cmd->out.time_get.i_delay );
- break;
- case CMD_FLUSH:
- assert( p_sys->p_audiotrack );
- if( b_error )
- break;
- JNIThread_Flush( env, p_aout,
- p_cmd->in.flush.b_wait );
- JNIThread_InitDelay( env, p_aout );
- p_buffer = NULL;
- break;
- default:
- vlc_assert_unreachable();
- }
- if( p_sys->b_audiotrack_exception )
- b_error = true;
- if( b_error )
- p_sys->i_samples_queued = 0;
-
- if( b_remove_cmd )
- {
- TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
- p_cmd->id = CMD_DONE;
- if( p_cmd->pf_destroy )
- p_cmd->pf_destroy( p_cmd );
- }
-
- /* signal that command is processed */
- vlc_cond_signal( &p_sys->cond );
- }
-end:
- if( env )
- {
- if( p_sys->p_bytearray )
- (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
- if( p_sys->p_floatarray )
- (*env)->DeleteGlobalRef( env, p_sys->p_floatarray );
- if( p_sys->p_bytebuffer )
- (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
- }
- vlc_mutex_unlock( &p_sys->mutex );
- return NULL;
+ AudioTrack_InitDelay( env, p_aout );
}
static int
-Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
-{
- int i_ret = VLC_EGENERIC;
- struct thread_cmd *p_cmd;
- aout_sys_t *p_sys = p_aout->sys;
-
- vlc_mutex_lock( &p_sys->mutex );
-
- p_cmd = ThreadCmd_New( CMD_START );
- if( p_cmd )
- {
- /* ask the thread to process the Start command */
- p_cmd->in.start.p_fmt = p_fmt;
-
- ThreadCmd_InsertHead( p_sys, p_cmd );
- if( ThreadCmd_Wait( p_sys, p_cmd ) )
- {
- i_ret = p_cmd->out.start.i_ret;
- if( i_ret == VLC_SUCCESS )
- *p_fmt = *p_cmd->out.start.p_fmt;
- }
- free( p_cmd );
- }
-
- vlc_mutex_unlock( &p_sys->mutex );
-
- if( i_ret == VLC_SUCCESS )
- aout_SoftVolumeStart( p_aout );
-
- return i_ret;
-}
-
-static void
-Stop( audio_output_t *p_aout )
-{
- aout_sys_t *p_sys = p_aout->sys;
- struct thread_cmd *p_cmd;
-
- vlc_mutex_lock( &p_sys->mutex );
-
- ThreadCmd_FlushQueue( p_sys );
-
- p_cmd = ThreadCmd_New( CMD_STOP );
- if( p_cmd )
- {
- /* ask the thread to process the Stop command */
- ThreadCmd_InsertHead( p_sys, p_cmd );
- ThreadCmd_Wait( p_sys, p_cmd );
-
- free( p_cmd );
- }
-
- vlc_mutex_unlock( &p_sys->mutex );
-}
-
-static void
-PlayCmd_Destroy( struct thread_cmd *p_cmd )
-{
- block_Release( p_cmd->in.play.p_buffer );
- free( p_cmd );
-}
-
-static void
-Play( audio_output_t *p_aout, block_t *p_buffer )
-{
- aout_sys_t *p_sys = p_aout->sys;
- struct thread_cmd *p_cmd;
-
- vlc_mutex_lock( &p_sys->mutex );
-
- while( p_sys->i_samples_queued != 0
- && FRAMES_TO_US( p_sys->i_samples_queued +
- p_buffer->i_nb_samples ) >= MAX_QUEUE_US )
- vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
-
- p_cmd = ThreadCmd_New( CMD_PLAY );
- if( p_cmd )
- {
- /* ask the thread to process the Play command */
- p_cmd->in.play.p_buffer = p_buffer;
- p_cmd->pf_destroy = PlayCmd_Destroy;
-
- ThreadCmd_InsertTail( p_sys, p_cmd );
-
- p_sys->i_samples_queued += p_buffer->i_nb_samples;
- } else
- block_Release( p_cmd->in.play.p_buffer );
-
- vlc_mutex_unlock( &p_sys->mutex );
-}
-
-static void
-Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
-{
- aout_sys_t *p_sys = p_aout->sys;
- struct thread_cmd *p_cmd;
-
- vlc_mutex_lock( &p_sys->mutex );
-
- p_cmd = ThreadCmd_New( CMD_PAUSE );
- if( p_cmd )
- {
- /* ask the thread to process the Pause command */
- p_cmd->in.pause.b_pause = b_pause;
- p_cmd->in.pause.i_date = i_date;
-
- ThreadCmd_InsertHead( p_sys, p_cmd );
- ThreadCmd_Wait( p_sys, p_cmd );
-
- free( p_cmd );
- }
-
- vlc_mutex_unlock( &p_sys->mutex );
-}
-
-static void
-Flush( audio_output_t *p_aout, bool b_wait )
-{
- aout_sys_t *p_sys = p_aout->sys;
- struct thread_cmd *p_cmd;
-
- vlc_mutex_lock( &p_sys->mutex );
-
- ThreadCmd_FlushQueue( p_sys );
-
- p_cmd = ThreadCmd_New( CMD_FLUSH );
- if( p_cmd)
- {
- /* ask the thread to process the Flush command */
- p_cmd->in.flush.b_wait = b_wait;
-
- ThreadCmd_InsertHead( p_sys, p_cmd );
- ThreadCmd_Wait( p_sys, p_cmd );
-
- free( p_cmd );
- }
-
- vlc_mutex_unlock( &p_sys->mutex );
-}
-
-static int
-TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
-{
- aout_sys_t *p_sys = p_aout->sys;
- struct thread_cmd *p_cmd;
- int i_ret = -1;
-
- vlc_mutex_lock( &p_sys->mutex );
-
- p_cmd = ThreadCmd_New( CMD_TIME_GET );
- if( p_cmd)
- {
- ThreadCmd_InsertHead( p_sys, p_cmd );
- ThreadCmd_Wait( p_sys, p_cmd );
-
- i_ret = p_cmd->out.time_get.i_ret;
- *p_delay = p_cmd->out.time_get.i_delay;
- free( p_cmd );
- }
-
- vlc_mutex_unlock( &p_sys->mutex );
-
- return i_ret;
-}
-
-
-static int
Open( vlc_object_t *obj )
{
audio_output_t *p_aout = (audio_output_t *) obj;
@@ -1596,10 +1192,6 @@ Open( vlc_object_t *obj )
if( unlikely( p_sys == NULL ) )
return VLC_ENOMEM;
- vlc_mutex_init( &p_sys->mutex );
- vlc_cond_init( &p_sys->cond );
- TAILQ_INIT( &p_sys->thread_cmd_queue );
-
p_aout->sys = p_sys;
p_aout->start = Start;
p_aout->stop = Stop;
@@ -1610,17 +1202,6 @@ Open( vlc_object_t *obj )
aout_SoftVolumeInit( p_aout );
- /* create JNIThread */
- p_sys->b_thread_run = true;
- if( vlc_clone( &p_sys->thread,
- JNIThread, p_aout, VLC_THREAD_PRIORITY_AUDIO ) )
- {
- msg_Err( p_aout, "JNIThread creation failed" );
- p_sys->b_thread_run = false;
- Close( obj );
- return VLC_EGENERIC;
- }
-
return VLC_SUCCESS;
}
@@ -1629,20 +1210,17 @@ Close( vlc_object_t *obj )
{
audio_output_t *p_aout = (audio_output_t *) obj;
aout_sys_t *p_sys = p_aout->sys;
+ JNIEnv *env;
- /* kill the thread */
- vlc_mutex_lock( &p_sys->mutex );
- if( p_sys->b_thread_run )
+ if( ( env = jni_get_env( THREAD_NAME ) ) )
{
- p_sys->b_thread_run = false;
- vlc_cond_signal( &p_sys->cond );
- vlc_mutex_unlock( &p_sys->mutex );
- vlc_join( p_sys->thread, NULL );
- } else
- vlc_mutex_unlock( &p_sys->mutex );
-
- vlc_mutex_destroy( &p_sys->mutex );
- vlc_cond_destroy( &p_sys->cond );
+ if( p_sys->p_bytearray )
+ (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
+ if( p_sys->p_floatarray )
+ (*env)->DeleteGlobalRef( env, p_sys->p_floatarray );
+ if( p_sys->p_bytebuffer )
+ (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
+ }
free( p_sys );
}
--
2.1.3
More information about the vlc-devel
mailing list