From 8ff0197a4391a43ea932f7f4218e14d2e259c087 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 28 Mar 2012 21:51:17 +0200 Subject: 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. --- src/output/osx_plugin.c | 93 ++++++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 56 deletions(-) (limited to 'src/output') 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 #include @@ -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 = { -- cgit v1.2.3 From e7a18625177e2831d96baf2f7fc16f23bc99975d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 4 Apr 2012 21:38:29 +0200 Subject: output/jack: workaround for libjack1 crash bug --- src/output/jack_output_plugin.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/output') diff --git a/src/output/jack_output_plugin.c b/src/output/jack_output_plugin.c index 2767d4eb8..bc13c2f85 100644 --- a/src/output/jack_output_plugin.c +++ b/src/output/jack_output_plugin.c @@ -143,6 +143,13 @@ mpd_jack_process(jack_nframes_t nframes, void *arg) for (unsigned i = 0; i < jd->audio_format.channels; ++i) { out = jack_port_get_buffer(jd->ports[i], nframes); + if (out == NULL) + /* workaround for libjack1 bug: if the server + connection fails, the process callback is + invoked anyway, but unable to get a + buffer */ + continue; + jack_ringbuffer_read(jd->ringbuffer[i], (char *)out, available * jack_sample_size); @@ -156,6 +163,12 @@ mpd_jack_process(jack_nframes_t nframes, void *arg) for (unsigned i = jd->audio_format.channels; i < jd->num_source_ports; ++i) { out = jack_port_get_buffer(jd->ports[i], nframes); + if (out == NULL) + /* workaround for libjack1 bug: if the server + connection fails, the process callback is + invoked anyway, but unable to get a + buffer */ + continue; for (jack_nframes_t f = 0; f < nframes; ++f) out[f] = 0.0; -- cgit v1.2.3 From a9edf85a692e6afbe6c5efc9f2784e2c5d191eab Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 4 Apr 2012 21:40:56 +0200 Subject: output/jack: check for connection failure before starting playback --- src/output/jack_output_plugin.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/output') diff --git a/src/output/jack_output_plugin.c b/src/output/jack_output_plugin.c index bc13c2f85..c67fcd38a 100644 --- a/src/output/jack_output_plugin.c +++ b/src/output/jack_output_plugin.c @@ -576,6 +576,9 @@ mpd_jack_open(void *data, struct audio_format *audio_format, GError **error_r) jd->pause = false; + if (jd->client != NULL && jd->shutdown) + mpd_jack_disconnect(jd); + if (jd->client == NULL && !mpd_jack_connect(jd, error_r)) return false; -- cgit v1.2.3 From 5acee73fc85e44179120a5818247fc0760038cff Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 5 Apr 2012 00:03:38 +0200 Subject: encoder/vorbis: generate end-of-stream packet when playback ends Add the encoder_plugin method end(). This is important for the recorder plugin. --- src/output/recorder_output_plugin.c | 2 +- src/output/shout_plugin.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/output') diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c index 10d64106c..2f088a107 100644 --- a/src/output/recorder_output_plugin.c +++ b/src/output/recorder_output_plugin.c @@ -191,7 +191,7 @@ recorder_output_close(void *data) /* flush the encoder and write the rest to the file */ - if (encoder_flush(recorder->encoder, NULL)) + if (encoder_end(recorder->encoder, NULL)) recorder_output_encoder_to_file(recorder, NULL); /* now really close everything */ diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c index 35efd9fc7..27ef3b993 100644 --- a/src/output/shout_plugin.c +++ b/src/output/shout_plugin.c @@ -358,7 +358,7 @@ static void close_shout_conn(struct shout_data * sd) sd->buf.len = 0; if (sd->encoder != NULL) { - if (encoder_flush(sd->encoder, NULL)) + if (encoder_end(sd->encoder, NULL)) write_page(sd, NULL); encoder_close(sd->encoder); -- cgit v1.2.3