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