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