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