summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/ao.rst8
-rw-r--r--audio/out/ao_openal.c85
2 files changed, 70 insertions, 23 deletions
diff --git a/DOCS/man/ao.rst b/DOCS/man/ao.rst
index 5beca55384..3fc1ba9734 100644
--- a/DOCS/man/ao.rst
+++ b/DOCS/man/ao.rst
@@ -112,6 +112,14 @@ Available audio output drivers are:
``openal``
Experimental OpenAL audio output driver
+ ``--openal-num-buffers=<2-128>``
+ Specify the number of audio buffers to use. Lower values are better for
+ lower CPU usage. Default: 4.
+
+ ``--openal-num-samples=<256-32768>``
+ Specify the number of complete samples to use for each buffer. Higher
+ values are better for lower CPU usage. Default: 8192.
+
``--openal-direct-channels=<yes|no>``
Enable OpenAL Soft's direct channel extension when available to avoid
tinting the sound with ambisonics or HRTF.
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}
},