summaryrefslogtreecommitdiffstats
path: root/audio/out/ao_openal.c
diff options
context:
space:
mode:
authorLAGonauta <lagonauta@gmail.com>2018-04-01 10:26:45 -0300
committerJan Ekström <jeebjp@gmail.com>2018-04-15 00:57:01 +0300
commit614ad62f891f8dc0156ae57631fb9195e56df026 (patch)
tree7e0b8d022a882d6433c8521a62f3436acd80d3d7 /audio/out/ao_openal.c
parent567df04012121a1d8e2a145deff11354fefd4876 (diff)
downloadmpv-614ad62f891f8dc0156ae57631fb9195e56df026.tar.bz2
mpv-614ad62f891f8dc0156ae57631fb9195e56df026.tar.xz
ao/openal: Add option to set buffering characteristics
One can now set the number of buffers and the buffer size. This can reduce the CPU usage and the total latency stays mostly the same. As there are sync mechanisms the A/V sync continue intact and working. It also modifies 6.1 channel order, as per OpenAL spec and add AOPLAY_FINAL_CHUNK support
Diffstat (limited to 'audio/out/ao_openal.c')
-rw-r--r--audio/out/ao_openal.c85
1 files changed, 62 insertions, 23 deletions
diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c
index 4d82a09ddb..9381d2a906 100644
--- a/audio/out/ao_openal.c
+++ b/audio/out/ao_openal.c
@@ -57,9 +57,10 @@
#include "options/m_option.h"
#define MAX_CHANS MP_NUM_CHANNELS
-#define NUM_BUF 128
-#define CHUNK_SAMPLES 256
-static ALuint buffers[NUM_BUF];
+#define MAX_BUF 128
+#define MAX_SAMPLES 32768
+static ALuint buffers[MAX_BUF];
+static ALuint buffer_size[MAX_BUF];
static ALuint source;
static int cur_buf;
@@ -69,7 +70,8 @@ static struct ao *ao_data;
struct priv {
ALenum al_format;
- int chunk_size;
+ int num_buffers;
+ int num_samples;
int direct_channels;
};
@@ -171,10 +173,11 @@ static ALenum get_supported_layout(int format, int channels)
// close audio device
static void uninit(struct ao *ao)
{
+ struct priv *p = ao->priv;
alSourceStop(source);
alSourcei(source, AL_BUFFER, 0);
- alDeleteBuffers(NUM_BUF, buffers);
+ alDeleteBuffers(p->num_buffers, buffers);
alDeleteSources(1, &source);
ALCcontext *ctx = alcGetCurrentContext();
@@ -217,7 +220,11 @@ static int init(struct ao *ao)
cur_buf = 0;
unqueue_buf = 0;
- alGenBuffers(NUM_BUF, buffers);
+ for (int i = 0; i < p->num_buffers; ++i) {
+ buffer_size[i] = 0;
+ }
+
+ alGenBuffers(p->num_buffers, buffers);
alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq);
if (alcGetError(dev) == ALC_NO_ERROR && freq)
@@ -259,7 +266,7 @@ static int init(struct ao *ao)
MP_CHMAP4(FL, FR, BL, BR), // 4.0
{0}, // 5.0
MP_CHMAP6(FL, FR, FC, LFE, BL, BR), // 5.1
- MP_CHMAP7(FL, FR, FC, LFE, BC, SL, SR), // 6.1
+ MP_CHMAP7(FL, FR, FC, LFE, SL, SR, BC), // 6.1
MP_CHMAP8(FL, FR, FC, LFE, BL, BR, SL, SR), // 7.1
};
ao->channels = possible_layouts[num_channels];
@@ -272,8 +279,7 @@ static int init(struct ao *ao)
goto err_out;
}
- p->chunk_size = CHUNK_SAMPLES * af_fmt_to_bytes(ao->format);
- ao->period_size = CHUNK_SAMPLES;
+ ao->period_size = p->num_samples;
return 0;
err_out:
@@ -291,10 +297,11 @@ static void drain(struct ao *ao)
}
}
-static void unqueue_buffers(void)
+static void unqueue_buffers(struct ao *ao)
{
+ struct priv *q = ao->priv;
ALint p;
- int till_wrap = NUM_BUF - unqueue_buf;
+ int till_wrap = q->num_buffers - unqueue_buf;
alGetSourcei(source, AL_BUFFERS_PROCESSED, &p);
if (p >= till_wrap) {
alSourceUnqueueBuffers(source, till_wrap, &buffers[unqueue_buf]);
@@ -313,7 +320,7 @@ static void unqueue_buffers(void)
static void reset(struct ao *ao)
{
alSourceStop(source);
- unqueue_buffers();
+ unqueue_buffers(ao);
}
/**
@@ -334,13 +341,14 @@ static void audio_resume(struct ao *ao)
static int get_space(struct ao *ao)
{
+ struct priv *p = ao->priv;
ALint queued;
- unqueue_buffers();
+ unqueue_buffers(ao);
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
- queued = NUM_BUF - queued - 3;
+ queued = p->num_buffers - queued;
if (queued < 0)
return 0;
- return queued * CHUNK_SAMPLES;
+ return p->num_samples * queued;
}
/**
@@ -349,25 +357,44 @@ static int get_space(struct ao *ao)
static int play(struct ao *ao, void **data, int samples, int flags)
{
struct priv *p = ao->priv;
- ALint state;
- int num = samples / CHUNK_SAMPLES;
+
+ int buffered_samples = 0;
+ int num = 0;
+ if (flags & AOPLAY_FINAL_CHUNK) {
+ num = 1;
+ buffered_samples = samples;
+ } else {
+ num = samples / p->num_samples;
+ buffered_samples = num * p->num_samples;
+ }
+
for (int i = 0; i < num; i++) {
char *d = *data;
- d += i * p->chunk_size * ao->channels.num;
- alBufferData(buffers[cur_buf], p->al_format, d, p->chunk_size * ao->channels.num, ao->samplerate);
+ if (flags & AOPLAY_FINAL_CHUNK) {
+ buffer_size[cur_buf] = samples;
+ } else {
+ buffer_size[cur_buf] = p->num_samples;
+ }
+ d += i * buffer_size[cur_buf] * ao->sstride;
+ alBufferData(buffers[cur_buf], p->al_format, d,
+ buffer_size[cur_buf] * ao->sstride, ao->samplerate);
alSourceQueueBuffers(source, 1, &buffers[cur_buf]);
- cur_buf = (cur_buf + 1) % NUM_BUF;
+ cur_buf = (cur_buf + 1) % p->num_buffers;
}
+
+ ALint state;
alGetSourcei(source, AL_SOURCE_STATE, &state);
if (state != AL_PLAYING) // checked here in case of an underrun
alSourcePlay(source);
- return num * CHUNK_SAMPLES;
+
+ return buffered_samples;
}
static double get_delay(struct ao *ao)
{
+ struct priv *p = ao->priv;
ALint queued;
- unqueue_buffers();
+ unqueue_buffers(ao);
alGetSourcei(source, AL_BUFFERS_QUEUED, &queued);
double soft_source_latency = 0;
@@ -384,7 +411,12 @@ static double get_delay(struct ao *ao)
soft_source_latency = -offset;
}
- return (queued * CHUNK_SAMPLES / (double)ao->samplerate) + soft_source_latency;
+ int queued_samples = 0;
+ for (int i = 0, index = cur_buf; i < queued; ++i) {
+ queued_samples += buffer_size[index];
+ index = (index + 1) % p->num_buffers;
+ }
+ return (queued_samples / (double)ao->samplerate) + soft_source_latency;
}
#define OPT_BASE_STRUCT struct priv
@@ -403,7 +435,14 @@ const struct ao_driver audio_out_openal = {
.reset = reset,
.drain = drain,
.priv_size = sizeof(struct priv),
+ .priv_defaults = &(const struct priv) {
+ .num_buffers = 4,
+ .num_samples = 8192,
+ .direct_channels = 0,
+ },
.options = (const struct m_option[]) {
+ OPT_INTRANGE("num-buffers", num_buffers, 0, 2, MAX_BUF),
+ OPT_INTRANGE("num-samples", num_samples, 0, 256, MAX_SAMPLES),
OPT_FLAG("direct-channels", direct_channels, 0),
{0}
},