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.
This commit is contained in:
parent
de0f46b947
commit
8ff0197a43
2
NEWS
2
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
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
assert(od->buffer != NULL);
|
||||
|
||||
g_mutex_lock(od->mutex);
|
||||
|
||||
bytes_to_copy = MIN(od->len, buffer_size);
|
||||
od->len -= bytes_to_copy;
|
||||
size_t nbytes;
|
||||
const void *src = fifo_buffer_read(od->buffer, &nbytes);
|
||||
|
||||
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;
|
||||
}
|
||||
if (src != NULL) {
|
||||
if (nbytes > buffer_size)
|
||||
nbytes = buffer_size;
|
||||
|
||||
memcpy((unsigned char*)buffer->mData + dest_pos,
|
||||
od->buffer + od->pos, bytes_to_copy);
|
||||
od->pos += bytes_to_copy;
|
||||
|
||||
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)
|
||||
void *dest;
|
||||
size_t max_length;
|
||||
|
||||
while (true) {
|
||||
dest = fifo_buffer_write(od->buffer, &max_length);
|
||||
if (dest != NULL)
|
||||
break;
|
||||
|
||||
/* 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;
|
||||
if (size > max_length)
|
||||
size = max_length;
|
||||
|
||||
nbytes = start < od->pos
|
||||
? od->pos - start
|
||||
: od->buffer_size - start;
|
||||
|
||||
assert(nbytes > 0);
|
||||
|
||||
if (nbytes > size)
|
||||
nbytes = size;
|
||||
|
||||
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 = {
|
||||
|
|
Loading…
Reference in New Issue