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 jobject p_bytebuffer; /* ByteBuffer ref (for WriteV21) */
62 audio_sample_format_t fmt; /* fmt setup by Start */
63 uint32_t i_pos_initial; /* initial position set by getPlaybackHeadPosition */
64 uint32_t i_samples_written; /* number of samples written since last flush */
65 uint32_t i_bytes_per_frame; /* byte per frame */
66 uint32_t i_max_audiotrack_samples;
67 mtime_t i_play_time; /* time when play was called */
68 bool b_audiotrack_exception; /* true if audiotrack throwed an exception */
69 int i_audiotrack_stuck_count;
70 uint8_t i_chans_to_reorder; /* do we need channel reordering */
71 uint8_t p_chan_table[AOUT_CHAN_MAX];
77 /* JNIThread control */
82 /* Shared between two threads, must be locked */
83 bool b_thread_run; /* is thread alive */
84 THREAD_CMD_QUEUE thread_cmd_queue; /* thread cmd queue */
85 uint32_t i_samples_queued; /* number of samples queued */
88 /* Soft volume helper */
89 #include "audio_output/volume.h"
91 //#define AUDIOTRACK_USE_FLOAT
92 // TODO: activate getTimestamp for new android versions
93 //#define AUDIOTRACK_USE_TIMESTAMP
96 set_shortname( "AudioTrack" )
97 set_description( N_( "Android AudioTrack audio output" ) )
98 set_capability( "audio output", 180 )
99 set_category( CAT_AUDIO )
100 set_subcategory( SUBCAT_AUDIO_AOUT )
102 add_shortcut( "audiotrack" )
103 set_callbacks( Open, Close )
108 TAILQ_ENTRY(thread_cmd) next;
120 audio_sample_format_t *p_fmt;
136 audio_sample_format_t *p_fmt;
143 void ( *pf_destroy )( struct thread_cmd * );
146 #define THREAD_NAME "android_audiotrack"
148 extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
149 extern void jni_detach_thread();
150 extern int jni_get_env(JNIEnv **env);
165 jmethodID getPlaybackHeadPosition;
166 jmethodID getTimestamp;
167 jmethodID getMinBufferSize;
168 jint STATE_INITIALIZED;
171 jint ERROR_BAD_VALUE;
172 jint ERROR_INVALID_OPERATION;
173 jint WRITE_NON_BLOCKING;
176 jint ENCODING_PCM_8BIT;
177 jint ENCODING_PCM_16BIT;
178 jint ENCODING_PCM_FLOAT;
179 bool has_ENCODING_PCM_FLOAT;
180 jint CHANNEL_OUT_MONO;
181 jint CHANNEL_OUT_STEREO;
182 jint CHANNEL_OUT_FRONT_LEFT;
183 jint CHANNEL_OUT_FRONT_RIGHT;
184 jint CHANNEL_OUT_BACK_LEFT;
185 jint CHANNEL_OUT_BACK_RIGHT;
186 jint CHANNEL_OUT_FRONT_CENTER;
187 jint CHANNEL_OUT_LOW_FREQUENCY;
188 jint CHANNEL_OUT_BACK_CENTER;
189 jint CHANNEL_OUT_5POINT1;
190 jint CHANNEL_OUT_SIDE_LEFT;
191 jint CHANNEL_OUT_SIDE_RIGHT;
192 bool has_CHANNEL_OUT_SIDE;
195 jint ERROR_DEAD_OBJECT;
196 bool has_ERROR_DEAD_OBJECT;
202 jfieldID framePosition;
207 /* init all jni fields.
208 * Done only one time during the first initialisation */
210 InitJNIFields( audio_output_t *p_aout )
212 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
213 static int i_init_state = -1;
214 bool ret, b_attached = false;
219 vlc_mutex_lock( &lock );
221 if( i_init_state != -1 )
224 if( jni_get_env(&env) < 0 )
226 jni_attach_thread( &env, THREAD_NAME );
235 #define CHECK_EXCEPTION( what, critical ) do { \
236 if( (*env)->ExceptionOccurred( env ) ) \
238 msg_Err( p_aout, "%s failed", what ); \
239 (*env)->ExceptionClear( env ); \
247 #define GET_CLASS( str, critical ) do { \
248 clazz = (*env)->FindClass( env, (str) ); \
249 CHECK_EXCEPTION( str, critical ); \
251 #define GET_ID( get, id, str, args, critical ) do { \
252 jfields.id = (*env)->get( env, clazz, (str), (args) ); \
253 CHECK_EXCEPTION( #get, critical ); \
255 #define GET_CONST_INT( id, str, critical ) do { \
257 field = (*env)->GetStaticFieldID( env, clazz, (str), "I" ); \
258 CHECK_EXCEPTION( #id, critical ); \
261 jfields.id = (*env)->GetStaticIntField( env, clazz, field ); \
262 CHECK_EXCEPTION( #id, critical ); \
266 /* AudioTrack class init */
267 GET_CLASS( "android/media/AudioTrack", true );
268 jfields.AudioTrack.clazz = (jclass) (*env)->NewGlobalRef( env, clazz );
269 CHECK_EXCEPTION( "NewGlobalRef", true );
271 GET_ID( GetMethodID, AudioTrack.ctor, "<init>", "(IIIIII)V", true );
272 GET_ID( GetMethodID, AudioTrack.release, "release", "()V", true );
273 GET_ID( GetMethodID, AudioTrack.getState, "getState", "()I", true );
274 GET_ID( GetMethodID, AudioTrack.play, "play", "()V", true );
275 GET_ID( GetMethodID, AudioTrack.stop, "stop", "()V", true );
276 GET_ID( GetMethodID, AudioTrack.flush, "flush", "()V", true );
277 GET_ID( GetMethodID, AudioTrack.pause, "pause", "()V", true );
279 GET_ID( GetMethodID, AudioTrack.writeV21, "write", "(Ljava/nio/ByteBuffer;II)I", false );
280 if( jfields.AudioTrack.writeV21 )
282 GET_CONST_INT( AudioTrack.WRITE_NON_BLOCKING, "WRITE_NON_BLOCKING", true );
284 GET_ID( GetMethodID, AudioTrack.write, "write", "([BII)I", true );
286 GET_ID( GetMethodID, AudioTrack.getTimestamp,
287 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
288 GET_ID( GetMethodID, AudioTrack.getPlaybackHeadPosition,
289 "getPlaybackHeadPosition", "()I", true );
291 GET_ID( GetStaticMethodID, AudioTrack.getMinBufferSize, "getMinBufferSize",
293 GET_CONST_INT( AudioTrack.STATE_INITIALIZED, "STATE_INITIALIZED", true );
294 GET_CONST_INT( AudioTrack.MODE_STREAM, "MODE_STREAM", true );
295 GET_CONST_INT( AudioTrack.ERROR, "ERROR", true );
296 GET_CONST_INT( AudioTrack.ERROR_BAD_VALUE , "ERROR_BAD_VALUE", true );
297 GET_CONST_INT( AudioTrack.ERROR_INVALID_OPERATION,
298 "ERROR_INVALID_OPERATION", true );
300 /* AudioTimestamp class init (if any) */
301 if( jfields.AudioTrack.getTimestamp )
303 GET_CLASS( "android/media/AudioTimestamp", true );
304 jfields.AudioTimestamp.clazz = (jclass) (*env)->NewGlobalRef( env,
306 CHECK_EXCEPTION( "NewGlobalRef", true );
308 GET_ID( GetMethodID, AudioTimestamp.ctor, "<init>", "()V", true );
309 GET_ID( GetFieldID, AudioTimestamp.framePosition,
310 "framePosition", "J", true );
311 GET_ID( GetFieldID, AudioTimestamp.nanoTime,
312 "nanoTime", "J", true );
315 /* AudioFormat class init */
316 GET_CLASS( "android/media/AudioFormat", true );
317 GET_CONST_INT( AudioFormat.ENCODING_PCM_8BIT, "ENCODING_PCM_8BIT", true );
318 GET_CONST_INT( AudioFormat.ENCODING_PCM_16BIT, "ENCODING_PCM_16BIT", true );
319 #ifdef AUDIOTRACK_USE_FLOAT
320 GET_CONST_INT( AudioFormat.ENCODING_PCM_FLOAT, "ENCODING_PCM_FLOAT",
322 jfields.AudioFormat.has_ENCODING_PCM_FLOAT = field != NULL;
324 jfields.AudioFormat.has_ENCODING_PCM_FLOAT = false;
326 GET_CONST_INT( AudioFormat.CHANNEL_OUT_MONO, "CHANNEL_OUT_MONO", true );
327 GET_CONST_INT( AudioFormat.CHANNEL_OUT_STEREO, "CHANNEL_OUT_STEREO", true );
328 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_LEFT, "CHANNEL_OUT_FRONT_LEFT", true );
329 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_RIGHT, "CHANNEL_OUT_FRONT_RIGHT", true );
330 GET_CONST_INT( AudioFormat.CHANNEL_OUT_5POINT1, "CHANNEL_OUT_5POINT1", true );
331 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_LEFT, "CHANNEL_OUT_BACK_LEFT", true );
332 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_RIGHT, "CHANNEL_OUT_BACK_RIGHT", true );
333 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_CENTER, "CHANNEL_OUT_FRONT_CENTER", true );
334 GET_CONST_INT( AudioFormat.CHANNEL_OUT_LOW_FREQUENCY, "CHANNEL_OUT_LOW_FREQUENCY", true );
335 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_CENTER, "CHANNEL_OUT_BACK_CENTER", true );
336 GET_CONST_INT( AudioFormat.CHANNEL_OUT_SIDE_LEFT, "CHANNEL_OUT_SIDE_LEFT", false );
339 GET_CONST_INT( AudioFormat.CHANNEL_OUT_SIDE_RIGHT, "CHANNEL_OUT_SIDE_RIGHT", true );
340 jfields.AudioFormat.has_CHANNEL_OUT_SIDE = true;
342 jfields.AudioFormat.has_CHANNEL_OUT_SIDE = false;
344 /* AudioManager class init */
345 GET_CLASS( "android/media/AudioManager", true );
346 GET_CONST_INT( AudioManager.ERROR_DEAD_OBJECT, "ERROR_DEAD_OBJECT", false );
347 jfields.AudioManager.has_ERROR_DEAD_OBJECT = field != NULL;
348 GET_CONST_INT( AudioManager.STREAM_MUSIC, "STREAM_MUSIC", true );
350 #undef CHECK_EXCEPTION
357 ret = i_init_state == 1;
359 msg_Err( p_aout, "AudioTrack jni init failed" );
362 vlc_mutex_unlock( &lock );
367 check_exception( JNIEnv *env, audio_output_t *p_aout,
370 if( (*env)->ExceptionOccurred( env ) )
372 aout_sys_t *p_sys = p_aout->sys;
374 p_sys->b_audiotrack_exception = true;
375 (*env)->ExceptionClear( env );
376 msg_Err( p_aout, "AudioTrack.%s triggered an exception !", method );
381 #define CHECK_AT_EXCEPTION( method ) check_exception( env, p_aout, method )
383 #define JNI_CALL( what, obj, method, ... ) (*env)->what( env, obj, method, ##__VA_ARGS__ )
385 #define JNI_CALL_INT( obj, method, ... ) JNI_CALL( CallIntMethod, obj, method, ##__VA_ARGS__ )
386 #define JNI_CALL_BOOL( obj, method, ... ) JNI_CALL( CallBooleanMethod, obj, method, ##__VA_ARGS__ )
387 #define JNI_CALL_VOID( obj, method, ... ) JNI_CALL( CallVoidMethod, obj, method, ##__VA_ARGS__ )
388 #define JNI_CALL_STATIC_INT( clazz, method, ... ) JNI_CALL( CallStaticIntMethod, clazz, method, ##__VA_ARGS__ )
390 #define JNI_AT_NEW( ... ) JNI_CALL( NewObject, jfields.AudioTrack.clazz, jfields.AudioTrack.ctor, ##__VA_ARGS__ )
391 #define JNI_AT_CALL_INT( method, ... ) JNI_CALL_INT( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
392 #define JNI_AT_CALL_BOOL( method, ... ) JNI_CALL_BOOL( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
393 #define JNI_AT_CALL_VOID( method, ... ) JNI_CALL_VOID( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
394 #define JNI_AT_CALL_STATIC_INT( method, ... ) JNI_CALL( CallStaticIntMethod, jfields.AudioTrack.clazz, jfields.AudioTrack.method, ##__VA_ARGS__ )
396 #define JNI_AUDIOTIMESTAMP_GET_LONG( field ) JNI_CALL( GetLongField, p_sys->p_audioTimestamp, jfields.AudioTimestamp.field )
398 static inline mtime_t
399 frames_to_us( aout_sys_t *p_sys, uint32_t i_nb_frames )
401 return i_nb_frames * CLOCK_FREQ / p_sys->fmt.i_rate;
403 #define FRAMES_TO_US(x) frames_to_us( p_sys, (x) )
405 static struct thread_cmd *
406 ThreadCmd_New( int id )
408 struct thread_cmd *p_cmd = calloc( 1, sizeof(struct thread_cmd) );
417 ThreadCmd_InsertHead( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
419 TAILQ_INSERT_HEAD( &p_sys->thread_cmd_queue, p_cmd, next);
420 vlc_cond_signal( &p_sys->cond );
424 ThreadCmd_InsertTail( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
426 TAILQ_INSERT_TAIL( &p_sys->thread_cmd_queue, p_cmd, next);
427 vlc_cond_signal( &p_sys->cond );
431 ThreadCmd_Wait( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
433 while( p_cmd->id != CMD_DONE )
434 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
436 return p_cmd->id == CMD_DONE;
440 ThreadCmd_FlushQueue( aout_sys_t *p_sys )
442 struct thread_cmd *p_cmd, *p_cmd_next;
444 for ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue );
445 p_cmd != NULL; p_cmd = p_cmd_next )
447 p_cmd_next = TAILQ_NEXT( p_cmd, next );
448 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
449 if( p_cmd->pf_destroy )
450 p_cmd->pf_destroy( p_cmd );
455 JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout )
457 aout_sys_t *p_sys = p_aout->sys;
459 if( p_sys->p_audiotrack )
460 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
462 p_sys->i_pos_initial = 0;
464 /* HACK: On some broken devices, head position is still moving after a
465 * flush or a stop. So, wait for the head position to be stabilized. */
466 if( unlikely( p_sys->i_pos_initial != 0 ) )
470 i_last_pos = p_sys->i_pos_initial;
472 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
473 } while( p_sys->i_pos_initial != i_last_pos );
475 p_sys->i_samples_written = 0;
476 p_sys->i_samples_queued = 0;
480 JNIThread_GetAudioTrackPos( JNIEnv *env, audio_output_t *p_aout )
482 aout_sys_t *p_sys = p_aout->sys;
485 * getPlaybackHeadPosition: Returns the playback head position expressed in
486 * frames. Though the "int" type is signed 32-bits, the value should be
487 * reinterpreted as if it is unsigned 32-bits. That is, the next position
488 * after 0x7FFFFFFF is (int) 0x80000000. This is a continuously advancing
489 * counter. It will wrap (overflow) periodically, for example approximately
490 * once every 27:03:11 hours:minutes:seconds at 44.1 kHz. It is reset to
491 * zero by flush(), reload(), and stop().
494 return JNI_AT_CALL_INT( getPlaybackHeadPosition ) - p_sys->i_pos_initial;
498 JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
500 aout_sys_t *p_sys = p_aout->sys;
502 uint32_t i_audiotrack_delay = 0;
504 if( p_sys->i_samples_queued == 0 )
506 if( p_sys->p_audioTimestamp )
508 mtime_t i_current_time = mdate();
510 * getTimestamp: Poll for a timestamp on demand.
512 * If you need to track timestamps during initial warmup or after a
513 * routing or mode change, you should request a new timestamp once per
514 * second until the reported timestamps show that the audio clock is
515 * stable. Thereafter, query for a new timestamp approximately once
516 * every 10 seconds to once per minute. Calling this method more often
517 * is inefficient. It is also counter-productive to call this method
518 * more often than recommended, because the short-term differences
519 * between successive timestamp reports are not meaningful. If you need
520 * a high-resolution mapping between frame position and presentation
521 * time, consider implementing that at application level, based on
522 * low-resolution timestamps.
525 if( JNI_AT_CALL_BOOL( getTimestamp, p_sys->p_audioTimestamp ) )
527 jlong i_frame_time = JNI_AUDIOTIMESTAMP_GET_LONG( nanoTime ) / 1000;
528 /* frame time should be after last play time
529 * frame time shouldn't be in the future
530 * frame time should be less than 10 seconds old */
531 if( i_frame_time > p_sys->i_play_time
532 && i_current_time > i_frame_time
533 && ( i_current_time - i_frame_time ) <= INT64_C(10000000) )
535 jlong i_time_diff = i_current_time - i_frame_time;
536 jlong i_frames_diff = i_time_diff * p_sys->fmt.i_rate
538 i_frame_pos = JNI_AUDIOTIMESTAMP_GET_LONG( framePosition )
540 if( p_sys->i_samples_written > i_frame_pos )
541 i_audiotrack_delay = p_sys->i_samples_written - i_frame_pos;
545 if( i_audiotrack_delay == 0 )
547 uint32_t i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
549 if( p_sys->i_samples_written > i_audiotrack_pos )
550 i_audiotrack_delay = p_sys->i_samples_written - i_audiotrack_pos;
553 if( i_audiotrack_delay > 0 )
555 *p_delay = FRAMES_TO_US( p_sys->i_samples_queued + i_audiotrack_delay );
562 AudioTrack_GetChanOrder( uint16_t i_physical_channels, uint32_t p_chans_out[] )
564 #define HAS_CHAN( x ) ( ( i_physical_channels & (x) ) == (x) )
565 /* samples will be in the following order: FL FR FC LFE BL BR BC SL SR */
568 if( HAS_CHAN( AOUT_CHAN_LEFT ) )
569 p_chans_out[i++] = AOUT_CHAN_LEFT;
570 if( HAS_CHAN( AOUT_CHAN_RIGHT ) )
571 p_chans_out[i++] = AOUT_CHAN_RIGHT;
573 if( HAS_CHAN( AOUT_CHAN_CENTER ) )
574 p_chans_out[i++] = AOUT_CHAN_CENTER;
576 if( HAS_CHAN( AOUT_CHAN_LFE ) )
577 p_chans_out[i++] = AOUT_CHAN_LFE;
579 if( HAS_CHAN( AOUT_CHAN_REARLEFT ) )
580 p_chans_out[i++] = AOUT_CHAN_REARLEFT;
581 if( HAS_CHAN( AOUT_CHAN_REARRIGHT ) )
582 p_chans_out[i++] = AOUT_CHAN_REARRIGHT;
584 if( HAS_CHAN( AOUT_CHAN_REARCENTER ) )
585 p_chans_out[i++] = AOUT_CHAN_REARCENTER;
587 if( HAS_CHAN( AOUT_CHAN_MIDDLELEFT ) )
588 p_chans_out[i++] = AOUT_CHAN_MIDDLELEFT;
589 if( HAS_CHAN( AOUT_CHAN_MIDDLERIGHT ) )
590 p_chans_out[i++] = AOUT_CHAN_MIDDLERIGHT;
592 assert( i <= AOUT_CHAN_MAX );
597 * Configure and create an Android AudioTrack.
598 * returns NULL on configuration error
601 JNIThread_NewAudioTrack( JNIEnv *env, audio_output_t *p_aout,
603 vlc_fourcc_t i_vlc_format,
604 uint16_t i_physical_channels,
605 int *p_audiotrack_size )
607 int i_size, i_min_buffer_size, i_channel_config, i_format;
608 jobject p_audiotrack;
610 switch( i_vlc_format )
613 i_format = jfields.AudioFormat.ENCODING_PCM_8BIT;
616 i_format = jfields.AudioFormat.ENCODING_PCM_16BIT;
619 i_format = jfields.AudioFormat.ENCODING_PCM_FLOAT;
622 vlc_assert_unreachable();
625 switch( i_physical_channels )
628 /* bitmask of CHANNEL_OUT_7POINT1 doesn't correspond to 5POINT1 and
630 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_5POINT1 |
631 jfields.AudioFormat.CHANNEL_OUT_SIDE_LEFT |
632 jfields.AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
635 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_5POINT1;
638 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_MONO;
641 case AOUT_CHANS_STEREO:
642 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_STEREO;
646 i_min_buffer_size = JNI_AT_CALL_STATIC_INT( getMinBufferSize, i_rate,
647 i_channel_config, i_format );
648 if( i_min_buffer_size <= 0 )
650 msg_Warn( p_aout, "getMinBufferSize returned an invalid size" ) ;
653 i_size = i_min_buffer_size * 4;
655 /* create AudioTrack object */
656 p_audiotrack = JNI_AT_NEW( jfields.AudioManager.STREAM_MUSIC, i_rate,
657 i_channel_config, i_format, i_size,
658 jfields.AudioTrack.MODE_STREAM );
659 if( CHECK_AT_EXCEPTION( "AudioTrack<init>" ) || !p_audiotrack )
661 msg_Warn( p_aout, "AudioTrack Init failed" ) ;
664 if( JNI_CALL_INT( p_audiotrack, jfields.AudioTrack.getState )
665 != jfields.AudioTrack.STATE_INITIALIZED )
667 JNI_CALL_VOID( p_audiotrack, jfields.AudioTrack.release );
668 (*env)->DeleteLocalRef( env, p_audiotrack );
669 msg_Err( p_aout, "AudioTrack getState failed" );
672 *p_audiotrack_size = i_size;
678 JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
680 aout_sys_t *p_sys = p_aout->sys;
681 jobject p_audiotrack = NULL;
682 int i_nb_channels, i_audiotrack_size;
683 uint32_t p_chans_out[AOUT_CHAN_MAX];
685 aout_FormatPrint( p_aout, "VLC is looking for:", &p_sys->fmt );
687 p_sys->fmt.i_original_channels = p_sys->fmt.i_physical_channels;
689 /* 4000 <= frequency <= 48000 */
690 p_sys->fmt.i_rate = VLC_CLIP( p_sys->fmt.i_rate, 4000, 48000 );
692 /* We can only accept U8, S16N, FL32, and AC3 */
693 switch( p_sys->fmt.i_format )
700 if( !jfields.AudioFormat.has_ENCODING_PCM_FLOAT )
701 p_sys->fmt.i_format = VLC_CODEC_S16N;
704 p_sys->fmt.i_format = VLC_CODEC_S16N;
708 /* Android AudioTrack supports only mono, stereo, 5.1 and 7.1.
709 * Android will downmix to stereo if audio output doesn't handle 5.1 or 7.1
711 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
712 if( i_nb_channels > 5 )
714 if( i_nb_channels > 7 && jfields.AudioFormat.has_CHANNEL_OUT_SIDE )
715 p_sys->fmt.i_physical_channels = AOUT_CHANS_7_1;
717 p_sys->fmt.i_physical_channels = AOUT_CHANS_5_1;
720 if( i_nb_channels == 1 )
721 p_sys->fmt.i_physical_channels = AOUT_CHAN_LEFT;
723 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
725 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
729 /* Try to create an AudioTrack with the most advanced channel and
730 * format configuration. If NewAudioTrack fails, try again with a less
731 * advanced format (PCM S16N). If it fails again, try again with Stereo
733 p_audiotrack = JNIThread_NewAudioTrack( env, p_aout, p_sys->fmt.i_rate,
735 p_sys->fmt.i_physical_channels,
736 &i_audiotrack_size );
739 if( p_sys->fmt.i_format == VLC_CODEC_FL32 )
741 msg_Warn( p_aout, "FL32 configuration failed, "
742 "fallback to S16N PCM" );
743 p_sys->fmt.i_format = VLC_CODEC_S16N;
745 else if( i_nb_channels > 5 )
747 msg_Warn( p_aout, "5.1 or 7.1 configuration failed, "
748 "fallback to Stereo" );
749 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
750 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
755 } while( !p_audiotrack );
760 p_sys->p_audiotrack = (*env)->NewGlobalRef( env, p_audiotrack );
761 (*env)->DeleteLocalRef( env, p_audiotrack );
762 if( !p_sys->p_audiotrack )
765 memset( p_chans_out, 0, sizeof(p_chans_out) );
766 AudioTrack_GetChanOrder( p_sys->fmt.i_physical_channels, p_chans_out );
767 p_sys->i_chans_to_reorder =
768 aout_CheckChannelReorder( NULL, p_chans_out,
769 p_sys->fmt.i_physical_channels,
770 p_sys->p_chan_table );
772 p_sys->i_bytes_per_frame = i_nb_channels *
773 aout_BitsPerSample( p_sys->fmt.i_format ) /
775 p_sys->i_max_audiotrack_samples = i_audiotrack_size /
776 p_sys->i_bytes_per_frame;
778 #ifdef AUDIOTRACK_USE_TIMESTAMP
779 if( jfields.AudioTimestamp.clazz )
781 /* create AudioTimestamp object */
782 jobject p_audioTimestamp = JNI_CALL( NewObject,
783 jfields.AudioTimestamp.clazz,
784 jfields.AudioTimestamp.ctor );
785 if( !p_audioTimestamp )
787 JNIThread_Stop( env, p_aout );
790 p_sys->p_audioTimestamp = (*env)->NewGlobalRef( env, p_audioTimestamp );
791 (*env)->DeleteLocalRef( env, p_audioTimestamp );
792 if( !p_sys->p_audioTimestamp )
794 JNIThread_Stop( env, p_aout );
800 if( jfields.AudioTrack.writeV21 )
802 msg_Dbg( p_aout, "using WRITE_V21");
803 p_sys->i_write_type = WRITE_V21;
807 msg_Dbg( p_aout, "using WRITE");
808 p_sys->i_write_type = WRITE;
811 JNI_AT_CALL_VOID( play );
812 CHECK_AT_EXCEPTION( "play" );
813 p_sys->i_play_time = mdate();
815 aout_FormatPrint( p_aout, "VLC will output:", &p_sys->fmt );
821 JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
823 aout_sys_t *p_sys = p_aout->sys;
825 if( p_sys->p_audiotrack )
827 if( !p_sys->b_audiotrack_exception )
829 JNI_AT_CALL_VOID( stop );
830 if( !CHECK_AT_EXCEPTION( "stop" ) )
831 JNI_AT_CALL_VOID( release );
833 (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
834 p_sys->p_audiotrack = NULL;
836 p_sys->b_audiotrack_exception = false;
838 if( p_sys->p_audioTimestamp )
840 (*env)->DeleteGlobalRef( env, p_sys->p_audioTimestamp );
841 p_sys->p_audioTimestamp = NULL;
846 * Non blocking write function.
847 * Do a calculation between current position and audiotrack position and assure
848 * that we won't wait in AudioTrack.write() method
851 JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
852 size_t i_buffer_offset )
854 aout_sys_t *p_sys = p_aout->sys;
857 uint32_t i_audiotrack_pos;
858 uint32_t i_samples_pending;
860 i_data = p_buffer->i_buffer - i_buffer_offset;
861 i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
862 if( i_audiotrack_pos > p_sys->i_samples_written )
864 msg_Warn( p_aout, "audiotrack position is ahead. Should NOT happen" );
865 JNIThread_InitDelay( env, p_aout );
868 i_samples_pending = p_sys->i_samples_written - i_audiotrack_pos;
870 /* check if audiotrack buffer is not full before writing on it. */
871 if( i_samples_pending >= p_sys->i_max_audiotrack_samples )
874 /* HACK: AudioFlinger can drop frames without notifying us and there is
875 * no way to know it. It it happens, i_audiotrack_pos won't move and
876 * the current code will be stuck because it'll assume that audiotrack
877 * internal buffer is full when it's not. It can happen only after
878 * Android 4.4.2 if we send frames too quickly. This HACK is just an
879 * other precaution since it shouldn't happen anymore thanks to the
880 * HACK in JNIThread_Play */
882 p_sys->i_audiotrack_stuck_count++;
883 if( p_sys->i_audiotrack_stuck_count > 100 )
885 msg_Warn( p_aout, "AudioFlinger underrun, force write" );
886 i_samples_pending = 0;
887 p_sys->i_audiotrack_stuck_count = 0;
890 p_sys->i_audiotrack_stuck_count = 0;
891 i_samples = __MIN( p_sys->i_max_audiotrack_samples - i_samples_pending,
892 BYTES_TO_FRAMES( i_data ) );
894 i_data = i_samples * p_sys->i_bytes_per_frame;
896 return JNI_AT_CALL_INT( write, p_sys->p_bytearray,
897 i_buffer_offset, i_data );
901 * Non blocking write function for Lollipop and after.
902 * It calls a new write method with WRITE_NON_BLOCKING flags.
905 JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer,
906 size_t i_buffer_offset )
908 aout_sys_t *p_sys = p_aout->sys;
910 size_t i_data = p_buffer->i_buffer - i_buffer_offset;
911 uint8_t *p_data = p_buffer->p_buffer + i_buffer_offset;
913 if( !p_sys->p_bytebuffer )
915 jobject p_bytebuffer;
917 p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_data, i_data );
919 return jfields.AudioTrack.ERROR_BAD_VALUE;
921 p_sys->p_bytebuffer = (*env)->NewGlobalRef( env, p_bytebuffer );
922 (*env)->DeleteLocalRef( env, p_bytebuffer );
924 if( !p_sys->p_bytebuffer || (*env)->ExceptionOccurred( env ) )
926 p_sys->p_bytebuffer = NULL;
927 (*env)->ExceptionClear( env );
928 return jfields.AudioTrack.ERROR_BAD_VALUE;
932 i_ret = JNI_AT_CALL_INT( writeV21, p_sys->p_bytebuffer, i_data,
933 jfields.AudioTrack.WRITE_NON_BLOCKING );
936 /* don't delete the bytebuffer if we wrote nothing, keep it for next
938 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
939 p_sys->p_bytebuffer = NULL;
945 JNIThread_PreparePlay( JNIEnv *env, audio_output_t *p_aout,
948 aout_sys_t *p_sys = p_aout->sys;
950 if( p_sys->i_chans_to_reorder )
951 aout_ChannelReorder( p_buffer->p_buffer, p_buffer->i_buffer,
952 p_sys->i_chans_to_reorder, p_sys->p_chan_table,
953 p_sys->fmt.i_format );
955 switch( p_sys->i_write_type )
958 /* check if we need to realloc a ByteArray */
959 if( p_buffer->i_buffer > p_sys->i_bytearray_size )
961 jbyteArray p_bytearray;
963 if( p_sys->p_bytearray )
965 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
966 p_sys->p_bytearray = NULL;
969 p_bytearray = (*env)->NewByteArray( env, p_buffer->i_buffer );
972 p_sys->p_bytearray = (*env)->NewGlobalRef( env, p_bytearray );
973 (*env)->DeleteLocalRef( env, p_bytearray );
975 p_sys->i_bytearray_size = p_buffer->i_buffer;
977 if( !p_sys->p_bytearray )
980 /* copy p_buffer in to ByteArray */
981 (*env)->SetByteArrayRegion( env, p_sys->p_bytearray, 0,
983 (jbyte *)p_buffer->p_buffer);
993 JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
994 block_t *p_buffer, size_t *p_buffer_offset, mtime_t *p_wait )
996 aout_sys_t *p_sys = p_aout->sys;
999 switch( p_sys->i_write_type )
1002 i_ret = JNIThread_WriteV21( env, p_aout, p_buffer, *p_buffer_offset );
1005 i_ret = JNIThread_Write( env, p_aout, p_buffer, *p_buffer_offset );
1008 vlc_assert_unreachable();
1012 if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
1013 && i_ret == jfields.AudioManager.ERROR_DEAD_OBJECT )
1015 msg_Warn( p_aout, "ERROR_DEAD_OBJECT: "
1016 "try recreating AudioTrack" );
1017 JNIThread_Stop( env, p_aout );
1018 i_ret = JNIThread_Start( env, p_aout );
1022 if( i_ret == jfields.AudioTrack.ERROR_INVALID_OPERATION )
1023 str = "ERROR_INVALID_OPERATION";
1024 else if( i_ret == jfields.AudioTrack.ERROR_BAD_VALUE )
1025 str = "ERROR_BAD_VALUE";
1028 msg_Err( p_aout, "Write failed: %s", str );
1030 } else if( i_ret == 0 )
1032 /* audiotrack internal buffer is full, wait a little: between 10ms and
1033 * 20ms depending on devices or rate */
1034 *p_wait = FRAMES_TO_US( p_sys->i_max_audiotrack_samples / 20 );
1037 uint32_t i_samples = i_ret / p_sys->i_bytes_per_frame;
1038 p_sys->i_samples_queued -= i_samples;
1039 p_sys->i_samples_written += i_samples;
1041 *p_buffer_offset += i_ret;
1043 /* HACK: There is a known issue in audiotrack, "due to an internal
1044 * timeout within the AudioTrackThread". It happens after android
1045 * 4.4.2, it's not a problem for Android 5.0 since we use an other way
1046 * to write samples. A working hack is to wait a little between each
1047 * write. This hack is done only for API 19 (AudioTimestamp was added
1050 if( p_sys->i_write_type == WRITE && jfields.AudioTimestamp.clazz )
1051 *p_wait = FRAMES_TO_US( i_samples ) / 2;
1053 return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
1057 JNIThread_Pause( JNIEnv *env, audio_output_t *p_aout,
1058 bool b_pause, mtime_t i_date )
1060 VLC_UNUSED( i_date );
1062 aout_sys_t *p_sys = p_aout->sys;
1066 JNI_AT_CALL_VOID( pause );
1067 CHECK_AT_EXCEPTION( "pause" );
1070 JNI_AT_CALL_VOID( play );
1071 CHECK_AT_EXCEPTION( "play" );
1072 p_sys->i_play_time = mdate();
1077 JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
1080 aout_sys_t *p_sys = p_aout->sys;
1083 * stop(): Stops playing the audio data. When used on an instance created
1084 * in MODE_STREAM mode, audio will stop playing after the last buffer that
1085 * was written has been played. For an immediate stop, use pause(),
1086 * followed by flush() to discard audio data that hasn't been played back
1089 * flush(): Flushes the audio data currently queued for playback. Any data
1090 * that has not been played back will be discarded. No-op if not stopped
1091 * or paused, or if the track's creation mode is not MODE_STREAM.
1095 JNI_AT_CALL_VOID( stop );
1096 if( CHECK_AT_EXCEPTION( "stop" ) )
1100 JNI_AT_CALL_VOID( pause );
1101 if( CHECK_AT_EXCEPTION( "pause" ) )
1103 JNI_AT_CALL_VOID( flush );
1105 JNI_AT_CALL_VOID( play );
1106 CHECK_AT_EXCEPTION( "play" );
1107 p_sys->i_play_time = mdate();
1109 if( p_sys->p_bytebuffer )
1111 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1112 p_sys->p_bytebuffer = NULL;
1117 JNIThread( void *data )
1119 audio_output_t *p_aout = data;
1120 aout_sys_t *p_sys = p_aout->sys;
1121 bool b_error = false;
1122 bool b_paused = false;
1123 block_t *p_buffer = NULL;
1124 size_t i_buffer_offset = 0;
1125 mtime_t i_play_deadline = 0;
1128 jni_attach_thread( &env, THREAD_NAME );
1130 vlc_mutex_lock( &p_sys->mutex );
1134 while( p_sys->b_thread_run )
1136 struct thread_cmd *p_cmd;
1137 bool b_remove_cmd = true;
1139 /* wait to process a command */
1140 while( ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue ) ) == NULL
1141 && p_sys->b_thread_run )
1142 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1144 if( !p_sys->b_thread_run || p_cmd == NULL )
1147 if( b_paused && p_cmd->id == CMD_PLAY )
1149 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1153 if( p_cmd->id == CMD_PLAY && i_play_deadline > 0 )
1155 if( mdate() > i_play_deadline )
1156 i_play_deadline = 0;
1160 while( p_cmd == TAILQ_FIRST( &p_sys->thread_cmd_queue )
1161 && i_ret != ETIMEDOUT && p_sys->b_thread_run )
1162 i_ret = vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex,
1168 /* process a command */
1172 assert( !p_sys->p_audiotrack );
1174 p_cmd->out.start.i_ret = -1;
1177 p_sys->fmt = *p_cmd->in.start.p_fmt;
1178 p_cmd->out.start.i_ret =
1179 JNIThread_Start( env, p_aout );
1180 JNIThread_InitDelay( env, p_aout );
1181 p_cmd->out.start.p_fmt = &p_sys->fmt;
1185 assert( p_sys->p_audiotrack );
1186 JNIThread_Stop( env, p_aout );
1187 JNIThread_InitDelay( env, p_aout );
1194 mtime_t i_play_wait = 0;
1196 assert( p_sys->p_audiotrack );
1199 if( p_buffer == NULL )
1201 p_buffer = p_cmd->in.play.p_buffer;
1202 b_error = JNIThread_PreparePlay( env, p_aout, p_buffer )
1207 b_error = JNIThread_Play( env, p_aout, p_buffer,
1209 &i_play_wait ) != VLC_SUCCESS;
1210 if( i_buffer_offset < p_buffer->i_buffer )
1212 /* buffer is not fully processed, try again with the
1213 * same cmd and buffer */
1214 b_remove_cmd = false;
1219 i_buffer_offset = 0;
1221 if( i_play_wait > 0 )
1222 i_play_deadline = mdate() + i_play_wait;
1226 assert( p_sys->p_audiotrack );
1229 JNIThread_Pause( env, p_aout,
1230 p_cmd->in.pause.b_pause,
1231 p_cmd->in.pause.i_date );
1232 b_paused = p_cmd->in.pause.b_pause;
1235 assert( p_sys->p_audiotrack );
1238 p_cmd->out.time_get.i_ret = -1;
1241 p_cmd->out.time_get.i_ret =
1242 JNIThread_TimeGet( env, p_aout,
1243 &p_cmd->out.time_get.i_delay );
1246 assert( p_sys->p_audiotrack );
1249 JNIThread_Flush( env, p_aout,
1250 p_cmd->in.flush.b_wait );
1251 JNIThread_InitDelay( env, p_aout );
1255 vlc_assert_unreachable();
1257 if( p_sys->b_audiotrack_exception )
1260 p_sys->i_samples_queued = 0;
1264 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
1265 p_cmd->id = CMD_DONE;
1266 if( p_cmd->pf_destroy )
1267 p_cmd->pf_destroy( p_cmd );
1270 /* signal that command is processed */
1271 vlc_cond_signal( &p_sys->cond );
1276 if( p_sys->p_bytearray )
1277 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
1278 if( p_sys->p_bytebuffer )
1279 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1280 jni_detach_thread();
1282 vlc_mutex_unlock( &p_sys->mutex );
1287 Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
1289 int i_ret = VLC_EGENERIC;
1290 struct thread_cmd *p_cmd;
1291 aout_sys_t *p_sys = p_aout->sys;
1293 vlc_mutex_lock( &p_sys->mutex );
1295 p_cmd = ThreadCmd_New( CMD_START );
1298 /* ask the thread to process the Start command */
1299 p_cmd->in.start.p_fmt = p_fmt;
1301 ThreadCmd_InsertHead( p_sys, p_cmd );
1302 if( ThreadCmd_Wait( p_sys, p_cmd ) )
1304 i_ret = p_cmd->out.start.i_ret;
1305 if( i_ret == VLC_SUCCESS )
1306 *p_fmt = *p_cmd->out.start.p_fmt;
1311 vlc_mutex_unlock( &p_sys->mutex );
1313 if( i_ret == VLC_SUCCESS )
1314 aout_SoftVolumeStart( p_aout );
1320 Stop( audio_output_t *p_aout )
1322 aout_sys_t *p_sys = p_aout->sys;
1323 struct thread_cmd *p_cmd;
1325 vlc_mutex_lock( &p_sys->mutex );
1327 ThreadCmd_FlushQueue( p_sys );
1329 p_cmd = ThreadCmd_New( CMD_STOP );
1332 /* ask the thread to process the Stop command */
1333 ThreadCmd_InsertHead( p_sys, p_cmd );
1334 ThreadCmd_Wait( p_sys, p_cmd );
1339 vlc_mutex_unlock( &p_sys->mutex );
1343 PlayCmd_Destroy( struct thread_cmd *p_cmd )
1345 block_Release( p_cmd->in.play.p_buffer );
1350 Play( audio_output_t *p_aout, block_t *p_buffer )
1352 aout_sys_t *p_sys = p_aout->sys;
1353 struct thread_cmd *p_cmd;
1355 vlc_mutex_lock( &p_sys->mutex );
1357 while( p_sys->i_samples_queued != 0
1358 && FRAMES_TO_US( p_sys->i_samples_queued +
1359 p_buffer->i_nb_samples ) >= MAX_QUEUE_US )
1360 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1362 p_cmd = ThreadCmd_New( CMD_PLAY );
1365 /* ask the thread to process the Play command */
1366 p_cmd->in.play.p_buffer = p_buffer;
1367 p_cmd->pf_destroy = PlayCmd_Destroy;
1369 ThreadCmd_InsertTail( p_sys, p_cmd );
1371 p_sys->i_samples_queued += p_buffer->i_nb_samples;
1373 block_Release( p_cmd->in.play.p_buffer );
1375 vlc_mutex_unlock( &p_sys->mutex );
1379 Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
1381 aout_sys_t *p_sys = p_aout->sys;
1382 struct thread_cmd *p_cmd;
1384 vlc_mutex_lock( &p_sys->mutex );
1386 p_cmd = ThreadCmd_New( CMD_PAUSE );
1389 /* ask the thread to process the Pause command */
1390 p_cmd->in.pause.b_pause = b_pause;
1391 p_cmd->in.pause.i_date = i_date;
1393 ThreadCmd_InsertHead( p_sys, p_cmd );
1394 ThreadCmd_Wait( p_sys, p_cmd );
1399 vlc_mutex_unlock( &p_sys->mutex );
1403 Flush( audio_output_t *p_aout, bool b_wait )
1405 aout_sys_t *p_sys = p_aout->sys;
1406 struct thread_cmd *p_cmd;
1408 vlc_mutex_lock( &p_sys->mutex );
1410 ThreadCmd_FlushQueue( p_sys );
1412 p_cmd = ThreadCmd_New( CMD_FLUSH );
1415 /* ask the thread to process the Flush command */
1416 p_cmd->in.flush.b_wait = b_wait;
1418 ThreadCmd_InsertHead( p_sys, p_cmd );
1419 ThreadCmd_Wait( p_sys, p_cmd );
1424 vlc_mutex_unlock( &p_sys->mutex );
1428 TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
1430 aout_sys_t *p_sys = p_aout->sys;
1431 struct thread_cmd *p_cmd;
1434 vlc_mutex_lock( &p_sys->mutex );
1436 p_cmd = ThreadCmd_New( CMD_TIME_GET );
1439 ThreadCmd_InsertHead( p_sys, p_cmd );
1440 ThreadCmd_Wait( p_sys, p_cmd );
1442 i_ret = p_cmd->out.time_get.i_ret;
1443 *p_delay = p_cmd->out.time_get.i_delay;
1447 vlc_mutex_unlock( &p_sys->mutex );
1454 Open( vlc_object_t *obj )
1456 audio_output_t *p_aout = (audio_output_t *) obj;
1459 if( !InitJNIFields( p_aout ) )
1460 return VLC_EGENERIC;
1462 p_sys = calloc( 1, sizeof (aout_sys_t) );
1464 if( unlikely( p_sys == NULL ) )
1467 vlc_mutex_init( &p_sys->mutex );
1468 vlc_cond_init( &p_sys->cond );
1469 TAILQ_INIT( &p_sys->thread_cmd_queue );
1471 p_aout->sys = p_sys;
1472 p_aout->start = Start;
1473 p_aout->stop = Stop;
1474 p_aout->play = Play;
1475 p_aout->pause = Pause;
1476 p_aout->flush = Flush;
1477 p_aout->time_get = TimeGet;
1479 aout_SoftVolumeInit( p_aout );
1481 /* create JNIThread */
1482 p_sys->b_thread_run = true;
1483 if( vlc_clone( &p_sys->thread,
1484 JNIThread, p_aout, VLC_THREAD_PRIORITY_AUDIO ) )
1486 msg_Err( p_aout, "JNIThread creation failed" );
1487 p_sys->b_thread_run = false;
1489 return VLC_EGENERIC;
1496 Close( vlc_object_t *obj )
1498 audio_output_t *p_aout = (audio_output_t *) obj;
1499 aout_sys_t *p_sys = p_aout->sys;
1501 /* kill the thread */
1502 vlc_mutex_lock( &p_sys->mutex );
1503 if( p_sys->b_thread_run )
1505 p_sys->b_thread_run = false;
1506 vlc_cond_signal( &p_sys->cond );
1507 vlc_mutex_unlock( &p_sys->mutex );
1508 vlc_join( p_sys->thread, NULL );
1510 vlc_mutex_unlock( &p_sys->mutex );
1512 vlc_mutex_destroy( &p_sys->mutex );
1513 vlc_cond_destroy( &p_sys->cond );