1 /*****************************************************************************
2 * audiotrack.c: Android Java AudioTrack audio output module
3 *****************************************************************************
4 * Copyright © 2012-2015 VLC authors and VideoLAN, VideoLabs
6 * Authors: Thomas Guillem <thomas@gllm.fr>
7 * Ming Hu <tewilove@gmail.com>
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.
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.
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 *****************************************************************************/
32 #include <sys/queue.h>
34 #include <vlc_atomic.h>
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
38 #include <vlc_threads.h>
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
44 static int Open( vlc_object_t * );
45 static void Close( vlc_object_t * );
48 typedef TAILQ_HEAD(, thread_cmd) THREAD_CMD_QUEUE;
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 */
66 /* JNIThread control */
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 */
78 /* Soft volume helper */
79 #include "audio_output/volume.h"
81 //#define AUDIOTRACK_USE_FLOAT
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 )
90 add_shortcut( "audiotrack" )
91 set_callbacks( Open, Close )
96 TAILQ_ENTRY(thread_cmd) next;
107 audio_sample_format_t *p_fmt;
123 audio_sample_format_t *p_fmt;
126 void ( *pf_destroy )( struct thread_cmd * );
129 #define THREAD_NAME "android_audiotrack"
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);
147 jmethodID getPlaybackHeadPosition;
148 jmethodID getTimestamp;
149 jmethodID getMinBufferSize;
150 jint STATE_INITIALIZED;
153 jint ERROR_BAD_VALUE;
154 jint ERROR_INVALID_OPERATION;
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;
165 jint ERROR_DEAD_OBJECT;
166 bool has_ERROR_DEAD_OBJECT;
172 jfieldID framePosition;
177 /* init all jni fields.
178 * Done only one time during the first initialisation */
180 InitJNIFields( audio_output_t *p_aout )
182 static vlc_mutex_t lock = VLC_STATIC_MUTEX;
183 static int i_init_state = -1;
184 bool ret, b_attached = false;
189 vlc_mutex_lock( &lock );
191 if( i_init_state != -1 )
194 if( jni_get_env(&env) < 0 )
196 jni_attach_thread( &env, THREAD_NAME );
205 #define CHECK_EXCEPTION( what, critical ) do { \
206 if( (*env)->ExceptionOccurred( env ) ) \
208 msg_Err( p_aout, "%s failed", what ); \
209 (*env)->ExceptionClear( env ); \
217 #define GET_CLASS( str, critical ) do { \
218 clazz = (*env)->FindClass( env, (str) ); \
219 CHECK_EXCEPTION( str, critical ); \
221 #define GET_ID( get, id, str, args, critical ) do { \
222 jfields.id = (*env)->get( env, clazz, (str), (args) ); \
223 CHECK_EXCEPTION( #get, critical ); \
225 #define GET_CONST_INT( id, str, critical ) do { \
227 field = (*env)->GetStaticFieldID( env, clazz, (str), "I" ); \
228 CHECK_EXCEPTION( #id, critical ); \
231 jfields.id = (*env)->GetStaticIntField( env, clazz, field ); \
232 CHECK_EXCEPTION( #id, critical ); \
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 );
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 );
250 GET_ID( GetMethodID, AudioTrack.getTimestamp,
251 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
252 GET_ID( GetMethodID, AudioTrack.getPlaybackHeadPosition,
253 "getPlaybackHeadPosition", "()I", true );
255 GET_ID( GetStaticMethodID, AudioTrack.getMinBufferSize, "getMinBufferSize",
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 );
264 /* AudioTimestamp class init (if any) */
265 if( jfields.AudioTrack.getTimestamp )
267 GET_CLASS( "android/media/AudioTimestamp", true );
268 jfields.AudioTimestamp.clazz = (jclass) (*env)->NewGlobalRef( env,
270 CHECK_EXCEPTION( "NewGlobalRef", true );
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 );
279 jfields.AudioTimestamp.clazz = NULL;
280 jfields.AudioTimestamp.ctor = NULL;
281 jfields.AudioTimestamp.framePosition = NULL;
282 jfields.AudioTimestamp.nanoTime = NULL;
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",
292 jfields.AudioFormat.has_ENCODING_PCM_FLOAT = field != NULL;
294 jfields.AudioFormat.has_ENCODING_PCM_FLOAT = false;
296 GET_CONST_INT( AudioFormat.CHANNEL_OUT_MONO, "CHANNEL_OUT_MONO", true );
297 GET_CONST_INT( AudioFormat.CHANNEL_OUT_STEREO, "CHANNEL_OUT_STEREO", true );
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 );
305 #undef CHECK_EXCEPTION
312 ret = i_init_state == 1;
314 msg_Err( p_aout, "AudioTrack jni init failed" );
317 vlc_mutex_unlock( &lock );
322 check_exception( JNIEnv *env, audio_output_t *p_aout,
325 if( (*env)->ExceptionOccurred( env ) )
327 aout_sys_t *p_sys = p_aout->sys;
329 p_sys->b_audiotrack_exception = true;
330 (*env)->ExceptionClear( env );
331 msg_Err( p_aout, "AudioTrack.%s triggered an exception !", method );
336 #define CHECK_AT_EXCEPTION( method ) check_exception( env, p_aout, method )
338 #define JNI_CALL( what, obj, method, ... ) (*env)->what( env, obj, method, ##__VA_ARGS__ )
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__ )
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__ )
351 #define JNI_AUDIOTIMESTAMP_GET_LONG( field ) JNI_CALL( GetLongField, p_sys->p_audioTimestamp, jfields.AudioTimestamp.field )
353 static inline mtime_t
354 frames_to_us( aout_sys_t *p_sys, uint32_t i_nb_frames )
356 return i_nb_frames * CLOCK_FREQ / p_sys->fmt.i_rate;
358 #define FRAMES_TO_US(x) frames_to_us( p_sys, (x) )
360 static struct thread_cmd *
361 ThreadCmd_New( int id )
363 struct thread_cmd *p_cmd = calloc( 1, sizeof(struct thread_cmd) );
372 ThreadCmd_InsertHead( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
374 TAILQ_INSERT_HEAD( &p_sys->thread_cmd_queue, p_cmd, next);
375 vlc_cond_signal( &p_sys->cond );
379 ThreadCmd_InsertTail( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
381 TAILQ_INSERT_TAIL( &p_sys->thread_cmd_queue, p_cmd, next);
382 vlc_cond_signal( &p_sys->cond );
386 ThreadCmd_Wait( aout_sys_t *p_sys, struct thread_cmd *p_cmd )
388 while( p_cmd->id != CMD_DONE )
389 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
391 return p_cmd->id == CMD_DONE;
395 ThreadCmd_FlushQueue( aout_sys_t *p_sys )
397 struct thread_cmd *p_cmd, *p_cmd_next;
399 for ( p_cmd = TAILQ_FIRST( &p_sys->thread_cmd_queue );
400 p_cmd != NULL; p_cmd = p_cmd_next )
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 );
410 JNIThread_InitDelay( JNIEnv *env, audio_output_t *p_aout, uint32_t *p_delay )
412 aout_sys_t *p_sys = p_aout->sys;
414 if( p_sys->p_audiotrack )
415 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
417 p_sys->i_pos_initial = 0;
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 ) )
425 i_last_pos = p_sys->i_pos_initial;
427 p_sys->i_pos_initial = JNI_AT_CALL_INT( getPlaybackHeadPosition );
428 } while( p_sys->i_pos_initial != i_last_pos );
430 p_sys->i_samples_written = 0;
435 JNIThread_SetDelay( JNIEnv *env, audio_output_t *p_aout, uint32_t *p_delay )
437 aout_sys_t *p_sys = p_aout->sys;
438 bool b_frame_delay_set = false;
440 mtime_t i_current_time = mdate();
442 if( p_sys->p_audioTimestamp )
445 * getTimestamp: Poll for a timestamp on demand.
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.
460 if( JNI_AT_CALL_BOOL( getTimestamp, p_sys->p_audioTimestamp ) )
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) )
470 jlong i_time_diff = i_current_time - i_frame_time;
471 jlong i_frames_diff = i_time_diff * p_sys->fmt.i_rate
473 i_frame_pos = JNI_AUDIOTIMESTAMP_GET_LONG( framePosition )
475 b_frame_delay_set = true;
479 if( !b_frame_delay_set )
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().
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;
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;
502 JNIThread_Start( JNIEnv *env, audio_output_t *p_aout )
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;
509 /* 4000 <= frequency <= 48000 */
510 i_rate = p_sys->fmt.i_rate;
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;
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;
526 if( p_sys->fmt.i_format == VLC_CODEC_S16N )
528 i_format = jfields.AudioFormat.ENCODING_PCM_16BIT;
530 } else if( p_sys->fmt.i_format == VLC_CODEC_FL32 )
532 i_format = jfields.AudioFormat.ENCODING_PCM_FLOAT;
536 i_format = jfields.AudioFormat.ENCODING_PCM_8BIT;
539 p_sys->fmt.i_original_channels = p_sys->fmt.i_physical_channels;
541 i_nb_channels = aout_FormatNbChannels( &p_sys->fmt );
542 switch( i_nb_channels )
545 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_MONO;
546 p_sys->fmt.i_physical_channels = AOUT_CHAN_CENTER;
549 i_nb_channels = 2; // XXX: AudioTrack handle only stereo for now
551 i_channel_config = jfields.AudioFormat.CHANNEL_OUT_STEREO;
552 p_sys->fmt.i_physical_channels = AOUT_CHANS_STEREO;
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 )
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;
565 i_size = i_min_buffer_size * 2; // double buffering
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 )
573 p_sys->p_audiotrack = (*env)->NewGlobalRef( env, p_audiotrack );
574 (*env)->DeleteLocalRef( env, p_audiotrack );
575 if( !p_sys->p_audiotrack )
577 if( JNI_AT_CALL_INT( getState ) != jfields.AudioTrack.STATE_INITIALIZED )
579 msg_Err( p_aout, "AudioTrack init failed" );
583 if( jfields.AudioTimestamp.clazz )
585 /* create AudioTimestamp object */
586 jobject p_audioTimestamp = JNI_CALL( NewObject,
587 jfields.AudioTimestamp.clazz,
588 jfields.AudioTimestamp.ctor );
589 if( !p_audioTimestamp )
591 p_sys->p_audioTimestamp = (*env)->NewGlobalRef( env, p_audioTimestamp );
592 (*env)->DeleteLocalRef( env, p_audioTimestamp );
593 if( !p_sys->p_audioTimestamp )
597 p_sys->fmt.i_rate = i_rate;
599 JNI_AT_CALL_VOID( play );
600 CHECK_AT_EXCEPTION( "play" );
601 p_sys->i_play_time = mdate();
605 if( p_sys->p_audiotrack )
607 JNI_AT_CALL_VOID( release );
608 (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
609 p_sys->p_audiotrack = NULL;
615 JNIThread_Stop( JNIEnv *env, audio_output_t *p_aout )
617 aout_sys_t *p_sys = p_aout->sys;
619 if( !p_sys->b_audiotrack_exception )
621 JNI_AT_CALL_VOID( stop );
622 if( !CHECK_AT_EXCEPTION( "stop" ) )
623 JNI_AT_CALL_VOID( release );
625 p_sys->b_audiotrack_exception = false;
626 (*env)->DeleteGlobalRef( env, p_sys->p_audiotrack );
627 p_sys->p_audiotrack = NULL;
629 if( p_sys->p_audioTimestamp )
631 (*env)->DeleteGlobalRef( env, p_sys->p_audioTimestamp );
632 p_sys->p_audioTimestamp = NULL;
637 JNIThread_Play( JNIEnv *env, audio_output_t *p_aout,
640 aout_sys_t *p_sys = p_aout->sys;
643 /* check if we need to realloc a ByteArray */
644 if( p_buffer->i_buffer > p_sys->i_bytearray_size )
646 jbyteArray p_bytearray;
648 if( p_sys->p_bytearray )
650 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
651 p_sys->p_bytearray = NULL;
654 p_bytearray = (*env)->NewByteArray( env, p_buffer->i_buffer );
657 p_sys->p_bytearray = (*env)->NewGlobalRef( env, p_bytearray );
658 (*env)->DeleteLocalRef( env, p_bytearray );
660 p_sys->i_bytearray_size = p_buffer->i_buffer;
662 if( !p_sys->p_bytearray )
665 /* copy p_buffer in to ByteArray */
666 (*env)->SetByteArrayRegion( env, p_sys->p_bytearray, 0,
668 (jbyte *)p_buffer->p_buffer);
670 while ( p_buffer->i_buffer > (unsigned int) i_offset )
674 /* write ByteArray */
675 i_ret = JNI_AT_CALL_INT( write, p_sys->p_bytearray, i_offset,
676 p_buffer->i_buffer - i_offset);
678 if( jfields.AudioManager.has_ERROR_DEAD_OBJECT
679 && i_ret == jfields.AudioManager.ERROR_DEAD_OBJECT )
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 )
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";
696 msg_Err( p_aout, "Write failed: %s", str );
703 p_sys->i_samples_written += p_buffer->i_nb_samples;
708 JNIThread_Pause( JNIEnv *env, audio_output_t *p_aout,
709 bool b_pause, mtime_t i_date )
711 VLC_UNUSED( i_date );
713 aout_sys_t *p_sys = p_aout->sys;
717 JNI_AT_CALL_VOID( pause );
718 CHECK_AT_EXCEPTION( "pause" );
721 JNI_AT_CALL_VOID( play );
722 CHECK_AT_EXCEPTION( "play" );
723 p_sys->i_play_time = mdate();
728 JNIThread_Flush( JNIEnv *env, audio_output_t *p_aout,
731 aout_sys_t *p_sys = p_aout->sys;
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
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.
746 JNI_AT_CALL_VOID( stop );
747 if( CHECK_AT_EXCEPTION( "stop" ) )
751 JNI_AT_CALL_VOID( pause );
752 if( CHECK_AT_EXCEPTION( "pause" ) )
754 JNI_AT_CALL_VOID( flush );
756 JNI_AT_CALL_VOID( play );
757 CHECK_AT_EXCEPTION( "play" );
758 p_sys->i_play_time = mdate();
762 JNIThread( void *data )
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;
771 jni_attach_thread( &env, THREAD_NAME );
773 vlc_mutex_lock( &p_sys->mutex );
777 while( p_sys->b_thread_run )
779 struct thread_cmd *p_cmd;
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 );
786 if( !p_sys->b_thread_run || p_cmd == NULL )
789 if( b_paused && p_cmd->id == CMD_PLAY )
791 vlc_cond_wait( &p_sys->cond, &p_sys->mutex );
795 TAILQ_REMOVE( &p_sys->thread_cmd_queue, p_cmd, next );
797 if( p_cmd->id == CMD_PLAY )
799 p_sys->i_samples_queued -= p_cmd->in.play.p_buffer->i_nb_samples;
800 vlc_cond_signal( &p_sys->cond );
803 vlc_mutex_unlock( &p_sys->mutex );
804 /* process a command */
808 assert( !p_sys->p_audiotrack );
810 p_cmd->out.start.i_ret = -1;
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;
821 assert( p_sys->p_audiotrack );
822 JNIThread_Stop( env, p_aout );
823 JNIThread_InitDelay( env, p_aout, &i_audiotrack_delay );
828 assert( p_sys->p_audiotrack );
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 );
836 assert( p_sys->p_audiotrack );
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;
845 assert( p_sys->p_audiotrack );
848 JNIThread_Flush( env, p_aout,
849 p_cmd->in.flush.b_wait );
850 JNIThread_InitDelay( env, p_aout, &i_audiotrack_delay );
853 vlc_assert_unreachable();
855 if( p_sys->b_audiotrack_exception )
858 vlc_mutex_lock( &p_sys->mutex );
860 p_sys->i_audiotrack_delay = i_audiotrack_delay;
862 p_cmd->id = CMD_DONE;
863 if( p_cmd->pf_destroy )
864 p_cmd->pf_destroy( p_cmd );
866 /* signal that command is processed */
867 vlc_cond_signal( &p_sys->cond );
872 if( p_sys->p_bytearray )
873 (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
876 vlc_mutex_unlock( &p_sys->mutex );
881 Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
883 int i_ret = VLC_EGENERIC;
884 struct thread_cmd *p_cmd;
885 aout_sys_t *p_sys = p_aout->sys;
887 vlc_mutex_lock( &p_sys->mutex );
889 p_cmd = ThreadCmd_New( CMD_START );
892 /* ask the thread to process the Start command */
893 p_cmd->in.start.p_fmt = p_fmt;
895 ThreadCmd_InsertHead( p_sys, p_cmd );
896 if( ThreadCmd_Wait( p_sys, p_cmd ) )
898 i_ret = p_cmd->out.start.i_ret;
899 if( i_ret == VLC_SUCCESS )
900 *p_fmt = *p_cmd->out.start.p_fmt;
905 vlc_mutex_unlock( &p_sys->mutex );
907 if( i_ret == VLC_SUCCESS )
908 aout_SoftVolumeStart( p_aout );
914 Stop( audio_output_t *p_aout )
916 aout_sys_t *p_sys = p_aout->sys;
917 struct thread_cmd *p_cmd;
919 vlc_mutex_lock( &p_sys->mutex );
921 p_sys->i_samples_queued = 0;
922 ThreadCmd_FlushQueue( p_sys );
924 p_cmd = ThreadCmd_New( CMD_STOP );
927 /* ask the thread to process the Stop command */
928 ThreadCmd_InsertHead( p_sys, p_cmd );
929 ThreadCmd_Wait( p_sys, p_cmd );
934 vlc_mutex_unlock( &p_sys->mutex );
938 PlayCmd_Destroy( struct thread_cmd *p_cmd )
940 block_Release( p_cmd->in.play.p_buffer );
945 Play( audio_output_t *p_aout, block_t *p_buffer )
947 aout_sys_t *p_sys = p_aout->sys;
948 struct thread_cmd *p_cmd;
950 vlc_mutex_lock( &p_sys->mutex );
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 );
957 p_cmd = ThreadCmd_New( CMD_PLAY );
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;
964 ThreadCmd_InsertTail( p_sys, p_cmd );
966 p_sys->i_samples_queued += p_buffer->i_nb_samples;
968 block_Release( p_cmd->in.play.p_buffer );
970 vlc_mutex_unlock( &p_sys->mutex );
974 Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
976 aout_sys_t *p_sys = p_aout->sys;
977 struct thread_cmd *p_cmd;
979 vlc_mutex_lock( &p_sys->mutex );
981 p_cmd = ThreadCmd_New( CMD_PAUSE );
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;
988 ThreadCmd_InsertHead( p_sys, p_cmd );
989 ThreadCmd_Wait( p_sys, p_cmd );
994 vlc_mutex_unlock( &p_sys->mutex );
998 Flush( audio_output_t *p_aout, bool b_wait )
1000 aout_sys_t *p_sys = p_aout->sys;
1001 struct thread_cmd *p_cmd;
1003 vlc_mutex_lock( &p_sys->mutex );
1005 p_sys->i_samples_queued = 0;
1006 ThreadCmd_FlushQueue( p_sys );
1008 p_cmd = ThreadCmd_New( CMD_FLUSH );
1011 /* ask the thread to process the Flush command */
1012 p_cmd->in.flush.b_wait = b_wait;
1014 ThreadCmd_InsertHead( p_sys, p_cmd );
1015 ThreadCmd_Wait( p_sys, p_cmd );
1020 vlc_mutex_unlock( &p_sys->mutex );
1024 TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
1026 aout_sys_t *p_sys = p_aout->sys;
1029 vlc_mutex_lock( &p_sys->mutex );
1030 if( p_sys->i_samples_queued != 0 )
1032 *p_delay = FRAMES_TO_US( p_sys->i_samples_queued +
1033 p_sys->i_audiotrack_delay );
1037 vlc_mutex_unlock( &p_sys->mutex );
1044 Open( vlc_object_t *obj )
1046 audio_output_t *p_aout = (audio_output_t *) obj;
1049 if( !InitJNIFields( p_aout ) )
1050 return VLC_EGENERIC;
1052 p_sys = calloc( 1, sizeof (aout_sys_t) );
1054 if( unlikely( p_sys == NULL ) )
1057 vlc_mutex_init( &p_sys->mutex );
1058 vlc_cond_init( &p_sys->cond );
1059 TAILQ_INIT( &p_sys->thread_cmd_queue );
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 ) )
1066 msg_Err( p_aout, "JNIThread creation failed" );
1067 p_sys->b_thread_run = false;
1069 return VLC_EGENERIC;
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;
1080 aout_SoftVolumeInit( p_aout );
1086 Close( vlc_object_t *obj )
1088 audio_output_t *p_aout = (audio_output_t *) obj;
1089 aout_sys_t *p_sys = p_aout->sys;
1091 /* kill the thread */
1092 vlc_mutex_lock( &p_sys->mutex );
1093 if( p_sys->b_thread_run )
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 );
1100 vlc_mutex_unlock( &p_sys->mutex );
1102 vlc_mutex_destroy( &p_sys->mutex );
1103 vlc_cond_destroy( &p_sys->cond );