]> git.sesse.net Git - vlc/blob - modules/audio_output/audiotrack.c
audiotrack: deactivate getTimestamp
[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     mtime_t i_current_time = mdate();
479
480     if( p_sys->i_samples_queued == 0 )
481         return -1;
482     if( p_sys->p_audioTimestamp )
483     {
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_wait = 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 && p_buffer == p_cmd->in.play.p_buffer
925             && i_play_wait > 0 )
926         {
927             int i_ret = 0;
928             mtime_t i_deadline = mdate() + i_play_wait;
929
930             while( p_cmd == TAILQ_FIRST( &p_sys->thread_cmd_queue )
931                    && i_ret != ETIMEDOUT && p_sys->b_thread_run )
932                 i_ret = vlc_cond_timedwait( &p_sys->cond, &p_sys->mutex,
933                                             i_deadline );
934             i_play_wait = 0;
935             continue;
936         }
937
938         /* process a command */
939         switch( p_cmd->id )
940         {
941             case CMD_START:
942                 assert( !p_sys->p_audiotrack );
943                 if( b_error ) {
944                     p_cmd->out.start.i_ret = -1;
945                     break;
946                 }
947                 p_sys->fmt = *p_cmd->in.start.p_fmt;
948                 p_cmd->out.start.i_ret =
949                         JNIThread_Start( env, p_aout );
950                 JNIThread_InitDelay( env, p_aout );
951                 p_cmd->out.start.p_fmt = &p_sys->fmt;
952                 b_paused = false;
953                 break;
954             case CMD_STOP:
955                 assert( p_sys->p_audiotrack );
956                 JNIThread_Stop( env, p_aout );
957                 JNIThread_InitDelay( env, p_aout );
958                 b_paused = false;
959                 b_error = false;
960                 p_buffer = NULL;
961                 break;
962             case CMD_PLAY:
963                 assert( p_sys->p_audiotrack );
964                 if( b_error )
965                     break;
966                 if( p_buffer == NULL )
967                     p_buffer = p_cmd->in.play.p_buffer;
968                 b_error = JNIThread_Play( env, p_aout, &p_buffer,
969                                           &i_play_wait ) != VLC_SUCCESS;
970                 if( p_buffer != NULL )
971                     b_remove_cmd = false;
972                 break;
973             case CMD_PAUSE:
974                 assert( p_sys->p_audiotrack );
975                 if( b_error )
976                     break;
977                 JNIThread_Pause( env, p_aout,
978                                  p_cmd->in.pause.b_pause,
979                                  p_cmd->in.pause.i_date );
980                 b_paused = p_cmd->in.pause.b_pause;
981                 break;
982             case CMD_TIME_GET:
983                 assert( p_sys->p_audiotrack );
984                 if( b_error )
985                     break;
986                 p_cmd->out.time_get.i_ret =
987                         JNIThread_TimeGet( env, p_aout,
988                                            &p_cmd->out.time_get.i_delay );
989                 break;
990             case CMD_FLUSH:
991                 assert( p_sys->p_audiotrack );
992                 if( b_error )
993                     break;
994                 JNIThread_Flush( env, p_aout,
995                                  p_cmd->in.flush.b_wait );
996                 JNIThread_InitDelay( env, p_aout );
997                 p_buffer = NULL;
998                 break;
999             default:
1000                 vlc_assert_unreachable();
1001         }
1002         if( p_sys->b_audiotrack_exception )
1003             b_error = true;
1004
1005         if( b_remove_cmd )
1006         {
1007             TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
1008             p_cmd->id = CMD_DONE;
1009             if( p_cmd->pf_destroy )
1010                 p_cmd->pf_destroy( p_cmd );
1011         }
1012
1013         /* signal that command is processed */
1014         vlc_cond_signal( &p_sys->cond );
1015     }
1016 end:
1017     if( env )
1018     {
1019         if( p_sys->p_bytearray )
1020             (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
1021         if( p_sys->p_bytebuffer )
1022             (*env)->DeleteGlobalRef( env, p_sys->p_bytebuffer );
1023         jni_detach_thread();
1024     }
1025     vlc_mutex_unlock( &p_sys->mutex );
1026     return NULL;
1027 }
1028
1029 static int
1030 Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
1031 {
1032     int i_ret = VLC_EGENERIC;
1033     struct thread_cmd *p_cmd;
1034     aout_sys_t *p_sys = p_aout->sys;
1035
1036     vlc_mutex_lock( &p_sys->mutex );
1037
1038     p_cmd = ThreadCmd_New( CMD_START );
1039     if( p_cmd )
1040     {
1041         /* ask the thread to process the Start command */
1042         p_cmd->in.start.p_fmt = p_fmt;
1043
1044         ThreadCmd_InsertHead( p_sys, p_cmd );
1045         if( ThreadCmd_Wait( p_sys, p_cmd ) )
1046         {
1047             i_ret = p_cmd->out.start.i_ret;
1048             if( i_ret == VLC_SUCCESS )
1049                 *p_fmt = *p_cmd->out.start.p_fmt;
1050         }
1051         free( p_cmd );
1052     }
1053
1054     vlc_mutex_unlock( &p_sys->mutex );
1055
1056     if( i_ret == VLC_SUCCESS )
1057         aout_SoftVolumeStart( p_aout );
1058
1059     return i_ret;
1060 }
1061
1062 static void
1063 Stop( audio_output_t *p_aout )
1064 {
1065     aout_sys_t *p_sys = p_aout->sys;
1066     struct thread_cmd *p_cmd;
1067
1068     vlc_mutex_lock( &p_sys->mutex );
1069
1070     ThreadCmd_FlushQueue( p_sys );
1071
1072     p_cmd = ThreadCmd_New( CMD_STOP );
1073     if( p_cmd )
1074     {
1075         /* ask the thread to process the Stop command */
1076         ThreadCmd_InsertHead( p_sys, p_cmd );
1077         ThreadCmd_Wait( p_sys, p_cmd );
1078
1079         free( p_cmd );
1080     }
1081
1082     vlc_mutex_unlock( &p_sys->mutex );
1083 }
1084
1085 static void
1086 PlayCmd_Destroy( struct thread_cmd *p_cmd )
1087 {
1088     block_Release( p_cmd->in.play.p_buffer );
1089     free( p_cmd );
1090 }
1091
1092 static void
1093 Play( audio_output_t *p_aout, block_t *p_buffer )
1094 {
1095     aout_sys_t *p_sys = p_aout->sys;
1096     struct thread_cmd *p_cmd;
1097
1098     vlc_mutex_lock( &p_sys->mutex );
1099
1100     while( p_sys->i_samples_queued != 0
1101            && FRAMES_TO_US( p_sys->i_samples_queued +
1102                             p_buffer->i_nb_samples ) >= MAX_QUEUE_US )
1103         vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
1104
1105     p_cmd = ThreadCmd_New( CMD_PLAY );
1106     if( p_cmd )
1107     {
1108         /* ask the thread to process the Play command */
1109         p_cmd->in.play.p_buffer = p_buffer;
1110         p_cmd->pf_destroy = PlayCmd_Destroy;
1111
1112         ThreadCmd_InsertTail( p_sys, p_cmd );
1113
1114         p_sys->i_samples_queued += p_buffer->i_nb_samples;
1115     } else
1116          block_Release( p_cmd->in.play.p_buffer );
1117
1118     vlc_mutex_unlock( &p_sys->mutex );
1119 }
1120
1121 static void
1122 Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
1123 {
1124     aout_sys_t *p_sys = p_aout->sys;
1125     struct thread_cmd *p_cmd;
1126
1127     vlc_mutex_lock( &p_sys->mutex );
1128
1129     p_cmd = ThreadCmd_New( CMD_PAUSE );
1130     if( p_cmd )
1131     {
1132         /* ask the thread to process the Pause command */
1133         p_cmd->in.pause.b_pause = b_pause;
1134         p_cmd->in.pause.i_date = i_date;
1135
1136         ThreadCmd_InsertHead( p_sys, p_cmd );
1137         ThreadCmd_Wait( p_sys, p_cmd );
1138
1139         free( p_cmd );
1140     }
1141
1142     vlc_mutex_unlock( &p_sys->mutex );
1143 }
1144
1145 static void
1146 Flush( audio_output_t *p_aout, bool b_wait )
1147 {
1148     aout_sys_t *p_sys = p_aout->sys;
1149     struct thread_cmd *p_cmd;
1150
1151     vlc_mutex_lock( &p_sys->mutex );
1152
1153     ThreadCmd_FlushQueue( p_sys );
1154
1155     p_cmd = ThreadCmd_New( CMD_FLUSH );
1156     if( p_cmd)
1157     {
1158         /* ask the thread to process the Flush command */
1159         p_cmd->in.flush.b_wait = b_wait;
1160
1161         ThreadCmd_InsertHead( p_sys, p_cmd );
1162         ThreadCmd_Wait( p_sys, p_cmd );
1163
1164         free( p_cmd );
1165     }
1166
1167     vlc_mutex_unlock( &p_sys->mutex );
1168 }
1169
1170 static int
1171 TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
1172 {
1173     aout_sys_t *p_sys = p_aout->sys;
1174     struct thread_cmd *p_cmd;
1175     int i_ret = -1;
1176
1177     vlc_mutex_lock( &p_sys->mutex );
1178
1179     p_cmd = ThreadCmd_New( CMD_TIME_GET );
1180     if( p_cmd)
1181     {
1182         ThreadCmd_InsertHead( p_sys, p_cmd );
1183         ThreadCmd_Wait( p_sys, p_cmd );
1184
1185         i_ret = p_cmd->out.time_get.i_ret;
1186         *p_delay = p_cmd->out.time_get.i_delay;
1187         free( p_cmd );
1188     }
1189
1190     vlc_mutex_unlock( &p_sys->mutex );
1191
1192     return i_ret;
1193 }
1194
1195
1196 static int
1197 Open( vlc_object_t *obj )
1198 {
1199     audio_output_t *p_aout = (audio_output_t *) obj;
1200     aout_sys_t *p_sys;
1201
1202     if( !InitJNIFields( p_aout ) )
1203         return VLC_EGENERIC;
1204
1205     p_sys = calloc( 1, sizeof (aout_sys_t) );
1206
1207     if( unlikely( p_sys == NULL ) )
1208         return VLC_ENOMEM;
1209
1210     vlc_mutex_init( &p_sys->mutex );
1211     vlc_cond_init( &p_sys->cond );
1212     TAILQ_INIT( &p_sys->thread_cmd_queue );
1213
1214     /* create JNIThread */
1215     p_sys->b_thread_run = true;
1216     if( vlc_clone( &p_sys->thread,
1217                    JNIThread, p_aout, VLC_THREAD_PRIORITY_AUDIO ) )
1218     {
1219         msg_Err( p_aout, "JNIThread creation failed" );
1220         p_sys->b_thread_run = false;
1221         Close( obj );
1222         return VLC_EGENERIC;
1223     }
1224
1225     p_aout->sys = p_sys;
1226     p_aout->start = Start;
1227     p_aout->stop = Stop;
1228     p_aout->play = Play;
1229     p_aout->pause = Pause;
1230     p_aout->flush = Flush;
1231     p_aout->time_get = TimeGet;
1232
1233     aout_SoftVolumeInit( p_aout );
1234
1235     return VLC_SUCCESS;
1236 }
1237
1238 static void
1239 Close( vlc_object_t *obj )
1240 {
1241     audio_output_t *p_aout = (audio_output_t *) obj;
1242     aout_sys_t *p_sys = p_aout->sys;
1243
1244     /* kill the thread */
1245     vlc_mutex_lock( &p_sys->mutex );
1246     if( p_sys->b_thread_run )
1247     {
1248         p_sys->b_thread_run = false;
1249         vlc_cond_signal( &p_sys->cond );
1250         vlc_mutex_unlock( &p_sys->mutex );
1251         vlc_join( p_sys->thread, NULL );
1252     } else
1253         vlc_mutex_unlock( &p_sys->mutex );
1254
1255     vlc_mutex_destroy( &p_sys->mutex );
1256     vlc_cond_destroy( &p_sys->cond );
1257
1258     free( p_sys );
1259 }