From 4f500149af0d4e50938b5c93b6c16a5de4e43685 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 19 Mar 2012 19:51:19 +0100 Subject: text_input_stream: detect end-of-file Fixes endless loop when the last line of a text file was not terminated (bug 3470). --- src/text_input_stream.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/text_input_stream.c b/src/text_input_stream.c index 29fb6dce6..6d0436d41 100644 --- a/src/text_input_stream.c +++ b/src/text_input_stream.c @@ -24,6 +24,7 @@ #include +#include #include struct text_input_stream { @@ -67,7 +68,12 @@ text_input_stream_read(struct text_input_stream *tis) do { dest = fifo_buffer_write(tis->buffer, &length); - if (dest != NULL) { + if (dest != NULL && length >= 2) { + /* reserve one byte for the null terminator if + the last line is not terminated by a + newline character */ + --length; + nbytes = input_stream_read(tis->is, dest, length, &error); if (nbytes > 0) @@ -77,13 +83,22 @@ text_input_stream_read(struct text_input_stream *tis) g_error_free(error); return NULL; } - } + } else + nbytes = 0; src = fifo_buffer_read(tis->buffer, &length); if (src == NULL) return NULL; p = memchr(src, '\n', length); + if (p == NULL && nbytes == 0) { + /* end of file (or line too long): terminate + the current line */ + dest = fifo_buffer_write(tis->buffer, &nbytes); + assert(dest != NULL); + *(char *)dest = '\n'; + fifo_buffer_append(tis->buffer, 1); + } } while (p == NULL); length = p - src + 1; -- cgit v1.2.3 From b9e64d04720cc114aa405a86332b7cb1321db8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Wed, 15 Feb 2012 20:52:48 +0100 Subject: decoder/audiofile: fix compiler warnings with libaudiofile 0.3.3 This might break older versions, I didn't test. --- src/decoder/audiofile_decoder_plugin.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/decoder/audiofile_decoder_plugin.c b/src/decoder/audiofile_decoder_plugin.c index a8311a3c9..de236a6e2 100644 --- a/src/decoder/audiofile_decoder_plugin.c +++ b/src/decoder/audiofile_decoder_plugin.c @@ -64,14 +64,14 @@ audiofile_file_read(AFvirtualfile *vfile, void *data, size_t length) return nbytes; } -static long +static AFfileoffset audiofile_file_length(AFvirtualfile *vfile) { struct input_stream *is = (struct input_stream *) vfile->closure; return is->size; } -static long +static AFfileoffset audiofile_file_tell(AFvirtualfile *vfile) { struct input_stream *is = (struct input_stream *) vfile->closure; @@ -86,8 +86,8 @@ audiofile_file_destroy(AFvirtualfile *vfile) vfile->closure = NULL; } -static long -audiofile_file_seek(AFvirtualfile *vfile, long offset, int is_relative) +static AFfileoffset +audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset offset, int is_relative) { struct input_stream *is = (struct input_stream *) vfile->closure; int whence = (is_relative ? SEEK_CUR : SEEK_SET); -- cgit v1.2.3 From 79eb7623efb3105094dcb77f8688e39b8288155e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 19 Mar 2012 20:37:17 +0100 Subject: event_pipe, test: explicitly ignore write() return value Some compilers are very picky, but we really aren't interested in the return value. --- src/event_pipe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/event_pipe.c b/src/event_pipe.c index 5b519984f..484b7a625 100644 --- a/src/event_pipe.c +++ b/src/event_pipe.c @@ -159,5 +159,6 @@ void event_pipe_emit_fast(enum pipe_event event) assert((unsigned)event < PIPE_EVENT_MAX); pipe_events[event] = true; - (void)write(event_pipe[1], "", 1); + + G_GNUC_UNUSED ssize_t nbytes = write(event_pipe[1], "", 1); } -- cgit v1.2.3 From de0f46b947c6016bb72379527ea7af75190b5c4b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 10:32:33 -0500 Subject: Use g_message and not g_debug when removing song When adding or updating a song, we get a log message even if debug is not enabled. It seems odd that removing a song shouldn't be done at the same log level; otherwise looking at the log leads you to believe songs are never removed from the library on update. Signed-off-by: Dan McGee --- src/update_remove.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/update_remove.c b/src/update_remove.c index f7c2342a2..8d60be222 100644 --- a/src/update_remove.c +++ b/src/update_remove.c @@ -49,7 +49,7 @@ song_remove_event(void) assert(removed_song != NULL); uri = song_get_uri(removed_song); - g_debug("removing: %s", uri); + g_message("removing %s", uri); g_free(uri); #ifdef ENABLE_SQLITE -- cgit v1.2.3 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') 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 83174de420eb2a63d77a7953081b3fb360ecbc31 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 4 Apr 2012 08:56:45 +0200 Subject: update: properly skip symlinks in path that is to be updated. --- src/update_walk.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/update_walk.c b/src/update_walk.c index 03fa78456..5d2f778ff 100644 --- a/src/update_walk.c +++ b/src/update_walk.c @@ -848,6 +848,9 @@ directory_make_child_checked(struct directory *parent, const char *path) return NULL; } + if (skip_symlink(parent, path)) + return NULL; + /* if we're adding directory paths, make sure to delete filenames with potentially the same name */ conflicting = songvec_find(&parent->songs, base); @@ -896,7 +899,8 @@ updatePath(const char *path) name = g_path_get_basename(path); - if (stat_directory_child(parent, name, &st) == 0) + if (!skip_symlink(parent, name) && + stat_directory_child(parent, name, &st) == 0) updateInDirectory(parent, name, &st); else delete_name_in(parent, name); -- cgit v1.2.3 From 09aa0dc676ead2a76c720a033271c8c7dbef1548 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 4 Apr 2012 12:22:16 +0200 Subject: uri: remove g_basename() call from uri_get_suffix() g_basename() is deprecated in GLib 2.32. Instead, verify that the suffix does not have a backslash, to catch Windows path names. --- src/uri.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/uri.c b/src/uri.c index f4d590a60..bd5aa0249 100644 --- a/src/uri.c +++ b/src/uri.c @@ -34,13 +34,13 @@ bool uri_has_scheme(const char *uri) const char * uri_get_suffix(const char *uri) { - const char *suffix = strrchr(g_basename(uri), '.'); + const char *suffix = strrchr(uri, '.'); if (suffix == NULL) return NULL; ++suffix; - if (strchr(suffix, '/') != NULL) + if (strpbrk(suffix, "/\\") != NULL) return NULL; return suffix; -- cgit v1.2.3 From d8e423df1a3c4ea7db547089c8cf0647268cfd44 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 4 Apr 2012 19:08:05 +0200 Subject: directory: use strrchr() instead of g_basename() g_basename() is deprecated in GLib 2.32. --- src/directory.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/directory.c b/src/directory.c index fa15d41b1..1e3a4cf28 100644 --- a/src/directory.c +++ b/src/directory.c @@ -68,7 +68,15 @@ directory_free(struct directory *directory) const char * directory_get_name(const struct directory *directory) { - return g_basename(directory->path); + assert(!directory_is_root(directory)); + assert(directory->path != NULL); + + const char *slash = strrchr(directory->path, '/'); + assert((slash == NULL) == directory_is_root(directory->parent)); + + return slash != NULL + ? slash + 1 + : directory->path; } void -- 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') 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') 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 98a468a1013401298205390db43b63a6ff3a3478 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 4 Apr 2012 23:10:38 +0200 Subject: encoder/vorbis: generate end-of-stream packet before tag Don't reset the ogg_stream_state object, because this discards the end-of-stream packet that was just added. --- src/encoder/vorbis_encoder.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'src') diff --git a/src/encoder/vorbis_encoder.c b/src/encoder/vorbis_encoder.c index 38a998bd2..519d7cbf6 100644 --- a/src/encoder/vorbis_encoder.c +++ b/src/encoder/vorbis_encoder.c @@ -285,8 +285,6 @@ vorbis_encoder_pre_tag(struct encoder *_encoder, G_GNUC_UNUSED GError **error) vorbis_analysis_init(&encoder->vd, &encoder->vi); vorbis_block_init(&encoder->vd, &encoder->vb); - ogg_stream_reset(&encoder->os); - encoder->flush = true; return true; } -- cgit v1.2.3 From 466c337bcb71fb6bca0384300586e7213685d53d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 5 Apr 2012 00:05:21 +0200 Subject: encoder_plugin: add state assertions --- src/encoder_plugin.h | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/encoder_plugin.h b/src/encoder_plugin.h index fb00413e6..af3f76a40 100644 --- a/src/encoder_plugin.h +++ b/src/encoder_plugin.h @@ -22,6 +22,7 @@ #include +#include #include #include @@ -32,6 +33,10 @@ struct tag; struct encoder { const struct encoder_plugin *plugin; + +#ifndef NDEBUG + bool open, pre_tag, tag; +#endif }; struct encoder_plugin { @@ -73,6 +78,10 @@ encoder_struct_init(struct encoder *encoder, const struct encoder_plugin *plugin) { encoder->plugin = plugin; + +#ifndef NDEBUG + encoder->open = false; +#endif } /** @@ -98,6 +107,8 @@ encoder_init(const struct encoder_plugin *plugin, static inline void encoder_finish(struct encoder *encoder) { + assert(!encoder->open); + encoder->plugin->finish(encoder); } @@ -116,7 +127,14 @@ static inline bool encoder_open(struct encoder *encoder, struct audio_format *audio_format, GError **error) { - return encoder->plugin->open(encoder, audio_format, error); + assert(!encoder->open); + + bool success = encoder->plugin->open(encoder, audio_format, error); +#ifndef NDEBUG + encoder->open = success; + encoder->pre_tag = encoder->tag = false; +#endif + return success; } /** @@ -128,8 +146,14 @@ encoder_open(struct encoder *encoder, struct audio_format *audio_format, static inline void encoder_close(struct encoder *encoder) { + assert(encoder->open); + if (encoder->plugin->close != NULL) encoder->plugin->close(encoder); + +#ifndef NDEBUG + encoder->open = false; +#endif } /** @@ -143,6 +167,10 @@ encoder_close(struct encoder *encoder) static inline bool encoder_flush(struct encoder *encoder, GError **error) { + assert(encoder->open); + assert(!encoder->pre_tag); + assert(!encoder->tag); + /* this method is optional */ return encoder->plugin->flush != NULL ? encoder->plugin->flush(encoder, error) @@ -162,10 +190,19 @@ encoder_flush(struct encoder *encoder, GError **error) static inline bool encoder_pre_tag(struct encoder *encoder, GError **error) { + assert(encoder->open); + assert(!encoder->pre_tag); + assert(!encoder->tag); + /* this method is optional */ - return encoder->plugin->pre_tag != NULL + bool success = encoder->plugin->pre_tag != NULL ? encoder->plugin->pre_tag(encoder, error) : true; + +#ifndef NDEBUG + encoder->pre_tag = success; +#endif + return success; } /** @@ -182,6 +219,14 @@ encoder_pre_tag(struct encoder *encoder, GError **error) static inline bool encoder_tag(struct encoder *encoder, const struct tag *tag, GError **error) { + assert(encoder->open); + assert(!encoder->pre_tag); + assert(encoder->tag); + +#ifndef NDEBUG + encoder->tag = false; +#endif + /* this method is optional */ return encoder->plugin->tag != NULL ? encoder->plugin->tag(encoder, tag, error) @@ -201,6 +246,10 @@ static inline bool encoder_write(struct encoder *encoder, const void *data, size_t length, GError **error) { + assert(encoder->open); + assert(!encoder->pre_tag); + assert(!encoder->tag); + return encoder->plugin->write(encoder, data, length, error); } @@ -215,6 +264,16 @@ encoder_write(struct encoder *encoder, const void *data, size_t length, static inline size_t encoder_read(struct encoder *encoder, void *dest, size_t length) { + assert(encoder->open); + assert(!encoder->pre_tag || !encoder->tag); + +#ifndef NDEBUG + if (encoder->pre_tag) { + encoder->pre_tag = false; + encoder->tag = true; + } +#endif + return encoder->plugin->read(encoder, dest, length); } -- 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/encoder/flac_encoder.c | 1 + src/encoder/twolame_encoder.c | 1 + src/encoder/vorbis_encoder.c | 1 + src/encoder_plugin.h | 39 +++++++++++++++++++++++++++++++++++-- src/output/recorder_output_plugin.c | 2 +- src/output/shout_plugin.c | 2 +- 6 files changed, 42 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/encoder/flac_encoder.c b/src/encoder/flac_encoder.c index 6389513ef..e2c455e3a 100644 --- a/src/encoder/flac_encoder.c +++ b/src/encoder/flac_encoder.c @@ -354,6 +354,7 @@ const struct encoder_plugin flac_encoder_plugin = { .finish = flac_encoder_finish, .open = flac_encoder_open, .close = flac_encoder_close, + .end = flac_encoder_flush, .flush = flac_encoder_flush, .write = flac_encoder_write, .read = flac_encoder_read, diff --git a/src/encoder/twolame_encoder.c b/src/encoder/twolame_encoder.c index d20af551b..073c3128f 100644 --- a/src/encoder/twolame_encoder.c +++ b/src/encoder/twolame_encoder.c @@ -300,6 +300,7 @@ const struct encoder_plugin twolame_encoder_plugin = { .finish = twolame_encoder_finish, .open = twolame_encoder_open, .close = twolame_encoder_close, + .end = twolame_encoder_flush, .flush = twolame_encoder_flush, .write = twolame_encoder_write, .read = twolame_encoder_read, diff --git a/src/encoder/vorbis_encoder.c b/src/encoder/vorbis_encoder.c index 519d7cbf6..9f09b2ac7 100644 --- a/src/encoder/vorbis_encoder.c +++ b/src/encoder/vorbis_encoder.c @@ -405,6 +405,7 @@ const struct encoder_plugin vorbis_encoder_plugin = { .finish = vorbis_encoder_finish, .open = vorbis_encoder_open, .close = vorbis_encoder_close, + .end = vorbis_encoder_pre_tag, .flush = vorbis_encoder_flush, .pre_tag = vorbis_encoder_pre_tag, .tag = vorbis_encoder_tag, diff --git a/src/encoder_plugin.h b/src/encoder_plugin.h index af3f76a40..70eee51a2 100644 --- a/src/encoder_plugin.h +++ b/src/encoder_plugin.h @@ -35,7 +35,7 @@ struct encoder { const struct encoder_plugin *plugin; #ifndef NDEBUG - bool open, pre_tag, tag; + bool open, pre_tag, tag, end; #endif }; @@ -53,6 +53,8 @@ struct encoder_plugin { void (*close)(struct encoder *encoder); + bool (*end)(struct encoder *encoder, GError **error); + bool (*flush)(struct encoder *encoder, GError **error); bool (*pre_tag)(struct encoder *encoder, GError **error); @@ -132,7 +134,7 @@ encoder_open(struct encoder *encoder, struct audio_format *audio_format, bool success = encoder->plugin->open(encoder, audio_format, error); #ifndef NDEBUG encoder->open = success; - encoder->pre_tag = encoder->tag = false; + encoder->pre_tag = encoder->tag = encoder->end = false; #endif return success; } @@ -156,6 +158,35 @@ encoder_close(struct encoder *encoder) #endif } +/** + * Ends the stream: flushes the encoder object, generate an + * end-of-stream marker (if applicable), make everything which might + * currently be buffered available by encoder_read(). + * + * After this function has been called, the encoder may not be usable + * for more data, and only encoder_read() and encoder_close() can be + * called. + * + * @param encoder the encoder + * @param error location to store the error occuring, or NULL to ignore errors. + * @return true on success + */ +static inline bool +encoder_end(struct encoder *encoder, GError **error) +{ + assert(encoder->open); + assert(!encoder->end); + +#ifndef NDEBUG + encoder->end = true; +#endif + + /* this method is optional */ + return encoder->plugin->end != NULL + ? encoder->plugin->end(encoder, error) + : true; +} + /** * Flushes an encoder object, make everything which might currently be * buffered available by encoder_read(). @@ -170,6 +201,7 @@ encoder_flush(struct encoder *encoder, GError **error) assert(encoder->open); assert(!encoder->pre_tag); assert(!encoder->tag); + assert(!encoder->end); /* this method is optional */ return encoder->plugin->flush != NULL @@ -193,6 +225,7 @@ encoder_pre_tag(struct encoder *encoder, GError **error) assert(encoder->open); assert(!encoder->pre_tag); assert(!encoder->tag); + assert(!encoder->end); /* this method is optional */ bool success = encoder->plugin->pre_tag != NULL @@ -222,6 +255,7 @@ encoder_tag(struct encoder *encoder, const struct tag *tag, GError **error) assert(encoder->open); assert(!encoder->pre_tag); assert(encoder->tag); + assert(!encoder->end); #ifndef NDEBUG encoder->tag = false; @@ -249,6 +283,7 @@ encoder_write(struct encoder *encoder, const void *data, size_t length, assert(encoder->open); assert(!encoder->pre_tag); assert(!encoder->tag); + assert(!encoder->end); return encoder->plugin->write(encoder, data, length, error); } 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