// _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
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;
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")
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 ()
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)) {
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)
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 = p_aout->format.i_physical_channels;
- switch(aout_FormatNbChannels(&p_aout->format))
+ 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;
}
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);
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;
}
}
/* 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
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->play = Play;
- p_aout->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 );
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);
+}