1 /*****************************************************************************
2 * audiotrack.c: Android Java AudioTrack audio output module
3 *****************************************************************************
4 * Copyright © 2012-2015 VLC authors and VideoLAN, VideoLabs
6 * Authors: Thomas Guillem <thomas@gllm.fr>
7 * Ming Hu <tewilove@gmail.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
32 #include <sys/queue.h>
34 #include <vlc_atomic.h>
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
38 #include <vlc_threads.h>
40 /* Maximum VLC buffers queued by the internal queue in microseconds. This delay
41 * doesn't include audiotrack delay */
42 #define MAX_QUEUE_US INT64_C(1000000) // 1000ms
44 static int Open( vlc_object_t * );
45 static void Close( vlc_object_t * );
46 static void JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout );
49 typedef TAILQ_HEAD(, thread_cmd) THREAD_CMD_QUEUE;
56 /* Owned by JNIThread */
57 jobject p_audiotrack; /* AudioTrack ref */
58 jobject p_audioTimestamp; /* AudioTimestamp ref */
59 jbyteArray p_bytearray; /* ByteArray ref (for Write) */
60 size_t i_bytearray_size; /* size of the ByteArray */
61 jfloatArray p_floatarray; /* FloatArray ref (for WriteFloat) */
62 size_t i_floatarray_size; /* size of the FloatArray */
63 jobject p_bytebuffer; /* ByteBuffer ref (for WriteV21) */
64 audio_sample_format_t fmt; /* fmt setup by Start */
65 uint32_t i_pos_initial; /* initial position set by getPlaybackHeadPosition */
66 uint32_t i_samples_written; /* number of samples written since last flush */
67 uint32_t i_bytes_per_frame; /* byte per frame */
68 uint32_t i_max_audiotrack_samples;
69 mtime_t i_play_time; /* time when play was called */
70 bool b_audiotrack_exception; /* true if audiotrack throwed an exception */
71 int i_audiotrack_stuck_count;
72 uint8_t i_chans_to_reorder; /* do we need channel reordering */
73 uint8_t p_chan_table[AOUT_CHAN_MAX];
80 /* JNIThread control */
85 /* Shared between two threads, must be locked */
86 bool b_thread_run; /* is thread alive */
87 THREAD_CMD_QUEUE thread_cmd_queue; /* thread cmd queue */
88 uint32_t i_samples_queued; /* number of samples queued */
91 /* Soft volume helper */
92 #include "audio_output/volume.h"
94 #define AUDIOTRACK_USE_FLOAT
95 // TODO: activate getTimestamp for new android versions
96 //#define AUDIOTRACK_USE_TIMESTAMP
99 set_shortname( "AudioTrack" )
100 set_description( N_( "Android AudioTrack audio output" ) )
101 set_capability( "audio output", 180 )
102 set_category( CAT_AUDIO )
103 set_subcategory( SUBCAT_AUDIO_AOUT )
105 add_shortcut( "audiotrack" )
106 set_callbacks( Open, Close )
111 TAILQ_ENTRY(thread_cmd) next;
123 audio_sample_format_t *p_fmt;
139 audio_sample_format_t *p_fmt;
146 void ( *pf_destroy )( struct thread_cmd * );
149 #define THREAD_NAME "android_audiotrack"
151 extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
152 extern void jni_detach_thread();
153 extern int jni_get_env(JNIEnv **env);
168 jmethodID writeFloat;
169 jmethodID getPlaybackHeadPosition;
170 jmethodID getTimestamp;
171 jmethodID getMinBufferSize;
172 jint STATE_INITIALIZED;
175 jint ERROR_BAD_VALUE;
176 jint ERROR_INVALID_OPERATION;
177 jint WRITE_NON_BLOCKING;
180 jint ENCODING_PCM_8BIT;
181 jint ENCODING_PCM_16BIT;
182 jint ENCODING_PCM_FLOAT;
183 bool has_ENCODING_PCM_FLOAT;
184 jint CHANNEL_OUT_MONO;
185 jint CHANNEL_OUT_STEREO;
186 jint CHANNEL_OUT_FRONT_LEFT;
187 jint CHANNEL_OUT_FRONT_RIGHT;
188 jint CHANNEL_OUT_BACK_LEFT;
189 jint CHANNEL_OUT_BACK_RIGHT;
190 jint CHANNEL_OUT_FRONT_CENTER;
191 jint CHANNEL_OUT_LOW_FREQUENCY;
192 jint CHANNEL_OUT_BACK_CENTER;
193 jint CHANNEL_OUT_5POINT1;
194 jint CHANNEL_OUT_SIDE_LEFT;
195 jint CHANNEL_OUT_SIDE_RIGHT;
196 bool has_CHANNEL_OUT_SIDE;
199 jint ERROR_DEAD_OBJECT;
200 bool has_ERROR_DEAD_OBJECT;
206 jfieldID framePosition;
211 /* init all jni fields.
212 * Done only one time during the first initialisation */
214 InitJNIFields( audio_output_t *p_aout )
216 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
217 static int i_init_state = -1;
218 bool ret, b_attached = false;
223 vlc_mutex_lock( &lock );
225 if( i_init_state != -1 )
228 if( jni_get_env(&env) < 0 )
230 jni_attach_thread( &env, THREAD_NAME );
239 #define CHECK_EXCEPTION( what, critical ) do { \
240 if( (*env)->ExceptionOccurred( env ) ) \
242 msg_Err( p_aout, "%s failed", what ); \
243 (*env)->ExceptionClear( env ); \
251 #define GET_CLASS( str, critical ) do { \
252 clazz = (*env)->FindClass( env, (str) ); \
253 CHECK_EXCEPTION( str, critical ); \
255 #define GET_ID( get, id, str, args, critical ) do { \
256 jfields.id = (*env)->get( env, clazz, (str), (args) ); \
257 CHECK_EXCEPTION( #get, critical ); \
259 #define GET_CONST_INT( id, str, critical ) do { \
261 field = (*env)->GetStaticFieldID( env, clazz, (str), "I" ); \
262 CHECK_EXCEPTION( #id, critical ); \
265 jfields.id = (*env)->GetStaticIntField( env, clazz, field ); \
266 CHECK_EXCEPTION( #id, critical ); \
270 /* AudioTrack class init */
271 GET_CLASS( "android/media/AudioTrack", true );
272 jfields.AudioTrack.clazz = (jclass) (*env)->NewGlobalRef( env, clazz );
273 CHECK_EXCEPTION( "NewGlobalRef", true );
275 GET_ID( GetMethodID, AudioTrack.ctor, "<init>", "(IIIIII)V", true );
276 GET_ID( GetMethodID, AudioTrack.release, "release", "()V", true );
277 GET_ID( GetMethodID, AudioTrack.getState, "getState", "()I", true );
278 GET_ID( GetMethodID, AudioTrack.play, "play", "()V", true );
279 GET_ID( GetMethodID, AudioTrack.stop, "stop", "()V", true );
280 GET_ID( GetMethodID, AudioTrack.flush, "flush", "()V", true );
281 GET_ID( GetMethodID, AudioTrack.pause, "pause", "()V", true );
283 GET_ID( GetMethodID, AudioTrack.writeV21, "write", "(Ljava/nio/ByteBuffer;II)I", false );
284 if( jfields.AudioTrack.writeV21 )
286 GET_CONST_INT( AudioTrack.WRITE_NON_BLOCKING, "WRITE_NON_BLOCKING", true );
287 #ifdef AUDIOTRACK_USE_FLOAT
288 GET_ID( GetMethodID, AudioTrack.writeFloat, "write", "([FIII)I", true );
291 GET_ID( GetMethodID, AudioTrack.write, "write", "([BII)I", true );
293 GET_ID( GetMethodID, AudioTrack.getTimestamp,
294 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
295 GET_ID( GetMethodID, AudioTrack.getPlaybackHeadPosition,
296 "getPlaybackHeadPosition", "()I", true );
298 GET_ID( GetStaticMethodID, AudioTrack.getMinBufferSize, "getMinBufferSize",
300 GET_CONST_INT( AudioTrack.STATE_INITIALIZED, "STATE_INITIALIZED", true );
301 GET_CONST_INT( AudioTrack.MODE_STREAM, "MODE_STREAM", true );
302 GET_CONST_INT( AudioTrack.ERROR, "ERROR", true );
303 GET_CONST_INT( AudioTrack.ERROR_BAD_VALUE , "ERROR_BAD_VALUE", true );
304 GET_CONST_INT( AudioTrack.ERROR_INVALID_OPERATION,
305 "ERROR_INVALID_OPERATION", true );
307 /* AudioTimestamp class init (if any) */
308 if( jfields.AudioTrack.getTimestamp )
310 GET_CLASS( "android/media/AudioTimestamp", true );
311 jfields.AudioTimestamp.clazz = (jclass) (*env)->NewGlobalRef( env,
313 CHECK_EXCEPTION( "NewGlobalRef", true );
315 GET_ID( GetMethodID, AudioTimestamp.ctor, "<init>", "()V", true );
316 GET_ID( GetFieldID, AudioTimestamp.framePosition,
317 "framePosition", "J", true );
318 GET_ID( GetFieldID, AudioTimestamp.nanoTime,
319 "nanoTime", "J", true );
322 /* AudioFormat class init */
323 GET_CLASS( "android/media/AudioFormat", true );
324 GET_CONST_INT( AudioFormat.ENCODING_PCM_8BIT, "ENCODING_PCM_8BIT", true );
325 GET_CONST_INT( AudioFormat.ENCODING_PCM_16BIT, "ENCODING_PCM_16BIT", true );
326 #ifdef AUDIOTRACK_USE_FLOAT
327 GET_CONST_INT( AudioFormat.ENCODING_PCM_FLOAT, "ENCODING_PCM_FLOAT",
329 jfields.AudioFormat.has_ENCODING_PCM_FLOAT = field != NULL &&
330 jfields.AudioTrack.writeFloat;
332 jfields.AudioFormat.has_ENCODING_PCM_FLOAT = false;
334 GET_CONST_INT( AudioFormat.CHANNEL_OUT_MONO, "CHANNEL_OUT_MONO", true );
335 GET_CONST_INT( AudioFormat.CHANNEL_OUT_STEREO, "CHANNEL_OUT_STEREO", true );
336 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_LEFT, "CHANNEL_OUT_FRONT_LEFT", true );
337 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_RIGHT, "CHANNEL_OUT_FRONT_RIGHT", true );
338 GET_CONST_INT( AudioFormat.CHANNEL_OUT_5POINT1, "CHANNEL_OUT_5POINT1", true );
339 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_LEFT, "CHANNEL_OUT_BACK_LEFT", true );
340 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_RIGHT, "CHANNEL_OUT_BACK_RIGHT", true );
341 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_CENTER, "CHANNEL_OUT_FRONT_CENTER", true );
342 GET_CONST_INT( AudioFormat.CHANNEL_OUT_LOW_FREQUENCY, "CHANNEL_OUT_LOW_FREQUENCY", true );
343 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_CENTER, "CHANNEL_OUT_BACK_CENTER", true );
344 GET_CONST_INT( AudioFormat.CHANNEL_OUT_SIDE_LEFT, "CHANNEL_OUT_SIDE_LEFT", false );
347 GET_CONST_INT( AudioFormat.CHANNEL_OUT_SIDE_RIGHT, "CHANNEL_OUT_SIDE_RIGHT", true );
348 jfields.AudioFormat.has_CHANNEL_OUT_SIDE = true;
350 jfields.AudioFormat.has_CHANNEL_OUT_SIDE = false;
352 /* AudioManager class init */
353 GET_CLASS( "android/media/AudioManager", true );
354 GET_CONST_INT( AudioManager.ERROR_DEAD_OBJECT, "ERROR_DEAD_OBJECT", false );
355 jfields.AudioManager.has_ERROR_DEAD_OBJECT = field != NULL;
356 GET_CONST_INT( AudioManager.STREAM_MUSIC, "STREAM_MUSIC", true );
358 #undef CHECK_EXCEPTION
365 ret = i_init_state == 1;
367 msg_Err( p_aout, "AudioTrack jni init failed" );
370 vlc_mutex_unlock( &lock );
375 check_exception( JNIEnv *env, audio_output_t *p_aout,
378 if( (*env)->ExceptionOccurred( env ) )
380 aout_sys_t *p_sys = p_aout->sys;
382 p_sys->b_audiotrack_exception = true;
383 (*env)->ExceptionClear( env );
384 msg_Err( p_aout, "AudioTrack.%s triggered an exception !", method );
389 #define CHECK_AT_EXCEPTION( method ) check_exception( env, p_aout, method )
391 #define JNI_CALL( what, obj, method, ... ) (*env)->what( env, obj, method, ##__VA_ARGS__ )
393 #define JNI_CALL_INT( obj, method, ... ) JNI_CALL( CallIntMethod, obj, method, ##__VA_ARGS__ )
394 #define JNI_CALL_BOOL( obj, method, ... ) JNI_CALL( CallBooleanMethod, obj, method, ##__VA_ARGS__ )
395 #define JNI_CALL_VOID( obj, method, ... ) JNI_CALL( CallVoidMethod, obj, method, ##__VA_ARGS__ )
396 #define JNI_CALL_STATIC_INT( clazz, method, ... ) JNI_CALL( CallStaticIntMethod, clazz, method, ##__VA_ARGS__ )
398 #define JNI_AT_NEW( ... ) JNI_CALL( NewObject, jfields.AudioTrack.clazz, jfields.AudioTrack.ctor, ##__VA_ARGS__ )
399 #define JNI_AT_CALL_INT( method, ... ) JNI_CALL_INT( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
400 #define JNI_AT_CALL_BOOL( method, ... ) JNI_CALL_BOOL( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
401 #define JNI_AT_CALL_VOID( method, ... ) JNI_CALL_VOID( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
402 #define JNI_AT_CALL_STATIC_INT( method, ... ) JNI_CALL( CallStaticIntMethod, jfields.AudioTrack.clazz, jfields.AudioTrack.method, ##__VA_ARGS__ )
404 #define JNI_AUDIOTIMESTAMP_GET_LONG( field ) JNI_CALL( GetLongField, p_sys->p_audioTimestamp, jfields.AudioTimestamp.field )
406 static inline mtime_t
407 frames_to_us( aout_sys_t *p_sys, uint32_t i_nb_frames )
409 return i_nb_frames * CLOCK_FREQ / p_sys->fmt.i_rate;
411 #define FRAMES_TO_US(x) frames_to_us( p_sys, (x) )
413 static struct thread_cmd *
414 ThreadCmd_New( int id )
416 struct thread_cmd *p_cmd = calloc( 1, sizeof(struct thread_cmd) );
425 ThreadCmd_InsertHead( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
427 TAILQ_INSERT_HEAD( &p_sys->thread_cmd_queue, p_cmd, next);
428 vlc_cond_signal( &p_sys->cond );
432 ThreadCmd_InsertTail( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
434 TAILQ_INSERT_TAIL( &p_sys->thread_cmd_queue, p_cmd, next);
435 vlc_cond_signal( &p_sys->cond );
439 ThreadCmd_Wait( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
441 while( p_cmd->id != CMD_DONE )
442 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
444 return p_cmd->id == CMD_DONE;
448 ThreadCmd_FlushQueue( aout_sys_t *p_sys )
450 struct thread_cmd *p_cmd, *p_cmd_next;
452 for ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue );
453 p_cmd != NULL; p_cmd = p_cmd_next )
455 p_cmd_next = TAILQ_NEXT( p_cmd, next );
456 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
457 if( p_cmd->pf_destroy )
458 p_cmd->pf_destroy( p_cmd );
463 JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout )
465 aout_sys_t *p_sys = p_aout->sys;
467 if( p_sys->p_audiotrack )
468 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
470 p_sys->i_pos_initial = 0;
472 /* HACK: On some broken devices, head position is still moving after a
473 * flush or a stop. So, wait for the head position to be stabilized. */
474 if( unlikely( p_sys->i_pos_initial != 0 ) )
478 i_last_pos = p_sys->i_pos_initial;
480 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
481 } while( p_sys->i_pos_initial != i_last_pos );
483 p_sys->i_samples_written = 0;
484 p_sys->i_samples_queued = 0;
488 JNIThread_GetAudioTrackPos( JNIEnv *env, audio_output_t *p_aout )
490 aout_sys_t *p_sys = p_aout->sys;
493 * getPlaybackHeadPosition: Returns the playback head position expressed in
494 * frames. Though the "int" type is signed 32-bits, the value should be
495 * reinterpreted as if it is unsigned 32-bits. That is, the next position
496 * after 0x7FFFFFFF is (int) 0x80000000. This is a continuously advancing
497 * counter. It will wrap (overflow) periodically, for example approximately
498 * once every 27:03:11 hours:minutes:seconds at 44.1 kHz. It is reset to
499 * zero by flush(), reload(), and stop().
502 return JNI_AT_CALL_INT( getPlaybackHeadPosition ) - p_sys->i_pos_initial;
506 JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
508 aout_sys_t *p_sys = p_aout->sys;
510 uint32_t i_audiotrack_delay = 0;
512 if( p_sys->i_samples_queued == 0 )
514 if( p_sys->p_audioTimestamp )
516 mtime_t i_current_time = mdate();
518 * getTimestamp: Poll for a timestamp on demand.
520 * If you need to track timestamps during initial warmup or after a
521 * routing or mode change, you should request a new timestamp once per
522 * second until the reported timestamps show that the audio clock is
523 * stable. Thereafter, query for a new timestamp approximately once
524 * every 10 seconds to once per minute. Calling this method more often
525 * is inefficient. It is also counter-productive to call this method
526 * more often than recommended, because the short-term differences
527 * between successive timestamp reports are not meaningful. If you need
528 * a high-resolution mapping between frame position and presentation
529 * time, consider implementing that at application level, based on
530 * low-resolution timestamps.
533 if( JNI_AT_CALL_BOOL( getTimestamp, p_sys->p_audioTimestamp ) )
535 jlong i_frame_time = JNI_AUDIOTIMESTAMP_GET_LONG( nanoTime ) / 1000;
536 /* frame time should be after last play time
537 * frame time shouldn't be in the future
538 * frame time should be less than 10 seconds old */
539 if( i_frame_time > p_sys->i_play_time
540 && i_current_time > i_frame_time
541 && ( i_current_time - i_frame_time ) <= INT64_C(10000000) )
543 jlong i_time_diff = i_current_time - i_frame_time;
544 jlong i_frames_diff = i_time_diff * p_sys->fmt.i_rate
546 i_frame_pos = JNI_AUDIOTIMESTAMP_GET_LONG( framePosition )
548 if( p_sys->i_samples_written > i_frame_pos )
549 i_audiotrack_delay = p_sys->i_samples_written - i_frame_pos;
553 if( i_audiotrack_delay == 0 )
555 uint32_t i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
557 if( p_sys->i_samples_written > i_audiotrack_pos )
558 i_audiotrack_delay = p_sys->i_samples_written - i_audiotrack_pos;
561 if( i_audiotrack_delay > 0 )
563 *p_delay = FRAMES_TO_US( p_sys->i_samples_queued + i_audiotrack_delay );
570 AudioTrack_GetChanOrder( uint16_t i_physical_channels, uint32_t p_chans_out[] )
572 #define HAS_CHAN( x ) ( ( i_physical_channels & (x) ) == (x) )
573 /* samples will be in the following order: FL FR FC LFE BL BR BC SL SR */
576 if( HAS_CHAN( AOUT_CHAN_LEFT ) )
577 p_chans_out[i++] = AOUT_CHAN_LEFT;
578 if( HAS_CHAN( AOUT_CHAN_RIGHT ) )
579 p_chans_out[i++] = AOUT_CHAN_RIGHT;
581 if( HAS_CHAN( AOUT_CHAN_CENTER ) )
582 p_chans_out[i++] = AOUT_CHAN_CENTER;
584 if( HAS_CHAN( AOUT_CHAN_LFE ) )
585 p_chans_out[i++] = AOUT_CHAN_LFE;
587 if( HAS_CHAN( AOUT_CHAN_REARLEFT ) )
588 p_chans_out[i++] = AOUT_CHAN_REARLEFT;
589 if( HAS_CHAN( AOUT_CHAN_REARRIGHT ) )
590 p_chans_out[i++] = AOUT_CHAN_REARRIGHT;
592 if( HAS_CHAN( AOUT_CHAN_REARCENTER ) )
593 p_chans_out[i++] = AOUT_CHAN_REARCENTER;
595 if( HAS_CHAN( AOUT_CHAN_MIDDLELEFT ) )
596 p_chans_out[i++] = AOUT_CHAN_MIDDLELEFT;
597 if( HAS_CHAN( AOUT_CHAN_MIDDLERIGHT ) )
598 p_chans_out[i++] = AOUT_CHAN_MIDDLERIGHT;
600 assert( i <= AOUT_CHAN_MAX );
605 * Configure and create an Android AudioTrack.
606 * returns NULL on configuration error
609 JNIThread_NewAudioTrack( JNIEnv *env, audio_output_t *p_aout,
611 vlc_fourcc_t i_vlc_format,
612 uint16_t i_physical_channels,
613 int *p_audiotrack_size )
615 int i_size, i_min_buffer_size, i_channel_config, i_format;
616 jobject p_audiotrack;
618 switch( i_vlc_format )
621 i_format = jfields.AudioFormat.ENCODING_PCM_8BIT;
624 i_format = jfields.AudioFormat.ENCODING_PCM_16BIT;
627 i_format = jfields.AudioFormat.ENCODING_PCM_FLOAT;
630 vlc_assert_unreachable();
633 switch( i_physical_channels )
636 /* bitmask of CHANNEL_OUT_7POINT1 doesn't correspond to 5POINT1 and
638 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_5POINT1 |
639 jfields.AudioFormat.CHANNEL_OUT_SIDE_LEFT |
640 jfields.AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
643 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_5POINT1;
646 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_MONO;
649 case AOUT_CHANS_STEREO:
650 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_STEREO;
654 i_min_buffer_size = JNI_AT_CALL_STATIC_INT( getMinBufferSize, i_rate,
655 i_channel_config, i_format );
656 if( i_min_buffer_size <= 0 )
658 msg_Warn( p_aout, "getMinBufferSize returned an invalid size" ) ;
661 i_size = i_min_buffer_size * 4;
663 /* create AudioTrack object */
664 p_audiotrack = JNI_AT_NEW( jfields.AudioManager.STREAM_MUSIC, i_rate,
665 i_channel_config, i_format, i_size,
666 jfields.AudioTrack.MODE_STREAM );
667 if( CHECK_AT_EXCEPTION( "AudioTrack<init>" ) || !p_audiotrack )
669 msg_Warn( p_aout, "AudioTrack Init failed" ) ;
672 if( JNI_CALL_INT( p_audiotrack, jfields.AudioTrack.getState )
673 != jfields.AudioTrack.STATE_INITIALIZED )
675 JNI_CALL_VOID( p_audiotrack, jfields.AudioTrack.release );
676 (*env)->DeleteLocalRef( env, p_audiotrack );
677 msg_Err( p_aout, "AudioTrack getState failed" );
680 *p_audiotrack_size = i_size;
686 JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
688 aout_sys_t *p_sys = p_aout->sys;
689 jobject p_audiotrack = NULL;
690 int i_nb_channels, i_audiotrack_size;
691 uint32_t p_chans_out[AOUT_CHAN_MAX];
693 aout_FormatPrint( p_aout, "VLC is looking for:", &p_sys->fmt );
695 p_sys->fmt.i_original_channels = p_sys->fmt.i_physical_channels;
697 /* 4000 <= frequency <= 48000 */
698 p_sys->fmt.i_rate = VLC_CLIP( p_sys->fmt.i_rate, 4000, 48000 );
700 /* We can only accept U8, S16N, FL32, and AC3 */
701 switch( p_sys->fmt.i_format )
708 if( !jfields.AudioFormat.has_ENCODING_PCM_FLOAT )
709 p_sys->fmt.i_format = VLC_CODEC_S16N;
712 p_sys->fmt.i_format = VLC_CODEC_S16N;
716 /* Android AudioTrack supports only mono, stereo, 5.1 and 7.1.
717 * Android will downmix to stereo if audio output doesn't handle 5.1 or 7.1
719 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
720 if( i_nb_channels > 5 )
722 if( i_nb_channels > 7 && jfields.AudioFormat.has_CHANNEL_OUT_SIDE )
723 p_sys->fmt.i_physical_channels = AOUT_CHANS_7_1;
725 p_sys->fmt.i_physical_channels = AOUT_CHANS_5_1;
728 if( i_nb_channels == 1 )
729 p_sys->fmt.i_physical_channels = AOUT_CHAN_LEFT;
731 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
733 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
737 /* Try to create an AudioTrack with the most advanced channel and
738 * format configuration. If NewAudioTrack fails, try again with a less
739 * advanced format (PCM S16N). If it fails again, try again with Stereo
741 p_audiotrack = JNIThread_NewAudioTrack( env, p_aout, p_sys->fmt.i_rate,
743 p_sys->fmt.i_physical_channels,
744 &i_audiotrack_size );
747 if( p_sys->fmt.i_format == VLC_CODEC_FL32 )
749 msg_Warn( p_aout, "FL32 configuration failed, "
750 "fallback to S16N PCM" );
751 p_sys->fmt.i_format = VLC_CODEC_S16N;
753 else if( i_nb_channels > 5 )
755 msg_Warn( p_aout, "5.1 or 7.1 configuration failed, "
756 "fallback to Stereo" );
757 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
758 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
763 } while( !p_audiotrack );
768 p_sys->p_audiotrack = (*env)->NewGlobalRef( env, p_audiotrack );
769 (*env)->DeleteLocalRef( env, p_audiotrack );
770 if( !p_sys->p_audiotrack )
773 memset( p_chans_out, 0, sizeof(p_chans_out) );
774 AudioTrack_GetChanOrder( p_sys->fmt.i_physical_channels, p_chans_out );
775 p_sys->i_chans_to_reorder =
776 aout_CheckChannelReorder( NULL, p_chans_out,
777 p_sys->fmt.i_physical_channels,
778 p_sys->p_chan_table );
780 p_sys->i_bytes_per_frame = i_nb_channels *
781 aout_BitsPerSample( p_sys->fmt.i_format ) /
783 p_sys->i_max_audiotrack_samples = i_audiotrack_size /
784 p_sys->i_bytes_per_frame;
786 #ifdef AUDIOTRACK_USE_TIMESTAMP
787 if( jfields.AudioTimestamp.clazz )
789 /* create AudioTimestamp object */
790 jobject p_audioTimestamp = JNI_CALL( NewObject,
791 jfields.AudioTimestamp.clazz,
792 jfields.AudioTimestamp.ctor );
793 if( !p_audioTimestamp )
795 JNIThread_Stop( env, p_aout );
798 p_sys->p_audioTimestamp = (*env)->NewGlobalRef( env, p_audioTimestamp );
799 (*env)->DeleteLocalRef( env, p_audioTimestamp );
800 if( !p_sys->p_audioTimestamp )
802 JNIThread_Stop( env, p_aout );
808 if( p_sys->fmt.i_format == VLC_CODEC_FL32 )
810 msg_Dbg( p_aout, "using WRITE_FLOAT");
811 p_sys->i_write_type = WRITE_FLOAT;
813 else if( jfields.AudioTrack.writeV21 )
814 msg_Dbg( p_aout, "using WRITE_V21");
815 p_sys->i_write_type = WRITE_V21;
819 msg_Dbg( p_aout, "using WRITE");
820 p_sys->i_write_type = WRITE;
823 JNI_AT_CALL_VOID( play );
824 CHECK_AT_EXCEPTION( "play" );
825 p_sys->i_play_time = mdate();
827 aout_FormatPrint( p_aout, "VLC will output:", &p_sys->fmt );
833 JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
835 aout_sys_t *p_sys = p_aout->sys;
837 if( p_sys->p_audiotrack )
839 if( !p_sys->b_audiotrack_exception )
841 JNI_AT_CALL_VOID( stop );
842 if( !CHECK_AT_EXCEPTION( "stop" ) )
843 JNI_AT_CALL_VOID( release );
845 (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
846 p_sys->p_audiotrack = NULL;
848 p_sys->b_audiotrack_exception = false;
850 if( p_sys->p_audioTimestamp )
852 (*env)->DeleteGlobalRef( env, p_sys->p_audioTimestamp );
853 p_sys->p_audioTimestamp = NULL;
858 * Non blocking write function.
859 * Do a calculation between current position and audiotrack position and assure
860 * that we won't wait in AudioTrack.write() method
863 JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
864 size_t i_buffer_offset )
866 aout_sys_t *p_sys = p_aout->sys;
869 uint32_t i_audiotrack_pos;
870 uint32_t i_samples_pending;
872 i_data = p_buffer->i_buffer - i_buffer_offset;
873 i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
874 if( i_audiotrack_pos > p_sys->i_samples_written )
876 msg_Warn( p_aout, "audiotrack position is ahead. Should NOT happen" );
877 JNIThread_InitDelay( env, p_aout );
880 i_samples_pending = p_sys->i_samples_written - i_audiotrack_pos;
882 /* check if audiotrack buffer is not full before writing on it. */
883 if( i_samples_pending >= p_sys->i_max_audiotrack_samples )
886 /* HACK: AudioFlinger can drop frames without notifying us and there is
887 * no way to know it. It it happens, i_audiotrack_pos won't move and
888 * the current code will be stuck because it'll assume that audiotrack
889 * internal buffer is full when it's not. It can happen only after
890 * Android 4.4.2 if we send frames too quickly. This HACK is just an
891 * other precaution since it shouldn't happen anymore thanks to the
892 * HACK in JNIThread_Play */
894 p_sys->i_audiotrack_stuck_count++;
895 if( p_sys->i_audiotrack_stuck_count > 100 )
897 msg_Warn( p_aout, "AudioFlinger underrun, force write" );
898 i_samples_pending = 0;
899 p_sys->i_audiotrack_stuck_count = 0;
902 p_sys->i_audiotrack_stuck_count = 0;
903 i_samples = __MIN( p_sys->i_max_audiotrack_samples - i_samples_pending,
904 BYTES_TO_FRAMES( i_data ) );
906 i_data = i_samples * p_sys->i_bytes_per_frame;
908 return JNI_AT_CALL_INT( write, p_sys->p_bytearray,
909 i_buffer_offset, i_data );
913 * Non blocking write function for Lollipop and after.
914 * It calls a new write method with WRITE_NON_BLOCKING flags.
917 JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
918 size_t i_buffer_offset )
920 aout_sys_t *p_sys = p_aout->sys;
922 size_t i_data = p_buffer->i_buffer - i_buffer_offset;
923 uint8_t *p_data = p_buffer->p_buffer + i_buffer_offset;
925 if( !p_sys->p_bytebuffer )
927 jobject p_bytebuffer;
929 p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_data, i_data );
931 return jfields.AudioTrack.ERROR_BAD_VALUE;
933 p_sys->p_bytebuffer = (*env)->NewGlobalRef( env, p_bytebuffer );
934 (*env)->DeleteLocalRef( env, p_bytebuffer );
936 if( !p_sys->p_bytebuffer || (*env)->ExceptionOccurred( env ) )
938 p_sys->p_bytebuffer = NULL;
939 (*env)->ExceptionClear( env );
940 return jfields.AudioTrack.ERROR_BAD_VALUE;
944 i_ret = JNI_AT_CALL_INT( writeV21, p_sys->p_bytebuffer, i_data,
945 jfields.AudioTrack.WRITE_NON_BLOCKING );
948 /* don't delete the bytebuffer if we wrote nothing, keep it for next
950 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
951 p_sys->p_bytebuffer = NULL;
957 * Non blocking write float function for Lollipop and after.
958 * It calls a new write method with WRITE_NON_BLOCKING flags.
961 JNIThread_WriteFloat( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
962 size_t i_buffer_offset )
964 aout_sys_t *p_sys = p_aout->sys;
968 i_buffer_offset /= 4;
969 i_data = p_buffer->i_buffer / 4 - i_buffer_offset;
971 i_ret = JNI_AT_CALL_INT( writeFloat, p_sys->p_floatarray,
972 i_buffer_offset, i_data,
973 jfields.AudioTrack.WRITE_NON_BLOCKING );
981 JNIThread_PreparePlay( JNIEnv *env, audio_output_t *p_aout,
984 aout_sys_t *p_sys = p_aout->sys;
986 if( p_sys->i_chans_to_reorder )
987 aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer,
988 p_sys->i_chans_to_reorder, p_sys->p_chan_table,
989 p_sys->fmt.i_format );
991 switch( p_sys->i_write_type )
994 /* check if we need to realloc a ByteArray */
995 if( p_buffer->i_buffer > p_sys->i_bytearray_size )
997 jbyteArray p_bytearray;
999 if( p_sys->p_bytearray )
1001 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
1002 p_sys->p_bytearray = NULL;
1005 p_bytearray = (*env)->NewByteArray( env, p_buffer->i_buffer );
1008 p_sys->p_bytearray = (*env)->NewGlobalRef( env, p_bytearray );
1009 (*env)->DeleteLocalRef( env, p_bytearray );
1011 p_sys->i_bytearray_size = p_buffer->i_buffer;
1013 if( !p_sys->p_bytearray )
1014 return VLC_EGENERIC;
1016 /* copy p_buffer in to ByteArray */
1017 (*env)->SetByteArrayRegion( env, p_sys->p_bytearray, 0,
1019 (jbyte *)p_buffer->p_buffer);
1023 size_t i_data = p_buffer->i_buffer / 4;
1025 /* check if we need to realloc a floatArray */
1026 if( i_data > p_sys->i_floatarray_size )
1028 jfloatArray p_floatarray;
1030 if( p_sys->p_floatarray )
1032 (*env)->DeleteGlobalRef( env, p_sys->p_floatarray );
1033 p_sys->p_floatarray = NULL;
1036 p_floatarray = (*env)->NewFloatArray( env, i_data );
1039 p_sys->p_floatarray = (*env)->NewGlobalRef( env, p_floatarray );
1040 (*env)->DeleteLocalRef( env, p_floatarray );
1042 p_sys->i_floatarray_size = i_data;
1044 if( !p_sys->p_floatarray )
1045 return VLC_EGENERIC;
1047 /* copy p_buffer in to FloatArray */
1048 (*env)->SetFloatArrayRegion( env, p_sys->p_floatarray, 0, i_data,
1049 (jfloat *)p_buffer->p_buffer);
1061 JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
1062 block_t *p_buffer, size_t *p_buffer_offset, mtime_t *p_wait )
1064 aout_sys_t *p_sys = p_aout->sys;
1067 switch( p_sys->i_write_type )
1070 i_ret = JNIThread_WriteV21( env, p_aout, p_buffer, *p_buffer_offset );
1073 i_ret = JNIThread_Write( env, p_aout, p_buffer, *p_buffer_offset );
1076 i_ret = JNIThread_WriteFloat( env, p_aout, p_buffer, *p_buffer_offset );
1079 vlc_assert_unreachable();
1083 if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
1084 && i_ret == jfields.AudioManager.ERROR_DEAD_OBJECT )
1086 msg_Warn( p_aout, "ERROR_DEAD_OBJECT: "
1087 "try recreating AudioTrack" );
1088 JNIThread_Stop( env, p_aout );
1089 i_ret = JNIThread_Start( env, p_aout );
1093 if( i_ret == jfields.AudioTrack.ERROR_INVALID_OPERATION )
1094 str = "ERROR_INVALID_OPERATION";
1095 else if( i_ret == jfields.AudioTrack.ERROR_BAD_VALUE )
1096 str = "ERROR_BAD_VALUE";
1099 msg_Err( p_aout, "Write failed: %s", str );
1101 } else if( i_ret == 0 )
1103 /* audiotrack internal buffer is full, wait a little: between 10ms and
1104 * 20ms depending on devices or rate */
1105 *p_wait = FRAMES_TO_US( p_sys->i_max_audiotrack_samples / 20 );
1108 uint32_t i_samples = i_ret / p_sys->i_bytes_per_frame;
1109 p_sys->i_samples_queued -= i_samples;
1110 p_sys->i_samples_written += i_samples;
1112 *p_buffer_offset += i_ret;
1114 /* HACK: There is a known issue in audiotrack, "due to an internal
1115 * timeout within the AudioTrackThread". It happens after android
1116 * 4.4.2, it's not a problem for Android 5.0 since we use an other way
1117 * to write samples. A working hack is to wait a little between each
1118 * write. This hack is done only for API 19 (AudioTimestamp was added
1121 if( p_sys->i_write_type == WRITE && jfields.AudioTimestamp.clazz )
1122 *p_wait = FRAMES_TO_US( i_samples ) / 2;
1124 return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
1128 JNIThread_Pause( JNIEnv *env, audio_output_t *p_aout,
1129 bool b_pause, mtime_t i_date )
1131 VLC_UNUSED( i_date );
1133 aout_sys_t *p_sys = p_aout->sys;
1137 JNI_AT_CALL_VOID( pause );
1138 CHECK_AT_EXCEPTION( "pause" );
1141 JNI_AT_CALL_VOID( play );
1142 CHECK_AT_EXCEPTION( "play" );
1143 p_sys->i_play_time = mdate();
1148 JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
1151 aout_sys_t *p_sys = p_aout->sys;
1154 * stop(): Stops playing the audio data. When used on an instance created
1155 * in MODE_STREAM mode, audio will stop playing after the last buffer that
1156 * was written has been played. For an immediate stop, use pause(),
1157 * followed by flush() to discard audio data that hasn't been played back
1160 * flush(): Flushes the audio data currently queued for playback. Any data
1161 * that has not been played back will be discarded. No-op if not stopped
1162 * or paused, or if the track's creation mode is not MODE_STREAM.
1166 JNI_AT_CALL_VOID( stop );
1167 if( CHECK_AT_EXCEPTION( "stop" ) )
1171 JNI_AT_CALL_VOID( pause );
1172 if( CHECK_AT_EXCEPTION( "pause" ) )
1174 JNI_AT_CALL_VOID( flush );
1176 JNI_AT_CALL_VOID( play );
1177 CHECK_AT_EXCEPTION( "play" );
1178 p_sys->i_play_time = mdate();
1180 if( p_sys->p_bytebuffer )
1182 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1183 p_sys->p_bytebuffer = NULL;
1188 JNIThread( void *data )
1190 audio_output_t *p_aout = data;
1191 aout_sys_t *p_sys = p_aout->sys;
1192 bool b_error = false;
1193 bool b_paused = false;
1194 block_t *p_buffer = NULL;
1195 size_t i_buffer_offset = 0;
1196 mtime_t i_play_deadline = 0;
1199 jni_attach_thread( &env, THREAD_NAME );
1201 vlc_mutex_lock( &p_sys->mutex );
1205 while( p_sys->b_thread_run )
1207 struct thread_cmd *p_cmd;
1208 bool b_remove_cmd = true;
1210 /* wait to process a command */
1211 while( ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue ) ) == NULL
1212 && p_sys->b_thread_run )
1213 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1215 if( !p_sys->b_thread_run || p_cmd == NULL )
1218 if( b_paused && p_cmd->id == CMD_PLAY )
1220 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1224 if( p_cmd->id == CMD_PLAY && i_play_deadline > 0 )
1226 if( mdate() > i_play_deadline )
1227 i_play_deadline = 0;
1231 while( p_cmd == TAILQ_FIRST( &p_sys->thread_cmd_queue )
1232 && i_ret != ETIMEDOUT && p_sys->b_thread_run )
1233 i_ret = vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex,
1239 /* process a command */
1243 assert( !p_sys->p_audiotrack );
1245 p_cmd->out.start.i_ret = -1;
1248 p_sys->fmt = *p_cmd->in.start.p_fmt;
1249 p_cmd->out.start.i_ret =
1250 JNIThread_Start( env, p_aout );
1251 JNIThread_InitDelay( env, p_aout );
1252 p_cmd->out.start.p_fmt = &p_sys->fmt;
1256 assert( p_sys->p_audiotrack );
1257 JNIThread_Stop( env, p_aout );
1258 JNIThread_InitDelay( env, p_aout );
1265 mtime_t i_play_wait = 0;
1267 assert( p_sys->p_audiotrack );
1270 if( p_buffer == NULL )
1272 p_buffer = p_cmd->in.play.p_buffer;
1273 b_error = JNIThread_PreparePlay( env, p_aout, p_buffer )
1278 b_error = JNIThread_Play( env, p_aout, p_buffer,
1280 &i_play_wait ) != VLC_SUCCESS;
1281 if( i_buffer_offset < p_buffer->i_buffer )
1283 /* buffer is not fully processed, try again with the
1284 * same cmd and buffer */
1285 b_remove_cmd = false;
1290 i_buffer_offset = 0;
1292 if( i_play_wait > 0 )
1293 i_play_deadline = mdate() + i_play_wait;
1297 assert( p_sys->p_audiotrack );
1300 JNIThread_Pause( env, p_aout,
1301 p_cmd->in.pause.b_pause,
1302 p_cmd->in.pause.i_date );
1303 b_paused = p_cmd->in.pause.b_pause;
1306 assert( p_sys->p_audiotrack );
1309 p_cmd->out.time_get.i_ret = -1;
1312 p_cmd->out.time_get.i_ret =
1313 JNIThread_TimeGet( env, p_aout,
1314 &p_cmd->out.time_get.i_delay );
1317 assert( p_sys->p_audiotrack );
1320 JNIThread_Flush( env, p_aout,
1321 p_cmd->in.flush.b_wait );
1322 JNIThread_InitDelay( env, p_aout );
1326 vlc_assert_unreachable();
1328 if( p_sys->b_audiotrack_exception )
1331 p_sys->i_samples_queued = 0;
1335 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
1336 p_cmd->id = CMD_DONE;
1337 if( p_cmd->pf_destroy )
1338 p_cmd->pf_destroy( p_cmd );
1341 /* signal that command is processed */
1342 vlc_cond_signal( &p_sys->cond );
1347 if( p_sys->p_bytearray )
1348 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
1349 if( p_sys->p_floatarray )
1350 (*env)->DeleteGlobalRef( env, p_sys->p_floatarray );
1351 if( p_sys->p_bytebuffer )
1352 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1353 jni_detach_thread();
1355 vlc_mutex_unlock( &p_sys->mutex );
1360 Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
1362 int i_ret = VLC_EGENERIC;
1363 struct thread_cmd *p_cmd;
1364 aout_sys_t *p_sys = p_aout->sys;
1366 vlc_mutex_lock( &p_sys->mutex );
1368 p_cmd = ThreadCmd_New( CMD_START );
1371 /* ask the thread to process the Start command */
1372 p_cmd->in.start.p_fmt = p_fmt;
1374 ThreadCmd_InsertHead( p_sys, p_cmd );
1375 if( ThreadCmd_Wait( p_sys, p_cmd ) )
1377 i_ret = p_cmd->out.start.i_ret;
1378 if( i_ret == VLC_SUCCESS )
1379 *p_fmt = *p_cmd->out.start.p_fmt;
1384 vlc_mutex_unlock( &p_sys->mutex );
1386 if( i_ret == VLC_SUCCESS )
1387 aout_SoftVolumeStart( p_aout );
1393 Stop( audio_output_t *p_aout )
1395 aout_sys_t *p_sys = p_aout->sys;
1396 struct thread_cmd *p_cmd;
1398 vlc_mutex_lock( &p_sys->mutex );
1400 ThreadCmd_FlushQueue( p_sys );
1402 p_cmd = ThreadCmd_New( CMD_STOP );
1405 /* ask the thread to process the Stop command */
1406 ThreadCmd_InsertHead( p_sys, p_cmd );
1407 ThreadCmd_Wait( p_sys, p_cmd );
1412 vlc_mutex_unlock( &p_sys->mutex );
1416 PlayCmd_Destroy( struct thread_cmd *p_cmd )
1418 block_Release( p_cmd->in.play.p_buffer );
1423 Play( audio_output_t *p_aout, block_t *p_buffer )
1425 aout_sys_t *p_sys = p_aout->sys;
1426 struct thread_cmd *p_cmd;
1428 vlc_mutex_lock( &p_sys->mutex );
1430 while( p_sys->i_samples_queued != 0
1431 && FRAMES_TO_US( p_sys->i_samples_queued +
1432 p_buffer->i_nb_samples ) >= MAX_QUEUE_US )
1433 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1435 p_cmd = ThreadCmd_New( CMD_PLAY );
1438 /* ask the thread to process the Play command */
1439 p_cmd->in.play.p_buffer = p_buffer;
1440 p_cmd->pf_destroy = PlayCmd_Destroy;
1442 ThreadCmd_InsertTail( p_sys, p_cmd );
1444 p_sys->i_samples_queued += p_buffer->i_nb_samples;
1446 block_Release( p_cmd->in.play.p_buffer );
1448 vlc_mutex_unlock( &p_sys->mutex );
1452 Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
1454 aout_sys_t *p_sys = p_aout->sys;
1455 struct thread_cmd *p_cmd;
1457 vlc_mutex_lock( &p_sys->mutex );
1459 p_cmd = ThreadCmd_New( CMD_PAUSE );
1462 /* ask the thread to process the Pause command */
1463 p_cmd->in.pause.b_pause = b_pause;
1464 p_cmd->in.pause.i_date = i_date;
1466 ThreadCmd_InsertHead( p_sys, p_cmd );
1467 ThreadCmd_Wait( p_sys, p_cmd );
1472 vlc_mutex_unlock( &p_sys->mutex );
1476 Flush( audio_output_t *p_aout, bool b_wait )
1478 aout_sys_t *p_sys = p_aout->sys;
1479 struct thread_cmd *p_cmd;
1481 vlc_mutex_lock( &p_sys->mutex );
1483 ThreadCmd_FlushQueue( p_sys );
1485 p_cmd = ThreadCmd_New( CMD_FLUSH );
1488 /* ask the thread to process the Flush command */
1489 p_cmd->in.flush.b_wait = b_wait;
1491 ThreadCmd_InsertHead( p_sys, p_cmd );
1492 ThreadCmd_Wait( p_sys, p_cmd );
1497 vlc_mutex_unlock( &p_sys->mutex );
1501 TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
1503 aout_sys_t *p_sys = p_aout->sys;
1504 struct thread_cmd *p_cmd;
1507 vlc_mutex_lock( &p_sys->mutex );
1509 p_cmd = ThreadCmd_New( CMD_TIME_GET );
1512 ThreadCmd_InsertHead( p_sys, p_cmd );
1513 ThreadCmd_Wait( p_sys, p_cmd );
1515 i_ret = p_cmd->out.time_get.i_ret;
1516 *p_delay = p_cmd->out.time_get.i_delay;
1520 vlc_mutex_unlock( &p_sys->mutex );
1527 Open( vlc_object_t *obj )
1529 audio_output_t *p_aout = (audio_output_t *) obj;
1532 if( !InitJNIFields( p_aout ) )
1533 return VLC_EGENERIC;
1535 p_sys = calloc( 1, sizeof (aout_sys_t) );
1537 if( unlikely( p_sys == NULL ) )
1540 vlc_mutex_init( &p_sys->mutex );
1541 vlc_cond_init( &p_sys->cond );
1542 TAILQ_INIT( &p_sys->thread_cmd_queue );
1544 p_aout->sys = p_sys;
1545 p_aout->start = Start;
1546 p_aout->stop = Stop;
1547 p_aout->play = Play;
1548 p_aout->pause = Pause;
1549 p_aout->flush = Flush;
1550 p_aout->time_get = TimeGet;
1552 aout_SoftVolumeInit( p_aout );
1554 /* create JNIThread */
1555 p_sys->b_thread_run = true;
1556 if( vlc_clone( &p_sys->thread,
1557 JNIThread, p_aout, VLC_THREAD_PRIORITY_AUDIO ) )
1559 msg_Err( p_aout, "JNIThread creation failed" );
1560 p_sys->b_thread_run = false;
1562 return VLC_EGENERIC;
1569 Close( vlc_object_t *obj )
1571 audio_output_t *p_aout = (audio_output_t *) obj;
1572 aout_sys_t *p_sys = p_aout->sys;
1574 /* kill the thread */
1575 vlc_mutex_lock( &p_sys->mutex );
1576 if( p_sys->b_thread_run )
1578 p_sys->b_thread_run = false;
1579 vlc_cond_signal( &p_sys->cond );
1580 vlc_mutex_unlock( &p_sys->mutex );
1581 vlc_join( p_sys->thread, NULL );
1583 vlc_mutex_unlock( &p_sys->mutex );
1585 vlc_mutex_destroy( &p_sys->mutex );
1586 vlc_cond_destroy( &p_sys->cond );