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 * );
48 typedef TAILQ_HEAD(, thread_cmd) THREAD_CMD_QUEUE;
55 /* Owned by JNIThread */
56 jobject p_audiotrack; /* AudioTrack ref */
57 jobject p_audioTimestamp; /* AudioTimestamp ref */
58 jbyteArray p_bytearray; /* ByteArray ref (for Write) */
59 size_t i_bytearray_size; /* size of the ByteArray */
60 jobject p_bytebuffer; /* ByteBuffer ref (for WriteV21) */
61 audio_sample_format_t fmt; /* fmt setup by Start */
62 uint32_t i_pos_initial; /* initial position set by getPlaybackHeadPosition */
63 uint32_t i_samples_written; /* number of samples written since last flush */
64 uint32_t i_bytes_per_frame; /* byte per frame */
65 uint32_t i_max_audiotrack_samples;
66 mtime_t i_play_time; /* time when play was called */
67 bool b_audiotrack_exception; /* true if audiotrack throwed an exception */
68 int i_audiotrack_stuck_count;
69 uint8_t i_chans_to_reorder; /* do we need channel reordering */
70 uint8_t p_chan_table[AOUT_CHAN_MAX];
72 /* JNIThread control */
77 /* Shared between two threads, must be locked */
78 bool b_thread_run; /* is thread alive */
79 THREAD_CMD_QUEUE thread_cmd_queue; /* thread cmd queue */
80 uint32_t i_samples_queued; /* number of samples queued */
83 /* Soft volume helper */
84 #include "audio_output/volume.h"
86 //#define AUDIOTRACK_USE_FLOAT
87 // TODO: activate getTimestamp for new android versions
88 //#define AUDIOTRACK_USE_TIMESTAMP
91 set_shortname( "AudioTrack" )
92 set_description( N_( "Android AudioTrack audio output" ) )
93 set_capability( "audio output", 180 )
94 set_category( CAT_AUDIO )
95 set_subcategory( SUBCAT_AUDIO_AOUT )
97 add_shortcut( "audiotrack" )
98 set_callbacks( Open, Close )
103 TAILQ_ENTRY(thread_cmd) next;
115 audio_sample_format_t *p_fmt;
131 audio_sample_format_t *p_fmt;
138 void ( *pf_destroy )( struct thread_cmd * );
141 #define THREAD_NAME "android_audiotrack"
143 extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
144 extern void jni_detach_thread();
145 extern int jni_get_env(JNIEnv **env);
160 jmethodID getPlaybackHeadPosition;
161 jmethodID getTimestamp;
162 jmethodID getMinBufferSize;
163 jint STATE_INITIALIZED;
166 jint ERROR_BAD_VALUE;
167 jint ERROR_INVALID_OPERATION;
168 jint WRITE_NON_BLOCKING;
171 jint ENCODING_PCM_8BIT;
172 jint ENCODING_PCM_16BIT;
173 jint ENCODING_PCM_FLOAT;
174 bool has_ENCODING_PCM_FLOAT;
175 jint CHANNEL_OUT_MONO;
176 jint CHANNEL_OUT_STEREO;
177 jint CHANNEL_OUT_BACK_LEFT;
178 jint CHANNEL_OUT_BACK_RIGHT;
179 jint CHANNEL_OUT_FRONT_CENTER;
180 jint CHANNEL_OUT_LOW_FREQUENCY;
181 jint CHANNEL_OUT_BACK_CENTER;
182 jint CHANNEL_OUT_5POINT1;
183 jint CHANNEL_OUT_SIDE_LEFT;
184 jint CHANNEL_OUT_SIDE_RIGHT;
185 bool has_CHANNEL_OUT_SIDE;
188 jint ERROR_DEAD_OBJECT;
189 bool has_ERROR_DEAD_OBJECT;
195 jfieldID framePosition;
200 /* init all jni fields.
201 * Done only one time during the first initialisation */
203 InitJNIFields( audio_output_t *p_aout )
205 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
206 static int i_init_state = -1;
207 bool ret, b_attached = false;
212 vlc_mutex_lock( &lock );
214 if( i_init_state != -1 )
217 if( jni_get_env(&env) < 0 )
219 jni_attach_thread( &env, THREAD_NAME );
228 #define CHECK_EXCEPTION( what, critical ) do { \
229 if( (*env)->ExceptionOccurred( env ) ) \
231 msg_Err( p_aout, "%s failed", what ); \
232 (*env)->ExceptionClear( env ); \
240 #define GET_CLASS( str, critical ) do { \
241 clazz = (*env)->FindClass( env, (str) ); \
242 CHECK_EXCEPTION( str, critical ); \
244 #define GET_ID( get, id, str, args, critical ) do { \
245 jfields.id = (*env)->get( env, clazz, (str), (args) ); \
246 CHECK_EXCEPTION( #get, critical ); \
248 #define GET_CONST_INT( id, str, critical ) do { \
250 field = (*env)->GetStaticFieldID( env, clazz, (str), "I" ); \
251 CHECK_EXCEPTION( #id, critical ); \
254 jfields.id = (*env)->GetStaticIntField( env, clazz, field ); \
255 CHECK_EXCEPTION( #id, critical ); \
259 /* AudioTrack class init */
260 GET_CLASS( "android/media/AudioTrack", true );
261 jfields.AudioTrack.clazz = (jclass) (*env)->NewGlobalRef( env, clazz );
262 CHECK_EXCEPTION( "NewGlobalRef", true );
264 GET_ID( GetMethodID, AudioTrack.ctor, "<init>", "(IIIIII)V", true );
265 GET_ID( GetMethodID, AudioTrack.release, "release", "()V", true );
266 GET_ID( GetMethodID, AudioTrack.getState, "getState", "()I", true );
267 GET_ID( GetMethodID, AudioTrack.play, "play", "()V", true );
268 GET_ID( GetMethodID, AudioTrack.stop, "stop", "()V", true );
269 GET_ID( GetMethodID, AudioTrack.flush, "flush", "()V", true );
270 GET_ID( GetMethodID, AudioTrack.pause, "pause", "()V", true );
272 GET_ID( GetMethodID, AudioTrack.writeV21, "write", "(Ljava/nio/ByteBuffer;II)I", false );
273 if( jfields.AudioTrack.writeV21 )
275 jfields.AudioTrack.write = NULL;
276 GET_CONST_INT( AudioTrack.WRITE_NON_BLOCKING, "WRITE_NON_BLOCKING", true );
278 GET_ID( GetMethodID, AudioTrack.write, "write", "([BII)I", true );
280 GET_ID( GetMethodID, AudioTrack.getTimestamp,
281 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
282 GET_ID( GetMethodID, AudioTrack.getPlaybackHeadPosition,
283 "getPlaybackHeadPosition", "()I", true );
285 GET_ID( GetStaticMethodID, AudioTrack.getMinBufferSize, "getMinBufferSize",
287 GET_CONST_INT( AudioTrack.STATE_INITIALIZED, "STATE_INITIALIZED", true );
288 GET_CONST_INT( AudioTrack.MODE_STREAM, "MODE_STREAM", true );
289 GET_CONST_INT( AudioTrack.ERROR, "ERROR", true );
290 GET_CONST_INT( AudioTrack.ERROR_BAD_VALUE , "ERROR_BAD_VALUE", true );
291 GET_CONST_INT( AudioTrack.ERROR_INVALID_OPERATION,
292 "ERROR_INVALID_OPERATION", true );
294 /* AudioTimestamp class init (if any) */
295 if( jfields.AudioTrack.getTimestamp )
297 GET_CLASS( "android/media/AudioTimestamp", true );
298 jfields.AudioTimestamp.clazz = (jclass) (*env)->NewGlobalRef( env,
300 CHECK_EXCEPTION( "NewGlobalRef", true );
302 GET_ID( GetMethodID, AudioTimestamp.ctor, "<init>", "()V", true );
303 GET_ID( GetFieldID, AudioTimestamp.framePosition,
304 "framePosition", "J", true );
305 GET_ID( GetFieldID, AudioTimestamp.nanoTime,
306 "nanoTime", "J", true );
309 jfields.AudioTimestamp.clazz = NULL;
310 jfields.AudioTimestamp.ctor = NULL;
311 jfields.AudioTimestamp.framePosition = NULL;
312 jfields.AudioTimestamp.nanoTime = NULL;
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_5POINT1, "CHANNEL_OUT_5POINT1", true );
329 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_LEFT, "CHANNEL_OUT_BACK_LEFT", true );
330 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_RIGHT, "CHANNEL_OUT_BACK_RIGHT", true );
331 GET_CONST_INT( AudioFormat.CHANNEL_OUT_FRONT_CENTER, "CHANNEL_OUT_FRONT_CENTER", true );
332 GET_CONST_INT( AudioFormat.CHANNEL_OUT_LOW_FREQUENCY, "CHANNEL_OUT_LOW_FREQUENCY", true );
333 GET_CONST_INT( AudioFormat.CHANNEL_OUT_BACK_CENTER, "CHANNEL_OUT_BACK_CENTER", true );
334 GET_CONST_INT( AudioFormat.CHANNEL_OUT_SIDE_LEFT, "CHANNEL_OUT_SIDE_LEFT", false );
337 GET_CONST_INT( AudioFormat.CHANNEL_OUT_SIDE_RIGHT, "CHANNEL_OUT_SIDE_RIGHT", true );
338 jfields.AudioFormat.has_CHANNEL_OUT_SIDE = true;
340 jfields.AudioFormat.has_CHANNEL_OUT_SIDE = false;
342 /* AudioManager class init */
343 GET_CLASS( "android/media/AudioManager", true );
344 GET_CONST_INT( AudioManager.ERROR_DEAD_OBJECT, "ERROR_DEAD_OBJECT", false );
345 jfields.AudioManager.has_ERROR_DEAD_OBJECT = field != NULL;
346 GET_CONST_INT( AudioManager.STREAM_MUSIC, "STREAM_MUSIC", true );
348 #undef CHECK_EXCEPTION
355 ret = i_init_state == 1;
357 msg_Err( p_aout, "AudioTrack jni init failed" );
360 vlc_mutex_unlock( &lock );
365 check_exception( JNIEnv *env, audio_output_t *p_aout,
368 if( (*env)->ExceptionOccurred( env ) )
370 aout_sys_t *p_sys = p_aout->sys;
372 p_sys->b_audiotrack_exception = true;
373 (*env)->ExceptionClear( env );
374 msg_Err( p_aout, "AudioTrack.%s triggered an exception !", method );
379 #define CHECK_AT_EXCEPTION( method ) check_exception( env, p_aout, method )
381 #define JNI_CALL( what, obj, method, ... ) (*env)->what( env, obj, method, ##__VA_ARGS__ )
383 #define JNI_CALL_INT( obj, method, ... ) JNI_CALL( CallIntMethod, obj, method, ##__VA_ARGS__ )
384 #define JNI_CALL_BOOL( obj, method, ... ) JNI_CALL( CallBooleanMethod, obj, method, ##__VA_ARGS__ )
385 #define JNI_CALL_VOID( obj, method, ... ) JNI_CALL( CallVoidMethod, obj, method, ##__VA_ARGS__ )
386 #define JNI_CALL_STATIC_INT( clazz, method, ... ) JNI_CALL( CallStaticIntMethod, clazz, method, ##__VA_ARGS__ )
388 #define JNI_AT_NEW( ... ) JNI_CALL( NewObject, jfields.AudioTrack.clazz, jfields.AudioTrack.ctor, ##__VA_ARGS__ )
389 #define JNI_AT_CALL_INT( method, ... ) JNI_CALL_INT( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
390 #define JNI_AT_CALL_BOOL( method, ... ) JNI_CALL_BOOL( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
391 #define JNI_AT_CALL_VOID( method, ... ) JNI_CALL_VOID( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
392 #define JNI_AT_CALL_STATIC_INT( method, ... ) JNI_CALL( CallStaticIntMethod, jfields.AudioTrack.clazz, jfields.AudioTrack.method, ##__VA_ARGS__ )
394 #define JNI_AUDIOTIMESTAMP_GET_LONG( field ) JNI_CALL( GetLongField, p_sys->p_audioTimestamp, jfields.AudioTimestamp.field )
396 static inline mtime_t
397 frames_to_us( aout_sys_t *p_sys, uint32_t i_nb_frames )
399 return i_nb_frames * CLOCK_FREQ / p_sys->fmt.i_rate;
401 #define FRAMES_TO_US(x) frames_to_us( p_sys, (x) )
403 static struct thread_cmd *
404 ThreadCmd_New( int id )
406 struct thread_cmd *p_cmd = calloc( 1, sizeof(struct thread_cmd) );
415 ThreadCmd_InsertHead( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
417 TAILQ_INSERT_HEAD( &p_sys->thread_cmd_queue, p_cmd, next);
418 vlc_cond_signal( &p_sys->cond );
422 ThreadCmd_InsertTail( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
424 TAILQ_INSERT_TAIL( &p_sys->thread_cmd_queue, p_cmd, next);
425 vlc_cond_signal( &p_sys->cond );
429 ThreadCmd_Wait( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
431 while( p_cmd->id != CMD_DONE )
432 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
434 return p_cmd->id == CMD_DONE;
438 ThreadCmd_FlushQueue( aout_sys_t *p_sys )
440 struct thread_cmd *p_cmd, *p_cmd_next;
442 for ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue );
443 p_cmd != NULL; p_cmd = p_cmd_next )
445 p_cmd_next = TAILQ_NEXT( p_cmd, next );
446 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
447 if( p_cmd->pf_destroy )
448 p_cmd->pf_destroy( p_cmd );
453 JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout )
455 aout_sys_t *p_sys = p_aout->sys;
457 if( p_sys->p_audiotrack )
458 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
460 p_sys->i_pos_initial = 0;
462 /* HACK: On some broken devices, head position is still moving after a
463 * flush or a stop. So, wait for the head position to be stabilized. */
464 if( unlikely( p_sys->i_pos_initial != 0 ) )
468 i_last_pos = p_sys->i_pos_initial;
470 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
471 } while( p_sys->i_pos_initial != i_last_pos );
473 p_sys->i_samples_written = 0;
474 p_sys->i_samples_queued = 0;
478 JNIThread_GetAudioTrackPos( JNIEnv *env, audio_output_t *p_aout )
480 aout_sys_t *p_sys = p_aout->sys;
483 * getPlaybackHeadPosition: Returns the playback head position expressed in
484 * frames. Though the "int" type is signed 32-bits, the value should be
485 * reinterpreted as if it is unsigned 32-bits. That is, the next position
486 * after 0x7FFFFFFF is (int) 0x80000000. This is a continuously advancing
487 * counter. It will wrap (overflow) periodically, for example approximately
488 * once every 27:03:11 hours:minutes:seconds at 44.1 kHz. It is reset to
489 * zero by flush(), reload(), and stop().
492 return JNI_AT_CALL_INT( getPlaybackHeadPosition ) - p_sys->i_pos_initial;
496 JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
498 aout_sys_t *p_sys = p_aout->sys;
500 uint32_t i_audiotrack_delay = 0;
502 if( p_sys->i_samples_queued == 0 )
504 if( p_sys->p_audioTimestamp )
506 mtime_t i_current_time = mdate();
508 * getTimestamp: Poll for a timestamp on demand.
510 * If you need to track timestamps during initial warmup or after a
511 * routing or mode change, you should request a new timestamp once per
512 * second until the reported timestamps show that the audio clock is
513 * stable. Thereafter, query for a new timestamp approximately once
514 * every 10 seconds to once per minute. Calling this method more often
515 * is inefficient. It is also counter-productive to call this method
516 * more often than recommended, because the short-term differences
517 * between successive timestamp reports are not meaningful. If you need
518 * a high-resolution mapping between frame position and presentation
519 * time, consider implementing that at application level, based on
520 * low-resolution timestamps.
523 if( JNI_AT_CALL_BOOL( getTimestamp, p_sys->p_audioTimestamp ) )
525 jlong i_frame_time = JNI_AUDIOTIMESTAMP_GET_LONG( nanoTime ) / 1000;
526 /* frame time should be after last play time
527 * frame time shouldn't be in the future
528 * frame time should be less than 10 seconds old */
529 if( i_frame_time > p_sys->i_play_time
530 && i_current_time > i_frame_time
531 && ( i_current_time - i_frame_time ) <= INT64_C(10000000) )
533 jlong i_time_diff = i_current_time - i_frame_time;
534 jlong i_frames_diff = i_time_diff * p_sys->fmt.i_rate
536 i_frame_pos = JNI_AUDIOTIMESTAMP_GET_LONG( framePosition )
538 if( p_sys->i_samples_written > i_frame_pos )
539 i_audiotrack_delay = p_sys->i_samples_written - i_frame_pos;
543 if( i_audiotrack_delay == 0 )
545 uint32_t i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
547 if( p_sys->i_samples_written > i_audiotrack_pos )
548 i_audiotrack_delay = p_sys->i_samples_written - i_audiotrack_pos;
551 if( i_audiotrack_delay > 0 )
553 *p_delay = FRAMES_TO_US( p_sys->i_samples_queued + i_audiotrack_delay );
560 AudioTrack_GetChanOrder( int i_mask, uint32_t p_chans_out[] )
562 #define HAS_CHAN( x ) ( ( i_mask & (jfields.AudioFormat.x) ) == (jfields.AudioFormat.x) )
563 const int i_sides = jfields.AudioFormat.CHANNEL_OUT_SIDE_LEFT |
564 jfields.AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
565 const int i_backs = jfields.AudioFormat.CHANNEL_OUT_BACK_LEFT |
566 jfields.AudioFormat.CHANNEL_OUT_BACK_RIGHT;
568 /* verify has FL/FR */
569 if ( !HAS_CHAN( CHANNEL_OUT_STEREO ) )
572 /* verify uses SIDE as a pair (ok if not using SIDE at all) */
573 bool b_has_sides = false;
574 if( jfields.AudioFormat.has_CHANNEL_OUT_SIDE && ( i_mask & i_sides ) != 0 )
576 if( ( i_mask & i_sides ) != i_sides )
580 /* verify uses BACK as a pair (ok if not using BACK at all) */
581 bool b_has_backs = false;
582 if( ( i_mask & i_backs ) != 0 )
584 if( ( i_mask & i_backs ) != i_backs )
589 const bool b_has_FC = HAS_CHAN( CHANNEL_OUT_FRONT_CENTER );
590 const bool b_has_LFE = HAS_CHAN( CHANNEL_OUT_LOW_FREQUENCY );
591 const bool b_has_BC = HAS_CHAN( CHANNEL_OUT_BACK_CENTER );
593 /* compute at what index each channel is: samples will be in the following
594 * order: FL FR FC LFE BL BR BC SL SR
595 * when a channel is not present, its index is set to the same as the index
596 * of the preceding channel. */
598 const int i_FC = b_has_FC ? 2 : 1;
599 const int i_LFE = b_has_LFE ? i_FC + 1 : i_FC;
600 const int i_BL = b_has_backs ? i_LFE + 1 : i_LFE;
601 const int i_BR = b_has_backs ? i_BL + 1 : i_BL;
602 const int i_BC = b_has_BC ? i_BR + 1 : i_BR;
603 const int i_SL = b_has_sides ? i_BC + 1 : i_BC;
604 const int i_SR = b_has_sides ? i_SL + 1 : i_SL;
606 p_chans_out[0] = AOUT_CHAN_LEFT;
607 p_chans_out[1] = AOUT_CHAN_RIGHT;
609 p_chans_out[i_FC] = AOUT_CHAN_CENTER;
611 p_chans_out[i_LFE] = AOUT_CHAN_LFE;
614 p_chans_out[i_BL] = AOUT_CHAN_REARLEFT;
615 p_chans_out[i_BR] = AOUT_CHAN_REARRIGHT;
618 p_chans_out[i_BC] = AOUT_CHAN_REARCENTER;
621 p_chans_out[i_SL] = AOUT_CHAN_MIDDLELEFT;
622 p_chans_out[i_SR] = AOUT_CHAN_MIDDLERIGHT;
631 * Configure and create an Android AudioTrack.
632 * returns -1 on critical error, 0 on success, 1 on configuration error
635 JNIThread_Configure( JNIEnv *env, audio_output_t *p_aout )
637 struct aout_sys_t *p_sys = p_aout->sys;
638 int i_size, i_min_buffer_size, i_channel_config, i_format,
639 i_format_size, i_nb_channels;
640 uint8_t i_chans_to_reorder = 0;
641 uint8_t p_chan_table[AOUT_CHAN_MAX];
642 jobject p_audiotrack;
643 audio_sample_format_t fmt = p_sys->fmt;
645 /* 4000 <= frequency <= 48000 */
646 if( fmt.i_rate < 4000 )
648 if( fmt.i_rate > 48000 )
651 /* We can only accept U8, S16N, FL32 */
652 switch( fmt.i_format )
659 if( !jfields.AudioFormat.has_ENCODING_PCM_FLOAT )
660 fmt.i_format = VLC_CODEC_S16N;
663 fmt.i_format = VLC_CODEC_S16N;
666 switch( fmt.i_format )
669 i_format = jfields.AudioFormat.ENCODING_PCM_8BIT;
673 i_format = jfields.AudioFormat.ENCODING_PCM_16BIT;
677 i_format = jfields.AudioFormat.ENCODING_PCM_FLOAT;
681 vlc_assert_unreachable();
684 i_nb_channels = aout_FormatNbChannels( &fmt );
686 /* Android AudioTrack support only mono, stereo, 5.1 and 7.1.
687 * Android will downmix to stereo if audio output doesn't handle 5.1 or 7.1
689 if( i_nb_channels > 5 )
691 uint32_t p_chans_out[AOUT_CHAN_MAX];
693 if( i_nb_channels > 7 && jfields.AudioFormat.has_CHANNEL_OUT_SIDE )
695 fmt.i_physical_channels = AOUT_CHANS_7_1;
696 /* bitmak of CHANNEL_OUT_7POINT1 doesn't correspond to 5POINT1 and
698 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_5POINT1 |
699 jfields.AudioFormat.CHANNEL_OUT_SIDE_LEFT |
700 jfields.AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
703 fmt.i_physical_channels = AOUT_CHANS_5_1;
704 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_5POINT1;
706 if( AudioTrack_GetChanOrder( i_channel_config, p_chans_out ) )
708 aout_CheckChannelReorder( NULL, p_chans_out,
709 fmt.i_physical_channels,
715 if( i_nb_channels == 1 )
717 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_MONO;
720 fmt.i_physical_channels = AOUT_CHANS_STEREO;
721 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_STEREO;
724 i_nb_channels = aout_FormatNbChannels( &fmt );
726 i_min_buffer_size = JNI_AT_CALL_STATIC_INT( getMinBufferSize, fmt.i_rate,
727 i_channel_config, i_format );
728 if( i_min_buffer_size <= 0 )
730 msg_Warn( p_aout, "getMinBufferSize returned an invalid size" ) ;
733 i_size = i_min_buffer_size * 4;
735 /* create AudioTrack object */
736 p_audiotrack = JNI_AT_NEW( jfields.AudioManager.STREAM_MUSIC, fmt.i_rate,
737 i_channel_config, i_format, i_size,
738 jfields.AudioTrack.MODE_STREAM );
739 if( CHECK_AT_EXCEPTION( "AudioTrack<init>" ) || !p_audiotrack )
741 p_sys->p_audiotrack = (*env)->NewGlobalRef( env, p_audiotrack );
742 (*env)->DeleteLocalRef( env, p_audiotrack );
743 if( !p_sys->p_audiotrack )
746 p_sys->i_chans_to_reorder = i_chans_to_reorder;
747 if( i_chans_to_reorder )
748 memcpy( p_sys->p_chan_table, p_chan_table, sizeof(p_sys->p_chan_table) );
749 p_sys->i_bytes_per_frame = i_nb_channels * i_format_size;
750 p_sys->i_max_audiotrack_samples = i_size / p_sys->i_bytes_per_frame;
757 JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
759 aout_sys_t *p_sys = p_aout->sys;
762 aout_FormatPrint( p_aout, "VLC is looking for:", &p_sys->fmt );
763 p_sys->fmt.i_original_channels = p_sys->fmt.i_physical_channels;
765 i_ret = JNIThread_Configure( env, p_aout );
768 /* configuration error, try to fallback to stereo */
769 if( ( p_sys->fmt.i_format != VLC_CODEC_U8 &&
770 p_sys->fmt.i_format != VLC_CODEC_S16N ) ||
771 aout_FormatNbChannels( &p_sys->fmt ) > 2 )
774 "AudioTrack configuration failed, try again in stereo" );
775 p_sys->fmt.i_format = VLC_CODEC_S16N;
776 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
778 i_ret = JNIThread_Configure( env, p_aout );
784 aout_FormatPrint( p_aout, "VLC will output:", &p_sys->fmt );
786 if( JNI_AT_CALL_INT( getState ) != jfields.AudioTrack.STATE_INITIALIZED )
788 msg_Err( p_aout, "AudioTrack init failed" );
792 #ifdef AUDIOTRACK_USE_TIMESTAMP
793 if( jfields.AudioTimestamp.clazz )
795 /* create AudioTimestamp object */
796 jobject p_audioTimestamp = JNI_CALL( NewObject,
797 jfields.AudioTimestamp.clazz,
798 jfields.AudioTimestamp.ctor );
799 if( !p_audioTimestamp )
801 p_sys->p_audioTimestamp = (*env)->NewGlobalRef( env, p_audioTimestamp );
802 (*env)->DeleteLocalRef( env, p_audioTimestamp );
803 if( !p_sys->p_audioTimestamp )
808 JNI_AT_CALL_VOID( play );
809 CHECK_AT_EXCEPTION( "play" );
810 p_sys->i_play_time = mdate();
814 if( p_sys->p_audiotrack )
816 JNI_AT_CALL_VOID( release );
817 (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
818 p_sys->p_audiotrack = NULL;
824 JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
826 aout_sys_t *p_sys = p_aout->sys;
828 if( !p_sys->b_audiotrack_exception )
830 JNI_AT_CALL_VOID( stop );
831 if( !CHECK_AT_EXCEPTION( "stop" ) )
832 JNI_AT_CALL_VOID( release );
834 p_sys->b_audiotrack_exception = false;
835 (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
836 p_sys->p_audiotrack = NULL;
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 )
853 aout_sys_t *p_sys = p_aout->sys;
854 uint8_t *p_data = p_buffer->p_buffer;
857 uint32_t i_audiotrack_pos;
858 uint32_t i_samples_pending;
860 i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
861 if( i_audiotrack_pos > p_sys->i_samples_written )
863 msg_Warn( p_aout, "audiotrack position is ahead. Should NOT happen" );
864 JNIThread_InitDelay( env, p_aout );
867 i_samples_pending = p_sys->i_samples_written - i_audiotrack_pos;
869 /* check if audiotrack buffer is not full before writing on it. */
870 if( i_samples_pending >= p_sys->i_max_audiotrack_samples )
873 /* HACK: AudioFlinger can drop frames without notifying us and there is
874 * no way to know it. It it happens, i_audiotrack_pos won't move and
875 * the current code will be stuck because it'll assume that audiotrack
876 * internal buffer is full when it's not. It can happen only after
877 * Android 4.4.2 if we send frames too quickly. This HACK is just an
878 * other precaution since it shouldn't happen anymore thanks to the
879 * HACK in JNIThread_Play */
881 p_sys->i_audiotrack_stuck_count++;
882 if( p_sys->i_audiotrack_stuck_count > 100 )
884 msg_Warn( p_aout, "AudioFlinger underrun, force write" );
885 i_samples_pending = 0;
886 p_sys->i_audiotrack_stuck_count = 0;
889 p_sys->i_audiotrack_stuck_count = 0;
890 i_samples = __MIN( p_sys->i_max_audiotrack_samples - i_samples_pending,
891 p_buffer->i_nb_samples );
893 i_data = i_samples * p_sys->i_bytes_per_frame;
895 /* check if we need to realloc a ByteArray */
896 if( i_data > p_sys->i_bytearray_size )
898 jbyteArray p_bytearray;
900 if( p_sys->p_bytearray )
902 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
903 p_sys->p_bytearray = NULL;
906 p_bytearray = (*env)->NewByteArray( env, i_data );
909 p_sys->p_bytearray = (*env)->NewGlobalRef( env, p_bytearray );
910 (*env)->DeleteLocalRef( env, p_bytearray );
912 p_sys->i_bytearray_size = i_data;
914 if( !p_sys->p_bytearray )
915 return jfields.AudioTrack.ERROR_BAD_VALUE;
917 /* copy p_buffer in to ByteArray */
918 (*env)->SetByteArrayRegion( env, p_sys->p_bytearray, 0, i_data,
921 return JNI_AT_CALL_INT( write, p_sys->p_bytearray, 0, i_data );
925 * Non blocking write function for Lollipop and after.
926 * It calls a new write method with WRITE_NON_BLOCKING flags.
929 JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
931 aout_sys_t *p_sys = p_aout->sys;
934 if( !p_sys->p_bytebuffer )
936 jobject p_bytebuffer;
938 p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_buffer->p_buffer,
939 p_buffer->i_buffer );
941 return jfields.AudioTrack.ERROR_BAD_VALUE;
943 p_sys->p_bytebuffer = (*env)->NewGlobalRef( env, p_bytebuffer );
944 (*env)->DeleteLocalRef( env, p_bytebuffer );
946 if( !p_sys->p_bytebuffer || (*env)->ExceptionOccurred( env ) )
948 p_sys->p_bytebuffer = NULL;
949 (*env)->ExceptionClear( env );
950 return jfields.AudioTrack.ERROR_BAD_VALUE;
954 i_ret = JNI_AT_CALL_INT( writeV21, p_sys->p_bytebuffer, p_buffer->i_buffer,
955 jfields.AudioTrack.WRITE_NON_BLOCKING );
958 /* don't delete the bytebuffer if we wrote nothing, keep it for next
960 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
961 p_sys->p_bytebuffer = NULL;
967 JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
968 block_t **pp_buffer, mtime_t *p_wait )
970 aout_sys_t *p_sys = p_aout->sys;
971 block_t *p_buffer = *pp_buffer;
974 if( jfields.AudioTrack.writeV21 )
975 i_ret = JNIThread_WriteV21( env, p_aout, p_buffer );
977 i_ret = JNIThread_Write( env, p_aout, p_buffer );
980 if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
981 && i_ret == jfields.AudioManager.ERROR_DEAD_OBJECT )
983 msg_Warn( p_aout, "ERROR_DEAD_OBJECT: "
984 "try recreating AudioTrack" );
985 JNIThread_Stop( env, p_aout );
986 i_ret = JNIThread_Start( env, p_aout );
990 if( i_ret == jfields.AudioTrack.ERROR_INVALID_OPERATION )
991 str = "ERROR_INVALID_OPERATION";
992 else if( i_ret == jfields.AudioTrack.ERROR_BAD_VALUE )
993 str = "ERROR_BAD_VALUE";
996 msg_Err( p_aout, "Write failed: %s", str );
998 } else if( i_ret == 0 )
1000 /* audiotrack internal buffer is full, wait a little: between 10ms and
1001 * 20ms depending on devices or rate */
1002 *p_wait = FRAMES_TO_US( p_sys->i_max_audiotrack_samples / 20 );
1005 uint32_t i_samples = i_ret / p_sys->i_bytes_per_frame;
1006 p_sys->i_samples_queued -= i_samples;
1007 p_sys->i_samples_written += i_samples;
1009 p_buffer->p_buffer += i_ret;
1010 p_buffer->i_buffer -= i_ret;
1011 p_buffer->i_nb_samples -= i_samples;
1012 if( p_buffer->i_buffer == 0 )
1015 /* HACK: There is a known issue in audiotrack, "due to an internal
1016 * timeout within the AudioTrackThread". It happens after android
1017 * 4.4.2, it's not a problem for Android 5.0 since we use an other way
1018 * to write samples. A working hack is to wait a little between each
1019 * write. This hack is done only for API 19 (AudioTimestamp was added
1022 if( jfields.AudioTimestamp.clazz && !jfields.AudioTrack.writeV21 )
1023 *p_wait = FRAMES_TO_US( i_samples ) / 2;
1025 return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
1029 JNIThread_Pause( JNIEnv *env, audio_output_t *p_aout,
1030 bool b_pause, mtime_t i_date )
1032 VLC_UNUSED( i_date );
1034 aout_sys_t *p_sys = p_aout->sys;
1038 JNI_AT_CALL_VOID( pause );
1039 CHECK_AT_EXCEPTION( "pause" );
1042 JNI_AT_CALL_VOID( play );
1043 CHECK_AT_EXCEPTION( "play" );
1044 p_sys->i_play_time = mdate();
1049 JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
1052 aout_sys_t *p_sys = p_aout->sys;
1055 * stop(): Stops playing the audio data. When used on an instance created
1056 * in MODE_STREAM mode, audio will stop playing after the last buffer that
1057 * was written has been played. For an immediate stop, use pause(),
1058 * followed by flush() to discard audio data that hasn't been played back
1061 * flush(): Flushes the audio data currently queued for playback. Any data
1062 * that has not been played back will be discarded. No-op if not stopped
1063 * or paused, or if the track's creation mode is not MODE_STREAM.
1067 JNI_AT_CALL_VOID( stop );
1068 if( CHECK_AT_EXCEPTION( "stop" ) )
1072 JNI_AT_CALL_VOID( pause );
1073 if( CHECK_AT_EXCEPTION( "pause" ) )
1075 JNI_AT_CALL_VOID( flush );
1077 JNI_AT_CALL_VOID( play );
1078 CHECK_AT_EXCEPTION( "play" );
1079 p_sys->i_play_time = mdate();
1081 if( p_sys->p_bytebuffer )
1083 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1084 p_sys->p_bytebuffer = NULL;
1089 JNIThread( void *data )
1091 audio_output_t *p_aout = data;
1092 aout_sys_t *p_sys = p_aout->sys;
1093 bool b_error = false;
1094 bool b_paused = false;
1095 block_t *p_buffer = NULL;
1096 mtime_t i_play_deadline = 0;
1099 jni_attach_thread( &env, THREAD_NAME );
1101 vlc_mutex_lock( &p_sys->mutex );
1105 while( p_sys->b_thread_run )
1107 struct thread_cmd *p_cmd;
1108 bool b_remove_cmd = true;
1110 /* wait to process a command */
1111 while( ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue ) ) == NULL
1112 && p_sys->b_thread_run )
1113 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1115 if( !p_sys->b_thread_run || p_cmd == NULL )
1118 if( b_paused && p_cmd->id == CMD_PLAY )
1120 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1124 if( p_cmd->id == CMD_PLAY && i_play_deadline > 0 )
1126 if( mdate() > i_play_deadline )
1127 i_play_deadline = 0;
1131 while( p_cmd == TAILQ_FIRST( &p_sys->thread_cmd_queue )
1132 && i_ret != ETIMEDOUT && p_sys->b_thread_run )
1133 i_ret = vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex,
1139 /* process a command */
1143 assert( !p_sys->p_audiotrack );
1145 p_cmd->out.start.i_ret = -1;
1148 p_sys->fmt = *p_cmd->in.start.p_fmt;
1149 p_cmd->out.start.i_ret =
1150 JNIThread_Start( env, p_aout );
1151 JNIThread_InitDelay( env, p_aout );
1152 p_cmd->out.start.p_fmt = &p_sys->fmt;
1156 assert( p_sys->p_audiotrack );
1157 JNIThread_Stop( env, p_aout );
1158 JNIThread_InitDelay( env, p_aout );
1165 mtime_t i_play_wait = 0;
1167 assert( p_sys->p_audiotrack );
1170 if( p_buffer == NULL )
1172 p_buffer = p_cmd->in.play.p_buffer;
1173 if( p_sys->i_chans_to_reorder )
1174 aout_ChannelReorder( p_buffer->p_buffer,
1176 p_sys->i_chans_to_reorder,
1177 p_sys->p_chan_table,
1178 p_sys->fmt.i_format );
1181 b_error = JNIThread_Play( env, p_aout, &p_buffer,
1182 &i_play_wait ) != VLC_SUCCESS;
1183 if( p_buffer != NULL )
1184 b_remove_cmd = false;
1185 if( i_play_wait > 0 )
1186 i_play_deadline = mdate() + i_play_wait;
1190 assert( p_sys->p_audiotrack );
1193 JNIThread_Pause( env, p_aout,
1194 p_cmd->in.pause.b_pause,
1195 p_cmd->in.pause.i_date );
1196 b_paused = p_cmd->in.pause.b_pause;
1199 assert( p_sys->p_audiotrack );
1202 p_cmd->out.time_get.i_ret =
1203 JNIThread_TimeGet( env, p_aout,
1204 &p_cmd->out.time_get.i_delay );
1207 assert( p_sys->p_audiotrack );
1210 JNIThread_Flush( env, p_aout,
1211 p_cmd->in.flush.b_wait );
1212 JNIThread_InitDelay( env, p_aout );
1216 vlc_assert_unreachable();
1218 if( p_sys->b_audiotrack_exception )
1223 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
1224 p_cmd->id = CMD_DONE;
1225 if( p_cmd->pf_destroy )
1226 p_cmd->pf_destroy( p_cmd );
1229 /* signal that command is processed */
1230 vlc_cond_signal( &p_sys->cond );
1235 if( p_sys->p_bytearray )
1236 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
1237 if( p_sys->p_bytebuffer )
1238 (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1239 jni_detach_thread();
1241 vlc_mutex_unlock( &p_sys->mutex );
1246 Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
1248 int i_ret = VLC_EGENERIC;
1249 struct thread_cmd *p_cmd;
1250 aout_sys_t *p_sys = p_aout->sys;
1252 vlc_mutex_lock( &p_sys->mutex );
1254 p_cmd = ThreadCmd_New( CMD_START );
1257 /* ask the thread to process the Start command */
1258 p_cmd->in.start.p_fmt = p_fmt;
1260 ThreadCmd_InsertHead( p_sys, p_cmd );
1261 if( ThreadCmd_Wait( p_sys, p_cmd ) )
1263 i_ret = p_cmd->out.start.i_ret;
1264 if( i_ret == VLC_SUCCESS )
1265 *p_fmt = *p_cmd->out.start.p_fmt;
1270 vlc_mutex_unlock( &p_sys->mutex );
1272 if( i_ret == VLC_SUCCESS )
1273 aout_SoftVolumeStart( p_aout );
1279 Stop( audio_output_t *p_aout )
1281 aout_sys_t *p_sys = p_aout->sys;
1282 struct thread_cmd *p_cmd;
1284 vlc_mutex_lock( &p_sys->mutex );
1286 ThreadCmd_FlushQueue( p_sys );
1288 p_cmd = ThreadCmd_New( CMD_STOP );
1291 /* ask the thread to process the Stop command */
1292 ThreadCmd_InsertHead( p_sys, p_cmd );
1293 ThreadCmd_Wait( p_sys, p_cmd );
1298 vlc_mutex_unlock( &p_sys->mutex );
1302 PlayCmd_Destroy( struct thread_cmd *p_cmd )
1304 block_Release( p_cmd->in.play.p_buffer );
1309 Play( audio_output_t *p_aout, block_t *p_buffer )
1311 aout_sys_t *p_sys = p_aout->sys;
1312 struct thread_cmd *p_cmd;
1314 vlc_mutex_lock( &p_sys->mutex );
1316 while( p_sys->i_samples_queued != 0
1317 && FRAMES_TO_US( p_sys->i_samples_queued +
1318 p_buffer->i_nb_samples ) >= MAX_QUEUE_US )
1319 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1321 p_cmd = ThreadCmd_New( CMD_PLAY );
1324 /* ask the thread to process the Play command */
1325 p_cmd->in.play.p_buffer = p_buffer;
1326 p_cmd->pf_destroy = PlayCmd_Destroy;
1328 ThreadCmd_InsertTail( p_sys, p_cmd );
1330 p_sys->i_samples_queued += p_buffer->i_nb_samples;
1332 block_Release( p_cmd->in.play.p_buffer );
1334 vlc_mutex_unlock( &p_sys->mutex );
1338 Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
1340 aout_sys_t *p_sys = p_aout->sys;
1341 struct thread_cmd *p_cmd;
1343 vlc_mutex_lock( &p_sys->mutex );
1345 p_cmd = ThreadCmd_New( CMD_PAUSE );
1348 /* ask the thread to process the Pause command */
1349 p_cmd->in.pause.b_pause = b_pause;
1350 p_cmd->in.pause.i_date = i_date;
1352 ThreadCmd_InsertHead( p_sys, p_cmd );
1353 ThreadCmd_Wait( p_sys, p_cmd );
1358 vlc_mutex_unlock( &p_sys->mutex );
1362 Flush( audio_output_t *p_aout, bool b_wait )
1364 aout_sys_t *p_sys = p_aout->sys;
1365 struct thread_cmd *p_cmd;
1367 vlc_mutex_lock( &p_sys->mutex );
1369 ThreadCmd_FlushQueue( p_sys );
1371 p_cmd = ThreadCmd_New( CMD_FLUSH );
1374 /* ask the thread to process the Flush command */
1375 p_cmd->in.flush.b_wait = b_wait;
1377 ThreadCmd_InsertHead( p_sys, p_cmd );
1378 ThreadCmd_Wait( p_sys, p_cmd );
1383 vlc_mutex_unlock( &p_sys->mutex );
1387 TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
1389 aout_sys_t *p_sys = p_aout->sys;
1390 struct thread_cmd *p_cmd;
1393 vlc_mutex_lock( &p_sys->mutex );
1395 p_cmd = ThreadCmd_New( CMD_TIME_GET );
1398 ThreadCmd_InsertHead( p_sys, p_cmd );
1399 ThreadCmd_Wait( p_sys, p_cmd );
1401 i_ret = p_cmd->out.time_get.i_ret;
1402 *p_delay = p_cmd->out.time_get.i_delay;
1406 vlc_mutex_unlock( &p_sys->mutex );
1413 Open( vlc_object_t *obj )
1415 audio_output_t *p_aout = (audio_output_t *) obj;
1418 if( !InitJNIFields( p_aout ) )
1419 return VLC_EGENERIC;
1421 p_sys = calloc( 1, sizeof (aout_sys_t) );
1423 if( unlikely( p_sys == NULL ) )
1426 vlc_mutex_init( &p_sys->mutex );
1427 vlc_cond_init( &p_sys->cond );
1428 TAILQ_INIT( &p_sys->thread_cmd_queue );
1430 p_aout->sys = p_sys;
1431 p_aout->start = Start;
1432 p_aout->stop = Stop;
1433 p_aout->play = Play;
1434 p_aout->pause = Pause;
1435 p_aout->flush = Flush;
1436 p_aout->time_get = TimeGet;
1438 aout_SoftVolumeInit( p_aout );
1440 /* create JNIThread */
1441 p_sys->b_thread_run = true;
1442 if( vlc_clone( &p_sys->thread,
1443 JNIThread, p_aout, VLC_THREAD_PRIORITY_AUDIO ) )
1445 msg_Err( p_aout, "JNIThread creation failed" );
1446 p_sys->b_thread_run = false;
1448 return VLC_EGENERIC;
1455 Close( vlc_object_t *obj )
1457 audio_output_t *p_aout = (audio_output_t *) obj;
1458 aout_sys_t *p_sys = p_aout->sys;
1460 /* kill the thread */
1461 vlc_mutex_lock( &p_sys->mutex );
1462 if( p_sys->b_thread_run )
1464 p_sys->b_thread_run = false;
1465 vlc_cond_signal( &p_sys->cond );
1466 vlc_mutex_unlock( &p_sys->mutex );
1467 vlc_join( p_sys->thread, NULL );
1469 vlc_mutex_unlock( &p_sys->mutex );
1471 vlc_mutex_destroy( &p_sys->mutex );
1472 vlc_cond_destroy( &p_sys->cond );