From 5acee73fc85e44179120a5818247fc0760038cff Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Thu, 5 Apr 2012 00:03:38 +0200
Subject: [PATCH] encoder/vorbis: generate end-of-stream packet when playback
 ends

Add the encoder_plugin method end().  This is important for the
recorder plugin.
---
 NEWS                                |  1 +
 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 +-
 test/run_encoder.c                  |  2 +-
 test/test_vorbis_encoder.c          |  2 +-
 9 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/NEWS b/NEWS
index caa3cd073..5a215dadd 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ ver 0.16.8 (2012/??/??)
   - ffmpeg: read the "year" tag
 * encoder:
   - vorbis: generate end-of-stream packet before tag
+  - vorbis: generate end-of-stream packet when playback ends
 * output:
   - jack: check for connection failure before starting playback
   - jack: workaround for libjack1 crash bug
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);
diff --git a/test/run_encoder.c b/test/run_encoder.c
index 16e633029..4c05a06c7 100644
--- a/test/run_encoder.c
+++ b/test/run_encoder.c
@@ -121,7 +121,7 @@ int main(int argc, char **argv)
 		encoder_to_stdout(encoder);
 	}
 
-	ret = encoder_flush(encoder, &error);
+	ret = encoder_end(encoder, &error);
 	if (!ret) {
 		g_printerr("encoder_flush() failed: %s\n",
 			   error->message);
diff --git a/test/test_vorbis_encoder.c b/test/test_vorbis_encoder.c
index 370a8a59e..969ab7687 100644
--- a/test/test_vorbis_encoder.c
+++ b/test/test_vorbis_encoder.c
@@ -99,7 +99,7 @@ main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
 
 	/* finish */
 
-	success = encoder_flush(encoder, NULL);
+	success = encoder_end(encoder, NULL);
 	assert(success);
 
 	encoder_to_stdout(encoder);