From a77506ae215df09ed02c30f39a3be663a3180d5b Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Fri, 6 Aug 2010 22:18:01 +0200
Subject: [PATCH] output/httpd: forced flush after 32 kB of input data

Avoid buffer underruns on the streaming client, if the encoder is "too
efficient" (e.g. when encoding silence while paused).
---
 src/output/httpd_internal.h      |  8 ++++++++
 src/output/httpd_output_plugin.c | 15 +++++++++++++++
 2 files changed, 23 insertions(+)

diff --git a/src/output/httpd_internal.h b/src/output/httpd_internal.h
index 55843e73f..14a5cf350 100644
--- a/src/output/httpd_internal.h
+++ b/src/output/httpd_internal.h
@@ -51,6 +51,14 @@ struct httpd_output {
 	 */
 	struct encoder *encoder;
 
+	/**
+	 * Number of bytes which were fed into the encoder, without
+	 * ever receiving new output.  This is used to estimate
+	 * whether MPD should manually flush the encoder, to avoid
+	 * buffer underruns in the client.
+	 */
+	size_t unflushed_input;
+
 	/**
 	 * The MIME type produced by the #encoder.
 	 */
diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c
index 140ea7d82..a71e21604 100644
--- a/src/output/httpd_output_plugin.c
+++ b/src/output/httpd_output_plugin.c
@@ -262,12 +262,22 @@ httpd_output_read_page(struct httpd_output *httpd)
 {
 	size_t size = 0, nbytes;
 
+	if (httpd->unflushed_input >= 65536) {
+		/* we have fed a lot of input into the encoder, but it
+		   didn't give anything back yet - flush now to avoid
+		   buffer underruns */
+		encoder_flush(httpd->encoder, NULL);
+		httpd->unflushed_input = 0;
+	}
+
 	do {
 		nbytes = encoder_read(httpd->encoder, httpd->buffer + size,
 				      sizeof(httpd->buffer) - size);
 		if (nbytes == 0)
 			break;
 
+		httpd->unflushed_input = 0;
+
 		size += nbytes;
 	} while (size < sizeof(httpd->buffer));
 
@@ -292,6 +302,9 @@ httpd_output_encoder_open(struct httpd_output *httpd,
 	   bytes of encoder output after opening it, because it has to
 	   be sent to every new client */
 	httpd->header = httpd_output_read_page(httpd);
+
+	httpd->unflushed_input = 0;
+
 	return true;
 }
 
@@ -451,6 +464,8 @@ httpd_output_encode_and_play(struct httpd_output *httpd,
 	if (!success)
 		return false;
 
+	httpd->unflushed_input += size;
+
 	httpd_output_encoder_to_clients(httpd);
 
 	return true;