aboutsummaryrefslogtreecommitdiffstats
path: root/src/output/openal_output_plugin.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/output/openal_output_plugin.c (renamed from src/output/openal_plugin.c)128
1 files changed, 68 insertions, 60 deletions
diff --git a/src/output/openal_plugin.c b/src/output/openal_output_plugin.c
index e5db8ac34..ebd35ef12 100644
--- a/src/output/openal_plugin.c
+++ b/src/output/openal_output_plugin.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2010 The Music Player Daemon Project
+ * Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,8 @@
*/
#include "config.h"
+#include "openal_output_plugin.h"
#include "output_api.h"
-#include "timer.h"
#include <glib.h>
@@ -38,12 +38,13 @@
#define NUM_BUFFERS 16
struct openal_data {
+ struct audio_output base;
+
const char *device_name;
ALCdevice *device;
ALCcontext *context;
- Timer *timer;
ALuint buffers[NUM_BUFFERS];
- int filled;
+ unsigned filled;
ALuint source;
ALenum format;
ALuint frequency;
@@ -80,6 +81,29 @@ openal_audio_format(struct audio_format *audio_format)
}
}
+G_GNUC_PURE
+static inline ALint
+openal_get_source_i(const struct openal_data *od, ALenum param)
+{
+ ALint value;
+ alGetSourcei(od->source, param, &value);
+ return value;
+}
+
+G_GNUC_PURE
+static inline bool
+openal_has_processed(const struct openal_data *od)
+{
+ return openal_get_source_i(od, AL_BUFFERS_PROCESSED) > 0;
+}
+
+G_GNUC_PURE
+static inline ALint
+openal_is_playing(const struct openal_data *od)
+{
+ return openal_get_source_i(od, AL_SOURCE_STATE) == AL_PLAYING;
+}
+
static bool
openal_setup_context(struct openal_data *od,
GError **error)
@@ -106,23 +130,8 @@ openal_setup_context(struct openal_data *od,
return true;
}
-static void
-openal_unqueue_buffers(struct openal_data *od)
-{
- ALint num;
- ALuint buffer;
-
- alGetSourcei(od->source, AL_BUFFERS_QUEUED, &num);
-
- while (num--) {
- alSourceUnqueueBuffers(od->source, 1, &buffer);
- }
-}
-
-static void *
-openal_init(G_GNUC_UNUSED const struct audio_format *audio_format,
- const struct config_param *param,
- G_GNUC_UNUSED GError **error)
+static struct audio_output *
+openal_init(const struct config_param *param, GError **error_r)
{
const char *device_name = config_get_block_string(param, "device", NULL);
struct openal_data *od;
@@ -132,35 +141,33 @@ openal_init(G_GNUC_UNUSED const struct audio_format *audio_format,
}
od = g_new(struct openal_data, 1);
+ if (!ao_base_init(&od->base, &openal_output_plugin, param, error_r)) {
+ g_free(od);
+ return NULL;
+ }
+
od->device_name = device_name;
- return od;
+ return &od->base;
}
static void
-openal_finish(void *data)
+openal_finish(struct audio_output *ao)
{
- struct openal_data *od = data;
+ struct openal_data *od = (struct openal_data *)ao;
+ ao_base_finish(&od->base);
g_free(od);
}
static bool
-openal_open(void *data, struct audio_format *audio_format,
+openal_open(struct audio_output *ao, struct audio_format *audio_format,
GError **error)
{
- struct openal_data *od = data;
+ struct openal_data *od = (struct openal_data *)ao;
od->format = openal_audio_format(audio_format);
- if (!od->format) {
- struct audio_format_string s;
- g_set_error(error, openal_output_quark(), 0,
- "Unsupported audio format: %s",
- audio_format_to_string(audio_format, &s));
- return false;
- }
-
if (!openal_setup_context(od, error)) {
return false;
}
@@ -184,18 +191,16 @@ openal_open(void *data, struct audio_format *audio_format,
}
od->filled = 0;
- od->timer = timer_new(audio_format);
od->frequency = audio_format->sample_rate;
return true;
}
static void
-openal_close(void *data)
+openal_close(struct audio_output *ao)
{
- struct openal_data *od = data;
+ struct openal_data *od = (struct openal_data *)ao;
- timer_free(od->timer);
alcMakeContextCurrent(od->context);
alDeleteSources(1, &od->source);
alDeleteBuffers(NUM_BUFFERS, od->buffers);
@@ -203,61 +208,63 @@ openal_close(void *data)
alcCloseDevice(od->device);
}
+static unsigned
+openal_delay(struct audio_output *ao)
+{
+ struct openal_data *od = (struct openal_data *)ao;
+
+ return od->filled < NUM_BUFFERS || openal_has_processed(od)
+ ? 0
+ /* we don't know exactly how long we must wait for the
+ next buffer to finish, so this is a random
+ guess: */
+ : 50;
+}
+
static size_t
-openal_play(void *data, const void *chunk, size_t size,
+openal_play(struct audio_output *ao, const void *chunk, size_t size,
G_GNUC_UNUSED GError **error)
{
- struct openal_data *od = data;
+ struct openal_data *od = (struct openal_data *)ao;
ALuint buffer;
- ALint num, state;
if (alcGetCurrentContext() != od->context) {
alcMakeContextCurrent(od->context);
}
- alGetSourcei(od->source, AL_BUFFERS_PROCESSED, &num);
-
if (od->filled < NUM_BUFFERS) {
/* fill all buffers */
buffer = od->buffers[od->filled];
od->filled++;
} else {
/* wait for processed buffer */
- while (num < 1) {
- if (!od->timer->started) {
- timer_start(od->timer);
- } else {
- timer_sync(od->timer);
- }
-
- timer_add(od->timer, size);
-
- alGetSourcei(od->source, AL_BUFFERS_PROCESSED, &num);
- }
+ while (!openal_has_processed(od))
+ g_usleep(10);
alSourceUnqueueBuffers(od->source, 1, &buffer);
}
alBufferData(buffer, od->format, chunk, size, od->frequency);
alSourceQueueBuffers(od->source, 1, &buffer);
- alGetSourcei(od->source, AL_SOURCE_STATE, &state);
- if (state != AL_PLAYING) {
+ if (!openal_is_playing(od))
alSourcePlay(od->source);
- }
return size;
}
static void
-openal_cancel(void *data)
+openal_cancel(struct audio_output *ao)
{
- struct openal_data *od = data;
+ struct openal_data *od = (struct openal_data *)ao;
od->filled = 0;
alcMakeContextCurrent(od->context);
alSourceStop(od->source);
- openal_unqueue_buffers(od);
+
+ /* force-unqueue all buffers */
+ alSourcei(od->source, AL_BUFFER, 0);
+ od->filled = 0;
}
const struct audio_output_plugin openal_output_plugin = {
@@ -266,6 +273,7 @@ const struct audio_output_plugin openal_output_plugin = {
.finish = openal_finish,
.open = openal_open,
.close = openal_close,
+ .delay = openal_delay,
.play = openal_play,
.cancel = openal_cancel,
};