X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faudio_output%2Faudiotrack.c;h=8f46a8d7325ef67bb5bad4c66d2a558edb94ec7b;hb=49984f49d3004fec59304b4010c7df56d6a38d78;hp=314125641361142b09b43dab814071ed109ee503;hpb=f57c0a5b109867ebe90a806fe5b6a6e48cee5514;p=vlc diff --git a/modules/audio_output/audiotrack.c b/modules/audio_output/audiotrack.c index 3141256413..8f46a8d732 100644 --- a/modules/audio_output/audiotrack.c +++ b/modules/audio_output/audiotrack.c @@ -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 @@ -91,6 +93,14 @@ typedef int (*AudioTrack_flush)(void *); typedef int (*AudioTrack_pause)(void *); 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; @@ -108,14 +118,19 @@ struct aout_sys_t { AudioTrack_write at_write; AudioTrack_flush at_flush; AudioTrack_pause at_pause; + AudioTrack_getRenderPosition at_getRenderPosition; }; +/* Soft volume helper */ +#include "volume.h" + static void *InitLibrary(struct aout_sys_t *p_sys); static int Open(vlc_object_t *); static void Close(vlc_object_t *); -static void Play(audio_output_t *, block_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") @@ -123,6 +138,7 @@ vlc_module_begin () set_capability("audio output", 225) set_category(CAT_AUDIO) set_subcategory(SUBCAT_AUDIO_AOUT) + add_sw_gain() add_shortcut("android") set_callbacks(Open, Close) vlc_module_end () @@ -158,6 +174,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)) { @@ -174,28 +195,44 @@ static void *InitLibrary(struct aout_sys_t *p_sys) return p_library; } -static int Open(vlc_object_t *p_this) +static int TimeGet(audio_output_t *p_aout, mtime_t *restrict delay) { - struct aout_sys_t *p_sys; - audio_output_t *p_aout = (audio_output_t*)(p_this); + aout_sys_t *p_sys = p_aout->sys; + uint32_t hal, dsp; - int status, size; - int afSampleRate, afFrameCount, afLatency, minBufCount, minFrameCount; - int stream_type, channel, rate, format; + if (!p_sys->at_getRenderPosition) + return -1; - p_sys = (struct aout_sys_t*) malloc(sizeof(aout_sys_t)); - if (!p_sys) - return VLC_ENOMEM; + if (p_sys->at_getRenderPosition(&hal, &dsp, MUSIC)) + return -1; - p_sys->libmedia = InitLibrary(p_sys); - if (!p_sys->libmedia) { - msg_Err(p_aout, "Could not initialize libmedia.so!"); - free(p_sys); - return VLC_EGENERIC; + 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; + + int status, size; + int afSampleRate, afFrameCount, afLatency, minBufCount, minFrameCount; + int stream_type, channel, rate, format; + /* 4000 <= frequency <= 48000 */ - rate = p_aout->format.i_rate; + rate = fmt->i_rate; if (rate < 4000) rate = 4000; if (rate > 48000) @@ -203,23 +240,23 @@ static int Open(vlc_object_t *p_this) stream_type = MUSIC; - /* We can only accept U8 and S16L */ - if (p_aout->format.i_format != VLC_CODEC_U8 && p_aout->format.i_format != VLC_CODEC_S16L) - p_aout->format.i_format = VLC_CODEC_S16L; - format = (p_aout->format.i_format == VLC_CODEC_S16L) ? PCM_16_BIT : PCM_8_BIT; + /* We can only accept U8 and S16N */ + if (fmt->i_format != VLC_CODEC_U8 && fmt->i_format != VLC_CODEC_S16N) + fmt->i_format = VLC_CODEC_S16N; + format = (fmt->i_format == VLC_CODEC_S16N) ? PCM_16_BIT : PCM_8_BIT; /* TODO: android supports more channels */ - p_aout->format.i_original_channels = aout_FormatNbChannels(&p_aout->format); - switch(p_aout->format.i_original_channels) + fmt->i_original_channels = fmt->i_physical_channels; + switch(aout_FormatNbChannels(fmt)) { case 1: channel = CHANNEL_OUT_MONO; - p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; + fmt->i_physical_channels = AOUT_CHAN_CENTER; break; case 2: default: channel = CHANNEL_OUT_STEREO; - p_aout->format.i_physical_channels = AOUT_CHANS_STEREO; + fmt->i_physical_channels = AOUT_CHANS_STEREO; break; } @@ -229,9 +266,7 @@ static int Open(vlc_object_t *p_this) status ^= p_sys->as_getOutputFrameCount(&afFrameCount, stream_type); status ^= p_sys->as_getOutputLatency((uint32_t*)(&afLatency), stream_type); if (status != 0) { - msg_Err(p_aout, "Could not query the AudioStream parameters"); - dlclose(p_sys->libmedia); - free(p_sys); + msg_Err(aout, "Could not query the AudioStream parameters"); return VLC_EGENERIC; } minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate); @@ -242,9 +277,7 @@ static int Open(vlc_object_t *p_this) else { status = p_sys->at_getMinFrameCount(&minFrameCount, stream_type, rate); if (status != 0) { - msg_Err(p_aout, "Could not query the AudioTrack parameters"); - dlclose(p_sys->libmedia); - free(p_sys); + msg_Err(aout, "Could not query the AudioTrack parameters"); return VLC_EGENERIC; } } @@ -253,11 +286,8 @@ static int Open(vlc_object_t *p_this) /* Sizeof(AudioTrack) == 0x58 (not sure) on 2.2.1, this should be enough */ p_sys->AudioTrack = malloc(SIZE_OF_AUDIOTRACK); - if (!p_sys->AudioTrack) { - dlclose(p_sys->libmedia); - free(p_sys); + if (!p_sys->AudioTrack) return VLC_ENOMEM; - } *((uint32_t *) ((uint32_t)p_sys->AudioTrack + SIZE_OF_AUDIOTRACK - 4)) = 0xbaadbaad; // Higher than android 2.2 @@ -279,45 +309,56 @@ static int Open(vlc_object_t *p_this) status = p_sys->at_initCheck(p_sys->AudioTrack); } if (status != 0) { - msg_Err(p_aout, "Cannot create AudioTrack!"); - dlclose(p_sys->libmedia); + msg_Err(aout, "Cannot create AudioTrack!"); free(p_sys->AudioTrack); - free(p_sys); return VLC_EGENERIC; } - p_aout->sys = p_sys; - p_aout->pf_play = Play; - p_aout->pf_pause = Pause; + aout_SoftVolumeStart(aout); + + aout->sys = p_sys; + 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 */ - p_aout->format.i_rate = rate; + fmt->i_rate = rate; return VLC_SUCCESS; } -static void Close(vlc_object_t *p_this) +static void Stop(audio_output_t* p_aout) { - audio_output_t *p_aout = (audio_output_t*)p_this; aout_sys_t *p_sys = p_aout->sys; p_sys->at_stop(p_sys->AudioTrack); p_sys->at_flush(p_sys->AudioTrack); p_sys->at_dtor(p_sys->AudioTrack); free(p_sys->AudioTrack); - dlclose(p_sys->libmedia); - free(p_sys); } -/* FIXME: lipsync */ -static void Play(audio_output_t *p_aout, block_t *p_buffer) +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 ); @@ -325,6 +366,8 @@ static void Play(audio_output_t *p_aout, block_t *p_buffer) static void Pause(audio_output_t *p_aout, bool pause, mtime_t date) { + VLC_UNUSED(date); + aout_sys_t *p_sys = p_aout->sys; if (pause) { @@ -333,3 +376,49 @@ static void Pause(audio_output_t *p_aout, bool pause, mtime_t date) p_sys->at_start(p_sys->AudioTrack); } } + +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; + aout_sys_t *sys = malloc(sizeof (*sys)); + + if (unlikely(sys == NULL)) + return VLC_ENOMEM; + + sys->libmedia = InitLibrary(sys); + if (sys->libmedia == NULL) { + msg_Err(aout, "Could not initialize libmedia.so!"); + free(sys); + return VLC_EGENERIC; + } + + aout->sys = sys; + aout->start = Start; + aout->stop = Stop; + aout_SoftVolumeInit(aout); + return VLC_SUCCESS; +} + +static void Close(vlc_object_t *obj) +{ + audio_output_t *aout = (audio_output_t *)obj; + aout_sys_t *sys = aout->sys; + + dlclose(sys->libmedia); + free(sys); +}