Commit 141c6716 authored by Rafaël Carré's avatar Rafaël Carré

audiotrack: implement time synchronization

There is still a random offset between A/V which stays
constant until there's a flush but hopefully testing should
give a clue how to fix it.

Note: the symbols required are present only since 2.2
parent 81e9a6a8
......@@ -71,6 +71,8 @@ typedef int (*AudioSystem_getOutputSamplingRate)(int *, int);
// _ZN7android10AudioTrack16getMinFrameCountEPiij
typedef int (*AudioTrack_getMinFrameCount)(int *, int, unsigned int);
// _ZN7android11AudioSystem17getRenderPositionEPjS1_i
typedef int (*AudioTrack_getRenderPosition)(uint32_t *, uint32_t *, int);
// _ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_ii
typedef void (*AudioTrack_ctor)(void *, int, unsigned int, int, int, int, unsigned int, void (*)(int, void *, void *), void *, int, int);
// _ZN7android10AudioTrackC1EijiiijPFviPvS1_ES1_i
......@@ -94,6 +96,11 @@ struct aout_sys_t {
float soft_gain;
bool soft_mute;
int rate;
uint32_t samples_written;
uint32_t initial;
int bytes_per_frame;
void *libmedia;
void *AudioTrack;
......@@ -111,6 +118,7 @@ struct aout_sys_t {
AudioTrack_write at_write;
AudioTrack_flush at_flush;
AudioTrack_pause at_pause;
AudioTrack_getRenderPosition at_getRenderPosition;
};
/* Soft volume helper */
......@@ -122,6 +130,7 @@ static int Open(vlc_object_t *);
static void Close(vlc_object_t *);
static void Play(audio_output_t*, block_t*);
static void Pause (audio_output_t *, bool, mtime_t);
static void Flush (audio_output_t *, bool);
vlc_module_begin ()
set_shortname("AudioTrack")
......@@ -164,6 +173,11 @@ static void *InitLibrary(struct aout_sys_t *p_sys)
p_sys->at_flush = (AudioTrack_flush)(dlsym(p_library, "_ZN7android10AudioTrack5flushEv"));
p_sys->at_pause = (AudioTrack_pause)(dlsym(p_library, "_ZN7android10AudioTrack5pauseEv"));
/* this symbol can have different names depending on the mangling */
p_sys->at_getRenderPosition = (AudioTrack_getRenderPosition)(dlsym(p_library, "_ZN7android11AudioSystem17getRenderPositionEPjS1_i"));
if (!p_sys->at_getRenderPosition)
p_sys->at_getRenderPosition = (AudioTrack_getRenderPosition)(dlsym(p_library, "_ZN7android11AudioSystem17getRenderPositionEPjS1_19audio_stream_type_t"));
/* We need the first 3 or the last 1 */
if (!((p_sys->as_getOutputFrameCount && p_sys->as_getOutputLatency && p_sys->as_getOutputSamplingRate)
|| p_sys->at_getMinFrameCount)) {
......@@ -180,6 +194,34 @@ static void *InitLibrary(struct aout_sys_t *p_sys)
return p_library;
}
static int TimeGet(audio_output_t *p_aout, mtime_t *restrict delay)
{
aout_sys_t *p_sys = p_aout->sys;
uint32_t hal, dsp;
if (!p_sys->at_getRenderPosition)
return -1;
if (p_sys->at_getRenderPosition(&hal, &dsp, MUSIC))
return -1;
hal = (uint32_t)((uint64_t)hal * p_sys->rate / 44100);
if (p_sys->samples_written == 0) {
p_sys->initial = hal;
return -1;
}
hal -= p_sys->initial;
if (hal == 0)
return -1;
if (delay)
*delay = ((mtime_t)p_sys->samples_written - hal) * CLOCK_FREQ / p_sys->rate;
return 0;
}
static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
{
struct aout_sys_t *p_sys = aout->sys;
......@@ -277,8 +319,15 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
aout->time_get = NULL;
aout->play = Play;
aout->pause = Pause;
aout->flush = Flush;
aout->time_get = TimeGet;
p_sys->rate = rate;
p_sys->samples_written = 0;
p_sys->bytes_per_frame = aout_FormatNbChannels(fmt) * (format == PCM_16_BIT) ? 2 : 1;
p_sys->at_start(p_sys->AudioTrack);
TimeGet(aout, NULL); /* Gets the initial value of DAC samples counter */
fmt->i_rate = rate;
......@@ -295,14 +344,20 @@ static void Stop(audio_output_t* p_aout)
free(p_sys->AudioTrack);
}
/* FIXME: lipsync */
static void Play(audio_output_t* p_aout, block_t* p_buffer)
{
aout_sys_t *p_sys = p_aout->sys;
size_t length = 0;
while (length < p_buffer->i_buffer) {
length += p_sys->at_write(p_sys->AudioTrack, (char*)(p_buffer->p_buffer) + length, p_buffer->i_buffer - length);
while (p_buffer->i_buffer) {
int ret = p_sys->at_write(p_sys->AudioTrack, p_buffer->p_buffer, p_buffer->i_buffer);
if (ret < 0) {
msg_Err(p_aout, "Write failed (error %d)", ret);
break;
}
p_sys->samples_written += ret / p_sys->bytes_per_frame;
p_buffer->p_buffer += ret;
p_buffer->i_buffer -= ret;
}
block_Release( p_buffer );
......@@ -321,6 +376,21 @@ static void Pause(audio_output_t *p_aout, bool pause, mtime_t date)
}
}
static void Flush (audio_output_t *p_aout, bool wait)
{
aout_sys_t *p_sys = p_aout->sys;
if (wait) {
mtime_t delay;
if (!TimeGet(p_aout, &delay))
msleep(delay);
} else {
p_sys->at_stop(p_sys->AudioTrack);
p_sys->at_flush(p_sys->AudioTrack);
p_sys->samples_written = 0;
p_sys->at_start(p_sys->AudioTrack);
}
}
static int Open(vlc_object_t *obj)
{
audio_output_t *aout = (audio_output_t *)obj;
......
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