diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/out/ao_openal.c | 85 |
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} }, |