aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2012-03-28 21:51:17 +0200
committerMax Kellermann <max@duempel.org>2012-03-28 21:51:17 +0200
commit8ff0197a4391a43ea932f7f4218e14d2e259c087 (patch)
treee6d0e155cb3394c6e1f7d45e918b94e2d4661736
parentde0f46b947c6016bb72379527ea7af75190b5c4b (diff)
downloadmpd-8ff0197a4391a43ea932f7f4218e14d2e259c087.tar.gz
mpd-8ff0197a4391a43ea932f7f4218e14d2e259c087.tar.xz
mpd-8ff0197a4391a43ea932f7f4218e14d2e259c087.zip
output/osx: use the fifo_buffer library instead of rolling own
The existing buffer implementation has a major flaw: it is unable to re-fill the buffer until it has been consumed completely, leading to many occasions where the render callback needs to generate silence, just because the play() implementation was unable to append more data. The fifo_buffer library handles that well.
Diffstat (limited to '')
-rw-r--r--NEWS2
-rw-r--r--src/output/osx_plugin.c93
2 files changed, 39 insertions, 56 deletions
diff --git a/NEWS b/NEWS
index 317679bd3..ddb612c3b 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,8 @@ ver 0.16.8 (2012/??/??)
* decoder:
- vorbis (and others): fix seeking at startup
- ffmpeg: read the "year" tag
+* output:
+ - osx: fix stuttering due to buffering bug
* fix endless loop in text file reader
diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c
index 5284afc29..501dcec10 100644
--- a/src/output/osx_plugin.c
+++ b/src/output/osx_plugin.c
@@ -19,6 +19,7 @@
#include "config.h"
#include "output_api.h"
+#include "fifo_buffer.h"
#include <glib.h>
#include <AudioUnit/AudioUnit.h>
@@ -31,10 +32,8 @@ struct osx_output {
AudioUnit au;
GMutex *mutex;
GCond *condition;
- char *buffer;
- size_t buffer_size;
- size_t pos;
- size_t len;
+
+ struct fifo_buffer *buffer;
};
/**
@@ -64,11 +63,6 @@ osx_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
oo->mutex = g_mutex_new();
oo->condition = g_cond_new();
- oo->pos = 0;
- oo->len = 0;
- oo->buffer = NULL;
- oo->buffer_size = 0;
-
return oo;
}
@@ -76,7 +70,6 @@ static void osx_output_finish(void *data)
{
struct osx_output *od = data;
- g_free(od->buffer);
g_mutex_free(od->mutex);
g_cond_free(od->condition);
g_free(od);
@@ -87,7 +80,7 @@ static void osx_output_cancel(void *data)
struct osx_output *od = data;
g_mutex_lock(od->mutex);
- od->len = 0;
+ fifo_buffer_clear(od->buffer);
g_mutex_unlock(od->mutex);
}
@@ -98,6 +91,8 @@ static void osx_output_close(void *data)
AudioOutputUnitStop(od->au);
AudioUnitUninitialize(od->au);
CloseComponent(od->au);
+
+ fifo_buffer_free(od->buffer);
}
static OSStatus
@@ -111,37 +106,29 @@ osx_render(void *vdata,
struct osx_output *od = (struct osx_output *) vdata;
AudioBuffer *buffer = &buffer_list->mBuffers[0];
size_t buffer_size = buffer->mDataByteSize;
- size_t bytes_to_copy;
- size_t trailer_length;
- size_t dest_pos = 0;
- g_mutex_lock(od->mutex);
+ assert(od->buffer != NULL);
- bytes_to_copy = MIN(od->len, buffer_size);
- od->len -= bytes_to_copy;
+ g_mutex_lock(od->mutex);
- trailer_length = od->buffer_size - od->pos;
- if (bytes_to_copy > trailer_length) {
- memcpy((unsigned char*)buffer->mData + dest_pos,
- od->buffer + od->pos, trailer_length);
- od->pos = 0;
- dest_pos += trailer_length;
- bytes_to_copy -= trailer_length;
- }
+ size_t nbytes;
+ const void *src = fifo_buffer_read(od->buffer, &nbytes);
- memcpy((unsigned char*)buffer->mData + dest_pos,
- od->buffer + od->pos, bytes_to_copy);
- od->pos += bytes_to_copy;
+ if (src != NULL) {
+ if (nbytes > buffer_size)
+ nbytes = buffer_size;
- if (od->pos >= od->buffer_size)
- od->pos = 0;
+ memcpy(buffer->mData, src, nbytes);
+ fifo_buffer_consume(od->buffer, nbytes);
+ } else
+ nbytes = 0;
g_cond_signal(od->condition);
g_mutex_unlock(od->mutex);
- if (bytes_to_copy < buffer_size)
- memset((unsigned char*)buffer->mData + bytes_to_copy, 0,
- buffer_size - bytes_to_copy);
+ if (nbytes < buffer_size)
+ memset((unsigned char*)buffer->mData + nbytes, 0,
+ buffer_size - nbytes);
return 0;
}
@@ -244,15 +231,12 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
}
/* create a buffer of 1s */
- od->buffer_size = (audio_format->sample_rate) *
- audio_format_frame_size(audio_format);
- od->buffer = g_realloc(od->buffer, od->buffer_size);
-
- od->pos = 0;
- od->len = 0;
+ od->buffer = fifo_buffer_new(audio_format->sample_rate *
+ audio_format_frame_size(audio_format));
status = AudioOutputUnitStart(od->au);
if (status != 0) {
+ fifo_buffer_free(od->buffer);
g_set_error(error, osx_output_quark(), 0,
"unable to start audio output: %s",
GetMacOSStatusCommentString(status));
@@ -267,33 +251,30 @@ osx_output_play(void *data, const void *chunk, size_t size,
G_GNUC_UNUSED GError **error)
{
struct osx_output *od = data;
- size_t start, nbytes;
g_mutex_lock(od->mutex);
- while (od->len >= od->buffer_size)
- /* wait for some free space in the buffer */
- g_cond_wait(od->condition, od->mutex);
-
- start = od->pos + od->len;
- if (start >= od->buffer_size)
- start -= od->buffer_size;
+ void *dest;
+ size_t max_length;
- nbytes = start < od->pos
- ? od->pos - start
- : od->buffer_size - start;
+ while (true) {
+ dest = fifo_buffer_write(od->buffer, &max_length);
+ if (dest != NULL)
+ break;
- assert(nbytes > 0);
+ /* wait for some free space in the buffer */
+ g_cond_wait(od->condition, od->mutex);
+ }
- if (nbytes > size)
- nbytes = size;
+ if (size > max_length)
+ size = max_length;
- memcpy(od->buffer + start, chunk, nbytes);
- od->len += nbytes;
+ memcpy(dest, chunk, size);
+ fifo_buffer_append(od->buffer, size);
g_mutex_unlock(od->mutex);
- return nbytes;
+ return size;
}
const struct audio_output_plugin osxPlugin = {