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 *****************************************************************************/
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
36 #include "../video_output/android/utils.h"
38 #define SMOOTHPOS_SAMPLE_COUNT 10
39 #define SMOOTHPOS_INTERVAL_US INT64_C(30000) // 30ms
41 #define AUDIOTIMESTAMP_INTERVAL_US VLC_TICK_FROM_MS(500) // 500ms
43 static int Open( vlc_object_t
* );
44 static void Close( vlc_object_t
* );
45 static void Stop( audio_output_t
* );
46 static int Start( audio_output_t
*, audio_sample_format_t
* );
47 static void *AudioTrack_Thread( void * );
49 /* There is an undefined behavior when configuring AudioTrack with SPDIF or
50 * more than 2 channels when there is no HDMI out. It may succeed and the
51 * Android ressampler will be used to downmix to stereo. It may fails cleanly,
52 * and this module will be able to recover and fallback to stereo. Finally, in
53 * some rare cases, it may crash during init or while ressampling. Because of
54 * the last case we don't try up to 8 channels and we use AT_DEV_STEREO device
61 #define AT_DEV_DEFAULT AT_DEV_STEREO
62 #define AT_DEV_MAX_CHANNELS 8
69 { "stereo", "Up to 2 channels (compat mode).", AT_DEV_STEREO
},
70 { "pcm", "Up to 8 channels.", AT_DEV_PCM
},
72 /* With "encoded", the module will try to play every audio codecs via
75 * With "encoded:ENCODING_FLAGS_MASK", the module will try to play only
76 * codecs specified by ENCODING_FLAGS_MASK. This extra value is a long long
77 * that contains binary-shifted AudioFormat.ENCODING_* values. */
78 { "encoded", "Up to 8 channels, passthrough if available.", AT_DEV_ENCODED
},
79 { NULL
, NULL
, AT_DEV_DEFAULT
},
90 jobject p_audiotrack
; /* AudioTrack ref */
92 audio_sample_format_t fmt
; /* fmt setup by Start */
101 /* Used by AudioTrack_getPlaybackHeadPosition */
103 uint32_t i_wrap_count
;
107 /* Used by AudioTrack_GetTimestampPositionUs */
109 jobject p_obj
; /* AudioTimestamp ref */
110 vlc_tick_t i_frame_us
;
112 vlc_tick_t i_play_time
; /* time when play was called */
113 vlc_tick_t i_last_time
;
116 /* Used by AudioTrack_GetSmoothPositionUs */
120 vlc_tick_t p_us
[SMOOTHPOS_SAMPLE_COUNT
];
122 vlc_tick_t i_last_time
;
123 vlc_tick_t i_latency_us
;
126 uint32_t i_max_audiotrack_samples
;
127 long long i_encoding_flags
;
129 uint8_t i_chans_to_reorder
; /* do we need channel reordering */
130 uint8_t p_chan_table
[AOUT_CHAN_MAX
];
140 vlc_thread_t thread
; /* AudioTrack_Thread */
142 vlc_cond_t aout_cond
; /* cond owned by aout */
143 vlc_cond_t thread_cond
; /* cond owned by AudioTrack_Thread */
145 /* These variables need locking on read and write */
146 bool b_thread_running
; /* Set to false by aout to stop the thread */
147 bool b_thread_paused
; /* If true, the thread won't process any data, see
149 bool b_thread_waiting
; /* If true, the thread is waiting for enough spaces
150 * in AudioTrack internal buffers */
152 uint64_t i_samples_written
; /* Number of samples written since last flush */
153 bool b_audiotrack_exception
; /* True if audiotrack threw an exception */
154 bool b_error
; /* generic error */
157 uint64_t i_read
; /* Number of bytes read */
158 uint64_t i_write
; /* Number of bytes written */
159 size_t i_size
; /* Size of the circular buffer in bytes */
161 jbyteArray p_bytearray
;
162 jfloatArray p_floatarray
;
163 jshortArray p_shortarray
;
172 /* Soft volume helper */
173 #include "audio_output/volume.h"
175 // Don't use Float for now since 5.1/7.1 Float is down sampled to Stereo Float
176 //#define AUDIOTRACK_USE_FLOAT
177 //#define AUDIOTRACK_HW_LATENCY
179 /* Get AudioTrack native sample rate: if activated, most of the resampling
180 * will be done by VLC */
181 #define AUDIOTRACK_NATIVE_SAMPLERATE
183 #define AUDIOTRACK_SESSION_ID_TEXT " Id of audio session the AudioTrack must be attached to"
186 set_shortname( "AudioTrack" )
187 set_description( "Android AudioTrack audio output" )
188 set_capability( "audio output", 180 )
189 set_category( CAT_AUDIO
)
190 set_subcategory( SUBCAT_AUDIO_AOUT
)
191 add_integer( "audiotrack-session-id", 0,
192 AUDIOTRACK_SESSION_ID_TEXT
, NULL
, true )
195 add_shortcut( "audiotrack" )
196 set_callbacks( Open
, Close
)
199 #define THREAD_NAME "android_audiotrack"
200 #define GET_ENV() android_getEnv( VLC_OBJECT(p_aout), THREAD_NAME )
215 jmethodID writeShortV23
;
216 jmethodID writeBufferV21
;
217 jmethodID writeFloat
;
218 jmethodID getPlaybackHeadPosition
;
219 jmethodID getTimestamp
;
220 jmethodID getMinBufferSize
;
221 jmethodID getNativeOutputSampleRate
;
222 jint STATE_INITIALIZED
;
225 jint ERROR_BAD_VALUE
;
226 jint ERROR_INVALID_OPERATION
;
227 jint WRITE_NON_BLOCKING
;
230 jint ENCODING_PCM_8BIT
;
231 jint ENCODING_PCM_16BIT
;
232 jint ENCODING_PCM_FLOAT
;
233 bool has_ENCODING_PCM_FLOAT
;
235 bool has_ENCODING_AC3
;
237 bool has_ENCODING_E_AC3
;
238 jint ENCODING_DOLBY_TRUEHD
;
239 bool has_ENCODING_DOLBY_TRUEHD
;
241 bool has_ENCODING_DTS
;
242 jint ENCODING_DTS_HD
;
243 bool has_ENCODING_DTS_HD
;
244 jint ENCODING_IEC61937
;
245 bool has_ENCODING_IEC61937
;
246 jint CHANNEL_OUT_MONO
;
247 jint CHANNEL_OUT_STEREO
;
248 jint CHANNEL_OUT_FRONT_LEFT
;
249 jint CHANNEL_OUT_FRONT_RIGHT
;
250 jint CHANNEL_OUT_BACK_LEFT
;
251 jint CHANNEL_OUT_BACK_RIGHT
;
252 jint CHANNEL_OUT_FRONT_CENTER
;
253 jint CHANNEL_OUT_LOW_FREQUENCY
;
254 jint CHANNEL_OUT_BACK_CENTER
;
255 jint CHANNEL_OUT_5POINT1
;
256 jint CHANNEL_OUT_SIDE_LEFT
;
257 jint CHANNEL_OUT_SIDE_RIGHT
;
258 bool has_CHANNEL_OUT_SIDE
;
261 jint ERROR_DEAD_OBJECT
;
262 bool has_ERROR_DEAD_OBJECT
;
267 jmethodID getOutputLatency
;
272 jfieldID framePosition
;
277 /* init all jni fields.
278 * Done only one time during the first initialisation */
280 InitJNIFields( audio_output_t
*p_aout
, JNIEnv
* env
)
282 static vlc_mutex_t lock
= VLC_STATIC_MUTEX
;
283 static int i_init_state
= -1;
288 vlc_mutex_lock( &lock
);
290 if( i_init_state
!= -1 )
293 #define CHECK_EXCEPTION( what, critical ) do { \
294 if( (*env)->ExceptionCheck( env ) ) \
296 msg_Err( p_aout, "%s failed", what ); \
297 (*env)->ExceptionClear( env ); \
305 #define GET_CLASS( str, critical ) do { \
306 clazz = (*env)->FindClass( env, (str) ); \
307 CHECK_EXCEPTION( "FindClass(" str ")", critical ); \
309 #define GET_ID( get, id, str, args, critical ) do { \
310 jfields.id = (*env)->get( env, clazz, (str), (args) ); \
311 CHECK_EXCEPTION( #get "(" #id ")", critical ); \
313 #define GET_CONST_INT( id, str, critical ) do { \
315 field = (*env)->GetStaticFieldID( env, clazz, (str), "I" ); \
316 CHECK_EXCEPTION( "GetStaticFieldID(" #id ")", critical ); \
319 jfields.id = (*env)->GetStaticIntField( env, clazz, field ); \
320 CHECK_EXCEPTION( #id, critical ); \
324 /* AudioTrack class init */
325 GET_CLASS( "android/media/AudioTrack", true );
326 jfields
.AudioTrack
.clazz
= (jclass
) (*env
)->NewGlobalRef( env
, clazz
);
327 CHECK_EXCEPTION( "NewGlobalRef", true );
329 GET_ID( GetMethodID
, AudioTrack
.ctor
, "<init>", "(IIIIIII)V", true );
330 GET_ID( GetMethodID
, AudioTrack
.release
, "release", "()V", true );
331 GET_ID( GetMethodID
, AudioTrack
.getState
, "getState", "()I", true );
332 GET_ID( GetMethodID
, AudioTrack
.play
, "play", "()V", true );
333 GET_ID( GetMethodID
, AudioTrack
.stop
, "stop", "()V", true );
334 GET_ID( GetMethodID
, AudioTrack
.flush
, "flush", "()V", true );
335 GET_ID( GetMethodID
, AudioTrack
.pause
, "pause", "()V", true );
337 GET_ID( GetMethodID
, AudioTrack
.writeV23
, "write", "([BIII)I", false );
338 GET_ID( GetMethodID
, AudioTrack
.writeShortV23
, "write", "([SIII)I", false );
339 if( !jfields
.AudioTrack
.writeV23
)
340 GET_ID( GetMethodID
, AudioTrack
.writeBufferV21
, "write", "(Ljava/nio/ByteBuffer;II)I", false );
342 if( jfields
.AudioTrack
.writeV23
|| jfields
.AudioTrack
.writeBufferV21
)
344 GET_CONST_INT( AudioTrack
.WRITE_NON_BLOCKING
, "WRITE_NON_BLOCKING", true );
345 #ifdef AUDIOTRACK_USE_FLOAT
346 GET_ID( GetMethodID
, AudioTrack
.writeFloat
, "write", "([FIII)I", true );
349 GET_ID( GetMethodID
, AudioTrack
.write
, "write", "([BII)I", true );
351 GET_ID( GetMethodID
, AudioTrack
.getTimestamp
,
352 "getTimestamp", "(Landroid/media/AudioTimestamp;)Z", false );
353 GET_ID( GetMethodID
, AudioTrack
.getPlaybackHeadPosition
,
354 "getPlaybackHeadPosition", "()I", true );
356 GET_ID( GetStaticMethodID
, AudioTrack
.getMinBufferSize
, "getMinBufferSize",
358 #ifdef AUDIOTRACK_NATIVE_SAMPLERATE
359 GET_ID( GetStaticMethodID
, AudioTrack
.getNativeOutputSampleRate
,
360 "getNativeOutputSampleRate", "(I)I", true );
362 GET_CONST_INT( AudioTrack
.STATE_INITIALIZED
, "STATE_INITIALIZED", true );
363 GET_CONST_INT( AudioTrack
.MODE_STREAM
, "MODE_STREAM", true );
364 GET_CONST_INT( AudioTrack
.ERROR
, "ERROR", true );
365 GET_CONST_INT( AudioTrack
.ERROR_BAD_VALUE
, "ERROR_BAD_VALUE", true );
366 GET_CONST_INT( AudioTrack
.ERROR_INVALID_OPERATION
,
367 "ERROR_INVALID_OPERATION", true );
369 /* AudioTimestamp class init (if any) */
370 if( jfields
.AudioTrack
.getTimestamp
)
372 GET_CLASS( "android/media/AudioTimestamp", true );
373 jfields
.AudioTimestamp
.clazz
= (jclass
) (*env
)->NewGlobalRef( env
,
375 CHECK_EXCEPTION( "NewGlobalRef", true );
377 GET_ID( GetMethodID
, AudioTimestamp
.ctor
, "<init>", "()V", true );
378 GET_ID( GetFieldID
, AudioTimestamp
.framePosition
,
379 "framePosition", "J", true );
380 GET_ID( GetFieldID
, AudioTimestamp
.nanoTime
,
381 "nanoTime", "J", true );
384 #ifdef AUDIOTRACK_HW_LATENCY
385 /* AudioSystem class init */
386 GET_CLASS( "android/media/AudioSystem", false );
389 jfields
.AudioSystem
.clazz
= (jclass
) (*env
)->NewGlobalRef( env
, clazz
);
390 GET_ID( GetStaticMethodID
, AudioSystem
.getOutputLatency
,
391 "getOutputLatency", "(I)I", false );
395 /* AudioFormat class init */
396 GET_CLASS( "android/media/AudioFormat", true );
397 GET_CONST_INT( AudioFormat
.ENCODING_PCM_8BIT
, "ENCODING_PCM_8BIT", true );
398 GET_CONST_INT( AudioFormat
.ENCODING_PCM_16BIT
, "ENCODING_PCM_16BIT", true );
399 #ifdef AUDIOTRACK_USE_FLOAT
400 GET_CONST_INT( AudioFormat
.ENCODING_PCM_FLOAT
, "ENCODING_PCM_FLOAT",
402 jfields
.AudioFormat
.has_ENCODING_PCM_FLOAT
= field
!= NULL
&&
403 jfields
.AudioTrack
.writeFloat
;
405 jfields
.AudioFormat
.has_ENCODING_PCM_FLOAT
= false;
408 if( jfields
.AudioTrack
.writeShortV23
)
410 GET_CONST_INT( AudioFormat
.ENCODING_IEC61937
, "ENCODING_IEC61937", false );
411 jfields
.AudioFormat
.has_ENCODING_IEC61937
= field
!= NULL
;
414 jfields
.AudioFormat
.has_ENCODING_IEC61937
= false;
416 GET_CONST_INT( AudioFormat
.ENCODING_AC3
, "ENCODING_AC3", false );
417 jfields
.AudioFormat
.has_ENCODING_AC3
= field
!= NULL
;
418 GET_CONST_INT( AudioFormat
.ENCODING_E_AC3
, "ENCODING_E_AC3", false );
419 jfields
.AudioFormat
.has_ENCODING_E_AC3
= field
!= NULL
;
421 GET_CONST_INT( AudioFormat
.ENCODING_DTS
, "ENCODING_DTS", false );
422 jfields
.AudioFormat
.has_ENCODING_DTS
= field
!= NULL
;
423 GET_CONST_INT( AudioFormat
.ENCODING_DTS_HD
, "ENCODING_DTS_HD", false );
424 jfields
.AudioFormat
.has_ENCODING_DTS_HD
= field
!= NULL
;
426 GET_CONST_INT( AudioFormat
.ENCODING_DOLBY_TRUEHD
, "ENCODING_DOLBY_TRUEHD",
428 jfields
.AudioFormat
.has_ENCODING_DOLBY_TRUEHD
= field
!= NULL
;
430 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_MONO
, "CHANNEL_OUT_MONO", true );
431 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_STEREO
, "CHANNEL_OUT_STEREO", true );
432 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_FRONT_LEFT
, "CHANNEL_OUT_FRONT_LEFT", true );
433 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_FRONT_RIGHT
, "CHANNEL_OUT_FRONT_RIGHT", true );
434 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_5POINT1
, "CHANNEL_OUT_5POINT1", true );
435 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_BACK_LEFT
, "CHANNEL_OUT_BACK_LEFT", true );
436 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_BACK_RIGHT
, "CHANNEL_OUT_BACK_RIGHT", true );
437 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_FRONT_CENTER
, "CHANNEL_OUT_FRONT_CENTER", true );
438 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_LOW_FREQUENCY
, "CHANNEL_OUT_LOW_FREQUENCY", true );
439 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_BACK_CENTER
, "CHANNEL_OUT_BACK_CENTER", true );
440 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_SIDE_LEFT
, "CHANNEL_OUT_SIDE_LEFT", false );
443 GET_CONST_INT( AudioFormat
.CHANNEL_OUT_SIDE_RIGHT
, "CHANNEL_OUT_SIDE_RIGHT", true );
444 jfields
.AudioFormat
.has_CHANNEL_OUT_SIDE
= true;
446 jfields
.AudioFormat
.has_CHANNEL_OUT_SIDE
= false;
448 /* AudioManager class init */
449 GET_CLASS( "android/media/AudioManager", true );
450 GET_CONST_INT( AudioManager
.ERROR_DEAD_OBJECT
, "ERROR_DEAD_OBJECT", false );
451 jfields
.AudioManager
.has_ERROR_DEAD_OBJECT
= field
!= NULL
;
452 GET_CONST_INT( AudioManager
.STREAM_MUSIC
, "STREAM_MUSIC", true );
454 #undef CHECK_EXCEPTION
461 ret
= i_init_state
== 1;
463 msg_Err( p_aout
, "AudioTrack jni init failed" );
464 vlc_mutex_unlock( &lock
);
469 check_exception( JNIEnv
*env
, audio_output_t
*p_aout
,
472 if( (*env
)->ExceptionCheck( env
) )
474 aout_sys_t
*p_sys
= p_aout
->sys
;
476 p_sys
->b_audiotrack_exception
= true;
477 p_sys
->b_error
= true;
478 (*env
)->ExceptionDescribe( env
);
479 (*env
)->ExceptionClear( env
);
480 msg_Err( p_aout
, "AudioTrack.%s triggered an exception !", method
);
485 #define CHECK_AT_EXCEPTION( method ) check_exception( env, p_aout, method )
487 #define JNI_CALL( what, obj, method, ... ) (*env)->what( env, obj, method, ##__VA_ARGS__ )
489 #define JNI_CALL_INT( obj, method, ... ) JNI_CALL( CallIntMethod, obj, method, ##__VA_ARGS__ )
490 #define JNI_CALL_BOOL( obj, method, ... ) JNI_CALL( CallBooleanMethod, obj, method, ##__VA_ARGS__ )
491 #define JNI_CALL_VOID( obj, method, ... ) JNI_CALL( CallVoidMethod, obj, method, ##__VA_ARGS__ )
492 #define JNI_CALL_STATIC_INT( clazz, method, ... ) JNI_CALL( CallStaticIntMethod, clazz, method, ##__VA_ARGS__ )
494 #define JNI_AT_NEW( ... ) JNI_CALL( NewObject, jfields.AudioTrack.clazz, jfields.AudioTrack.ctor, ##__VA_ARGS__ )
495 #define JNI_AT_CALL_INT( method, ... ) JNI_CALL_INT( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
496 #define JNI_AT_CALL_BOOL( method, ... ) JNI_CALL_BOOL( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
497 #define JNI_AT_CALL_VOID( method, ... ) JNI_CALL_VOID( p_sys->p_audiotrack, jfields.AudioTrack.method, ##__VA_ARGS__ )
498 #define JNI_AT_CALL_STATIC_INT( method, ... ) JNI_CALL( CallStaticIntMethod, jfields.AudioTrack.clazz, jfields.AudioTrack.method, ##__VA_ARGS__ )
500 #define JNI_AUDIOTIMESTAMP_GET_LONG( field ) JNI_CALL( GetLongField, p_sys->timestamp.p_obj, jfields.AudioTimestamp.field )
502 static inline vlc_tick_t
503 frames_to_us( aout_sys_t
*p_sys
, uint64_t i_nb_frames
)
505 return i_nb_frames
* CLOCK_FREQ
/ p_sys
->fmt
.i_rate
;
507 #define FRAMES_TO_US(x) frames_to_us( p_sys, (x) )
509 static inline uint64_t
510 bytes_to_frames( aout_sys_t
*p_sys
, size_t i_bytes
)
512 return i_bytes
* p_sys
->fmt
.i_frame_length
/ p_sys
->fmt
.i_bytes_per_frame
;
514 #define BYTES_TO_FRAMES(x) bytes_to_frames( p_sys, (x) )
515 #define BYTES_TO_US(x) frames_to_us( p_sys, bytes_to_frames( p_sys, (x) ) )
518 frames_to_bytes( aout_sys_t
*p_sys
, uint64_t i_frames
)
520 return i_frames
* p_sys
->fmt
.i_bytes_per_frame
/ p_sys
->fmt
.i_frame_length
;
522 #define FRAMES_TO_BYTES(x) frames_to_bytes( p_sys, (x) )
525 * Get the AudioTrack position
527 * The doc says that the position is reset to zero after flush but it's not
528 * true for all devices or Android versions.
531 AudioTrack_getPlaybackHeadPosition( JNIEnv
*env
, audio_output_t
*p_aout
)
534 * getPlaybackHeadPosition: Returns the playback head position expressed in
535 * frames. Though the "int" type is signed 32-bits, the value should be
536 * reinterpreted as if it is unsigned 32-bits. That is, the next position
537 * after 0x7FFFFFFF is (int) 0x80000000. This is a continuously advancing
538 * counter. It will wrap (overflow) periodically, for example approximately
539 * once every 27:03:11 hours:minutes:seconds at 44.1 kHz. It is reset to
540 * zero by flush(), reload(), and stop().
543 aout_sys_t
*p_sys
= p_aout
->sys
;
546 /* int32_t to uint32_t */
547 i_pos
= 0xFFFFFFFFL
& JNI_AT_CALL_INT( getPlaybackHeadPosition
);
549 /* uint32_t to uint64_t */
550 if( p_sys
->headpos
.i_last
> i_pos
)
551 p_sys
->headpos
.i_wrap_count
++;
552 p_sys
->headpos
.i_last
= i_pos
;
553 return p_sys
->headpos
.i_last
+ ((uint64_t)p_sys
->headpos
.i_wrap_count
<< 32);
557 * Reset AudioTrack position
559 * Called after flush, or start
562 AudioTrack_ResetPlaybackHeadPosition( JNIEnv
*env
, audio_output_t
*p_aout
)
565 aout_sys_t
*p_sys
= p_aout
->sys
;
567 p_sys
->headpos
.i_last
= 0;
568 p_sys
->headpos
.i_wrap_count
= 0;
572 * Reset AudioTrack SmoothPosition and TimestampPosition
575 AudioTrack_ResetPositions( JNIEnv
*env
, audio_output_t
*p_aout
)
577 aout_sys_t
*p_sys
= p_aout
->sys
;
580 p_sys
->timestamp
.i_play_time
= vlc_tick_now();
581 p_sys
->timestamp
.i_last_time
= 0;
582 p_sys
->timestamp
.i_frame_us
= 0;
583 p_sys
->timestamp
.i_frame_pos
= 0;
585 p_sys
->smoothpos
.i_count
= 0;
586 p_sys
->smoothpos
.i_idx
= 0;
587 p_sys
->smoothpos
.i_last_time
= 0;
588 p_sys
->smoothpos
.i_us
= 0;
589 p_sys
->smoothpos
.i_latency_us
= 0;
593 * Reset all AudioTrack positions and internal state
596 AudioTrack_Reset( JNIEnv
*env
, audio_output_t
*p_aout
)
598 aout_sys_t
*p_sys
= p_aout
->sys
;
600 AudioTrack_ResetPositions( env
, p_aout
);
601 AudioTrack_ResetPlaybackHeadPosition( env
, p_aout
);
602 p_sys
->i_samples_written
= 0;
606 * Get a smooth AudioTrack position
608 * This function smooth out the AudioTrack position since it has a very bad
609 * precision (+/- 20ms on old devices).
612 AudioTrack_GetSmoothPositionUs( JNIEnv
*env
, audio_output_t
*p_aout
)
614 aout_sys_t
*p_sys
= p_aout
->sys
;
615 uint64_t i_audiotrack_us
;
616 vlc_tick_t i_now
= vlc_tick_now();
618 /* Fetch an AudioTrack position every SMOOTHPOS_INTERVAL_US (30ms) */
619 if( i_now
- p_sys
->smoothpos
.i_last_time
>= SMOOTHPOS_INTERVAL_US
)
621 i_audiotrack_us
= FRAMES_TO_US( AudioTrack_getPlaybackHeadPosition( env
, p_aout
) );
623 p_sys
->smoothpos
.i_last_time
= i_now
;
625 /* Base the position off the current time */
626 p_sys
->smoothpos
.p_us
[p_sys
->smoothpos
.i_idx
] = i_audiotrack_us
- i_now
;
627 p_sys
->smoothpos
.i_idx
= (p_sys
->smoothpos
.i_idx
+ 1)
628 % SMOOTHPOS_SAMPLE_COUNT
;
629 if( p_sys
->smoothpos
.i_count
< SMOOTHPOS_SAMPLE_COUNT
)
630 p_sys
->smoothpos
.i_count
++;
632 /* Calculate the average position based off the current time */
633 p_sys
->smoothpos
.i_us
= 0;
634 for( uint32_t i
= 0; i
< p_sys
->smoothpos
.i_count
; ++i
)
635 p_sys
->smoothpos
.i_us
+= p_sys
->smoothpos
.p_us
[i
];
636 p_sys
->smoothpos
.i_us
/= p_sys
->smoothpos
.i_count
;
638 if( jfields
.AudioSystem
.getOutputLatency
)
640 int i_latency_ms
= JNI_CALL( CallStaticIntMethod
,
641 jfields
.AudioSystem
.clazz
,
642 jfields
.AudioSystem
.getOutputLatency
,
643 jfields
.AudioManager
.STREAM_MUSIC
);
645 p_sys
->smoothpos
.i_latency_us
= i_latency_ms
> 0 ?
646 i_latency_ms
* 1000L : 0;
649 if( p_sys
->smoothpos
.i_us
!= 0 )
650 return p_sys
->smoothpos
.i_us
+ i_now
- p_sys
->smoothpos
.i_latency_us
;
656 AudioTrack_GetTimestampPositionUs( JNIEnv
*env
, audio_output_t
*p_aout
)
658 aout_sys_t
*p_sys
= p_aout
->sys
;
661 if( !p_sys
->timestamp
.p_obj
)
664 i_now
= vlc_tick_now();
667 * getTimestamp: Poll for a timestamp on demand.
669 * If you need to track timestamps during initial warmup or after a
670 * routing or mode change, you should request a new timestamp once per
671 * second until the reported timestamps show that the audio clock is
672 * stable. Thereafter, query for a new timestamp approximately once
673 * every 10 seconds to once per minute. Calling this method more often
674 * is inefficient. It is also counter-productive to call this method
675 * more often than recommended, because the short-term differences
676 * between successive timestamp reports are not meaningful. If you need
677 * a high-resolution mapping between frame position and presentation
678 * time, consider implementing that at application level, based on
679 * low-resolution timestamps.
682 /* Fetch an AudioTrack timestamp every AUDIOTIMESTAMP_INTERVAL_US (500ms) */
683 if( i_now
- p_sys
->timestamp
.i_last_time
>= AUDIOTIMESTAMP_INTERVAL_US
)
685 p_sys
->timestamp
.i_last_time
= i_now
;
687 if( JNI_AT_CALL_BOOL( getTimestamp
, p_sys
->timestamp
.p_obj
) )
689 p_sys
->timestamp
.i_frame_us
= JNI_AUDIOTIMESTAMP_GET_LONG( nanoTime
) / 1000;
690 p_sys
->timestamp
.i_frame_pos
= JNI_AUDIOTIMESTAMP_GET_LONG( framePosition
);
694 p_sys
->timestamp
.i_frame_us
= 0;
695 p_sys
->timestamp
.i_frame_pos
= 0;
699 /* frame time should be after last play time
700 * frame time shouldn't be in the future
701 * frame time should be less than 10 seconds old */
702 if( p_sys
->timestamp
.i_frame_us
!= 0 && p_sys
->timestamp
.i_frame_pos
!= 0
703 && p_sys
->timestamp
.i_frame_us
> p_sys
->timestamp
.i_play_time
704 && i_now
> p_sys
->timestamp
.i_frame_us
705 && ( i_now
- p_sys
->timestamp
.i_frame_us
) <= INT64_C(10000000) )
707 jlong i_time_diff
= i_now
- p_sys
->timestamp
.i_frame_us
;
708 jlong i_frames_diff
= i_time_diff
* p_sys
->fmt
.i_rate
/ CLOCK_FREQ
;
709 return FRAMES_TO_US( p_sys
->timestamp
.i_frame_pos
+ i_frames_diff
);
715 TimeGet( audio_output_t
*p_aout
, vlc_tick_t
*restrict p_delay
)
717 aout_sys_t
*p_sys
= p_aout
->sys
;
718 vlc_tick_t i_audiotrack_us
;
721 if( p_sys
->b_passthrough
)
724 vlc_mutex_lock( &p_sys
->lock
);
726 if( p_sys
->b_error
|| !p_sys
->i_samples_written
|| !( env
= GET_ENV() ) )
729 i_audiotrack_us
= AudioTrack_GetTimestampPositionUs( env
, p_aout
);
731 if( i_audiotrack_us
<= 0 )
732 i_audiotrack_us
= AudioTrack_GetSmoothPositionUs(env
, p_aout
);
734 /* Debug log for both delays */
737 vlc_tick_t i_written_us
= FRAMES_TO_US( p_sys
->i_samples_written
);
738 vlc_tick_t i_ts_us
= AudioTrack_GetTimestampPositionUs( env
, p_aout
);
739 vlc_tick_t i_smooth_us
= 0;
742 i_smooth_us
= AudioTrack_GetSmoothPositionUs(env
, p_aout
);
743 else if ( p_sys
->smoothpos
.i_us
!= 0 )
744 i_smooth_us
= p_sys
->smoothpos
.i_us
+ vlc_tick_now()
745 - p_sys
->smoothpos
.i_latency_us
;
747 msg_Err( p_aout
, "TimeGet: TimeStamp: %lld, Smooth: %lld (latency: %lld)",
748 i_ts_us
? i_written_us
- i_ts_us
: 0,
749 i_smooth_us
? i_written_us
- i_smooth_us
: 0,
750 p_sys
->smoothpos
.i_latency_us
);
754 if( i_audiotrack_us
> 0 )
756 /* AudioTrack delay */
757 vlc_tick_t i_delay
= FRAMES_TO_US( p_sys
->i_samples_written
)
761 /* Circular buffer delay */
762 i_delay
+= BYTES_TO_US( p_sys
->circular
.i_write
763 - p_sys
->circular
.i_read
);
765 vlc_mutex_unlock( &p_sys
->lock
);
770 msg_Warn( p_aout
, "timing screwed, reset positions" );
771 AudioTrack_ResetPositions( env
, p_aout
);
776 vlc_mutex_unlock( &p_sys
->lock
);
781 AudioTrack_GetChanOrder( uint16_t i_physical_channels
, uint32_t p_chans_out
[] )
783 #define HAS_CHAN( x ) ( ( i_physical_channels & (x) ) == (x) )
784 /* samples will be in the following order: FL FR FC LFE BL BR BC SL SR */
787 if( HAS_CHAN( AOUT_CHAN_LEFT
) )
788 p_chans_out
[i
++] = AOUT_CHAN_LEFT
;
789 if( HAS_CHAN( AOUT_CHAN_RIGHT
) )
790 p_chans_out
[i
++] = AOUT_CHAN_RIGHT
;
792 if( HAS_CHAN( AOUT_CHAN_CENTER
) )
793 p_chans_out
[i
++] = AOUT_CHAN_CENTER
;
795 if( HAS_CHAN( AOUT_CHAN_LFE
) )
796 p_chans_out
[i
++] = AOUT_CHAN_LFE
;
798 if( HAS_CHAN( AOUT_CHAN_REARLEFT
) )
799 p_chans_out
[i
++] = AOUT_CHAN_REARLEFT
;
800 if( HAS_CHAN( AOUT_CHAN_REARRIGHT
) )
801 p_chans_out
[i
++] = AOUT_CHAN_REARRIGHT
;
803 if( HAS_CHAN( AOUT_CHAN_REARCENTER
) )
804 p_chans_out
[i
++] = AOUT_CHAN_REARCENTER
;
806 if( HAS_CHAN( AOUT_CHAN_MIDDLELEFT
) )
807 p_chans_out
[i
++] = AOUT_CHAN_MIDDLELEFT
;
808 if( HAS_CHAN( AOUT_CHAN_MIDDLERIGHT
) )
809 p_chans_out
[i
++] = AOUT_CHAN_MIDDLERIGHT
;
811 assert( i
<= AOUT_CHAN_MAX
);
816 * Create an Android AudioTrack.
817 * returns -1 on error, 0 on success.
820 AudioTrack_New( JNIEnv
*env
, audio_output_t
*p_aout
, unsigned int i_rate
,
821 int i_channel_config
, int i_format
, int i_size
)
823 aout_sys_t
*p_sys
= p_aout
->sys
;
824 jint session_id
= var_InheritInteger( p_aout
, "audiotrack-session-id" );
825 jobject p_audiotrack
= JNI_AT_NEW( jfields
.AudioManager
.STREAM_MUSIC
,
826 i_rate
, i_channel_config
, i_format
,
827 i_size
, jfields
.AudioTrack
.MODE_STREAM
,
829 if( CHECK_AT_EXCEPTION( "AudioTrack<init>" ) || !p_audiotrack
)
831 msg_Warn( p_aout
, "AudioTrack Init failed" ) ;
834 if( JNI_CALL_INT( p_audiotrack
, jfields
.AudioTrack
.getState
)
835 != jfields
.AudioTrack
.STATE_INITIALIZED
)
837 JNI_CALL_VOID( p_audiotrack
, jfields
.AudioTrack
.release
);
838 (*env
)->DeleteLocalRef( env
, p_audiotrack
);
839 msg_Err( p_aout
, "AudioTrack getState failed" );
843 p_sys
->p_audiotrack
= (*env
)->NewGlobalRef( env
, p_audiotrack
);
844 (*env
)->DeleteLocalRef( env
, p_audiotrack
);
845 if( !p_sys
->p_audiotrack
)
852 * Destroy and recreate an Android AudioTrack using the same arguments.
853 * returns -1 on error, 0 on success.
856 AudioTrack_Recreate( JNIEnv
*env
, audio_output_t
*p_aout
)
858 aout_sys_t
*p_sys
= p_aout
->sys
;
860 JNI_AT_CALL_VOID( release
);
861 (*env
)->DeleteGlobalRef( env
, p_sys
->p_audiotrack
);
862 p_sys
->p_audiotrack
= NULL
;
863 return AudioTrack_New( env
, p_aout
, p_sys
->audiotrack_args
.i_rate
,
864 p_sys
->audiotrack_args
.i_channel_config
,
865 p_sys
->audiotrack_args
.i_format
,
866 p_sys
->audiotrack_args
.i_size
);
870 * Configure and create an Android AudioTrack.
871 * returns -1 on configuration error, 0 on success.
874 AudioTrack_Create( JNIEnv
*env
, audio_output_t
*p_aout
,
877 uint16_t i_physical_channels
)
879 aout_sys_t
*p_sys
= p_aout
->sys
;
880 int i_size
, i_min_buffer_size
, i_channel_config
;
882 switch( i_physical_channels
)
885 /* bitmask of CHANNEL_OUT_7POINT1 doesn't correspond to 5POINT1 and
887 i_channel_config
= jfields
.AudioFormat
.CHANNEL_OUT_5POINT1
|
888 jfields
.AudioFormat
.CHANNEL_OUT_SIDE_LEFT
|
889 jfields
.AudioFormat
.CHANNEL_OUT_SIDE_RIGHT
;
892 i_channel_config
= jfields
.AudioFormat
.CHANNEL_OUT_5POINT1
;
895 i_channel_config
= jfields
.AudioFormat
.CHANNEL_OUT_MONO
;
897 case AOUT_CHANS_STEREO
:
898 i_channel_config
= jfields
.AudioFormat
.CHANNEL_OUT_STEREO
;
901 vlc_assert_unreachable();
904 i_min_buffer_size
= JNI_AT_CALL_STATIC_INT( getMinBufferSize
, i_rate
,
905 i_channel_config
, i_format
);
906 if( i_min_buffer_size
<= 0 )
908 msg_Warn( p_aout
, "getMinBufferSize returned an invalid size" ) ;
911 i_size
= i_min_buffer_size
* 2;
913 /* create AudioTrack object */
914 if( AudioTrack_New( env
, p_aout
, i_rate
, i_channel_config
,
915 i_format
, i_size
) != 0 )
918 p_sys
->audiotrack_args
.i_rate
= i_rate
;
919 p_sys
->audiotrack_args
.i_channel_config
= i_channel_config
;
920 p_sys
->audiotrack_args
.i_format
= i_format
;
921 p_sys
->audiotrack_args
.i_size
= i_size
;
927 AudioTrack_HasEncoding( audio_output_t
*p_aout
, vlc_fourcc_t i_format
,
930 aout_sys_t
*p_sys
= p_aout
->sys
;
932 #define MATCH_ENCODING_FLAG(x) jfields.AudioFormat.has_##x && \
933 ( p_sys->i_encoding_flags == 0 || p_sys->i_encoding_flags & (1 << jfields.AudioFormat.x) )
939 if( MATCH_ENCODING_FLAG( ENCODING_DTS_HD
)
940 && var_GetBool( p_aout
, "dtshd" ) )
945 return MATCH_ENCODING_FLAG( ENCODING_DTS
);
947 return MATCH_ENCODING_FLAG( ENCODING_AC3
);
949 return MATCH_ENCODING_FLAG( ENCODING_E_AC3
);
950 case VLC_CODEC_TRUEHD
:
952 return MATCH_ENCODING_FLAG( ENCODING_DOLBY_TRUEHD
);
959 StartPassthrough( JNIEnv
*env
, audio_output_t
*p_aout
)
961 aout_sys_t
*p_sys
= p_aout
->sys
;
964 if( jfields
.AudioFormat
.has_ENCODING_IEC61937
)
967 if( !AudioTrack_HasEncoding( p_aout
, p_sys
->fmt
.i_format
, &b_dtshd
) )
969 i_at_format
= jfields
.AudioFormat
.ENCODING_IEC61937
;
970 switch( p_sys
->fmt
.i_format
)
972 case VLC_CODEC_TRUEHD
:
974 p_sys
->fmt
.i_rate
= 192000;
975 p_sys
->fmt
.i_bytes_per_frame
= 16;
977 /* AudioFormat.ENCODING_IEC61937 documentation says that the
978 * channel layout must be stereo. Well, not for TrueHD
980 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_7_1
;
983 p_sys
->fmt
.i_bytes_per_frame
= 4;
984 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_STEREO
;
987 p_sys
->fmt
.i_rate
= 192000;
988 p_sys
->fmt
.i_bytes_per_frame
= 16;
992 p_sys
->fmt
.i_rate
= 192000;
994 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_STEREO
;
995 p_sys
->fmt
.i_bytes_per_frame
= 4;
1000 p_sys
->fmt
.i_frame_length
= 1;
1001 p_sys
->fmt
.i_channels
= aout_FormatNbChannels( &p_sys
->fmt
);
1002 p_sys
->fmt
.i_format
= VLC_CODEC_SPDIFL
;
1006 switch( p_sys
->fmt
.i_format
)
1009 if( !jfields
.AudioFormat
.has_ENCODING_AC3
)
1010 return VLC_EGENERIC
;
1011 i_at_format
= jfields
.AudioFormat
.ENCODING_AC3
;
1014 if( !jfields
.AudioFormat
.has_ENCODING_DTS
)
1015 return VLC_EGENERIC
;
1016 i_at_format
= jfields
.AudioFormat
.ENCODING_DTS
;
1019 return VLC_EGENERIC
;
1021 p_sys
->fmt
.i_bytes_per_frame
= 4;
1022 p_sys
->fmt
.i_frame_length
= 1;
1023 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_STEREO
;
1024 p_sys
->fmt
.i_channels
= 2;
1025 p_sys
->fmt
.i_format
= VLC_CODEC_SPDIFB
;
1028 int i_ret
= AudioTrack_Create( env
, p_aout
, p_sys
->fmt
.i_rate
, i_at_format
,
1029 p_sys
->fmt
.i_physical_channels
);
1030 if( i_ret
!= VLC_SUCCESS
)
1031 msg_Warn( p_aout
, "SPDIF configuration failed" );
1034 p_sys
->b_passthrough
= true;
1035 p_sys
->i_chans_to_reorder
= 0;
1042 StartPCM( JNIEnv
*env
, audio_output_t
*p_aout
, unsigned i_max_channels
)
1044 aout_sys_t
*p_sys
= p_aout
->sys
;
1045 unsigned i_nb_channels
;
1046 int i_at_format
, i_ret
;
1048 if (jfields
.AudioTrack
.getNativeOutputSampleRate
)
1050 JNI_AT_CALL_STATIC_INT( getNativeOutputSampleRate
,
1051 jfields
.AudioManager
.STREAM_MUSIC
);
1053 p_sys
->fmt
.i_rate
= VLC_CLIP( p_sys
->fmt
.i_rate
, 4000, 48000 );
1057 /* We can only accept U8, S16N, FL32, and AC3 */
1058 switch( p_sys
->fmt
.i_format
)
1061 i_at_format
= jfields
.AudioFormat
.ENCODING_PCM_8BIT
;
1063 case VLC_CODEC_S16N
:
1064 i_at_format
= jfields
.AudioFormat
.ENCODING_PCM_16BIT
;
1066 case VLC_CODEC_FL32
:
1067 if( jfields
.AudioFormat
.has_ENCODING_PCM_FLOAT
)
1068 i_at_format
= jfields
.AudioFormat
.ENCODING_PCM_FLOAT
;
1071 p_sys
->fmt
.i_format
= VLC_CODEC_S16N
;
1072 i_at_format
= jfields
.AudioFormat
.ENCODING_PCM_16BIT
;
1076 p_sys
->fmt
.i_format
= VLC_CODEC_S16N
;
1077 i_at_format
= jfields
.AudioFormat
.ENCODING_PCM_16BIT
;
1081 /* Android AudioTrack supports only mono, stereo, 5.1 and 7.1.
1082 * Android will downmix to stereo if audio output doesn't handle 5.1 or 7.1
1085 i_nb_channels
= aout_FormatNbChannels( &p_sys
->fmt
);
1086 if( i_nb_channels
== 0 )
1087 return VLC_EGENERIC
;
1088 if( AOUT_FMT_LINEAR( &p_sys
->fmt
) )
1089 i_nb_channels
= __MIN( i_max_channels
, i_nb_channels
);
1090 if( i_nb_channels
> 5 )
1092 if( i_nb_channels
> 7 && jfields
.AudioFormat
.has_CHANNEL_OUT_SIDE
)
1093 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_7_1
;
1095 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_5_1
;
1098 if( i_nb_channels
== 1 )
1099 p_sys
->fmt
.i_physical_channels
= AOUT_CHAN_LEFT
;
1101 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_STEREO
;
1104 /* Try to create an AudioTrack with the most advanced channel and
1105 * format configuration. If AudioTrack_Create fails, try again with a
1106 * less advanced format (PCM S16N). If it fails again, try again with
1107 * Stereo channels. */
1108 i_ret
= AudioTrack_Create( env
, p_aout
, p_sys
->fmt
.i_rate
, i_at_format
,
1109 p_sys
->fmt
.i_physical_channels
);
1112 if( p_sys
->fmt
.i_format
== VLC_CODEC_FL32
)
1114 msg_Warn( p_aout
, "FL32 configuration failed, "
1115 "fallback to S16N PCM" );
1116 p_sys
->fmt
.i_format
= VLC_CODEC_S16N
;
1118 else if( p_sys
->fmt
.i_physical_channels
& AOUT_CHANS_5_1
)
1120 msg_Warn( p_aout
, "5.1 or 7.1 configuration failed, "
1121 "fallback to Stereo" );
1122 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_STEREO
;
1127 } while( i_ret
!= 0 );
1129 if( i_ret
!= VLC_SUCCESS
)
1132 uint32_t p_chans_out
[AOUT_CHAN_MAX
];
1133 memset( p_chans_out
, 0, sizeof(p_chans_out
) );
1134 AudioTrack_GetChanOrder( p_sys
->fmt
.i_physical_channels
, p_chans_out
);
1135 p_sys
->i_chans_to_reorder
=
1136 aout_CheckChannelReorder( NULL
, p_chans_out
,
1137 p_sys
->fmt
.i_physical_channels
,
1138 p_sys
->p_chan_table
);
1139 aout_FormatPrepare( &p_sys
->fmt
);
1144 Start( audio_output_t
*p_aout
, audio_sample_format_t
*restrict p_fmt
)
1146 aout_sys_t
*p_sys
= p_aout
->sys
;
1149 bool b_try_passthrough
;
1150 unsigned i_max_channels
;
1152 if( p_sys
->at_dev
== AT_DEV_ENCODED
)
1154 b_try_passthrough
= true;
1155 i_max_channels
= AT_DEV_MAX_CHANNELS
;
1159 b_try_passthrough
= var_InheritBool( p_aout
, "spdif" );
1160 i_max_channels
= p_sys
->at_dev
== AT_DEV_STEREO
? 2 : AT_DEV_MAX_CHANNELS
;
1163 if( !( env
= GET_ENV() ) )
1164 return VLC_EGENERIC
;
1166 p_sys
->fmt
= *p_fmt
;
1168 aout_FormatPrint( p_aout
, "VLC is looking for:", &p_sys
->fmt
);
1170 bool low_latency
= false;
1171 if (p_sys
->fmt
.channel_type
== AUDIO_CHANNEL_TYPE_AMBISONICS
)
1173 p_sys
->fmt
.channel_type
= AUDIO_CHANNEL_TYPE_BITMAP
;
1175 /* TODO: detect sink channel layout */
1176 p_sys
->fmt
.i_physical_channels
= AOUT_CHANS_STEREO
;
1177 aout_FormatPrepare(&p_sys
->fmt
);
1181 if( AOUT_FMT_LINEAR( &p_sys
->fmt
) )
1182 i_ret
= StartPCM( env
, p_aout
, i_max_channels
);
1183 else if( b_try_passthrough
)
1184 i_ret
= StartPassthrough( env
, p_aout
);
1186 return VLC_EGENERIC
;
1189 return VLC_EGENERIC
;
1191 p_sys
->i_max_audiotrack_samples
= BYTES_TO_FRAMES( p_sys
->audiotrack_args
.i_size
);
1193 #ifdef AUDIOTRACK_HW_LATENCY
1194 if( jfields
.AudioTimestamp
.clazz
)
1196 /* create AudioTimestamp object */
1197 jobject p_obj
= JNI_CALL( NewObject
, jfields
.AudioTimestamp
.clazz
,
1198 jfields
.AudioTimestamp
.ctor
);
1201 p_sys
->timestamp
.p_obj
= (*env
)->NewGlobalRef( env
, p_obj
);
1202 (*env
)->DeleteLocalRef( env
, p_obj
);
1204 if( !p_sys
->timestamp
.p_obj
)
1209 AudioTrack_Reset( env
, p_aout
);
1211 if( p_sys
->fmt
.i_format
== VLC_CODEC_FL32
)
1213 msg_Dbg( p_aout
, "using WRITE_FLOATARRAY");
1214 p_sys
->i_write_type
= WRITE_FLOATARRAY
;
1216 else if( p_sys
->fmt
.i_format
== VLC_CODEC_SPDIFL
)
1218 assert( jfields
.AudioFormat
.has_ENCODING_IEC61937
);
1219 msg_Dbg( p_aout
, "using WRITE_SHORTARRAYV23");
1220 p_sys
->i_write_type
= WRITE_SHORTARRAYV23
;
1222 else if( jfields
.AudioTrack
.writeV23
)
1224 msg_Dbg( p_aout
, "using WRITE_BYTEARRAYV23");
1225 p_sys
->i_write_type
= WRITE_BYTEARRAYV23
;
1227 else if( jfields
.AudioTrack
.writeBufferV21
)
1229 msg_Dbg( p_aout
, "using WRITE_BYTEBUFFER");
1230 p_sys
->i_write_type
= WRITE_BYTEBUFFER
;
1234 msg_Dbg( p_aout
, "using WRITE_BYTEARRAY");
1235 p_sys
->i_write_type
= WRITE_BYTEARRAY
;
1238 p_sys
->circular
.i_read
= p_sys
->circular
.i_write
= 0;
1239 p_sys
->circular
.i_size
= (int)p_sys
->fmt
.i_rate
1240 * p_sys
->fmt
.i_bytes_per_frame
1241 / p_sys
->fmt
.i_frame_length
;
1244 /* 40 ms of buffering */
1245 p_sys
->circular
.i_size
= p_sys
->circular
.i_size
/ 25;
1249 /* 2 seconds of buffering */
1250 p_sys
->circular
.i_size
= p_sys
->circular
.i_size
* AOUT_MAX_PREPARE_TIME
1254 /* Allocate circular buffer */
1255 switch( p_sys
->i_write_type
)
1257 case WRITE_BYTEARRAY
:
1258 case WRITE_BYTEARRAYV23
:
1260 jbyteArray p_bytearray
;
1262 p_bytearray
= (*env
)->NewByteArray( env
, p_sys
->circular
.i_size
);
1265 p_sys
->circular
.u
.p_bytearray
= (*env
)->NewGlobalRef( env
, p_bytearray
);
1266 (*env
)->DeleteLocalRef( env
, p_bytearray
);
1269 if( !p_sys
->circular
.u
.p_bytearray
)
1271 msg_Err(p_aout
, "byte array allocation failed");
1276 case WRITE_SHORTARRAYV23
:
1278 jshortArray p_shortarray
;
1280 p_shortarray
= (*env
)->NewShortArray( env
,
1281 p_sys
->circular
.i_size
/ 2 );
1284 p_sys
->circular
.u
.p_shortarray
= (*env
)->NewGlobalRef( env
, p_shortarray
);
1285 (*env
)->DeleteLocalRef( env
, p_shortarray
);
1287 if( !p_sys
->circular
.u
.p_shortarray
)
1289 msg_Err(p_aout
, "short array allocation failed");
1294 case WRITE_FLOATARRAY
:
1296 jfloatArray p_floatarray
;
1298 p_floatarray
= (*env
)->NewFloatArray( env
,
1299 p_sys
->circular
.i_size
/ 4 );
1302 p_sys
->circular
.u
.p_floatarray
= (*env
)->NewGlobalRef( env
, p_floatarray
);
1303 (*env
)->DeleteLocalRef( env
, p_floatarray
);
1305 if( !p_sys
->circular
.u
.p_floatarray
)
1307 msg_Err(p_aout
, "float array allocation failed");
1312 case WRITE_BYTEBUFFER
:
1313 p_sys
->circular
.u
.bytebuffer
.p_data
= malloc( p_sys
->circular
.i_size
);
1314 if( !p_sys
->circular
.u
.bytebuffer
.p_data
)
1316 msg_Err(p_aout
, "bytebuffer allocation failed");
1322 /* Run AudioTrack_Thread */
1323 p_sys
->b_thread_running
= true;
1324 p_sys
->b_thread_paused
= false;
1325 if ( vlc_clone( &p_sys
->thread
, AudioTrack_Thread
, p_aout
,
1326 VLC_THREAD_PRIORITY_LOW
) )
1328 msg_Err(p_aout
, "vlc clone failed");
1332 JNI_AT_CALL_VOID( play
);
1333 CHECK_AT_EXCEPTION( "play" );
1335 *p_fmt
= p_sys
->fmt
;
1336 aout_SoftVolumeStart( p_aout
);
1338 aout_FormatPrint( p_aout
, "VLC will output:", &p_sys
->fmt
);
1344 return VLC_EGENERIC
;
1348 Stop( audio_output_t
*p_aout
)
1350 aout_sys_t
*p_sys
= p_aout
->sys
;
1353 if( !( env
= GET_ENV() ) )
1356 /* Stop the AudioTrack thread */
1357 vlc_mutex_lock( &p_sys
->lock
);
1358 if( p_sys
->b_thread_running
)
1360 p_sys
->b_thread_running
= false;
1361 vlc_cond_signal( &p_sys
->thread_cond
);
1362 vlc_mutex_unlock( &p_sys
->lock
);
1363 vlc_join( p_sys
->thread
, NULL
);
1366 vlc_mutex_unlock( &p_sys
->lock
);
1368 /* Release the AudioTrack object */
1369 if( p_sys
->p_audiotrack
)
1371 if( !p_sys
->b_audiotrack_exception
)
1373 JNI_AT_CALL_VOID( stop
);
1374 if( !CHECK_AT_EXCEPTION( "stop" ) )
1375 JNI_AT_CALL_VOID( release
);
1377 (*env
)->DeleteGlobalRef( env
, p_sys
->p_audiotrack
);
1378 p_sys
->p_audiotrack
= NULL
;
1381 /* Release the timestamp object */
1382 if( p_sys
->timestamp
.p_obj
)
1384 (*env
)->DeleteGlobalRef( env
, p_sys
->timestamp
.p_obj
);
1385 p_sys
->timestamp
.p_obj
= NULL
;
1388 /* Release the Circular buffer data */
1389 switch( p_sys
->i_write_type
)
1391 case WRITE_BYTEARRAY
:
1392 case WRITE_BYTEARRAYV23
:
1393 if( p_sys
->circular
.u
.p_bytearray
)
1395 (*env
)->DeleteGlobalRef( env
, p_sys
->circular
.u
.p_bytearray
);
1396 p_sys
->circular
.u
.p_bytearray
= NULL
;
1399 case WRITE_SHORTARRAYV23
:
1400 if( p_sys
->circular
.u
.p_shortarray
)
1402 (*env
)->DeleteGlobalRef( env
, p_sys
->circular
.u
.p_shortarray
);
1403 p_sys
->circular
.u
.p_shortarray
= NULL
;
1406 case WRITE_FLOATARRAY
:
1407 if( p_sys
->circular
.u
.p_floatarray
)
1409 (*env
)->DeleteGlobalRef( env
, p_sys
->circular
.u
.p_floatarray
);
1410 p_sys
->circular
.u
.p_floatarray
= NULL
;
1413 case WRITE_BYTEBUFFER
:
1414 free( p_sys
->circular
.u
.bytebuffer
.p_data
);
1415 p_sys
->circular
.u
.bytebuffer
.p_data
= NULL
;
1419 p_sys
->b_audiotrack_exception
= false;
1420 p_sys
->b_error
= false;
1421 p_sys
->b_passthrough
= false;
1425 * Non blocking write function, run from AudioTrack_Thread.
1426 * Do a calculation between current position and audiotrack position and assure
1427 * that we won't wait in AudioTrack.write() method.
1430 AudioTrack_PlayByteArray( JNIEnv
*env
, audio_output_t
*p_aout
,
1431 size_t i_data_size
, size_t i_data_offset
,
1434 aout_sys_t
*p_sys
= p_aout
->sys
;
1436 uint64_t i_audiotrack_pos
;
1437 uint64_t i_samples_pending
;
1439 i_audiotrack_pos
= AudioTrack_getPlaybackHeadPosition( env
, p_aout
);
1441 assert( i_audiotrack_pos
<= p_sys
->i_samples_written
);
1442 if( i_audiotrack_pos
> p_sys
->i_samples_written
)
1444 msg_Err( p_aout
, "audiotrack position is ahead. Should NOT happen" );
1445 p_sys
->i_samples_written
= 0;
1446 p_sys
->b_error
= true;
1449 i_samples_pending
= p_sys
->i_samples_written
- i_audiotrack_pos
;
1451 /* check if audiotrack buffer is not full before writing on it. */
1454 msg_Warn( p_aout
, "Force write. It may block..." );
1455 i_samples_pending
= 0;
1456 } else if( i_samples_pending
>= p_sys
->i_max_audiotrack_samples
)
1459 i_samples
= __MIN( p_sys
->i_max_audiotrack_samples
- i_samples_pending
,
1460 BYTES_TO_FRAMES( i_data_size
) );
1462 i_data_size
= FRAMES_TO_BYTES( i_samples
);
1464 return JNI_AT_CALL_INT( write
, p_sys
->circular
.u
.p_bytearray
,
1465 i_data_offset
, i_data_size
);
1469 * Non blocking write function for Android M and after, run from
1470 * AudioTrack_Thread. It calls a new write method with WRITE_NON_BLOCKING
1474 AudioTrack_PlayByteArrayV23( JNIEnv
*env
, audio_output_t
*p_aout
,
1475 size_t i_data_size
, size_t i_data_offset
)
1477 aout_sys_t
*p_sys
= p_aout
->sys
;
1479 return JNI_AT_CALL_INT( writeV23
, p_sys
->circular
.u
.p_bytearray
,
1480 i_data_offset
, i_data_size
,
1481 jfields
.AudioTrack
.WRITE_NON_BLOCKING
);
1485 * Non blocking play function for Lollipop and after, run from
1486 * AudioTrack_Thread. It calls a new write method with WRITE_NON_BLOCKING
1490 AudioTrack_PlayByteBuffer( JNIEnv
*env
, audio_output_t
*p_aout
,
1491 size_t i_data_size
, size_t i_data_offset
)
1493 aout_sys_t
*p_sys
= p_aout
->sys
;
1495 /* The same DirectByteBuffer will be used until the data_offset reaches 0.
1496 * The internal position of this buffer is moved by the writeBufferV21
1498 if( i_data_offset
== 0 )
1500 /* No need to get a global ref, this object will be only used from the
1502 if( p_sys
->circular
.u
.bytebuffer
.p_obj
)
1503 (*env
)->DeleteLocalRef( env
, p_sys
->circular
.u
.bytebuffer
.p_obj
);
1505 p_sys
->circular
.u
.bytebuffer
.p_obj
= (*env
)->NewDirectByteBuffer( env
,
1506 p_sys
->circular
.u
.bytebuffer
.p_data
,
1507 p_sys
->circular
.i_size
);
1508 if( !p_sys
->circular
.u
.bytebuffer
.p_obj
)
1510 if( (*env
)->ExceptionCheck( env
) )
1511 (*env
)->ExceptionClear( env
);
1512 return jfields
.AudioTrack
.ERROR
;
1516 return JNI_AT_CALL_INT( writeBufferV21
, p_sys
->circular
.u
.bytebuffer
.p_obj
,
1518 jfields
.AudioTrack
.WRITE_NON_BLOCKING
);
1522 * Non blocking short write function for Android M and after, run from
1523 * AudioTrack_Thread. It calls a new write method with WRITE_NON_BLOCKING
1527 AudioTrack_PlayShortArrayV23( JNIEnv
*env
, audio_output_t
*p_aout
,
1528 size_t i_data_size
, size_t i_data_offset
)
1530 aout_sys_t
*p_sys
= p_aout
->sys
;
1533 i_ret
= JNI_AT_CALL_INT( writeShortV23
, p_sys
->circular
.u
.p_shortarray
,
1534 i_data_offset
/ 2, i_data_size
/ 2,
1535 jfields
.AudioTrack
.WRITE_NON_BLOCKING
);
1543 * Non blocking play float function for Lollipop and after, run from
1544 * AudioTrack_Thread. It calls a new write method with WRITE_NON_BLOCKING
1548 AudioTrack_PlayFloatArray( JNIEnv
*env
, audio_output_t
*p_aout
,
1549 size_t i_data_size
, size_t i_data_offset
)
1551 aout_sys_t
*p_sys
= p_aout
->sys
;
1554 i_ret
= JNI_AT_CALL_INT( writeFloat
, p_sys
->circular
.u
.p_floatarray
,
1555 i_data_offset
/ 4, i_data_size
/ 4,
1556 jfields
.AudioTrack
.WRITE_NON_BLOCKING
);
1564 AudioTrack_Play( JNIEnv
*env
, audio_output_t
*p_aout
, size_t i_data_size
,
1565 size_t i_data_offset
, bool b_force
)
1567 aout_sys_t
*p_sys
= p_aout
->sys
;
1570 switch( p_sys
->i_write_type
)
1572 case WRITE_BYTEARRAYV23
:
1573 i_ret
= AudioTrack_PlayByteArrayV23( env
, p_aout
, i_data_size
,
1576 case WRITE_BYTEBUFFER
:
1577 i_ret
= AudioTrack_PlayByteBuffer( env
, p_aout
, i_data_size
,
1580 case WRITE_SHORTARRAYV23
:
1581 i_ret
= AudioTrack_PlayShortArrayV23( env
, p_aout
, i_data_size
,
1584 case WRITE_BYTEARRAY
:
1585 i_ret
= AudioTrack_PlayByteArray( env
, p_aout
, i_data_size
,
1586 i_data_offset
, b_force
);
1588 case WRITE_FLOATARRAY
:
1589 i_ret
= AudioTrack_PlayFloatArray( env
, p_aout
, i_data_size
,
1593 vlc_assert_unreachable();
1597 if( jfields
.AudioManager
.has_ERROR_DEAD_OBJECT
1598 && i_ret
== jfields
.AudioManager
.ERROR_DEAD_OBJECT
)
1600 msg_Warn( p_aout
, "ERROR_DEAD_OBJECT: "
1601 "try recreating AudioTrack" );
1602 if( ( i_ret
= AudioTrack_Recreate( env
, p_aout
) ) == 0 )
1604 AudioTrack_Reset( env
, p_aout
);
1605 JNI_AT_CALL_VOID( play
);
1606 CHECK_AT_EXCEPTION( "play" );
1611 if( i_ret
== jfields
.AudioTrack
.ERROR_INVALID_OPERATION
)
1612 str
= "ERROR_INVALID_OPERATION";
1613 else if( i_ret
== jfields
.AudioTrack
.ERROR_BAD_VALUE
)
1614 str
= "ERROR_BAD_VALUE";
1617 msg_Err( p_aout
, "Write failed: %s", str
);
1618 p_sys
->b_error
= true;
1621 p_sys
->i_samples_written
+= BYTES_TO_FRAMES( i_ret
);
1626 * This thread will play the data coming from the circular buffer.
1629 AudioTrack_Thread( void *p_data
)
1631 audio_output_t
*p_aout
= p_data
;
1632 aout_sys_t
*p_sys
= p_aout
->sys
;
1633 JNIEnv
*env
= GET_ENV();
1634 vlc_tick_t i_play_deadline
= 0;
1635 vlc_tick_t i_last_time_blocked
= 0;
1644 size_t i_data_offset
;
1647 vlc_mutex_lock( &p_sys
->lock
);
1649 /* Wait for free space in Audiotrack internal buffer */
1650 if( i_play_deadline
!= 0 && vlc_tick_now() < i_play_deadline
)
1652 /* Don't wake up the thread when there is new data since we are
1653 * waiting for more space */
1654 p_sys
->b_thread_waiting
= true;
1655 while( p_sys
->b_thread_running
&& i_ret
!= ETIMEDOUT
)
1656 i_ret
= vlc_cond_timedwait( &p_sys
->thread_cond
,
1659 i_play_deadline
= 0;
1660 p_sys
->b_thread_waiting
= false;
1663 /* Wait for not paused state */
1664 while( p_sys
->b_thread_running
&& p_sys
->b_thread_paused
)
1666 i_last_time_blocked
= 0;
1667 vlc_cond_wait( &p_sys
->thread_cond
, &p_sys
->lock
);
1670 /* Wait for more data in the circular buffer */
1671 while( p_sys
->b_thread_running
1672 && p_sys
->circular
.i_read
>= p_sys
->circular
.i_write
)
1673 vlc_cond_wait( &p_sys
->thread_cond
, &p_sys
->lock
);
1675 if( !p_sys
->b_thread_running
|| p_sys
->b_error
)
1677 vlc_mutex_unlock( &p_sys
->lock
);
1681 /* HACK: AudioFlinger can drop frames without notifying us and there is
1682 * no way to know it. If it happens, i_audiotrack_pos won't move and
1683 * the current code will be stuck because it'll assume that audiotrack
1684 * internal buffer is full when it's not. It may happen only after
1685 * Android 4.4.2 if we send frames too quickly. To fix this issue,
1686 * force the writing of the buffer after a certain delay. */
1687 if( i_last_time_blocked
!= 0 )
1688 b_forced
= vlc_tick_now() - i_last_time_blocked
>
1689 FRAMES_TO_US( p_sys
->i_max_audiotrack_samples
) * 2;
1693 i_data_offset
= p_sys
->circular
.i_read
% p_sys
->circular
.i_size
;
1694 i_data_size
= __MIN( p_sys
->circular
.i_size
- i_data_offset
,
1695 p_sys
->circular
.i_write
- p_sys
->circular
.i_read
);
1697 i_ret
= AudioTrack_Play( env
, p_aout
, i_data_size
, i_data_offset
,
1701 if( p_sys
->i_write_type
== WRITE_BYTEARRAY
)
1704 i_last_time_blocked
= 0;
1705 else if( i_last_time_blocked
== 0 )
1706 i_last_time_blocked
= vlc_tick_now();
1710 i_play_deadline
= vlc_tick_now() + __MAX( 10000, FRAMES_TO_US(
1711 p_sys
->i_max_audiotrack_samples
/ 5 ) );
1713 p_sys
->circular
.i_read
+= i_ret
;
1716 vlc_cond_signal( &p_sys
->aout_cond
);
1717 vlc_mutex_unlock( &p_sys
->lock
);
1720 if( p_sys
->circular
.u
.bytebuffer
.p_obj
)
1722 (*env
)->DeleteLocalRef( env
, p_sys
->circular
.u
.bytebuffer
.p_obj
);
1723 p_sys
->circular
.u
.bytebuffer
.p_obj
= NULL
;
1730 Play( audio_output_t
*p_aout
, block_t
*p_buffer
, vlc_tick_t i_date
)
1733 size_t i_buffer_offset
= 0;
1734 aout_sys_t
*p_sys
= p_aout
->sys
;
1736 vlc_mutex_lock( &p_sys
->lock
);
1738 if( p_sys
->b_error
|| !( env
= GET_ENV() ) )
1741 if( p_sys
->i_chans_to_reorder
)
1742 aout_ChannelReorder( p_buffer
->p_buffer
, p_buffer
->i_buffer
,
1743 p_sys
->i_chans_to_reorder
, p_sys
->p_chan_table
,
1744 p_sys
->fmt
.i_format
);
1746 while( i_buffer_offset
< p_buffer
->i_buffer
&& !p_sys
->b_error
)
1748 size_t i_circular_free
;
1749 size_t i_data_offset
;
1752 /* Wait for enough room in circular buffer */
1753 while( !p_sys
->b_error
&& ( i_circular_free
= p_sys
->circular
.i_size
-
1754 ( p_sys
->circular
.i_write
- p_sys
->circular
.i_read
) ) == 0 )
1755 vlc_cond_wait( &p_sys
->aout_cond
, &p_sys
->lock
);
1756 if( p_sys
->b_error
)
1759 i_data_offset
= p_sys
->circular
.i_write
% p_sys
->circular
.i_size
;
1760 i_data_size
= __MIN( p_buffer
->i_buffer
- i_buffer_offset
,
1761 p_sys
->circular
.i_size
- i_data_offset
);
1762 i_data_size
= __MIN( i_data_size
, i_circular_free
);
1764 switch( p_sys
->i_write_type
)
1766 case WRITE_BYTEARRAY
:
1767 case WRITE_BYTEARRAYV23
:
1768 (*env
)->SetByteArrayRegion( env
, p_sys
->circular
.u
.p_bytearray
,
1769 i_data_offset
, i_data_size
,
1770 (jbyte
*)p_buffer
->p_buffer
1773 case WRITE_SHORTARRAYV23
:
1774 i_data_offset
&= ~1;
1776 (*env
)->SetShortArrayRegion( env
, p_sys
->circular
.u
.p_shortarray
,
1777 i_data_offset
/ 2, i_data_size
/ 2,
1778 (jshort
*)p_buffer
->p_buffer
1779 + i_buffer_offset
/ 2);
1781 case WRITE_FLOATARRAY
:
1782 i_data_offset
&= ~3;
1784 (*env
)->SetFloatArrayRegion( env
, p_sys
->circular
.u
.p_floatarray
,
1785 i_data_offset
/ 4, i_data_size
/ 4,
1786 (jfloat
*)p_buffer
->p_buffer
1787 + i_buffer_offset
/ 4);
1790 case WRITE_BYTEBUFFER
:
1791 memcpy( p_sys
->circular
.u
.bytebuffer
.p_data
+ i_data_offset
,
1792 p_buffer
->p_buffer
+ i_buffer_offset
, i_data_size
);
1796 i_buffer_offset
+= i_data_size
;
1797 p_sys
->circular
.i_write
+= i_data_size
;
1799 if( !p_sys
->b_thread_waiting
)
1800 vlc_cond_signal( &p_sys
->thread_cond
);
1804 vlc_mutex_unlock( &p_sys
->lock
);
1805 block_Release( p_buffer
);
1810 Pause( audio_output_t
*p_aout
, bool b_pause
, vlc_tick_t i_date
)
1812 aout_sys_t
*p_sys
= p_aout
->sys
;
1814 VLC_UNUSED( i_date
);
1816 vlc_mutex_lock( &p_sys
->lock
);
1818 if( p_sys
->b_error
|| !( env
= GET_ENV() ) )
1823 p_sys
->b_thread_paused
= true;
1824 JNI_AT_CALL_VOID( pause
);
1825 CHECK_AT_EXCEPTION( "pause" );
1828 p_sys
->b_thread_paused
= false;
1829 AudioTrack_ResetPositions( env
, p_aout
);
1830 JNI_AT_CALL_VOID( play
);
1831 CHECK_AT_EXCEPTION( "play" );
1835 vlc_mutex_unlock( &p_sys
->lock
);
1839 Flush( audio_output_t
*p_aout
, bool b_wait
)
1841 aout_sys_t
*p_sys
= p_aout
->sys
;
1844 vlc_mutex_lock( &p_sys
->lock
);
1846 if( p_sys
->b_error
|| !( env
= GET_ENV() ) )
1850 * stop(): Stops playing the audio data. When used on an instance created
1851 * in MODE_STREAM mode, audio will stop playing after the last buffer that
1852 * was written has been played. For an immediate stop, use pause(),
1853 * followed by flush() to discard audio data that hasn't been played back
1856 * flush(): Flushes the audio data currently queued for playback. Any data
1857 * that has not been played back will be discarded. No-op if not stopped
1858 * or paused, or if the track's creation mode is not MODE_STREAM.
1862 /* Wait for the thread to process the circular buffer */
1863 while( !p_sys
->b_error
1864 && p_sys
->circular
.i_read
!= p_sys
->circular
.i_write
)
1865 vlc_cond_wait( &p_sys
->aout_cond
, &p_sys
->lock
);
1866 if( p_sys
->b_error
)
1869 JNI_AT_CALL_VOID( stop
);
1870 if( CHECK_AT_EXCEPTION( "stop" ) )
1874 JNI_AT_CALL_VOID( pause
);
1875 if( CHECK_AT_EXCEPTION( "pause" ) )
1877 JNI_AT_CALL_VOID( flush
);
1879 p_sys
->circular
.i_read
= p_sys
->circular
.i_write
= 0;
1881 /* HACK: Before Android 4.4, the head position is not reset to zero and is
1882 * still moving after a flush or a stop. This prevents to get a precise
1883 * head position and there is no way to know when it stabilizes. Therefore
1884 * recreate an AudioTrack object in that case. The AudioTimestamp class was
1885 * added in API Level 19, so if this class is not found, the Android
1886 * Version is 4.3 or before */
1887 if( !jfields
.AudioTimestamp
.clazz
&& p_sys
->i_samples_written
> 0 )
1889 if( AudioTrack_Recreate( env
, p_aout
) != 0 )
1891 p_sys
->b_error
= true;
1895 AudioTrack_Reset( env
, p_aout
);
1896 JNI_AT_CALL_VOID( play
);
1897 CHECK_AT_EXCEPTION( "play" );
1900 vlc_mutex_unlock( &p_sys
->lock
);
1903 static int DeviceSelect(audio_output_t
*p_aout
, const char *p_id
)
1905 aout_sys_t
*p_sys
= p_aout
->sys
;
1906 enum at_dev at_dev
= AT_DEV_DEFAULT
;
1910 for( unsigned int i
= 0; at_devs
[i
].id
; ++i
)
1912 if( strncmp( p_id
, at_devs
[i
].id
, strlen( at_devs
[i
].id
) ) == 0 )
1914 at_dev
= at_devs
[i
].at_dev
;
1920 long long i_encoding_flags
= 0;
1921 if( at_dev
== AT_DEV_ENCODED
)
1923 const size_t i_prefix_size
= strlen( "encoded:" );
1924 if( strncmp( p_id
, "encoded:", i_prefix_size
) == 0 )
1925 i_encoding_flags
= atoll( p_id
+ i_prefix_size
);
1928 if( at_dev
!= p_sys
->at_dev
|| i_encoding_flags
!= p_sys
->i_encoding_flags
)
1930 p_sys
->at_dev
= at_dev
;
1931 p_sys
->i_encoding_flags
= i_encoding_flags
;
1932 aout_RestartRequest( p_aout
, AOUT_RESTART_OUTPUT
);
1933 msg_Dbg( p_aout
, "selected device: %s", p_id
);
1935 if( at_dev
== AT_DEV_ENCODED
)
1937 static const vlc_fourcc_t enc_fourccs
[] = {
1938 VLC_CODEC_DTS
, VLC_CODEC_A52
, VLC_CODEC_EAC3
, VLC_CODEC_TRUEHD
,
1941 i
< sizeof( enc_fourccs
) / sizeof( enc_fourccs
[0] ); ++i
)
1944 if( AudioTrack_HasEncoding( p_aout
, enc_fourccs
[i
], &b_dtshd
) )
1945 msg_Dbg( p_aout
, "device has %4.4s passthrough support",
1946 b_dtshd
? "dtsh" : (const char *)&enc_fourccs
[i
] );
1950 aout_DeviceReport( p_aout
, p_id
);
1955 Open( vlc_object_t
*obj
)
1957 audio_output_t
*p_aout
= (audio_output_t
*) obj
;
1959 JNIEnv
*env
= GET_ENV();
1961 if( !env
|| !InitJNIFields( p_aout
, env
) )
1962 return VLC_EGENERIC
;
1964 p_sys
= calloc( 1, sizeof (aout_sys_t
) );
1966 if( unlikely( p_sys
== NULL
) )
1969 p_sys
->at_dev
= AT_DEV_DEFAULT
;
1970 vlc_mutex_init(&p_sys
->lock
);
1971 vlc_cond_init(&p_sys
->aout_cond
);
1972 vlc_cond_init(&p_sys
->thread_cond
);
1974 p_aout
->sys
= p_sys
;
1975 p_aout
->start
= Start
;
1976 p_aout
->stop
= Stop
;
1977 p_aout
->play
= Play
;
1978 p_aout
->pause
= Pause
;
1979 p_aout
->flush
= Flush
;
1980 p_aout
->time_get
= TimeGet
;
1981 p_aout
->device_select
= DeviceSelect
;
1983 for( unsigned int i
= 0; at_devs
[i
].id
; ++i
)
1984 aout_HotplugReport(p_aout
, at_devs
[i
].id
, at_devs
[i
].name
);
1986 aout_SoftVolumeInit( p_aout
);
1992 Close( vlc_object_t
*obj
)
1994 audio_output_t
*p_aout
= (audio_output_t
*) obj
;
1995 aout_sys_t
*p_sys
= p_aout
->sys
;
1997 vlc_mutex_destroy(&p_sys
->lock
);
1998 vlc_cond_destroy(&p_sys
->aout_cond
);
1999 vlc_cond_destroy(&p_sys
->thread_cond
);