From f398e4c324a15021aea66118e679144586f4cc51 Mon Sep 17 00:00:00 2001
From: Steven Blackburn <beeka@sourceforge.net>
Date: Wed, 28 Sep 2011 23:18:38 +0100
Subject: [PATCH 2/2] Add support for streaming to a DLNA client

The Naim Uniti does not appear to support icecast-style streaming of FLAC
music but does support the codec from a DLNA server. This change looks for
"transferMode.dlna.org: Streaming" in the HTTP request header and responds
with something the Uniti (and hopefully other DLNA clients) accepts.

The only difference in the DLNA streaming mode is the reponse header and
that icecast metadata is disabled. If a client request indicates both modes
are supported, the DLNA mode is preferred (as the Uniti says it supports
both but then rejects a FLAC ICY stream).

Note: This change may be specific to Naim equipment (the only device it was
tested on). E.g. the hardcoding of Content-Length which works but is not a
logically correct value. The change should be backwards-compatible, so
only those clients requesting a DLNA stream will see any difference.
---
 src/output/httpd_client.c |   43 ++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 38 insertions(+), 5 deletions(-)

diff --git a/src/output/httpd_client.c b/src/output/httpd_client.c
index 10892ae..f656ca0 100644
--- a/src/output/httpd_client.c
+++ b/src/output/httpd_client.c
@@ -93,6 +93,11 @@ struct httpd_client {
 	 */
 	size_t current_position;
 
+        /**
+         * If DLNA streaming was an option.
+         */
+        bool dlna_streaming_requested;
+
 	/* ICY */
 
 	/**
@@ -236,6 +241,15 @@ httpd_client_handle_line(struct httpd_client *client, const char *line)
 			return true;
 		}
 
+		if (g_ascii_strncasecmp(line, "transferMode.dlna.org: Streaming", 32) == 0) {
+			/* Send as dlna */
+			client->dlna_streaming_requested = true;
+			/* metadata is not supported by dlna streaming, so disable it */
+			client->metadata_supported = false;
+			client->metadata_requested = false;
+			return true;
+		}
+
 		/* expect more request headers */
 		return true;
 	}
@@ -287,16 +301,23 @@ httpd_client_send_response(struct httpd_client *client)
 	assert(client != NULL);
 	assert(client->state == RESPONSE);
 
-	if (!client->metadata_requested) {
+        if (client->dlna_streaming_requested) {
+		g_warning("httpd: sending a DLNA stream to the client");
 		g_snprintf(buffer, sizeof(buffer),
-			   "HTTP/1.1 200 OK\r\n"
+			   "HTTP/1.1 206 OK\r\n"
 			   "Content-Type: %s\r\n"
+			   "Content-Length: 10000\r\n"
+			   "Content-RangeX: 0-1000000/1000000\r\n"
+			   "transferMode.dlna.org: Streaming\r\n"
+			   "Accept-Ranges: bytes\r\n"
 			   "Connection: close\r\n"
-			   "Pragma: no-cache\r\n"
-			   "Cache-Control: no-cache, no-store\r\n"
+			   "realTimeInfo.dlna.org: DLNA.ORG_TLAG=*\r\n"
+			   "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0\r\n"
 			   "\r\n",
 			   client->httpd->content_type);
-	} else {
+
+        } else if (client->metadata_requested) {
+		g_warning("httpd: sending a icecast stream to the client");
 		gchar *metadata_header;
 
 		metadata_header = icy_server_metadata_header(
@@ -309,6 +330,17 @@ httpd_client_send_response(struct httpd_client *client)
 		g_strlcpy(buffer, metadata_header, sizeof(buffer));
 
 		g_free(metadata_header);
+
+       } else { /* revert to a normal HTTP request */
+		g_warning("httpd: sending an HTTP response to the client");
+		g_snprintf(buffer, sizeof(buffer),
+			   "HTTP/1.1 200 OK\r\n"
+			   "Content-Type: %s\r\n"
+			   "Connection: close\r\n"
+			   "Pragma: no-cache\r\n"
+			   "Cache-Control: no-cache, no-store\r\n"
+			   "\r\n",
+			   client->httpd->content_type);
 	}
 
 	status = g_io_channel_write_chars(client->channel,
@@ -476,6 +508,7 @@ httpd_client_new(struct httpd_output *httpd, int fd, bool metadata_supported)
 	client->input = fifo_buffer_new(4096);
 	client->state = REQUEST;
 
+	client->dlna_streaming_requested = false;
 	client->metadata_supported = metadata_supported;
 	client->metadata_requested = false;
 	client->metadata_sent = true;
-- 
1.7.4.4

