]> git.sesse.net Git - vlc/blob - modules/audio_output/audiotrack.c
audiotrack: fix play wait delay
[vlc] / modules / audio_output / audiotrack.c
1 /*****************************************************************************
2  * audiotrack.c: Android Java AudioTrack audio output module
3  *****************************************************************************
4  * Copyright © 2012-2015 VLC authors and VideoLAN, VideoLabs
5  *
6  * Authors: Thomas Guillem <thomas@gllm.fr>
7  *          Ming Hu <tewilove@gmail.com>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <assert.h>
29 #include <jni.h>
30 #include <dlfcn.h>
31 #include <stdbool.h>
32 #include <sys/queue.h>
33
34 #include <vlc_atomic.h>
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_aout.h>
38 #include <vlc_threads.h>
39
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
43
44 static int  Open( vlc_object_t * );
45 static void Close( vlc_object_t * );
46
47 struct thread_cmd;
48 typedef TAILQ_HEAD(, thread_cmd) THREAD_CMD_QUEUE;
49
50 struct aout_sys_t {
51     /* sw gain */
52     float soft_gain;
53     bool soft_mute;
54
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
69     /* JNIThread control */
70     vlc_mutex_t mutex;
71     vlc_cond_t cond;
72     vlc_thread_t thread;
73
74     /* Shared between two threads, must be locked */
75     bool b_thread_run; /* is thread alive */
76     THREAD_CMD_QUEUE thread_cmd_queue; /* thread cmd queue */
77     uint32_t i_samples_queued; /* number of samples queued */
78 };
79
80 /* Soft volume helper */
81 #include "audio_output/volume.h"
82
83 //#define AUDIOTRACK_USE_FLOAT
84 // TODO: activate getTimestamp for new android versions
85 //#define AUDIOTRACK_USE_TIMESTAMP
86
87 vlc_module_begin ()
88     set_shortname( "AudioTrack" )
89     set_description( N_( "Android AudioTrack audio output" ) )
90     set_capability( "audio output", 180 )
91     set_category( CAT_AUDIO )
92     set_subcategory( SUBCAT_AUDIO_AOUT )
93     add_sw_gain()
94     add_shortcut( "audiotrack" )
95     set_callbacks( Open, Close )
96 vlc_module_end ()
97
98 struct thread_cmd
99 {
100     TAILQ_ENTRY(thread_cmd) next;
101     enum {
102         CMD_START,
103         CMD_STOP,
104         CMD_PLAY,
105         CMD_PAUSE,
106         CMD_TIME_GET,
107         CMD_FLUSH,
108         CMD_DONE,
109     } id;
110     union {
111         struct {
112             audio_sample_format_t *p_fmt;
113         } start;
114         struct {
115             block_t *p_buffer;
116         } play;
117         struct {
118             bool b_pause;
119             mtime_t i_date;
120         } pause;
121         struct {
122             bool b_wait;
123         } flush;
124     } in;
125     union {
126         struct {
127             int i_ret;
128             audio_sample_format_t *p_fmt;
129         } start;
130         struct {
131             int i_ret;
132             mtime_t i_delay;
133         } time_get;
134     } out;
135     void ( *pf_destroy )( struct thread_cmd * );
136 };
137
138 #define THREAD_NAME "android_audiotrack"
139
140 extern int jni_attach_thread(JNIEnv **env, const char *thread_name);
141 extern void jni_detach_thread();
142 extern int jni_get_env(JNIEnv **env);
143
144 static struct
145 {
146     struct {
147         jclass clazz;
148         jmethodID ctor;
149         jmethodID release;
150         jmethodID getState;
151         jmethodID play;
152         jmethodID stop;
153         jmethodID flush;
154         jmethodID pause;
155         jmethodID write;
156         jmethodID writeV21;
157         jmethodID getPlaybackHeadPosition;
158         jmethodID getTimestamp;
159         jmethodID getMinBufferSize;
160         jint STATE_INITIALIZED;
161         jint MODE_STREAM;
162         jint ERROR;
163         jint ERROR_BAD_VALUE;
164         jint ERROR_INVALID_OPERATION;
165         jint WRITE_NON_BLOCKING;
166     } AudioTrack;
167     struct {
168         jint ENCODING_PCM_8BIT;
169         jint ENCODING_PCM_16BIT;
170         jint ENCODING_PCM_FLOAT;
171         bool has_ENCODING_PCM_FLOAT;
172         jint CHANNEL_OUT_MONO;
173         jint CHANNEL_OUT_STEREO;
174     } AudioFormat;
175     struct {
176         jint ERROR_DEAD_OBJECT;
177         bool has_ERROR_DEAD_OBJECT;
178         jint STREAM_MUSIC;
179     } AudioManager;
180     struct {
181         jclass clazz;
182         jmethodID ctor;
183         jfieldID framePosition;
184         jfieldID nanoTime;
185     } AudioTimestamp;
186 } jfields;
187
188 /* init all jni fields.
189  * Done only one time during the first initialisation */
190 static bool
191 InitJNIFields( audio_output_t *p_aout )
192 {
193     static vlc_mutex_t lock = VLC_STATIC_MUTEX;
194     static int i_init_state = -1;
195     bool ret, b_attached = false;
196     jclass clazz;
197     jfieldID field;
198     JNIEnv* env = NULL;
199
200     vlc_mutex_lock( &lock );
201
202     if( i_init_state != -1 )
203         goto end;
204
205     if( jni_get_env(&env) < 0 )
206     {
207         jni_attach_thread( &env, THREAD_NAME );
208         if( !env )
209         {
210             i_init_state = 0;
211             goto end;
212         }
213         b_attached = true;
214     }
215
216 #define CHECK_EXCEPTION( what, critical ) do { \
217     if( (*env)->ExceptionOccurred( env ) ) \
218     { \
219         msg_Err( p_aout, "%s failed", what ); \
220         (*env)->ExceptionClear( env ); \
221         if( (critical) ) \
222         { \
223             i_init_state = 0; \
224             goto end; \
225         } \
226     } \
227 } while( 0 )
228 #define GET_CLASS( str, critical ) do { \
229     clazz = (*env)->FindClass( env, (str) ); \
230     CHECK_EXCEPTION( str, critical ); \
231 } while( 0 )
232 #define GET_ID( get, id, str, args, critical ) do { \
233     jfields.id = (*env)->get( env, clazz, (str), (args) ); \
234     CHECK_EXCEPTION( #get, critical ); \
235 } while( 0 )
236 #define GET_CONST_INT( id, str, critical ) do { \
237     field = NULL; \
238     field = (*env)->GetStaticFieldID( env, clazz, (str), "I" ); \
239     CHECK_EXCEPTION( #id, critical ); \
240     if( field ) \
241     { \
242         jfields.id = (*env)->GetStaticIntField( env, clazz, field ); \
243         CHECK_EXCEPTION( #id, critical ); \
244     } \
245 } while( 0 )
246
247     /* AudioTrack class init */
248     GET_CLASS( "android/media/AudioTrack", true );
249     jfields.AudioTrack.clazz = (jclass) (*env)->NewGlobalRef( env, clazz );
250     CHECK_EXCEPTION( "NewGlobalRef", true );
251
252     GET_ID( GetMethodID, AudioTrack.ctor, "<init>", "(IIIIII)V", true );
253     GET_ID( GetMethodID, AudioTrack.release, "release", "()V", true );
254     GET_ID( GetMethodID, AudioTrack.getState, "getState", "()I", true );
255     GET_ID( GetMethodID, AudioTrack.play, "play", "()V", true );
256     GET_ID( GetMethodID, AudioTrack.stop, "stop", "()V", true );
257     GET_ID( GetMethodID, AudioTrack.flush, "flush", "()V", true );
258     GET_ID( GetMethodID, AudioTrack.pause, "pause", "()V", true );
259
260     GET_ID( GetMethodID, AudioTrack.writeV21, "write", "(Ljava/nio/ByteBuffer;II)I", false );
261     if( jfields.AudioTrack.writeV21 )
262     {
263         jfields.AudioTrack.write = NULL;
264         GET_CONST_INT( AudioTrack.WRITE_NON_BLOCKING, "WRITE_NON_BLOCKING", true );
265     } else
266         GET_ID( GetMethodID, AudioTrack.write, "write", "([BII)I", true );
267
268 #ifdef AUDIOTRACK_USE_TIMESTAMP
269     GET_ID( GetMethodID, AudioTrack.getTimestamp,
270             "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
271 #endif
272     GET_ID( GetMethodID, AudioTrack.getPlaybackHeadPosition,
273             "getPlaybackHeadPosition", "()I", true );
274
275     GET_ID( GetStaticMethodID, AudioTrack.getMinBufferSize, "getMinBufferSize",
276             "(III)I", true );
277     GET_CONST_INT( AudioTrack.STATE_INITIALIZED, "STATE_INITIALIZED", true );
278     GET_CONST_INT( AudioTrack.MODE_STREAM, "MODE_STREAM", true );
279     GET_CONST_INT( AudioTrack.ERROR, "ERROR", true );
280     GET_CONST_INT( AudioTrack.ERROR_BAD_VALUE , "ERROR_BAD_VALUE", true );
281     GET_CONST_INT( AudioTrack.ERROR_INVALID_OPERATION,
282                    "ERROR_INVALID_OPERATION", true );
283
284     /* AudioTimestamp class init (if any) */
285     if( jfields.AudioTrack.getTimestamp )
286     {
287         GET_CLASS( "android/media/AudioTimestamp", true );
288         jfields.AudioTimestamp.clazz = (jclass) (*env)->NewGlobalRef( env,
289                                                                       clazz );
290         CHECK_EXCEPTION( "NewGlobalRef", true );
291
292         GET_ID( GetMethodID, AudioTimestamp.ctor, "<init>", "()V", true );
293         GET_ID( GetFieldID, AudioTimestamp.framePosition,
294                 "framePosition", "J", true );
295         GET_ID( GetFieldID, AudioTimestamp.nanoTime,
296                 "nanoTime", "J", true );
297     } else
298     {
299         jfields.AudioTimestamp.clazz = NULL;
300         jfields.AudioTimestamp.ctor = NULL;
301         jfields.AudioTimestamp.framePosition = NULL;
302         jfields.AudioTimestamp.nanoTime = NULL;
303     }
304
305     /* AudioFormat class init */
306     GET_CLASS( "android/media/AudioFormat", true );
307     GET_CONST_INT( AudioFormat.ENCODING_PCM_8BIT, "ENCODING_PCM_8BIT", true );
308     GET_CONST_INT( AudioFormat.ENCODING_PCM_16BIT, "ENCODING_PCM_16BIT", true );
309 #ifdef AUDIOTRACK_USE_FLOAT
310     GET_CONST_INT( AudioFormat.ENCODING_PCM_FLOAT, "ENCODING_PCM_FLOAT",
311                    false );
312     jfields.AudioFormat.has_ENCODING_PCM_FLOAT = field != NULL;
313 #else
314     jfields.AudioFormat.has_ENCODING_PCM_FLOAT = false;
315 #endif
316     GET_CONST_INT( AudioFormat.CHANNEL_OUT_MONO, "CHANNEL_OUT_MONO", true );
317     GET_CONST_INT( AudioFormat.CHANNEL_OUT_STEREO, "CHANNEL_OUT_STEREO", true );
318
319     /* AudioManager class init */
320     GET_CLASS( "android/media/AudioManager", true );
321     GET_CONST_INT( AudioManager.ERROR_DEAD_OBJECT, "ERROR_DEAD_OBJECT", false );
322     jfields.AudioManager.has_ERROR_DEAD_OBJECT = field != NULL;
323     GET_CONST_INT( AudioManager.STREAM_MUSIC, "STREAM_MUSIC", true );
324
325 #undef CHECK_EXCEPTION
326 #undef GET_CLASS
327 #undef GET_ID
328 #undef GET_CONST_INT
329
330     i_init_state = 1;
331 end:
332     ret = i_init_state == 1;
333     if( !ret )
334         msg_Err( p_aout, "AudioTrack jni init failed" );
335     if( b_attached )
336         jni_detach_thread();
337     vlc_mutex_unlock( &lock );
338     return ret;
339 }
340
341 static inline bool
342 check_exception( JNIEnv *env, audio_output_t *p_aout,
343                  const char *method )
344 {
345     if( (*env)->ExceptionOccurred( env ) )
346     {
347         aout_sys_t *p_sys = p_aout->sys;
348
349         p_sys->b_audiotrack_exception = true;
350         (*env)->ExceptionClear( env );
351         msg_Err( p_aout, "AudioTrack.%s triggered an exception !", method );
352         return true;
353     } else
354         return false;
355 }
356 #define CHECK_AT_EXCEPTION( method ) check_exception( env, p_aout, method )
357
358 #define JNI_CALL( what, obj, method, ... ) (*env)->what( env, obj, method, ##__VA_ARGS__ )
359
360 #define JNI_CALL_INT( obj, method, ... ) JNI_CALL( CallIntMethod, obj, method, ##__VA_ARGS__ )
361 #define JNI_CALL_BOOL( obj, method, ... ) JNI_CALL( CallBooleanMethod, obj, method, ##__VA_ARGS__ )
362 #define JNI_CALL_VOID( obj, method, ... ) JNI_CALL( CallVoidMethod, obj, method, ##__VA_ARGS__ )
363 #define JNI_CALL_STATIC_INT( clazz, method, ... ) JNI_CALL( CallStaticIntMethod, clazz, method, ##__VA_ARGS__ )
364
365 #define JNI_AT_NEW( ... ) JNI_CALL( NewObject, jfields.AudioTrack.clazz, jfields.AudioTrack.ctor, ##__VA_ARGS__ )
366 #define JNI_AT_CALL_INT( method, ... ) JNI_CALL_INT( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
367 #define JNI_AT_CALL_BOOL( method, ... ) JNI_CALL_BOOL( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
368 #define JNI_AT_CALL_VOID( method, ... ) JNI_CALL_VOID( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
369 #define JNI_AT_CALL_STATIC_INT( method, ... ) JNI_CALL( CallStaticIntMethod, jfields.AudioTrack.clazz, jfields.AudioTrack.method, ##__VA_ARGS__ )
370
371 #define JNI_AUDIOTIMESTAMP_GET_LONG( field ) JNI_CALL( GetLongField, p_sys->p_audioTimestamp, jfields.AudioTimestamp.field )
372
373 static inline mtime_t
374 frames_to_us( aout_sys_t *p_sys, uint32_t i_nb_frames )
375 {
376     return  i_nb_frames * CLOCK_FREQ / p_sys->fmt.i_rate;
377 }
378 #define FRAMES_TO_US(x) frames_to_us( p_sys, (x) )
379
380 static struct thread_cmd *
381 ThreadCmd_New( int id )
382 {
383     struct thread_cmd *p_cmd = calloc( 1, sizeof(struct thread_cmd) );
384
385     if( p_cmd )
386         p_cmd->id = id;
387
388     return p_cmd;
389 }
390
391 static void
392 ThreadCmd_InsertHead( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
393 {
394     TAILQ_INSERT_HEAD( &p_sys->thread_cmd_queue, p_cmd, next);
395     vlc_cond_signal( &p_sys->cond );
396 }
397
398 static void
399 ThreadCmd_InsertTail( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
400 {
401     TAILQ_INSERT_TAIL( &p_sys->thread_cmd_queue, p_cmd, next);
402     vlc_cond_signal( &p_sys->cond );
403 }
404
405 static bool
406 ThreadCmd_Wait( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
407 {
408     while( p_cmd->id != CMD_DONE )
409         vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
410
411     return p_cmd->id == CMD_DONE;
412 }
413
414 static void
415 ThreadCmd_FlushQueue( aout_sys_t *p_sys )
416 {
417     struct thread_cmd *p_cmd, *p_cmd_next;
418
419     for ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue );
420           p_cmd != NULL; p_cmd = p_cmd_next )
421     {
422         p_cmd_next = TAILQ_NEXT( p_cmd, next );
423         TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
424         if( p_cmd->pf_destroy )
425             p_cmd->pf_destroy( p_cmd );
426     }
427 }
428
429 static void
430 JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout )
431 {
432     aout_sys_t *p_sys = p_aout->sys;
433
434     if( p_sys->p_audiotrack )
435         p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
436     else
437         p_sys->i_pos_initial = 0;
438
439     /* HACK: On some broken devices, head position is still moving after a
440      * flush or a stop. So, wait for the head position to be stabilized. */
441     if( unlikely( p_sys->i_pos_initial != 0 ) )
442     {
443         uint32_t i_last_pos;
444         do {
445             i_last_pos = p_sys->i_pos_initial;
446             msleep( 50000 );
447             p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
448         } while( p_sys->i_pos_initial != i_last_pos );
449     }
450     p_sys->i_samples_written = 0;
451     p_sys->i_samples_queued = 0;
452 }
453
454 static uint32_t
455 JNIThread_GetAudioTrackPos( JNIEnv *env, audio_output_t *p_aout )
456 {
457     aout_sys_t *p_sys = p_aout->sys;
458
459     /* Android doc:
460      * getPlaybackHeadPosition: Returns the playback head position expressed in
461      * frames. Though the "int" type is signed 32-bits, the value should be
462      * reinterpreted as if it is unsigned 32-bits. That is, the next position
463      * after 0x7FFFFFFF is (int) 0x80000000. This is a continuously advancing
464      * counter. It will wrap (overflow) periodically, for example approximately
465      * once every 27:03:11 hours:minutes:seconds at 44.1 kHz. It is reset to
466      * zero by flush(), reload(), and stop().
467      */
468
469     return JNI_AT_CALL_INT( getPlaybackHeadPosition ) - p_sys->i_pos_initial;
470 }
471
472 static int
473 JNIThread_TimeGet( JNIEnv *env, audio_output_t *p_aout, mtime_t *p_delay )
474 {
475     aout_sys_t *p_sys = p_aout->sys;
476     jlong i_frame_pos;
477     uint32_t i_audiotrack_delay = 0;
478
479     if( p_sys->i_samples_queued == 0 )
480         return -1;
481     if( p_sys->p_audioTimestamp )
482     {
483         mtime_t i_current_time = mdate();
484         /* Android doc:
485          * getTimestamp: Poll for a timestamp on demand.
486          *
487          * If you need to track timestamps during initial warmup or after a
488          * routing or mode change, you should request a new timestamp once per
489          * second until the reported timestamps show that the audio clock is
490          * stable. Thereafter, query for a new timestamp approximately once
491          * every 10 seconds to once per minute. Calling this method more often
492          * is inefficient. It is also counter-productive to call this method
493          * more often than recommended, because the short-term differences
494          * between successive timestamp reports are not meaningful. If you need
495          * a high-resolution mapping between frame position and presentation
496          * time, consider implementing that at application level, based on
497          * low-resolution timestamps.
498          */
499
500         if( JNI_AT_CALL_BOOL( getTimestamp, p_sys->p_audioTimestamp ) )
501         {
502             jlong i_frame_time = JNI_AUDIOTIMESTAMP_GET_LONG( nanoTime ) / 1000;
503             /* frame time should be after last play time
504              * frame time shouldn't be in the future
505              * frame time should be less than 10 seconds old */
506             if( i_frame_time > p_sys->i_play_time
507                 && i_current_time > i_frame_time
508                 && ( i_current_time - i_frame_time ) <= INT64_C(10000000) )
509             {
510                 jlong i_time_diff = i_current_time - i_frame_time;
511                 jlong i_frames_diff = i_time_diff *  p_sys->fmt.i_rate
512                                       / CLOCK_FREQ;
513                 i_frame_pos = JNI_AUDIOTIMESTAMP_GET_LONG( framePosition )
514                               + i_frames_diff;
515                 if( p_sys->i_samples_written > i_frame_pos )
516                     i_audiotrack_delay =  p_sys->i_samples_written - i_frame_pos;
517             }
518         }
519     }
520     if( i_audiotrack_delay == 0 )
521     {
522         uint32_t i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
523
524         if( p_sys->i_samples_written > i_audiotrack_pos )
525             i_audiotrack_delay = p_sys->i_samples_written - i_audiotrack_pos;
526     }
527
528     if( i_audiotrack_delay > 0 )
529     {
530         *p_delay = FRAMES_TO_US( p_sys->i_samples_queued + i_audiotrack_delay );
531         return 0;
532     } else
533         return -1;
534 }
535
536 static int
537 JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
538 {
539     struct aout_sys_t *p_sys = p_aout->sys;
540     int i_size, i_min_buffer_size, i_channel_config, i_rate, i_format,
541         i_format_size, i_nb_channels;
542     jobject p_audiotrack;
543
544     /* 4000 <= frequency <= 48000 */
545     i_rate = p_sys->fmt.i_rate;
546     if( i_rate < 4000 )
547         i_rate = 4000;
548     if( i_rate > 48000 )
549         i_rate = 48000;
550
551     /* We can only accept U8, S16N, and FL32 (depending on Android version) */
552     if( p_sys->fmt.i_format != VLC_CODEC_U8
553         && p_sys->fmt.i_format != VLC_CODEC_S16N
554         && p_sys->fmt.i_format != VLC_CODEC_FL32 )
555         p_sys->fmt.i_format = VLC_CODEC_S16N;
556
557     if( p_sys->fmt.i_format == VLC_CODEC_FL32
558         && !jfields.AudioFormat.has_ENCODING_PCM_FLOAT )
559         p_sys->fmt.i_format = VLC_CODEC_S16N;
560
561     if( p_sys->fmt.i_format == VLC_CODEC_S16N )
562     {
563         i_format = jfields.AudioFormat.ENCODING_PCM_16BIT;
564         i_format_size = 2;
565     } else if( p_sys->fmt.i_format == VLC_CODEC_FL32 )
566     {
567         i_format = jfields.AudioFormat.ENCODING_PCM_FLOAT;
568         i_format_size = 4;
569     } else
570     {
571         i_format = jfields.AudioFormat.ENCODING_PCM_8BIT;
572         i_format_size = 1;
573     }
574     p_sys->fmt.i_original_channels = p_sys->fmt.i_physical_channels;
575
576     i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
577     switch( i_nb_channels )
578     {
579     case 1:
580         i_channel_config = jfields.AudioFormat.CHANNEL_OUT_MONO;
581         p_sys->fmt.i_physical_channels = AOUT_CHAN_CENTER;
582         break;
583     default:
584         i_nb_channels = 2; // XXX: AudioTrack handle only stereo for now
585     case 2:
586         i_channel_config = jfields.AudioFormat.CHANNEL_OUT_STEREO;
587         p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
588         break;
589     }
590
591     i_min_buffer_size = JNI_AT_CALL_STATIC_INT( getMinBufferSize, i_rate,
592                                                 i_channel_config, i_format );
593     if( i_min_buffer_size <= 0 )
594     {
595         msg_Warn( p_aout, "getMinBufferSize returned an invalid size" ) ;
596         /* use a defaut min buffer size (shouldn't happen) */
597         i_min_buffer_size = i_nb_channels * i_format_size * 2048;
598     }
599
600     i_size = i_min_buffer_size * 4;
601     p_sys->i_bytes_per_frame = i_nb_channels * i_format_size;
602     p_sys->i_max_audiotrack_samples = i_size / p_sys->i_bytes_per_frame;
603
604     /* create AudioTrack object */
605     p_audiotrack = JNI_AT_NEW( jfields.AudioManager.STREAM_MUSIC, i_rate,
606                                i_channel_config, i_format, i_size,
607                                jfields.AudioTrack.MODE_STREAM );
608     if( CHECK_AT_EXCEPTION( "AudioTrack<init>" ) || !p_audiotrack )
609         return VLC_EGENERIC;
610     p_sys->p_audiotrack = (*env)->NewGlobalRef( env, p_audiotrack );
611     (*env)->DeleteLocalRef( env, p_audiotrack );
612     if( !p_sys->p_audiotrack )
613         return VLC_EGENERIC;
614     if( JNI_AT_CALL_INT( getState ) != jfields.AudioTrack.STATE_INITIALIZED )
615     {
616         msg_Err( p_aout, "AudioTrack init failed" );
617         goto error;
618     }
619
620     if( jfields.AudioTimestamp.clazz )
621     {
622         /* create AudioTimestamp object */
623         jobject p_audioTimestamp = JNI_CALL( NewObject,
624                                              jfields.AudioTimestamp.clazz,
625                                              jfields.AudioTimestamp.ctor );
626         if( !p_audioTimestamp )
627             goto error;
628         p_sys->p_audioTimestamp = (*env)->NewGlobalRef( env, p_audioTimestamp );
629         (*env)->DeleteLocalRef( env, p_audioTimestamp );
630         if( !p_sys->p_audioTimestamp )
631             goto error;
632     }
633
634     p_sys->fmt.i_rate = i_rate;
635
636     JNI_AT_CALL_VOID( play );
637     CHECK_AT_EXCEPTION( "play" );
638     p_sys->i_play_time = mdate();
639
640     return VLC_SUCCESS;
641 error:
642     if( p_sys->p_audiotrack )
643     {
644         JNI_AT_CALL_VOID( release );
645         (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
646         p_sys->p_audiotrack = NULL;
647     }
648     return VLC_EGENERIC;
649 }
650
651 static void
652 JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
653 {
654     aout_sys_t *p_sys = p_aout->sys;
655
656     if( !p_sys->b_audiotrack_exception )
657     {
658         JNI_AT_CALL_VOID( stop );
659         if( !CHECK_AT_EXCEPTION( "stop" ) )
660             JNI_AT_CALL_VOID( release );
661     }
662     p_sys->b_audiotrack_exception = false;
663     (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
664     p_sys->p_audiotrack = NULL;
665
666     if( p_sys->p_audioTimestamp )
667     {
668         (*env)->DeleteGlobalRef( env, p_sys->p_audioTimestamp );
669         p_sys->p_audioTimestamp = NULL;
670     }
671 }
672
673 /**
674  * Non blocking write function.
675  * Do a calculation between current position and audiotrack position and assure
676  * that we won't wait in AudioTrack.write() method
677  */
678 static int
679 JNIThread_Write( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
680 {
681     aout_sys_t *p_sys = p_aout->sys;
682     uint8_t *p_data = p_buffer->p_buffer;
683     size_t i_data;
684     uint32_t i_samples;
685     uint32_t i_audiotrack_pos;
686     uint32_t i_samples_pending;
687
688     i_audiotrack_pos = JNIThread_GetAudioTrackPos( env, p_aout );
689     if( i_audiotrack_pos > p_sys->i_samples_written )
690     {
691         msg_Warn( p_aout, "audiotrack position is ahead. Should NOT happen" );
692         JNIThread_InitDelay( env, p_aout );
693         return 0;
694     }
695     i_samples_pending = p_sys->i_samples_written - i_audiotrack_pos;
696
697     /* check if audiotrack buffer is not full before writing on it. */
698     if( i_samples_pending >= p_sys->i_max_audiotrack_samples )
699         return 0;
700     i_samples = __MIN( p_sys->i_max_audiotrack_samples - i_samples_pending,
701                        p_buffer->i_nb_samples );
702
703     i_data = i_samples * p_sys->i_bytes_per_frame;
704
705     /* check if we need to realloc a ByteArray */
706     if( i_data > p_sys->i_bytearray_size )
707     {
708         jbyteArray p_bytearray;
709
710         if( p_sys->p_bytearray )
711         {
712             (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
713             p_sys->p_bytearray = NULL;
714         }
715
716         p_bytearray = (*env)->NewByteArray( env, i_data );
717         if( p_bytearray )
718         {
719             p_sys->p_bytearray = (*env)->NewGlobalRef( env, p_bytearray );
720             (*env)->DeleteLocalRef( env, p_bytearray );
721         }
722         p_sys->i_bytearray_size = i_data;
723     }
724     if( !p_sys->p_bytearray )
725         return jfields.AudioTrack.ERROR_BAD_VALUE;
726
727     /* copy p_buffer in to ByteArray */
728     (*env)->SetByteArrayRegion( env, p_sys->p_bytearray, 0, i_data,
729                                 (jbyte *)p_data);
730
731     return JNI_AT_CALL_INT( write, p_sys->p_bytearray, 0, i_data );
732 }
733
734 /**
735  * JNIThread_Write doesn't always work on Lollipop. Probably because audiotrack
736  * buffer size is bigger than the one we pass in ctor arguments (and there is
737  * no way to know it). It's not an issue since there is a new write method that
738  * is non blocking.
739  */
740 static int
741 JNIThread_WriteV21( JNIEnv *env, audio_output_t *p_aout, block_t *p_buffer )
742 {
743     aout_sys_t *p_sys = p_aout->sys;
744     int i_ret;
745
746     if( !p_sys->p_bytebuffer )
747     {
748         jobject p_bytebuffer;
749
750         p_bytebuffer = (*env)->NewDirectByteBuffer( env, p_buffer->p_buffer,
751                                                     p_buffer->i_buffer );
752         if( !p_bytebuffer )
753             return jfields.AudioTrack.ERROR_BAD_VALUE;
754
755         p_sys->p_bytebuffer = (*env)->NewGlobalRef( env, p_bytebuffer );
756         (*env)->DeleteLocalRef( env, p_bytebuffer );
757
758         if( !p_sys->p_bytebuffer || (*env)->ExceptionOccurred( env ) )
759         {
760             p_sys->p_bytebuffer = NULL;
761             (*env)->ExceptionClear( env );
762             return jfields.AudioTrack.ERROR_BAD_VALUE;
763         }
764     }
765
766     i_ret = JNI_AT_CALL_INT( writeV21, p_sys->p_bytebuffer, p_buffer->i_buffer,
767                              jfields.AudioTrack.WRITE_NON_BLOCKING );
768     if( i_ret > 0 )
769     {
770         /* don't delete the bytebuffer if we wrote nothing, keep it for next
771          * call */
772         (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
773         p_sys->p_bytebuffer = NULL;
774     }
775     return i_ret;
776 }
777
778 static int
779 JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
780                 block_t **pp_buffer, mtime_t *p_wait )
781 {
782     aout_sys_t *p_sys = p_aout->sys;
783     block_t *p_buffer = *pp_buffer;
784     int i_ret;
785
786     if( jfields.AudioTrack.writeV21 )
787         i_ret = JNIThread_WriteV21( env, p_aout, p_buffer );
788     else
789         i_ret = JNIThread_Write( env, p_aout, p_buffer );
790
791     if( i_ret < 0 ) {
792         if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
793             && i_ret == jfields.AudioManager.ERROR_DEAD_OBJECT )
794         {
795             msg_Warn( p_aout, "ERROR_DEAD_OBJECT: "
796                               "try recreating AudioTrack" );
797             JNIThread_Stop( env, p_aout );
798             i_ret = JNIThread_Start( env, p_aout );
799         } else
800         {
801             const char *str;
802             if( i_ret == jfields.AudioTrack.ERROR_INVALID_OPERATION )
803                 str = "ERROR_INVALID_OPERATION";
804             else if( i_ret == jfields.AudioTrack.ERROR_BAD_VALUE )
805                 str = "ERROR_BAD_VALUE";
806             else
807                 str = "ERROR";
808             msg_Err( p_aout, "Write failed: %s", str );
809         }
810     } else if( i_ret == 0 )
811         *p_wait = FRAMES_TO_US( p_buffer->i_nb_samples );
812     else
813     {
814         uint32_t i_samples = i_ret / p_sys->i_bytes_per_frame;
815         p_sys->i_samples_queued -= i_samples;
816         p_sys->i_samples_written += i_samples;
817
818         p_buffer->p_buffer += i_ret;
819         p_buffer->i_buffer -= i_ret;
820         p_buffer->i_nb_samples -= i_samples;
821         if( p_buffer->i_buffer == 0 )
822             *pp_buffer = NULL;
823     }
824
825     return i_ret >= 0 ? VLC_SUCCESS : VLC_EGENERIC;
826 }
827
828 static void
829 JNIThread_Pause( JNIEnv *env, audio_output_t *p_aout,
830                  bool b_pause, mtime_t i_date )
831 {
832     VLC_UNUSED( i_date );
833
834     aout_sys_t *p_sys = p_aout->sys;
835
836     if( b_pause )
837     {
838         JNI_AT_CALL_VOID( pause );
839         CHECK_AT_EXCEPTION( "pause" );
840     } else
841     {
842         JNI_AT_CALL_VOID( play );
843         CHECK_AT_EXCEPTION( "play" );
844         p_sys->i_play_time = mdate();
845     }
846 }
847
848 static void
849 JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
850                  bool b_wait )
851 {
852     aout_sys_t *p_sys = p_aout->sys;
853
854     /* Android doc:
855      * stop(): Stops playing the audio data. When used on an instance created
856      * in MODE_STREAM mode, audio will stop playing after the last buffer that
857      * was written has been played. For an immediate stop, use pause(),
858      * followed by flush() to discard audio data that hasn't been played back
859      * yet.
860      *
861      * flush(): Flushes the audio data currently queued for playback. Any data
862      * that has not been played back will be discarded.  No-op if not stopped
863      * or paused, or if the track's creation mode is not MODE_STREAM.
864      */
865     if( b_wait )
866     {
867         JNI_AT_CALL_VOID( stop );
868         if( CHECK_AT_EXCEPTION( "stop" ) )
869             return;
870     } else
871     {
872         JNI_AT_CALL_VOID( pause );
873         if( CHECK_AT_EXCEPTION( "pause" ) )
874             return;
875         JNI_AT_CALL_VOID( flush );
876     }
877     JNI_AT_CALL_VOID( play );
878     CHECK_AT_EXCEPTION( "play" );
879     p_sys->i_play_time = mdate();
880
881     if( p_sys->p_bytebuffer )
882     {
883         (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
884         p_sys->p_bytebuffer = NULL;
885     }
886 }
887
888 static void *
889 JNIThread( void *data )
890 {
891     audio_output_t *p_aout = data;
892     aout_sys_t *p_sys = p_aout->sys;
893     bool b_error = false;
894     bool b_paused = false;
895     block_t *p_buffer = NULL;
896     mtime_t i_play_deadline = 0;
897     JNIEnv* env;
898
899     jni_attach_thread( &env, THREAD_NAME );
900
901     vlc_mutex_lock( &p_sys->mutex );
902     if( !env )
903         goto end;
904
905     while( p_sys->b_thread_run )
906     {
907         struct thread_cmd *p_cmd;
908         bool b_remove_cmd = true;
909
910         /* wait to process a command */
911         while( ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue ) ) == NULL
912                && p_sys->b_thread_run )
913             vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
914
915         if( !p_sys->b_thread_run || p_cmd == NULL )
916             break;
917
918         if( b_paused && p_cmd->id == CMD_PLAY )
919         {
920             vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
921             continue;
922         }
923
924         if( p_cmd->id == CMD_PLAY && i_play_deadline > 0 )
925         {
926             if( mdate() > i_play_deadline )
927                 i_play_deadline = 0;
928             else
929             {
930                 int i_ret = 0;
931                 while( p_cmd == TAILQ_FIRST( &p_sys->thread_cmd_queue )
932                        && i_ret != ETIMEDOUT && p_sys->b_thread_run )
933                     i_ret = vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex,
934                                                 i_play_deadline );
935                 continue;
936             }
937         }
938
939         /* process a command */
940         switch( p_cmd->id )
941         {
942             case CMD_START:
943                 assert( !p_sys->p_audiotrack );
944                 if( b_error ) {
945                     p_cmd->out.start.i_ret = -1;
946                     break;
947                 }
948                 p_sys->fmt = *p_cmd->in.start.p_fmt;
949                 p_cmd->out.start.i_ret =
950                         JNIThread_Start( env, p_aout );
951                 JNIThread_InitDelay( env, p_aout );
952                 p_cmd->out.start.p_fmt = &p_sys->fmt;
953                 b_paused = false;
954                 break;
955             case CMD_STOP:
956                 assert( p_sys->p_audiotrack );
957                 JNIThread_Stop( env, p_aout );
958                 JNIThread_InitDelay( env, p_aout );
959                 b_paused = false;
960                 b_error = false;
961                 p_buffer = NULL;
962                 break;
963             case CMD_PLAY:
964             {
965                 mtime_t i_play_wait = 0;
966
967                 assert( p_sys->p_audiotrack );
968                 if( b_error )
969                     break;
970                 if( p_buffer == NULL )
971                     p_buffer = p_cmd->in.play.p_buffer;
972                 b_error = JNIThread_Play( env, p_aout, &p_buffer,
973                                           &i_play_wait ) != VLC_SUCCESS;
974                 if( p_buffer != NULL )
975                     b_remove_cmd = false;
976                 if( i_play_wait > 0 )
977                     i_play_deadline = mdate() + i_play_wait;
978                 break;
979             }
980             case CMD_PAUSE:
981                 assert( p_sys->p_audiotrack );
982                 if( b_error )
983                     break;
984                 JNIThread_Pause( env, p_aout,
985                                  p_cmd->in.pause.b_pause,
986                                  p_cmd->in.pause.i_date );
987                 b_paused = p_cmd->in.pause.b_pause;
988                 break;
989             case CMD_TIME_GET:
990                 assert( p_sys->p_audiotrack );
991                 if( b_error )
992                     break;
993                 p_cmd->out.time_get.i_ret =
994                         JNIThread_TimeGet( env, p_aout,
995                                            &p_cmd->out.time_get.i_delay );
996                 break;
997             case CMD_FLUSH:
998                 assert( p_sys->p_audiotrack );
999                 if( b_error )
1000                     break;
1001                 JNIThread_Flush( env, p_aout,
1002                                  p_cmd->in.flush.b_wait );
1003                 JNIThread_InitDelay( env, p_aout );
1004                 p_buffer = NULL;
1005                 break;
1006             default:
1007                 vlc_assert_unreachable();
1008         }
1009         if( p_sys->b_audiotrack_exception )
1010             b_error = true;
1011
1012         if( b_remove_cmd )
1013         {
1014             TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
1015             p_cmd->id = CMD_DONE;
1016             if( p_cmd->pf_destroy )
1017                 p_cmd->pf_destroy( p_cmd );
1018         }
1019
1020         /* signal that command is processed */
1021         vlc_cond_signal( &p_sys->cond );
1022     }
1023 end:
1024     if( env )
1025     {
1026         if( p_sys->p_bytearray )
1027             (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
1028         if( p_sys->p_bytebuffer )
1029             (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1030         jni_detach_thread();
1031     }
1032     vlc_mutex_unlock( &p_sys->mutex );
1033     return NULL;
1034 }
1035
1036 static int
1037 Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
1038 {
1039     int i_ret = VLC_EGENERIC;
1040     struct thread_cmd *p_cmd;
1041     aout_sys_t *p_sys = p_aout->sys;
1042
1043     vlc_mutex_lock( &p_sys->mutex );
1044
1045     p_cmd = ThreadCmd_New( CMD_START );
1046     if( p_cmd )
1047     {
1048         /* ask the thread to process the Start command */
1049         p_cmd->in.start.p_fmt = p_fmt;
1050
1051         ThreadCmd_InsertHead( p_sys, p_cmd );
1052         if( ThreadCmd_Wait( p_sys, p_cmd ) )
1053         {
1054             i_ret = p_cmd->out.start.i_ret;
1055             if( i_ret == VLC_SUCCESS )
1056                 *p_fmt = *p_cmd->out.start.p_fmt;
1057         }
1058         free( p_cmd );
1059     }
1060
1061     vlc_mutex_unlock( &p_sys->mutex );
1062
1063     if( i_ret == VLC_SUCCESS )
1064         aout_SoftVolumeStart( p_aout );
1065
1066     return i_ret;
1067 }
1068
1069 static void
1070 Stop( audio_output_t *p_aout )
1071 {
1072     aout_sys_t *p_sys = p_aout->sys;
1073     struct thread_cmd *p_cmd;
1074
1075     vlc_mutex_lock( &p_sys->mutex );
1076
1077     ThreadCmd_FlushQueue( p_sys );
1078
1079     p_cmd = ThreadCmd_New( CMD_STOP );
1080     if( p_cmd )
1081     {
1082         /* ask the thread to process the Stop command */
1083         ThreadCmd_InsertHead( p_sys, p_cmd );
1084         ThreadCmd_Wait( p_sys, p_cmd );
1085
1086         free( p_cmd );
1087     }
1088
1089     vlc_mutex_unlock( &p_sys->mutex );
1090 }
1091
1092 static void
1093 PlayCmd_Destroy( struct thread_cmd *p_cmd )
1094 {
1095     block_Release( p_cmd->in.play.p_buffer );
1096     free( p_cmd );
1097 }
1098
1099 static void
1100 Play( audio_output_t *p_aout, block_t *p_buffer )
1101 {
1102     aout_sys_t *p_sys = p_aout->sys;
1103     struct thread_cmd *p_cmd;
1104
1105     vlc_mutex_lock( &p_sys->mutex );
1106
1107     while( p_sys->i_samples_queued != 0
1108            && FRAMES_TO_US( p_sys->i_samples_queued +
1109                             p_buffer->i_nb_samples ) >= MAX_QUEUE_US )
1110         vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1111
1112     p_cmd = ThreadCmd_New( CMD_PLAY );
1113     if( p_cmd )
1114     {
1115         /* ask the thread to process the Play command */
1116         p_cmd->in.play.p_buffer = p_buffer;
1117         p_cmd->pf_destroy = PlayCmd_Destroy;
1118
1119         ThreadCmd_InsertTail( p_sys, p_cmd );
1120
1121         p_sys->i_samples_queued += p_buffer->i_nb_samples;
1122     } else
1123          block_Release( p_cmd->in.play.p_buffer );
1124
1125     vlc_mutex_unlock( &p_sys->mutex );
1126 }
1127
1128 static void
1129 Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
1130 {
1131     aout_sys_t *p_sys = p_aout->sys;
1132     struct thread_cmd *p_cmd;
1133
1134     vlc_mutex_lock( &p_sys->mutex );
1135
1136     p_cmd = ThreadCmd_New( CMD_PAUSE );
1137     if( p_cmd )
1138     {
1139         /* ask the thread to process the Pause command */
1140         p_cmd->in.pause.b_pause = b_pause;
1141         p_cmd->in.pause.i_date = i_date;
1142
1143         ThreadCmd_InsertHead( p_sys, p_cmd );
1144         ThreadCmd_Wait( p_sys, p_cmd );
1145
1146         free( p_cmd );
1147     }
1148
1149     vlc_mutex_unlock( &p_sys->mutex );
1150 }
1151
1152 static void
1153 Flush( audio_output_t *p_aout, bool b_wait )
1154 {
1155     aout_sys_t *p_sys = p_aout->sys;
1156     struct thread_cmd *p_cmd;
1157
1158     vlc_mutex_lock( &p_sys->mutex );
1159
1160     ThreadCmd_FlushQueue( p_sys );
1161
1162     p_cmd = ThreadCmd_New( CMD_FLUSH );
1163     if( p_cmd)
1164     {
1165         /* ask the thread to process the Flush command */
1166         p_cmd->in.flush.b_wait = b_wait;
1167
1168         ThreadCmd_InsertHead( p_sys, p_cmd );
1169         ThreadCmd_Wait( p_sys, p_cmd );
1170
1171         free( p_cmd );
1172     }
1173
1174     vlc_mutex_unlock( &p_sys->mutex );
1175 }
1176
1177 static int
1178 TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
1179 {
1180     aout_sys_t *p_sys = p_aout->sys;
1181     struct thread_cmd *p_cmd;
1182     int i_ret = -1;
1183
1184     vlc_mutex_lock( &p_sys->mutex );
1185
1186     p_cmd = ThreadCmd_New( CMD_TIME_GET );
1187     if( p_cmd)
1188     {
1189         ThreadCmd_InsertHead( p_sys, p_cmd );
1190         ThreadCmd_Wait( p_sys, p_cmd );
1191
1192         i_ret = p_cmd->out.time_get.i_ret;
1193         *p_delay = p_cmd->out.time_get.i_delay;
1194         free( p_cmd );
1195     }
1196
1197     vlc_mutex_unlock( &p_sys->mutex );
1198
1199     return i_ret;
1200 }
1201
1202
1203 static int
1204 Open( vlc_object_t *obj )
1205 {
1206     audio_output_t *p_aout = (audio_output_t *) obj;
1207     aout_sys_t *p_sys;
1208
1209     if( !InitJNIFields( p_aout ) )
1210         return VLC_EGENERIC;
1211
1212     p_sys = calloc( 1, sizeof (aout_sys_t) );
1213
1214     if( unlikely( p_sys == NULL ) )
1215         return VLC_ENOMEM;
1216
1217     vlc_mutex_init( &p_sys->mutex );
1218     vlc_cond_init( &p_sys->cond );
1219     TAILQ_INIT( &p_sys->thread_cmd_queue );
1220
1221     p_aout->sys = p_sys;
1222     p_aout->start = Start;
1223     p_aout->stop = Stop;
1224     p_aout->play = Play;
1225     p_aout->pause = Pause;
1226     p_aout->flush = Flush;
1227     p_aout->time_get = TimeGet;
1228
1229     aout_SoftVolumeInit( p_aout );
1230
1231     /* create JNIThread */
1232     p_sys->b_thread_run = true;
1233     if( vlc_clone( &p_sys->thread,
1234                    JNIThread, p_aout, VLC_THREAD_PRIORITY_AUDIO ) )
1235     {
1236         msg_Err( p_aout, "JNIThread creation failed" );
1237         p_sys->b_thread_run = false;
1238         Close( obj );
1239         return VLC_EGENERIC;
1240     }
1241
1242     return VLC_SUCCESS;
1243 }
1244
1245 static void
1246 Close( vlc_object_t *obj )
1247 {
1248     audio_output_t *p_aout = (audio_output_t *) obj;
1249     aout_sys_t *p_sys = p_aout->sys;
1250
1251     /* kill the thread */
1252     vlc_mutex_lock( &p_sys->mutex );
1253     if( p_sys->b_thread_run )
1254     {
1255         p_sys->b_thread_run = false;
1256         vlc_cond_signal( &p_sys->cond );
1257         vlc_mutex_unlock( &p_sys->mutex );
1258         vlc_join( p_sys->thread, NULL );
1259     } else
1260         vlc_mutex_unlock( &p_sys->mutex );
1261
1262     vlc_mutex_destroy( &p_sys->mutex );
1263     vlc_cond_destroy( &p_sys->cond );
1264
1265     free( p_sys );
1266 }