Commit 985ff5cb authored by Thomas Guillem's avatar Thomas Guillem

audiotrack: handle HW latency

Since Android 4.3 there is a hidden method that retrieve the audio hardware
latency: AudioSystem.getOutputLatency() (that should not be used according to
the android comments).

This latency should not be used when we use AudioTrack.getTimestamp since it
already take into account the hardware latency. So why adding a new method ?
Because AudioTrack.getTimestamp don't work with Bluetooth (it returns false).

This fix lip sync with Bluetooth audio.
parent b50b9c35
...@@ -83,6 +83,7 @@ struct aout_sys_t { ...@@ -83,6 +83,7 @@ struct aout_sys_t {
mtime_t p_us[SMOOTHPOS_SAMPLE_COUNT]; mtime_t p_us[SMOOTHPOS_SAMPLE_COUNT];
mtime_t i_us; mtime_t i_us;
mtime_t i_last_time; mtime_t i_last_time;
mtime_t i_latency_us;
} smoothpos; } smoothpos;
uint64_t i_samples_written; /* number of samples written since last flush */ uint64_t i_samples_written; /* number of samples written since last flush */
...@@ -181,6 +182,10 @@ static struct ...@@ -181,6 +182,10 @@ static struct
bool has_ERROR_DEAD_OBJECT; bool has_ERROR_DEAD_OBJECT;
jint STREAM_MUSIC; jint STREAM_MUSIC;
} AudioManager; } AudioManager;
struct {
jclass clazz;
jmethodID getOutputLatency;
} AudioSystem;
struct { struct {
jclass clazz; jclass clazz;
jmethodID ctor; jmethodID ctor;
...@@ -297,6 +302,15 @@ InitJNIFields( audio_output_t *p_aout ) ...@@ -297,6 +302,15 @@ InitJNIFields( audio_output_t *p_aout )
"nanoTime", "J", true ); "nanoTime", "J", true );
} }
/* AudioSystem class init */
GET_CLASS( "android/media/AudioSystem", false );
if( clazz )
{
jfields.AudioSystem.clazz = (jclass) (*env)->NewGlobalRef( env, clazz );
GET_ID( GetStaticMethodID, AudioSystem.getOutputLatency,
"getOutputLatency", "(I)I", false );
}
/* AudioFormat class init */ /* AudioFormat class init */
GET_CLASS( "android/media/AudioFormat", true ); GET_CLASS( "android/media/AudioFormat", true );
GET_CONST_INT( AudioFormat.ENCODING_PCM_8BIT, "ENCODING_PCM_8BIT", true ); GET_CONST_INT( AudioFormat.ENCODING_PCM_8BIT, "ENCODING_PCM_8BIT", true );
...@@ -507,6 +521,7 @@ AudioTrack_ResetPositions( JNIEnv *env, audio_output_t *p_aout ) ...@@ -507,6 +521,7 @@ AudioTrack_ResetPositions( JNIEnv *env, audio_output_t *p_aout )
p_sys->smoothpos.i_idx = 0; p_sys->smoothpos.i_idx = 0;
p_sys->smoothpos.i_last_time = 0; p_sys->smoothpos.i_last_time = 0;
p_sys->smoothpos.i_us = 0; p_sys->smoothpos.i_us = 0;
p_sys->smoothpos.i_latency_us = 0;
} }
/** /**
...@@ -541,9 +556,20 @@ AudioTrack_GetSmoothPositionUs( JNIEnv *env, audio_output_t *p_aout ) ...@@ -541,9 +556,20 @@ AudioTrack_GetSmoothPositionUs( JNIEnv *env, audio_output_t *p_aout )
for( uint32_t i = 0; i < p_sys->smoothpos.i_count; ++i ) for( uint32_t i = 0; i < p_sys->smoothpos.i_count; ++i )
p_sys->smoothpos.i_us += p_sys->smoothpos.p_us[i]; p_sys->smoothpos.i_us += p_sys->smoothpos.p_us[i];
p_sys->smoothpos.i_us /= p_sys->smoothpos.i_count; p_sys->smoothpos.i_us /= p_sys->smoothpos.i_count;
if( jfields.AudioSystem.getOutputLatency )
{
int i_latency_ms = JNI_CALL( CallStaticIntMethod,
jfields.AudioSystem.clazz,
jfields.AudioSystem.getOutputLatency,
jfields.AudioManager.STREAM_MUSIC );
p_sys->smoothpos.i_latency_us = i_latency_ms > 0 ?
i_latency_ms * 1000L : 0;
}
} }
if( p_sys->smoothpos.i_us != 0 ) if( p_sys->smoothpos.i_us != 0 )
return p_sys->smoothpos.i_us + i_now; return p_sys->smoothpos.i_us + i_now - p_sys->smoothpos.i_latency_us;
else else
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment