ao_opensles: rework the heuristic of buffer/enqueue size setting

ao->device_buffer will only affect the enqueue size if the latter
is not specified. In other word, its intended purpose will solely
be setting/guarding the soft buffer size.

This guarantees that the soft buffer size will be consistent no
matter a specific enqueue size is set or not. (In the past it
would drop to the default of the generic audio-buffer option.)

opensles-frames-per-buffer has been renamed to opensles-frames-per
-enqueue, as it was never purposed to set the soft buffer size. It
will only make sure the size is never smaller than itself, just as
before.

opensles-buffer-size-in-ms is introduced to allow easy tuning of
the relative (i.e. in time) soft buffer size (and enqueue size,
unless the aforementioned option is set). As "device buffer" never
really made sense in this AO, this option OVERRIDES audio-buffer
whenever its value (including the default) is larger than 0.

Setting opensl-buffer-size-in-ms to 1 allows you to equate the soft
buffer size to the absolute enqueue size set with opensl-frames-per
-enqueue conveniently (unless it is less than 1ms).

When both are set to 0, audio-buffer will be the ultimate fallback.
If audio-buffer is also 0, the AO errors out.
This commit is contained in:
Tom Yan 2018-07-21 03:48:45 +08:00 committed by sfan5
parent 8baad91e7b
commit e1bd5288b7
1 changed files with 36 additions and 18 deletions

View File

@ -35,12 +35,13 @@ struct priv {
SLBufferQueueItf buffer_queue;
SLEngineItf engine;
SLPlayItf play;
char *buf;
size_t buffer_size;
void *buf;
int bytes_per_enqueue;
pthread_mutex_t buffer_lock;
double audio_latency;
int cfg_frames_per_buffer;
int frames_per_enqueue;
int buffer_size_in_ms;
};
#define DESTROY(thing) \
@ -65,7 +66,6 @@ static void uninit(struct ao *ao)
free(p->buf);
p->buf = NULL;
p->buffer_size = 0;
}
#undef DESTROY
@ -75,26 +75,22 @@ static void buffer_callback(SLBufferQueueItf buffer_queue, void *context)
struct ao *ao = context;
struct priv *p = ao->priv;
SLresult res;
void *data[1];
double delay;
pthread_mutex_lock(&p->buffer_lock);
data[0] = p->buf;
delay = 2 * p->buffer_size / (double)ao->bps;
delay = 2 * p->frames_per_enqueue / (double)ao->samplerate;
delay += p->audio_latency;
ao_read_data(ao, data, p->buffer_size / ao->sstride,
ao_read_data(ao, &p->buf, p->frames_per_enqueue,
mp_time_us() + 1000000LL * delay);
res = (*buffer_queue)->Enqueue(buffer_queue, p->buf, p->buffer_size);
res = (*buffer_queue)->Enqueue(buffer_queue, p->buf, p->bytes_per_enqueue);
if (res != SL_RESULT_SUCCESS)
MP_ERR(ao, "Failed to Enqueue: %d\n", res);
pthread_mutex_unlock(&p->buffer_lock);
}
#define DEFAULT_BUFFER_SIZE_MS 250
#define CHK(stmt) \
{ \
SLresult res = stmt; \
@ -143,17 +139,35 @@ static int init(struct ao *ao)
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
pcm.sampleRate = ao->samplerate * 1000;
if (p->cfg_frames_per_buffer)
ao->device_buffer = p->cfg_frames_per_buffer;
else
ao->device_buffer = ao->samplerate * DEFAULT_BUFFER_SIZE_MS / 1000;
p->buffer_size = ao->device_buffer * ao->channels.num *
if (p->buffer_size_in_ms) {
ao->device_buffer = ao->samplerate * p->buffer_size_in_ms / 1000;
// As the purpose of buffer_size_in_ms is to request a specific
// soft buffer size:
ao->def_buffer = 0;
}
// But it does not make sense if it is smaller than the enqueue size:
if (p->frames_per_enqueue) {
ao->device_buffer = MPMAX(ao->device_buffer, p->frames_per_enqueue);
} else {
if (ao->device_buffer) {
p->frames_per_enqueue = ao->device_buffer;
} else if (ao->def_buffer) {
p->frames_per_enqueue = ao->def_buffer * ao->samplerate;
} else {
MP_ERR(ao, "Enqueue size is not set and can neither be derived\n");
goto error;
}
}
p->bytes_per_enqueue = p->frames_per_enqueue * ao->channels.num *
af_fmt_to_bytes(ao->format);
p->buf = calloc(1, p->buffer_size);
p->buf = calloc(1, p->bytes_per_enqueue);
if (!p->buf) {
MP_ERR(ao, "Failed to allocate device buffer\n");
goto error;
}
int r = pthread_mutex_init(&p->buffer_lock, NULL);
if (r) {
MP_ERR(ao, "Failed to initialize the mutex: %d\n", r);
@ -236,8 +250,12 @@ const struct ao_driver audio_out_opensles = {
.resume = resume,
.priv_size = sizeof(struct priv),
.priv_defaults = &(const struct priv) {
.buffer_size_in_ms = 250,
},
.options = (const struct m_option[]) {
OPT_INTRANGE("frames-per-buffer", cfg_frames_per_buffer, 0, 1, 96000),
OPT_INTRANGE("frames-per-enqueue", frames_per_enqueue, 0, 1, 96000),
OPT_INTRANGE("buffer-size-in-ms", buffer_size_in_ms, 0, 0, 500),
{0}
},
.options_prefix = "opensles",