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];
73 /* JNIThread control */
78 /* Shared between two threads, must be locked */
79 bool b_thread_run; /* is thread alive */
80 THREAD_CMD_QUEUE thread_cmd_queue; /* thread cmd queue */
81 uint32_t i_samples_queued; /* number of samples queued */
84 /* Soft volume helper */
85 #include "audio_output/volume.h"
87 //#define AUDIOTRACK_USE_FLOAT
88 // TODO: activate getTimestamp for new android versions
89 //#define AUDIOTRACK_USE_TIMESTAMP
92 set_shortname( "AudioTrack" )
93 set_description( N_( "Android AudioTrack audio output" ) )
94 set_capability( "audio output", 180 )
95 set_category( CAT_AUDIO )
96 set_subcategory( SUBCAT_AUDIO_AOUT )
98 add_shortcut( "audiotrack" )
99 set_callbacks( Open, Close )
104 TAILQ_ENTRY(thread_cmd) next;
116 audio_sample_format_t *p_fmt;
132 audio_sample_format_t *p_fmt;
139 void ( *pf_destroy )( struct thread_cmd * );
142 #define THREAD_NAME "android_audiotrack"
144 extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
145 extern void jni_detach_thread();
146 extern int jni_get_env(JNIEnv **env);
161 jmethodID getPlaybackHeadPosition;
162 jmethodID getTimestamp;
163 jmethodID getMinBufferSize;
164 jint STATE_INITIALIZED;
167 jint ERROR_BAD_VALUE;
168 jint ERROR_INVALID_OPERATION;
169 jint WRITE_NON_BLOCKING;
172 jint ENCODING_PCM_8BIT;
173 jint ENCODING_PCM_16BIT;
174 jint ENCODING_PCM_FLOAT;
175 bool has_ENCODING_PCM_FLOAT;
176 jint CHANNEL_OUT_MONO;
177 jint CHANNEL_OUT_STEREO;
178 jint CHANNEL_OUT_FRONT_LEFT;
179 jint CHANNEL_OUT_FRONT_RIGHT;
180 jint CHANNEL_OUT_BACK_LEFT;
181 jint CHANNEL_OUT_BACK_RIGHT;
182 jint CHANNEL_OUT_FRONT_CENTER;
183 jint CHANNEL_OUT_LOW_FREQUENCY;
184 jint CHANNEL_OUT_BACK_CENTER;
185 jint CHANNEL_OUT_5POINT1;
186 jint CHANNEL_OUT_SIDE_LEFT;
187 jint CHANNEL_OUT_SIDE_RIGHT;
188 bool has_CHANNEL_OUT_SIDE;
191 jint ERROR_DEAD_OBJECT;
192 bool has_ERROR_DEAD_OBJECT;
198 jfieldID framePosition;
203 /* init all jni fields.
204 * Done only one time during the first initialisation */
206 InitJNIFields( audio_output_t *p_aout )
208 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
209 static int i_init_state = -1;
210 bool ret, b_attached = false;
215 vlc_mutex_lock( &lock );
217 if( i_init_state != -1 )
220 if( jni_get_env(&env) < 0 )
222 jni_attach_thread( &env, THREAD_NAME );
231 #define CHECK_EXCEPTION( what, critical ) do { \
232 if( (*env)->ExceptionOccurred( env ) ) \
234 msg_Err( p_aout, "%s failed", what ); \
235 (*env)->ExceptionClear( env ); \
243 #define GET_CLASS( str, critical ) do { \
244 clazz = (*env)->FindClass( env, (str) ); \
245 CHECK_EXCEPTION( str, critical ); \
247 #define GET_ID( get, id, str, args, critical ) do { \
248 jfields.id = (*env)->get( env, clazz, (str), (args) ); \
249 CHECK_EXCEPTION( #get, critical ); \
251 #define GET_CONST_INT( id, str, critical ) do { \
253 field = (*env)->GetStaticFieldID( env, clazz, (str), "I" ); \
254 CHECK_EXCEPTION( #id, critical ); \
257 jfields.id = (*env)->GetStaticIntField( env, clazz, field ); \
258 CHECK_EXCEPTION( #id, critical ); \
262 /* AudioTrack class init */
263 GET_CLASS( "android/media/AudioTrack", true );
264 jfields.AudioTrack.clazz = (jclass) (*env)->NewGlobalRef( env, clazz );
265 CHECK_EXCEPTION( "NewGlobalRef", true );
267 GET_ID( GetMethodID, AudioTrack.ctor, "<init>", "(IIIIII)V", true );
268 GET_ID( GetMethodID, AudioTrack.release, "release", "()V", true );
269 GET_ID( GetMethodID, AudioTrack.getState, "getState", "()I", true );
270 GET_ID( GetMethodID, AudioTrack.play, "play", "()V", true );
271 GET_ID( GetMethodID, AudioTrack.stop, "stop", "()V", true );
272 GET_ID( GetMethodID, AudioTrack.flush, "flush", "()V", true );
273 GET_ID( GetMethodID, AudioTrack.pause, "pause", "()V", true );
275 GET_ID( GetMethodID, AudioTrack.writeV21, "write", "(Ljava/nio/ByteBuffer;II)I", false );
276 if( jfields.AudioTrack.writeV21 )
278 GET_CONST_INT( AudioTrack.WRITE_NON_BLOCKING, "WRITE_NON_BLOCKING", true );
280 GET_ID( GetMethodID, AudioTrack.write, "write", "([BII)I", true );
282 GET_ID( GetMethodID, AudioTrack.getTimestamp,
283 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
284 GET_ID( GetMethodID, AudioTrack.getPlaybackHeadPosition,
285 "getPlaybackHeadPosition", "()I", true );
287 GET_ID( GetStaticMethodID, AudioTrack.getMinBufferSize, "getMinBufferSize",
289 GET_CONST_INT( AudioTrack.STATE_INITIALIZED, "STATE_INITIALIZED", true );
290 GET_CONST_INT( AudioTrack.MODE_STREAM, "MODE_STREAM", true );
291 GET_CONST_INT( AudioTrack.ERROR, "ERROR", true );
292 GET_CONST_INT( AudioTrack.ERROR_BAD_VALUE , "ERROR_BAD_VALUE", true );
293 GET_CONST_INT( AudioTrack.ERROR_INVALID_OPERATION,
294 "ERROR_INVALID_OPERATION", true );
296 /* AudioTimestamp class init (if any) */
297 if( jfields.AudioTrack.getTimestamp )
299 GET_CLASS( "android/media/AudioTimestamp", true );
300 jfields.AudioTimestamp.clazz = (jclass) (*env)->NewGlobalRef( env,
302 CHECK_EXCEPTION( "NewGlobalRef", true );
304 GET_ID( GetMethodID, AudioTimestamp.ctor, "<init>", "()V", true );
305 GET_ID( GetFieldID, AudioTimestamp.framePosition,
306 "framePosition", "J", true );
307 GET_ID( GetFieldID, AudioTimestamp.nanoTime,
308 "nanoTime", "J", true );
311 /* AudioFormat class init */
312 GET_CLASS( "android/media/AudioFormat", true );
313 GET_CONST_INT( AudioFormat.ENCODING_PCM_8BIT, "ENCODING_PCM_8BIT", true );
314 GET_CONST_INT( AudioFormat.ENCODING_PCM_16BIT, "ENCODING_PCM_16BIT", true );
315 #ifdef AUDIOTRACK_USE_FLOAT
316 GET_CONST_INT( AudioFormat.ENCODING_PCM_FLOAT, "ENCODING_PCM_FLOAT",
318 jfields.AudioFormat.has_ENCODING_PCM_FLOAT = field != NULL;
320 jfields.AudioFormat.has_ENCODING_PCM_FLOAT = false;
322 GET_CONST_INT( AudioFormat.CHANNEL_OUT_MONO, "CHANNEL_OUT_MONO", true );
323 GET_CONST_INT( AudioFormat.CHANNEL_OUT_STEREO, "CHANNEL_OUT_STEREO", true );
324 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_LEFT, "CHANNEL_OUT_FRONT_LEFT", true );
325 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_RIGHT, "CHANNEL_OUT_FRONT_RIGHT", true );
326 GET_CONST_INT( AudioFormat.CHANNEL_OUT_5POINT1, "CHANNEL_OUT_5POINT1", true );
327 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_LEFT, "CHANNEL_OUT_BACK_LEFT", true );
328 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_RIGHT, "CHANNEL_OUT_BACK_RIGHT", true );
329 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_CENTER, "CHANNEL_OUT_FRONT_CENTER", true );
330 GET_CONST_INT( AudioFormat.CHANNEL_OUT_LOW_FREQUENCY, "CHANNEL_OUT_LOW_FREQUENCY", true );
331 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_CENTER, "CHANNEL_OUT_BACK_CENTER", true );
332 GET_CONST_INT( AudioFormat.CHANNEL_OUT_SIDE_LEFT, "CHANNEL_OUT_SIDE_LEFT", false );
335 GET_CONST_INT( AudioFormat.CHANNEL_OUT_SIDE_RIGHT, "CHANNEL_OUT_SIDE_RIGHT", true );
336 jfields.AudioFormat.has_CHANNEL_OUT_SIDE = true;
338 jfields.AudioFormat.has_CHANNEL_OUT_SIDE = false;
340 /* AudioManager class init */
341 GET_CLASS( "android/media/AudioManager", true );
342 GET_CONST_INT( AudioManager.ERROR_DEAD_OBJECT, "ERROR_DEAD_OBJECT", false );
343 jfields.AudioManager.has_ERROR_DEAD_OBJECT = field != NULL;
344 GET_CONST_INT( AudioManager.STREAM_MUSIC, "STREAM_MUSIC", true );
346 #undef CHECK_EXCEPTION
353 ret = i_init_state == 1;
355 msg_Err( p_aout, "AudioTrack jni init failed" );
358 vlc_mutex_unlock( &lock );
363 check_exception( JNIEnv *env, audio_output_t *p_aout,
366 if( (*env)->ExceptionOccurred( env ) )
368 aout_sys_t *p_sys = p_aout->sys;
370 p_sys->b_audiotrack_exception = true;
371 (*env)->ExceptionClear( env );
372 msg_Err( p_aout, "AudioTrack.%s triggered an exception !", method );
377 #define CHECK_AT_EXCEPTION( method ) check_exception( env, p_aout, method )
379 #define JNI_CALL( what, obj, method, ... ) (*env)->what( env, obj, method, ##__VA_ARGS__ )
381 #define JNI_CALL_INT( obj, method, ... ) JNI_CALL( CallIntMethod, obj, method, ##__VA_ARGS__ )
382 #define JNI_CALL_BOOL( obj, method, ... ) JNI_CALL( CallBooleanMethod, obj, method, ##__VA_ARGS__ )
383 #define JNI_CALL_VOID( obj, method, ... ) JNI_CALL( CallVoidMethod, obj, method, ##__VA_ARGS__ )
384 #define JNI_CALL_STATIC_INT( clazz, method, ... ) JNI_CALL( CallStaticIntMethod, clazz, method, ##__VA_ARGS__ )
386 #define JNI_AT_NEW( ... ) JNI_CALL( NewObject, jfields.AudioTrack.clazz, jfields.AudioTrack.ctor, ##__VA_ARGS__ )
387 #define JNI_AT_CALL_INT( method, ... ) JNI_CALL_INT( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
388 #define JNI_AT_CALL_BOOL( method, ... ) JNI_CALL_BOOL( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
389 #define JNI_AT_CALL_VOID( method, ... ) JNI_CALL_VOID( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
390 #define JNI_AT_CALL_STATIC_INT( method, ... ) JNI_CALL( CallStaticIntMethod, jfields.AudioTrack.clazz, jfields.AudioTrack.method, ##__VA_ARGS__ )
392 #define JNI_AUDIOTIMESTAMP_GET_LONG( field ) JNI_CALL( GetLongField, p_sys->p_audioTimestamp, jfields.AudioTimestamp.field )
394 static inline mtime_t
395 frames_to_us( aout_sys_t *p_sys, uint32_t i_nb_frames )
397 return i_nb_frames * CLOCK_FREQ / p_sys->fmt.i_rate;
399 #define FRAMES_TO_US(x) frames_to_us( p_sys, (x) )
401 static struct thread_cmd *
402 ThreadCmd_New( int id )
404 struct thread_cmd *p_cmd = calloc( 1, sizeof(struct thread_cmd) );
413 ThreadCmd_InsertHead( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
415 TAILQ_INSERT_HEAD( &p_sys->thread_cmd_queue, p_cmd, next);
416 vlc_cond_signal( &p_sys->cond );
420 ThreadCmd_InsertTail( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
422 TAILQ_INSERT_TAIL( &p_sys->thread_cmd_queue, p_cmd, next);
423 vlc_cond_signal( &p_sys->cond );
427 ThreadCmd_Wait( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
429 while( p_cmd->id != CMD_DONE )
430 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
432 return p_cmd->id == CMD_DONE;
436 ThreadCmd_FlushQueue( aout_sys_t *p_sys )
438 struct thread_cmd *p_cmd, *p_cmd_next;
440 for ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue );
441 p_cmd != NULL; p_cmd = p_cmd_next )
443 p_cmd_next = TAILQ_NEXT( p_cmd, next );
444 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
445 if( p_cmd->pf_destroy )
446 p_cmd->pf_destroy( p_cmd );
451 JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout )
453 aout_sys_t *p_sys = p_aout->sys;
455 if( p_sys->p_audiotrack )
456 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
458 p_sys->i_pos_initial = 0;
460 /* HACK: On some broken devices, head position is still moving after a
461 * flush or a stop. So, wait for the head position to be stabilized. */
462 if( unlikely( p_sys->i_pos_initial != 0 ) )
466 i_last_pos = p_sys->i_pos_initial;
468 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
469 } while( p_sys->i_pos_initial != i_last_pos );
471 p_sys->i_samples_written = 0;
472 p_sys->i_samples_queued = 0;
476 JNIThread_GetAudioTrackPos( JNIEnv *env, audio_output_t *p_aout )
478 aout_sys_t *p_sys = p_aout->sys;
481 * getPlaybackHeadPosition: Returns the playback head position expressed in
482 * frames. Though the "int" type is signed 32-bits, the value should be
483 * reinterpreted as if it is unsigned 32-bits. That is, the next position
484 * after 0x7FFFFFFF is (int) 0x80000000. This is a continuously advancing
485 * counter. It will wrap (overflow) periodically, for example approximately
486 * once every 27:03:11 hours:minutes:seconds at 44.1 kHz. It is reset to
487 * zero by flush(), reload(), and stop().
490 return JNI_AT_CALL_INT( getPlaybackHeadPosition ) - p_sys->i_pos_initial;
494 JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
496 aout_sys_t *p_sys = p_aout->sys;
498 uint32_t i_audiotrack_delay = 0;
500 if( p_sys->i_samples_queued == 0 )
502 if( p_sys->p_audioTimestamp )
504 mtime_t i_current_time = mdate();
506 * getTimestamp: Poll for a timestamp on demand.
508 * If you need to track timestamps during initial warmup or after a
509 * routing or mode change, you should request a new timestamp once per
510 * second until the reported timestamps show that the audio clock is
511 * stable. Thereafter, query for a new timestamp approximately once
512 * every 10 seconds to once per minute. Calling this method more often
513 * is inefficient. It is also counter-productive to call this method
514 * more often than recommended, because the short-term differences
515 * between successive timestamp reports are not meaningful. If you need
516 * a high-resolution mapping between frame position and presentation
517 * time, consider implementing that at application level, based on
518 * low-resolution timestamps.
521 if( JNI_AT_CALL_BOOL( getTimestamp, p_sys->p_audioTimestamp ) )
523 jlong i_frame_time = JNI_AUDIOTIMESTAMP_GET_LONG( nanoTime ) / 1000;
524 /* frame time should be after last play time
525 * frame time shouldn't be in the future
526 * frame time should be less than 10 seconds old */
527 if( i_frame_time > p_sys->i_play_time
528 && i_current_time > i_frame_time
529 && ( i_current_time - i_frame_time ) <= INT64_C(10000000) )
531 jlong i_time_diff = i_current_time - i_frame_time;
532 jlong i_frames_diff = i_time_diff * p_sys->fmt.i_rate
534 i_frame_pos = JNI_AUDIOTIMESTAMP_GET_LONG( framePosition )
536 if( p_sys->i_samples_written > i_frame_pos )
537 i_audiotrack_delay = p_sys->i_samples_written - i_frame_pos;
541 if( i_audiotrack_delay == 0 )
543 uint32_t i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
545 if( p_sys->i_samples_written > i_audiotrack_pos )
546 i_audiotrack_delay = p_sys->i_samples_written - i_audiotrack_pos;
549 if( i_audiotrack_delay > 0 )
551 *p_delay = FRAMES_TO_US( p_sys->i_samples_queued + i_audiotrack_delay );
558 AudioTrack_GetChanOrder( uint16_t i_physical_channels, uint32_t p_chans_out[] )
560 #define HAS_CHAN( x ) ( ( i_physical_channels & (x) ) == (x) )
561 /* samples will be in the following order: FL FR FC LFE BL BR BC SL SR */
564 if( HAS_CHAN( AOUT_CHAN_LEFT ) )
565 p_chans_out[i++] = AOUT_CHAN_LEFT;
566 if( HAS_CHAN( AOUT_CHAN_RIGHT ) )
567 p_chans_out[i++] = AOUT_CHAN_RIGHT;
569 if( HAS_CHAN( AOUT_CHAN_CENTER ) )
570 p_chans_out[i++] = AOUT_CHAN_CENTER;
572 if( HAS_CHAN( AOUT_CHAN_LFE ) )
573 p_chans_out[i++] = AOUT_CHAN_LFE;
575 if( HAS_CHAN( AOUT_CHAN_REARLEFT ) )
576 p_chans_out[i++] = AOUT_CHAN_REARLEFT;
577 if( HAS_CHAN( AOUT_CHAN_REARRIGHT ) )
578 p_chans_out[i++] = AOUT_CHAN_REARRIGHT;
580 if( HAS_CHAN( AOUT_CHAN_REARCENTER ) )
581 p_chans_out[i++] = AOUT_CHAN_REARCENTER;
583 if( HAS_CHAN( AOUT_CHAN_MIDDLELEFT ) )
584 p_chans_out[i++] = AOUT_CHAN_MIDDLELEFT;
585 if( HAS_CHAN( AOUT_CHAN_MIDDLERIGHT ) )
586 p_chans_out[i++] = AOUT_CHAN_MIDDLERIGHT;
588 assert( i <= AOUT_CHAN_MAX );
593 * Configure and create an Android AudioTrack.
594 * returns NULL on configuration error
597 JNIThread_NewAudioTrack( JNIEnv *env, audio_output_t *p_aout,
599 vlc_fourcc_t i_vlc_format,
600 uint16_t i_physical_channels,
601 int *p_audiotrack_size )
603 int i_size, i_min_buffer_size, i_channel_config, i_format;
604 jobject p_audiotrack;
606 switch( i_vlc_format )
609 i_format = jfields.AudioFormat.ENCODING_PCM_8BIT;
612 i_format = jfields.AudioFormat.ENCODING_PCM_16BIT;
615 i_format = jfields.AudioFormat.ENCODING_PCM_FLOAT;
618 vlc_assert_unreachable();
621 switch( i_physical_channels )
624 /* bitmask of CHANNEL_OUT_7POINT1 doesn't correspond to 5POINT1 and
626 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_5POINT1 |
627 jfields.AudioFormat.CHANNEL_OUT_SIDE_LEFT |
628 jfields.AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
631 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_5POINT1;
634 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_MONO;
637 case AOUT_CHANS_STEREO:
638 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_STEREO;
642 i_min_buffer_size = JNI_AT_CALL_STATIC_INT( getMinBufferSize, i_rate,
643 i_channel_config, i_format );
644 if( i_min_buffer_size <= 0 )
646 msg_Warn( p_aout, "getMinBufferSize returned an invalid size" ) ;
649 i_size = i_min_buffer_size * 4;
651 /* create AudioTrack object */
652 p_audiotrack = JNI_AT_NEW( jfields.AudioManager.STREAM_MUSIC, i_rate,
653 i_channel_config, i_format, i_size,
654 jfields.AudioTrack.MODE_STREAM );
655 if( CHECK_AT_EXCEPTION( "AudioTrack<init>" ) || !p_audiotrack )
657 msg_Warn( p_aout, "AudioTrack Init failed" ) ;
660 if( JNI_CALL_INT( p_audiotrack, jfields.AudioTrack.getState )
661 != jfields.AudioTrack.STATE_INITIALIZED )
663 JNI_CALL_VOID( p_audiotrack, jfields.AudioTrack.release );
664 (*env)->DeleteLocalRef( env, p_audiotrack );
665 msg_Err( p_aout, "AudioTrack getState failed" );
668 *p_audiotrack_size = i_size;
674 JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
676 aout_sys_t *p_sys = p_aout->sys;
677 jobject p_audiotrack = NULL;
678 int i_nb_channels, i_audiotrack_size;
679 uint32_t p_chans_out[AOUT_CHAN_MAX];
681 aout_FormatPrint( p_aout, "VLC is looking for:", &p_sys->fmt );
683 p_sys->fmt.i_original_channels = p_sys->fmt.i_physical_channels;
685 /* 4000 <= frequency <= 48000 */
686 p_sys->fmt.i_rate = VLC_CLIP( p_sys->fmt.i_rate, 4000, 48000 );
688 /* We can only accept U8, S16N, FL32, and AC3 */
689 switch( p_sys->fmt.i_format )
696 if( !jfields.AudioFormat.has_ENCODING_PCM_FLOAT )
697 p_sys->fmt.i_format = VLC_CODEC_S16N;
700 p_sys->fmt.i_format = VLC_CODEC_S16N;
704 /* Android AudioTrack supports only mono, stereo, 5.1 and 7.1.
705 * Android will downmix to stereo if audio output doesn't handle 5.1 or 7.1
707 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
708 if( i_nb_channels > 5 )
710 if( i_nb_channels > 7 && jfields.AudioFormat.has_CHANNEL_OUT_SIDE )
711 p_sys->fmt.i_physical_channels = AOUT_CHANS_7_1;
713 p_sys->fmt.i_physical_channels = AOUT_CHANS_5_1;
716 if( i_nb_channels == 1 )
717 p_sys->fmt.i_physical_channels = AOUT_CHAN_LEFT;
719 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
721 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
725 /* Try to create an AudioTrack with the most advanced channel and
726 * format configuration. If NewAudioTrack fails, try again with a less
727 * advanced format (PCM S16N). If it fails again, try again with Stereo
729 p_audiotrack = JNIThread_NewAudioTrack( env, p_aout, p_sys->fmt.i_rate,
731 p_sys->fmt.i_physical_channels,
732 &i_audiotrack_size );
735 if( p_sys->fmt.i_format == VLC_CODEC_FL32 )
737 msg_Warn( p_aout, "FL32 configuration failed, "
738 "fallback to S16N PCM" );
739 p_sys->fmt.i_format = VLC_CODEC_S16N;
741 else if( i_nb_channels > 5 )
743 msg_Warn( p_aout, "5.1 or 7.1 configuration failed, "
744 "fallback to Stereo" );
745 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
746 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
751 } while( !p_audiotrack );
756 p_sys->p_audiotrack = (*env)->NewGlobalRef( env, p_audiotrack );
757 (*env)->DeleteLocalRef( env, p_audiotrack );
758 if( !p_sys->p_audiotrack )
761 memset( p_chans_out, 0, sizeof(p_chans_out) );
762 AudioTrack_GetChanOrder( p_sys->fmt.i_physical_channels, p_chans_out );
763 p_sys->i_chans_to_reorder =
764 aout_CheckChannelReorder( NULL, p_chans_out,
765 p_sys->fmt.i_physical_channels,
766 p_sys->p_chan_table );
768 p_sys->i_bytes_per_frame = i_nb_channels *
769 aout_BitsPerSample( p_sys->fmt.i_format ) /
771 p_sys->i_max_audiotrack_samples = i_audiotrack_size /
772 p_sys->i_bytes_per_frame;
774 #ifdef AUDIOTRACK_USE_TIMESTAMP
775 if( jfields.AudioTimestamp.clazz )
777 /* create AudioTimestamp object */
778 jobject p_audioTimestamp = JNI_CALL( NewObject,
779 jfields.AudioTimestamp.clazz,
780 jfields.AudioTimestamp.ctor );
781 if( !p_audioTimestamp )
783 JNIThread_Stop( env, p_aout );
786 p_sys->p_audioTimestamp = (*env)->NewGlobalRef( env, p_audioTimestamp );
787 (*env)->DeleteLocalRef( env, p_audioTimestamp );
788 if( !p_sys->p_audioTimestamp )
790 JNIThread_Stop( env, p_aout );
796 JNI_AT_CALL_VOID( play );
797 CHECK_AT_EXCEPTION( "play" );
798 p_sys->i_play_time = mdate();
800 aout_FormatPrint( p_aout, "VLC will output:", &p_sys->fmt );
806 JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
808 aout_sys_t *p_sys = p_aout->sys;
810 if( p_sys->p_audiotrack )
812 if( !p_sys->b_audiotrack_exception )
814 JNI_AT_CALL_VOID( stop );
815 if( !CHECK_AT_EXCEPTION( "stop" ) )
816 JNI_AT_CALL_VOID( release );
818 (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
819 p_sys->p_audiotrack = NULL;
821 p_sys->b_audiotrack_exception = false;
823 if( p_sys->p_audioTimestamp )
825 (*env)->DeleteGlobalRef( env, p_sys->p_audioTimestamp );
826 p_sys->p_audioTimestamp = NULL;
831 * Non blocking write function.
832 * Do a calculation between current position and audiotrack position and assure
833 * that we won't wait in AudioTrack.write() method
836 JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
838 aout_sys_t *p_sys = p_aout->sys;
839 uint8_t *p_data = p_buffer->p_buffer;
842 uint32_t i_audiotrack_pos;
843 uint32_t i_samples_pending;
845 i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
846 if( i_audiotrack_pos > p_sys->i_samples_written )
848 msg_Warn( p_aout, "audiotrack position is ahead. Should NOT happen" );
849 JNIThread_InitDelay( env, p_aout );
852 i_samples_pending = p_sys->i_samples_written - i_audiotrack_pos;
854 /* check if audiotrack buffer is not full before writing on it. */
855 if( i_samples_pending >= p_sys->i_max_audiotrack_samples )
858 /* HACK: AudioFlinger can drop frames without notifying us and there is
859 * no way to know it. It it happens, i_audiotrack_pos won't move and
860 * the current code will be stuck because it'll assume that audiotrack
861 * internal buffer is full when it's not. It can happen only after
862 * Android 4.4.2 if we send frames too quickly. This HACK is just an
863 * other precaution since it shouldn't happen anymore thanks to the
864 * HACK in JNIThread_Play */
866 p_sys->i_audiotrack_stuck_count++;
867 if( p_sys->i_audiotrack_stuck_count > 100 )
869 msg_Warn( p_aout, "AudioFlinger underrun, force write" );
870 i_samples_pending = 0;
871 p_sys->i_audiotrack_stuck_count = 0;
874 p_sys->i_audiotrack_stuck_count = 0;
875 i_samples = __MIN( p_sys->i_max_audiotrack_samples - i_samples_pending,
876 p_buffer->i_nb_samples );
878 i_data = i_samples * p_sys->i_bytes_per_frame;
880 /* check if we need to realloc a ByteArray */
881 if( i_data > p_sys->i_bytearray_size )
883 jbyteArray p_bytearray;
885 if( p_sys->p_bytearray )
887 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
888 p_sys->p_bytearray = NULL;
891 p_bytearray = (*env)->NewByteArray( env, i_data );
894 p_sys->p_bytearray = (*env)->NewGlobalRef( env, p_bytearray );
895 (*env)->DeleteLocalRef( env, p_bytearray );
897 p_sys->i_bytearray_size = i_data;
899 if( !p_sys->p_bytearray )
900 return jfields.AudioTrack.ERROR_BAD_VALUE;
902 /* copy p_buffer in to ByteArray */
903 (*env)->SetByteArrayRegion( env, p_sys->p_bytearray, 0, i_data,
906 return JNI_AT_CALL_INT( write, p_sys->p_bytearray, 0, i_data );
910 * Non blocking write function for Lollipop and after.
911 * It calls a new write method with WRITE_NON_BLOCKING flags.
914 JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
916 aout_sys_t *p_sys = p_aout->sys;
919 if( !p_sys->p_bytebuffer )
921 jobject p_bytebuffer;
923 p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_buffer->p_buffer,
924 p_buffer->i_buffer );
926 return jfields.AudioTrack.ERROR_BAD_VALUE;
928 p_sys->p_bytebuffer = (*env)->NewGlobalRef( env, p_bytebuffer );
929 (*env)->DeleteLocalRef( env, p_bytebuffer );
931 if( !p_sys->p_bytebuffer || (*env)->ExceptionOccurred( env ) )
933 p_sys->p_bytebuffer = NULL;
934 (*env)->ExceptionClear( env );
935 return jfields.AudioTrack.ERROR_BAD_VALUE;
939 i_ret = JNI_AT_CALL_INT( writeV21, p_sys->p_bytebuffer, p_buffer->i_buffer,
940 jfields.AudioTrack.WRITE_NON_BLOCKING );
943 /* don't delete the bytebuffer if we wrote nothing, keep it for next
945 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
946 p_sys->p_bytebuffer = NULL;
952 JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
953 block_t **pp_buffer, mtime_t *p_wait )
955 aout_sys_t *p_sys = p_aout->sys;
956 block_t *p_buffer = *pp_buffer;
959 if( jfields.AudioTrack.writeV21 )
960 i_ret = JNIThread_WriteV21( env, p_aout, p_buffer );
962 i_ret = JNIThread_Write( env, p_aout, p_buffer );
965 if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
966 && i_ret == jfields.AudioManager.ERROR_DEAD_OBJECT )
968 msg_Warn( p_aout, "ERROR_DEAD_OBJECT: "
969 "try recreating AudioTrack" );
970 JNIThread_Stop( env, p_aout );
971 i_ret = JNIThread_Start( env, p_aout );
975 if( i_ret == jfields.AudioTrack.ERROR_INVALID_OPERATION )
976 str = "ERROR_INVALID_OPERATION";
977 else if( i_ret == jfields.AudioTrack.ERROR_BAD_VALUE )
978 str = "ERROR_BAD_VALUE";
981 msg_Err( p_aout, "Write failed: %s", str );
983 } else if( i_ret == 0 )
985 /* audiotrack internal buffer is full, wait a little: between 10ms and
986 * 20ms depending on devices or rate */
987 *p_wait = FRAMES_TO_US( p_sys->i_max_audiotrack_samples / 20 );
990 uint32_t i_samples = i_ret / p_sys->i_bytes_per_frame;
991 p_sys->i_samples_queued -= i_samples;
992 p_sys->i_samples_written += i_samples;
994 p_buffer->p_buffer += i_ret;
995 p_buffer->i_buffer -= i_ret;
996 p_buffer->i_nb_samples -= i_samples;
997 if( p_buffer->i_buffer == 0 )
1000 /* HACK: There is a known issue in audiotrack, "due to an internal
1001 * timeout within the AudioTrackThread". It happens after android
1002 * 4.4.2, it's not a problem for Android 5.0 since we use an other way
1003 * to write samples. A working hack is to wait a little between each
1004 * write. This hack is done only for API 19 (AudioTimestamp was added
1007 if( jfields.AudioTimestamp.clazz && !jfields.AudioTrack.writeV21 )
1008 *p_wait = FRAMES_TO_US( i_samples ) / 2;
1010 return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
1014 JNIThread_Pause( JNIEnv *env, audio_output_t *p_aout,
1015 bool b_pause, mtime_t i_date )
1017 VLC_UNUSED( i_date );
1019 aout_sys_t *p_sys = p_aout->sys;
1023 JNI_AT_CALL_VOID( pause );
1024 CHECK_AT_EXCEPTION( "pause" );
1027 JNI_AT_CALL_VOID( play );
1028 CHECK_AT_EXCEPTION( "play" );
1029 p_sys->i_play_time = mdate();
1034 JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
1037 aout_sys_t *p_sys = p_aout->sys;
1040 * stop(): Stops playing the audio data. When used on an instance created
1041 * in MODE_STREAM mode, audio will stop playing after the last buffer that
1042 * was written has been played. For an immediate stop, use pause(),
1043 * followed by flush() to discard audio data that hasn't been played back
1046 * flush(): Flushes the audio data currently queued for playback. Any data
1047 * that has not been played back will be discarded. No-op if not stopped
1048 * or paused, or if the track's creation mode is not MODE_STREAM.
1052 JNI_AT_CALL_VOID( stop );
1053 if( CHECK_AT_EXCEPTION( "stop" ) )
1057 JNI_AT_CALL_VOID( pause );
1058 if( CHECK_AT_EXCEPTION( "pause" ) )
1060 JNI_AT_CALL_VOID( flush );
1062 JNI_AT_CALL_VOID( play );
1063 CHECK_AT_EXCEPTION( "play" );
1064 p_sys->i_play_time = mdate();
1066 if( p_sys->p_bytebuffer )
1068 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1069 p_sys->p_bytebuffer = NULL;
1074 JNIThread( void *data )
1076 audio_output_t *p_aout = data;
1077 aout_sys_t *p_sys = p_aout->sys;
1078 bool b_error = false;
1079 bool b_paused = false;
1080 block_t *p_buffer = NULL;
1081 mtime_t i_play_deadline = 0;
1084 jni_attach_thread( &env, THREAD_NAME );
1086 vlc_mutex_lock( &p_sys->mutex );
1090 while( p_sys->b_thread_run )
1092 struct thread_cmd *p_cmd;
1093 bool b_remove_cmd = true;
1095 /* wait to process a command */
1096 while( ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue ) ) == NULL
1097 && p_sys->b_thread_run )
1098 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1100 if( !p_sys->b_thread_run || p_cmd == NULL )
1103 if( b_paused && p_cmd->id == CMD_PLAY )
1105 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1109 if( p_cmd->id == CMD_PLAY && i_play_deadline > 0 )
1111 if( mdate() > i_play_deadline )
1112 i_play_deadline = 0;
1116 while( p_cmd == TAILQ_FIRST( &p_sys->thread_cmd_queue )
1117 && i_ret != ETIMEDOUT && p_sys->b_thread_run )
1118 i_ret = vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex,
1124 /* process a command */
1128 assert( !p_sys->p_audiotrack );
1130 p_cmd->out.start.i_ret = -1;
1133 p_sys->fmt = *p_cmd->in.start.p_fmt;
1134 p_cmd->out.start.i_ret =
1135 JNIThread_Start( env, p_aout );
1136 JNIThread_InitDelay( env, p_aout );
1137 p_cmd->out.start.p_fmt = &p_sys->fmt;
1141 assert( p_sys->p_audiotrack );
1142 JNIThread_Stop( env, p_aout );
1143 JNIThread_InitDelay( env, p_aout );
1150 mtime_t i_play_wait = 0;
1152 assert( p_sys->p_audiotrack );
1155 if( p_buffer == NULL )
1157 p_buffer = p_cmd->in.play.p_buffer;
1158 if( p_sys->i_chans_to_reorder )
1159 aout_ChannelReorder( p_buffer->p_buffer,
1161 p_sys->i_chans_to_reorder,
1162 p_sys->p_chan_table,
1163 p_sys->fmt.i_format );
1166 b_error = JNIThread_Play( env, p_aout, &p_buffer,
1167 &i_play_wait ) != VLC_SUCCESS;
1168 if( p_buffer != NULL )
1169 b_remove_cmd = false;
1170 if( i_play_wait > 0 )
1171 i_play_deadline = mdate() + i_play_wait;
1175 assert( p_sys->p_audiotrack );
1178 JNIThread_Pause( env, p_aout,
1179 p_cmd->in.pause.b_pause,
1180 p_cmd->in.pause.i_date );
1181 b_paused = p_cmd->in.pause.b_pause;
1184 assert( p_sys->p_audiotrack );
1187 p_cmd->out.time_get.i_ret = -1;
1190 p_cmd->out.time_get.i_ret =
1191 JNIThread_TimeGet( env, p_aout,
1192 &p_cmd->out.time_get.i_delay );
1195 assert( p_sys->p_audiotrack );
1198 JNIThread_Flush( env, p_aout,
1199 p_cmd->in.flush.b_wait );
1200 JNIThread_InitDelay( env, p_aout );
1204 vlc_assert_unreachable();
1206 if( p_sys->b_audiotrack_exception )
1209 p_sys->i_samples_queued = 0;
1213 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
1214 p_cmd->id = CMD_DONE;
1215 if( p_cmd->pf_destroy )
1216 p_cmd->pf_destroy( p_cmd );
1219 /* signal that command is processed */
1220 vlc_cond_signal( &p_sys->cond );
1225 if( p_sys->p_bytearray )
1226 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
1227 if( p_sys->p_bytebuffer )
1228 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1229 jni_detach_thread();
1231 vlc_mutex_unlock( &p_sys->mutex );
1236 Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
1238 int i_ret = VLC_EGENERIC;
1239 struct thread_cmd *p_cmd;
1240 aout_sys_t *p_sys = p_aout->sys;
1242 vlc_mutex_lock( &p_sys->mutex );
1244 p_cmd = ThreadCmd_New( CMD_START );
1247 /* ask the thread to process the Start command */
1248 p_cmd->in.start.p_fmt = p_fmt;
1250 ThreadCmd_InsertHead( p_sys, p_cmd );
1251 if( ThreadCmd_Wait( p_sys, p_cmd ) )
1253 i_ret = p_cmd->out.start.i_ret;
1254 if( i_ret == VLC_SUCCESS )
1255 *p_fmt = *p_cmd->out.start.p_fmt;
1260 vlc_mutex_unlock( &p_sys->mutex );
1262 if( i_ret == VLC_SUCCESS )
1263 aout_SoftVolumeStart( p_aout );
1269 Stop( audio_output_t *p_aout )
1271 aout_sys_t *p_sys = p_aout->sys;
1272 struct thread_cmd *p_cmd;
1274 vlc_mutex_lock( &p_sys->mutex );
1276 ThreadCmd_FlushQueue( p_sys );
1278 p_cmd = ThreadCmd_New( CMD_STOP );
1281 /* ask the thread to process the Stop command */
1282 ThreadCmd_InsertHead( p_sys, p_cmd );
1283 ThreadCmd_Wait( p_sys, p_cmd );
1288 vlc_mutex_unlock( &p_sys->mutex );
1292 PlayCmd_Destroy( struct thread_cmd *p_cmd )
1294 block_Release( p_cmd->in.play.p_buffer );
1299 Play( audio_output_t *p_aout, block_t *p_buffer )
1301 aout_sys_t *p_sys = p_aout->sys;
1302 struct thread_cmd *p_cmd;
1304 vlc_mutex_lock( &p_sys->mutex );
1306 while( p_sys->i_samples_queued != 0
1307 && FRAMES_TO_US( p_sys->i_samples_queued +
1308 p_buffer->i_nb_samples ) >= MAX_QUEUE_US )
1309 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1311 p_cmd = ThreadCmd_New( CMD_PLAY );
1314 /* ask the thread to process the Play command */
1315 p_cmd->in.play.p_buffer = p_buffer;
1316 p_cmd->pf_destroy = PlayCmd_Destroy;
1318 ThreadCmd_InsertTail( p_sys, p_cmd );
1320 p_sys->i_samples_queued += p_buffer->i_nb_samples;
1322 block_Release( p_cmd->in.play.p_buffer );
1324 vlc_mutex_unlock( &p_sys->mutex );
1328 Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
1330 aout_sys_t *p_sys = p_aout->sys;
1331 struct thread_cmd *p_cmd;
1333 vlc_mutex_lock( &p_sys->mutex );
1335 p_cmd = ThreadCmd_New( CMD_PAUSE );
1338 /* ask the thread to process the Pause command */
1339 p_cmd->in.pause.b_pause = b_pause;
1340 p_cmd->in.pause.i_date = i_date;
1342 ThreadCmd_InsertHead( p_sys, p_cmd );
1343 ThreadCmd_Wait( p_sys, p_cmd );
1348 vlc_mutex_unlock( &p_sys->mutex );
1352 Flush( audio_output_t *p_aout, bool b_wait )
1354 aout_sys_t *p_sys = p_aout->sys;
1355 struct thread_cmd *p_cmd;
1357 vlc_mutex_lock( &p_sys->mutex );
1359 ThreadCmd_FlushQueue( p_sys );
1361 p_cmd = ThreadCmd_New( CMD_FLUSH );
1364 /* ask the thread to process the Flush command */
1365 p_cmd->in.flush.b_wait = b_wait;
1367 ThreadCmd_InsertHead( p_sys, p_cmd );
1368 ThreadCmd_Wait( p_sys, p_cmd );
1373 vlc_mutex_unlock( &p_sys->mutex );
1377 TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
1379 aout_sys_t *p_sys = p_aout->sys;
1380 struct thread_cmd *p_cmd;
1383 vlc_mutex_lock( &p_sys->mutex );
1385 p_cmd = ThreadCmd_New( CMD_TIME_GET );
1388 ThreadCmd_InsertHead( p_sys, p_cmd );
1389 ThreadCmd_Wait( p_sys, p_cmd );
1391 i_ret = p_cmd->out.time_get.i_ret;
1392 *p_delay = p_cmd->out.time_get.i_delay;
1396 vlc_mutex_unlock( &p_sys->mutex );
1403 Open( vlc_object_t *obj )
1405 audio_output_t *p_aout = (audio_output_t *) obj;
1408 if( !InitJNIFields( p_aout ) )
1409 return VLC_EGENERIC;
1411 p_sys = calloc( 1, sizeof (aout_sys_t) );
1413 if( unlikely( p_sys == NULL ) )
1416 vlc_mutex_init( &p_sys->mutex );
1417 vlc_cond_init( &p_sys->cond );
1418 TAILQ_INIT( &p_sys->thread_cmd_queue );
1420 p_aout->sys = p_sys;
1421 p_aout->start = Start;
1422 p_aout->stop = Stop;
1423 p_aout->play = Play;
1424 p_aout->pause = Pause;
1425 p_aout->flush = Flush;
1426 p_aout->time_get = TimeGet;
1428 aout_SoftVolumeInit( p_aout );
1430 /* create JNIThread */
1431 p_sys->b_thread_run = true;
1432 if( vlc_clone( &p_sys->thread,
1433 JNIThread, p_aout, VLC_THREAD_PRIORITY_AUDIO ) )
1435 msg_Err( p_aout, "JNIThread creation failed" );
1436 p_sys->b_thread_run = false;
1438 return VLC_EGENERIC;
1445 Close( vlc_object_t *obj )
1447 audio_output_t *p_aout = (audio_output_t *) obj;
1448 aout_sys_t *p_sys = p_aout->sys;
1450 /* kill the thread */
1451 vlc_mutex_lock( &p_sys->mutex );
1452 if( p_sys->b_thread_run )
1454 p_sys->b_thread_run = false;
1455 vlc_cond_signal( &p_sys->cond );
1456 vlc_mutex_unlock( &p_sys->mutex );
1457 vlc_join( p_sys->thread, NULL );
1459 vlc_mutex_unlock( &p_sys->mutex );
1461 vlc_mutex_destroy( &p_sys->mutex );
1462 vlc_cond_destroy( &p_sys->cond );