[rhythmbox] daap: use souphttpsrc instead of our own HTTP client code



commit 4072afad6f912d9e90616c3a63b28a1ec13592ec
Author: Jay L. T. Cornwall <jay jcornwall me uk>
Date:   Wed Dec 30 13:03:34 2009 +1000

    daap: use souphttpsrc instead of our own HTTP client code
    
    This converts our DAAP source element into a bin containing a
    souphttpsrc element, using the extra-headers property to set the DAAP
    headers (which don't really do anything any more anyway).
    
    rb_daap_connection_get_headers now returns a GstStructure, since that's
    what souphttpsrc takes.

 plugins/daap/rb-daap-connection.c |   51 ++--
 plugins/daap/rb-daap-connection.h |    6 +-
 plugins/daap/rb-daap-source.c     |    7 +-
 plugins/daap/rb-daap-source.h     |    7 +-
 plugins/daap/rb-daap-src.c        |  626 +++++--------------------------------
 5 files changed, 117 insertions(+), 580 deletions(-)
---
diff --git a/plugins/daap/rb-daap-connection.c b/plugins/daap/rb-daap-connection.c
index 1237a47..5a2a66b 100644
--- a/plugins/daap/rb-daap-connection.c
+++ b/plugins/daap/rb-daap-connection.c
@@ -1656,16 +1656,15 @@ rb_daap_connection_do_something (RBDAAPConnection *connection)
 	return FALSE;
 }
 
-char *
+GstStructure *
 rb_daap_connection_get_headers (RBDAAPConnection *connection,
-				const gchar *uri,
-				gint64 bytes)
+				const gchar *uri)
 {
 	RBDAAPConnectionPrivate *priv = connection->priv;
-	GString *headers;
+	GstStructure *headers;
 	char hash[33] = {0};
 	char *norb_daap_uri = (char *)uri;
-	char *s;
+	char *request_id_str;
 
 	priv->request_id++;
 
@@ -1678,37 +1677,39 @@ rb_daap_connection_get_headers (RBDAAPConnection *connection,
 			       (guchar*)hash,
 			       priv->request_id);
 
-	headers = g_string_new ("Accept: */*\r\n"
-				"Cache-Control: no-cache\r\n"
-				"User-Agent: " RB_DAAP_USER_AGENT "\r\n"
-				"Accept-Language: en-us, en;q=5.0\r\n"
-				"Client-DAAP-Access-Index: 2\r\n"
-				"Client-DAAP-Version: 3.0\r\n");
-	g_string_append_printf (headers,
-				"Client-DAAP-Validation: %s\r\n"
-				"Client-DAAP-Request-ID: %d\r\n"
-				"Connection: close\r\n",
-				hash, priv->request_id);
+	request_id_str = g_strdup_printf ("%d", priv->request_id);
+	headers = gst_structure_new ("extra-headers",
+				     "Accept",                   G_TYPE_STRING, "*/*",
+				     "Cache-Control",            G_TYPE_STRING, "no-cache",
+				     "User-Agent",               G_TYPE_STRING, RB_DAAP_USER_AGENT,
+				     "Accept-Language",          G_TYPE_STRING, "en-us, en;q=5.0",
+				     "Client-DAAP-Access-Index", G_TYPE_STRING, "2",
+				     "Client-DAAP-Version",      G_TYPE_STRING, "3.0",
+				     "Client-DAAP-Validation",   G_TYPE_STRING, hash,
+				     "Client-DAAP-Request-ID",   G_TYPE_STRING, request_id_str,
+				     "Connection",               G_TYPE_STRING, "close",
+				     NULL);
+	g_free (request_id_str);
 
 	if (priv->password_protected) {
 		char *user_pass;
 		char *token;
+		char *auth_str;
 
 		user_pass = g_strdup_printf ("%s:%s", priv->username, priv->password);
 		token = g_base64_encode ((guchar *)user_pass, strlen (user_pass));
-		g_string_append_printf (headers, "Authentication: Basic %s\r\n", token);
+		auth_str = g_strdup_printf ("Basic %s", token);
+
+		gst_structure_set (headers,
+				   "Authentication", G_TYPE_STRING, auth_str,
+				   NULL);
+
+		g_free (auth_str);
 		g_free (token);
 		g_free (user_pass);
 	}
 
-	if (bytes != 0) {
-		g_string_append_printf (headers,"Range: bytes=%"G_GINT64_FORMAT"-\r\n", bytes);
-	}
-
-	s = headers->str;
-	g_string_free (headers, FALSE);
-
-	return s;
+	return headers;
 }
 
 GSList *
diff --git a/plugins/daap/rb-daap-connection.h b/plugins/daap/rb-daap-connection.h
index 11235ca..07f7c59 100644
--- a/plugins/daap/rb-daap-connection.h
+++ b/plugins/daap/rb-daap-connection.h
@@ -33,6 +33,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
+#include <gst/gst.h>
 #include "rhythmdb.h"
 
 G_BEGIN_DECLS
@@ -109,9 +110,8 @@ void               rb_daap_connection_disconnect      (RBDAAPConnection        *
 						       RBDAAPConnectionCallback callback,
 						       gpointer                 user_data);
 
-char *             rb_daap_connection_get_headers     (RBDAAPConnection         *connection,
-						       const char               *uri,
-						       gint64                    bytes);
+GstStructure *     rb_daap_connection_get_headers     (RBDAAPConnection         *connection,
+						       const char               *uri);
 
 GSList *           rb_daap_connection_get_playlists   (RBDAAPConnection         *connection);
 
diff --git a/plugins/daap/rb-daap-source.c b/plugins/daap/rb-daap-source.c
index 309e7aa..5e59e0a 100644
--- a/plugins/daap/rb-daap-source.c
+++ b/plugins/daap/rb-daap-source.c
@@ -726,17 +726,16 @@ rb_daap_source_show_popup (RBSource *source)
 	return TRUE;
 }
 
-char *
+GstStructure *
 rb_daap_source_get_headers (RBDAAPSource *source,
-			    const char *uri,
-			    gint64 bytes)
+			    const char *uri)
 {
 	/* If there is no connection then bail */
 	if (source->priv->connection == NULL) {
 		return NULL;
 	}
 
-	return rb_daap_connection_get_headers (source->priv->connection, uri, bytes);
+	return rb_daap_connection_get_headers (source->priv->connection, uri);
 }
 
 static char *
diff --git a/plugins/daap/rb-daap-source.h b/plugins/daap/rb-daap-source.h
index 914bd82..3e92ab1 100644
--- a/plugins/daap/rb-daap-source.h
+++ b/plugins/daap/rb-daap-source.h
@@ -34,6 +34,8 @@
 #include "rb-browser-source.h"
 #include "rb-plugin.h"
 
+#include <gst/gst.h>
+
 G_BEGIN_DECLS
 
 #define RB_TYPE_DAAP_SOURCE         (rb_daap_source_get_type ())
@@ -67,9 +69,8 @@ RBSource *	rb_daap_source_new 		(RBShell *shell,
 
 void 		rb_daap_source_disconnect 	(RBDAAPSource *daap_source);
 
-gchar *		rb_daap_source_get_headers 	(RBDAAPSource *source,
-					    	 const gchar *uri,
-					    	 gint64 bytes);
+GstStructure *	rb_daap_source_get_headers 	(RBDAAPSource *source,
+						 const gchar *uri);
 
 G_END_DECLS
 
diff --git a/plugins/daap/rb-daap-src.c b/plugins/daap/rb-daap-src.c
index c581cd1..60f66af 100644
--- a/plugins/daap/rb-daap-src.c
+++ b/plugins/daap/rb-daap-src.c
@@ -30,35 +30,11 @@
 
 #include "config.h"
 
-#include <string.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/ioctl.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <libsoup/soup.h>
-
-#include <glib/gi18n.h>
 #include <gst/gst.h>
-#include <gst/base/gstbasesrc.h>
-#include <gst/base/gstpushsrc.h>
+#include <string.h>
 
-#include "rb-daap-source.h"
-#include "rb-daap-src.h"
-#include "rb-debug.h"
 #include "rb-daap-plugin.h"
-
-/* needed for portability to some systems, e.g. Solaris */
-#ifndef MSG_NOSIGNAL
-#define MSG_NOSIGNAL 0
-#endif
-
+#include "rb-daap-src.h"
 
 #define RB_TYPE_DAAP_SRC (rb_daap_src_get_type())
 #define RB_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RB_TYPE_DAAP_SRC,RBDAAPSrc))
@@ -66,38 +42,23 @@
 #define RB_IS_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RB_TYPE_DAAP_SRC))
 #define RB_IS_DAAP_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),RB_TYPE_DAAP_SRC))
 
-#define RESPONSE_BUFFER_SIZE	(4096)
-
 typedef struct _RBDAAPSrc RBDAAPSrc;
 typedef struct _RBDAAPSrcClass RBDAAPSrcClass;
 
 struct _RBDAAPSrc
 {
-	GstPushSrc parent;
+	GstBin parent;
 
 	/* uri */
 	gchar *daap_uri;
 
-	/* connection */
-	int sock_fd;
-	gchar *buffer_base;
-	gchar *buffer;
-	guint buffer_size;
-	guint32 bytes_per_read;
-	gboolean chunked;
-	gboolean first_chunk;
-
-	gint64 size;
-
-	/* Seek stuff */
-	gint64 curoffset;
-	gint64 seek_bytes;
-	gboolean do_seek;
+	GstElement *souphttpsrc;
+	GstPad *ghostpad;
 };
 
 struct _RBDAAPSrcClass
 {
-	GstPushSrcClass parent_class;
+	GstBinClass parent_class;
 };
 
 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
@@ -134,9 +95,9 @@ _do_init (GType daap_src_type)
 			&urihandler_info);
 }
 
-GST_BOILERPLATE_FULL (RBDAAPSrc, rb_daap_src, GstElement, GST_TYPE_PUSH_SRC, _do_init);
+GST_BOILERPLATE_FULL (RBDAAPSrc, rb_daap_src, GstBin, GST_TYPE_BIN, _do_init);
 
-static void rb_daap_src_finalize (GObject *object);
+static void rb_daap_src_dispose (GObject *object);
 static void rb_daap_src_set_property (GObject *object,
 			  guint prop_id,
 			  const GValue *value,
@@ -146,12 +107,7 @@ static void rb_daap_src_get_property (GObject *object,
 			  GValue *value,
 			  GParamSpec *pspec);
 
-static gboolean rb_daap_src_start (GstBaseSrc *bsrc);
-static gboolean rb_daap_src_stop (GstBaseSrc *bsrc);
-static gboolean rb_daap_src_is_seekable (GstBaseSrc *bsrc);
-static gboolean rb_daap_src_get_size (GstBaseSrc *src, guint64 *size);
-static gboolean rb_daap_src_do_seek (GstBaseSrc *src, GstSegment *segment);
-static GstFlowReturn rb_daap_src_create (GstPushSrc *psrc, GstBuffer **outbuf);
+static GstStateChangeReturn rb_daap_src_change_state (GstElement *element, GstStateChange transition);
 
 void
 rb_daap_src_set_plugin (RBPlugin *plugin)
@@ -164,8 +120,6 @@ enum
 {
 	PROP_0,
 	PROP_LOCATION,
-	PROP_SEEKABLE,
-	PROP_BYTESPERREAD
 };
 
 static void
@@ -181,20 +135,15 @@ static void
 rb_daap_src_class_init (RBDAAPSrcClass *klass)
 {
 	GObjectClass *gobject_class;
-	GstElementClass *gstelement_class;
-	GstBaseSrcClass *gstbasesrc_class;
-	GstPushSrcClass *gstpushsrc_class;
+	GstElementClass *element_class;
 
 	gobject_class = G_OBJECT_CLASS (klass);
-	gstelement_class = GST_ELEMENT_CLASS (klass);
-	gstbasesrc_class = (GstBaseSrcClass *) klass;
-	gstpushsrc_class = (GstPushSrcClass *) klass;
-
-	parent_class = g_type_class_ref (GST_TYPE_PUSH_SRC);
-
+	gobject_class->dispose = rb_daap_src_dispose;
 	gobject_class->set_property = rb_daap_src_set_property;
 	gobject_class->get_property = rb_daap_src_get_property;
-	gobject_class->finalize = rb_daap_src_finalize;
+
+	element_class = GST_ELEMENT_CLASS (klass);
+	element_class->change_state = rb_daap_src_change_state;
 
 	g_object_class_install_property (gobject_class, PROP_LOCATION,
 			g_param_spec_string ("location",
@@ -202,40 +151,53 @@ rb_daap_src_class_init (RBDAAPSrcClass *klass)
 					     "location of the file to read",
 					     NULL,
 					     G_PARAM_READWRITE));
-
-	gstbasesrc_class->start = GST_DEBUG_FUNCPTR (rb_daap_src_start);
-	gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (rb_daap_src_stop);
-	gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (rb_daap_src_is_seekable);
-	gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (rb_daap_src_get_size);
-	gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (rb_daap_src_do_seek);
-
-	gstpushsrc_class->create = GST_DEBUG_FUNCPTR (rb_daap_src_create);
 }
 
 static void
 rb_daap_src_init (RBDAAPSrc *src, RBDAAPSrcClass *klass)
 {
+	GstPad *pad;
+
+	/* create actual source */
+	src->souphttpsrc = gst_element_factory_make ("souphttpsrc", NULL);
+	if (src->souphttpsrc == NULL) {
+		g_warning ("couldn't create souphttpsrc element");
+		return;
+	}
+
+	gst_bin_add (GST_BIN (src), src->souphttpsrc);
+	gst_object_ref (src->souphttpsrc);
+
+	/* create ghost pad */
+	pad = gst_element_get_pad (src->souphttpsrc, "src");
+	src->ghostpad = gst_ghost_pad_new ("src", pad);
+	gst_element_add_pad (GST_ELEMENT (src), src->ghostpad);
+	gst_object_ref (src->ghostpad);
+	gst_object_unref (pad);
+
 	src->daap_uri = NULL;
-	src->sock_fd = -1;
-	src->curoffset = 0;
-	src->bytes_per_read = 4096 * 2;
 }
 
 static void
-rb_daap_src_finalize (GObject *object)
+rb_daap_src_dispose (GObject *object)
 {
 	RBDAAPSrc *src;
 	src = RB_DAAP_SRC (object);
 
-	g_free (src->daap_uri);
-	src->daap_uri = NULL;
+	if (src->ghostpad) {
+		gst_object_unref (src->ghostpad);
+		src->ghostpad = NULL;
+	}
 
-	if (src->sock_fd != -1) {
-		close (src->sock_fd);
-		src->sock_fd = -1;
+	if (src->souphttpsrc) {
+		gst_object_unref (src->souphttpsrc);
+		src->souphttpsrc = NULL;
 	}
 
-	G_OBJECT_CLASS (parent_class)->finalize (object);
+	g_free (src->daap_uri);
+	src->daap_uri = NULL;
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
 }
 
 static void
@@ -279,481 +241,55 @@ rb_daap_src_get_property (GObject *object,
 	}
 }
 
-static gint
-rb_daap_src_write (RBDAAPSrc *src, const guchar *buf, size_t count)
-{
-	size_t bytes_written = 0;
-
-	while (bytes_written < count) {
-		ssize_t wrote = send (src->sock_fd, buf + bytes_written, count - bytes_written, MSG_NOSIGNAL);
-
-		if (wrote < 0) {
-			GST_WARNING ("error while writing: %s", g_strerror (errno));
-			return wrote;
-		}
-		if (wrote == 0)
-			break;
-
-		bytes_written += wrote;
-	}
-
-	GST_DEBUG_OBJECT (src, "wrote %d bytes succesfully", bytes_written);
-	return bytes_written;
-}
-
-static gint
-rb_daap_src_read (RBDAAPSrc *src, guchar *buf, size_t count)
-{
-	size_t bytes_read = 0;
-
-	if (src->buffer_size > 0) {
-		bytes_read = count;
-		if (bytes_read > src->buffer_size)
-			bytes_read = src->buffer_size;
-
-		GST_DEBUG_OBJECT (src, "reading %d bytes from buffer", bytes_read);
-		memcpy (buf, src->buffer, bytes_read);
-		src->buffer += bytes_read;
-		src->buffer_size -= bytes_read;
-
-		if (src->buffer_size == 0) {
-			g_free (src->buffer_base);
-			src->buffer_base = NULL;
-			src->buffer = NULL;
-		}
-	}
-
-	while (bytes_read < count) {
-		ssize_t ret = read (src->sock_fd, buf + bytes_read, count - bytes_read);
-
-		if (ret < 0) {
-			GST_WARNING ("error while reading: %s", g_strerror (errno));
-			return ret;
-		}
-		if (ret == 0)
-			break;
-		bytes_read += ret;
-	}
-
-	GST_DEBUG_OBJECT (src, "read %d bytes succesfully", bytes_read);
-	return bytes_read;
-}
-
-static gboolean
-_expect_char (RBDAAPSrc *src, guchar expected)
+GstStateChangeReturn
+rb_daap_src_change_state (GstElement *element, GstStateChange transition)
 {
-	guchar ch;
-	if (rb_daap_src_read (src, &ch, sizeof (ch)) <= 0)
-		return FALSE;
-	if (ch != expected) {
-		GST_DEBUG_OBJECT (src, "Expected char %d next, but got %d", expected, ch);
-		return FALSE;
-	}
-	return TRUE;
-}
-
-static gboolean
-rb_daap_src_read_chunk_size (RBDAAPSrc *src, gboolean first_chunk, gint64 *chunk_size)
-{
-	gchar chunk_buf[30];
-	gchar ch;
-	gint i = 0;
-	memset (&chunk_buf, 0, sizeof (chunk_buf));
-
-	GST_DEBUG_OBJECT (src, "reading next chunk size; first_chunk = %d", first_chunk);
-	if (!first_chunk) {
-		if (!_expect_char (src, '\r') ||
-		    !_expect_char (src, '\n')) {
-			return FALSE;
-		}
-	}
-
-	while (1) {
-		if (rb_daap_src_read (src, (guchar *)&ch, sizeof(ch)) <= 0)
-			return FALSE;
-
-		if (ch == '\r') {
-			if (!_expect_char (src, '\n')) {
-				return FALSE;
+	RBDAAPSrc *src = RB_DAAP_SRC (element);
+
+	switch (transition) {
+		case GST_STATE_CHANGE_NULL_TO_READY:
+		{
+			const char *http = "http";
+			char *httpuri;
+			GstStructure *headers;
+			RBDAAPSource *source;
+
+			/* Retrieve extra headers for the HTTP connection. */
+			source = rb_daap_plugin_find_source_for_uri (daap_plugin, src->daap_uri);
+			if (source == NULL) {
+				g_warning ("Unable to lookup source for URI: %s", src->daap_uri);
+				return GST_STATE_CHANGE_FAILURE;
 			}
-			*chunk_size = strtoul (chunk_buf, NULL, 16);
-			if (*chunk_size == 0) {
-				/* EOS */
-				GST_DEBUG_OBJECT (src, "got EOS chunk");
-				return TRUE;
-			} else if (*chunk_size == ULONG_MAX) {
-				/* overflow */
-				GST_DEBUG_OBJECT (src, "HTTP chunk size overflowed");
-				return FALSE;
-			}
-
-			GST_DEBUG_OBJECT (src, "got HTTP chunk size %lu", *chunk_size);
-			return TRUE;
-		} else if (isxdigit (ch)) {
-			chunk_buf[i++] = ch;
-		} else {
-			GST_DEBUG_OBJECT (src, "HTTP chunk size included illegal character %c", ch);
-			return FALSE;
-		}
-	}
-
-	g_assert_not_reached ();
-}
-
-static void
-_split_uri (const gchar *daap_uri, gchar **host, guint *port, gchar **path)
-{
-	gint locationlen;
-	const gchar *pathstart = NULL;
-	const gchar *hostport = NULL;
-	const gchar *portstart = NULL;
-
-	locationlen = strlen (daap_uri);
-	hostport = daap_uri + 7;
-	pathstart = strchr (hostport, '/');
-
-	if (pathstart) {
-		*path = g_strdup (pathstart);
-	} else {
-		*path = g_strdup ("/");
-		pathstart = daap_uri + locationlen;
-	}
-
-	portstart = strrchr (hostport, ':');
-	if (portstart) {
-		*host = g_strndup (hostport, portstart - hostport);
-		*port = strtoul (portstart + 1, NULL, 0);
-	} else {
-		*host = g_strndup (hostport, pathstart - hostport);
-		*port = 3869;
-	}
-}
-
-static gboolean
-rb_daap_src_open (RBDAAPSrc *src)
-{
-	int ret;
-	struct sockaddr *server;
-	int server_len;
-	RBDAAPSource *source;
-	gchar *headers;
-	gchar *host;
-	guint port;
-	gchar *path;
-	SoupMessageHeaders *header_table;
-	gchar *request;
-	gchar *response;
-	gchar *end_headers;
-	size_t readsize;
-	gboolean ok = TRUE;
-	guint http_status;
-	gchar *http_status_phrase = NULL;
-	gboolean parse_result;
-	SoupAddress *addr;
-	SoupAddressFamily addr_family;
-
-	if (src->buffer_base) {
-		g_free (src->buffer_base);
-		src->buffer_base = NULL;
-		src->buffer = NULL;
-		src->buffer_size = 0;
-	}
-
-	rb_debug ("Connecting to DAAP source: %s", src->daap_uri);
-
-	_split_uri (src->daap_uri, &host, &port, &path);
 
-	GST_DEBUG_OBJECT (src, "resolving server %s", host);
-	addr = soup_address_new (host, port);
-	if (soup_address_resolve_sync (addr, NULL) != SOUP_STATUS_OK) {
-		GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-				("Resolving %s failed", host));
-		return FALSE;
-	}
-
-	server = soup_address_get_sockaddr (addr, &server_len);
-	if (server == NULL) {
-		GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-				("Getting socket address from %s failed", host));
-		return FALSE;
-	}
-
-	g_object_get (addr, "family", &addr_family, NULL);
-
-	/* connect */
-	src->sock_fd = socket (addr_family, SOCK_STREAM, 0);
-	if (src->sock_fd == -1) {
-		GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
-		return FALSE;
-	}
-
-	GST_DEBUG_OBJECT (src, "connecting to server %s:%d", host, port);
-	ret = connect (src->sock_fd, server, server_len);
-	if (ret) {
-		if (errno == ECONNREFUSED) {
-			GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-					   (_("Connection to %s:%d refused."), host, port),
-					   (NULL));
-		} else {
-			GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-					   ("Connect to %s:%d failed: %s", host, port,
-					    g_strerror (errno)));
-		}
-		g_free (host);
-		g_free (path);
-		return FALSE;
-	}
-
-	g_object_unref (addr);
-
-	/* construct request */
-	source = rb_daap_plugin_find_source_for_uri (daap_plugin, src->daap_uri);
-	if (source == NULL) {
-		g_warning ("Unable to lookup source for URI: %s", src->daap_uri);
-		return FALSE;
-	}
-
-	/* The following can fail if the source is no longer connected */
-	headers = rb_daap_source_get_headers (source, src->daap_uri, src->seek_bytes);
-	if (headers == NULL) {
-		g_free (host);
-		g_free (path);
-		return FALSE;
-	}
-
-	request = g_strdup_printf ("GET %s HTTP/1.1\r\nHost: %s\r\n%s\r\n",
-				   path, host, headers);
-	g_free (headers);
-	g_free (host);
-	g_free (path);
-
-	/* send request */
-	GST_DEBUG_OBJECT (src, "Sending HTTP request:\n%s", request);
-	if (rb_daap_src_write (src, (guchar *)request, strlen (request)) <= 0) {
-		GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-				   ("Sending HTTP request to %s failed: %s",
-				    src->daap_uri, g_strerror (errno)));
-		g_free (request);
-		return FALSE;
-	}
-	g_free (request);
-
-	/* read response */
-	response = g_malloc0 (RESPONSE_BUFFER_SIZE + 1);
-	readsize = rb_daap_src_read (src, (guchar *)response, RESPONSE_BUFFER_SIZE);
-	if (readsize <= 0) {
-		g_free (response);
-		GST_DEBUG_OBJECT (src, "Error while reading HTTP response header");
-		return FALSE;
-	}
-	response[readsize] = '\0';
-	GST_DEBUG_OBJECT (src, "Got HTTP response:\n%s", response);
-
-	end_headers = strstr (response, "\r\n\r\n");
-	if (!end_headers) {
-		/* this means the DAAP server returned more than 4k of headers.
-		 * not terribly likely.
-		 */
-		g_free (response);
-		GST_DEBUG_OBJECT (src, "HTTP response header way too long");
-		return FALSE;
-	}
-
-	header_table = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
-	parse_result = soup_headers_parse_response (response,
-						    ((end_headers+2) - response),
-						    header_table,
-						    NULL,
-						    &http_status,
-						    &http_status_phrase);
-
-	if (parse_result) {
-		if (http_status == 200 || http_status == 206) {
-			const char *enc_str = NULL;
-			const char *len_str = NULL;
-			enc_str = soup_message_headers_get (header_table, "Transfer-Encoding");
-			len_str = soup_message_headers_get (header_table, "Content-Length");
-
-			if (enc_str) {
-				if (g_ascii_strcasecmp (enc_str, "chunked") == 0) {
-					src->chunked = TRUE;
-				} else {
-					GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-							   ("Unknown HTTP transfer encoding \"%s\"", enc_str));
-				}
-			} else {
-				src->chunked = FALSE;
-				if (len_str) {
-					char *e;
-					src->size = strtoul (len_str, &e, 10);
-					if (e == len_str) {
-						GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-								   ("Couldn't read HTTP content length \"%s\"", len_str));
-						ok = FALSE;
-					}
-				} else {
-					GST_DEBUG_OBJECT (src, "Response doesn't have a content length");
-					src->size = 0;
-				}
+			/* The following can fail if the source is no longer connected */
+			headers = rb_daap_source_get_headers (source, src->daap_uri);
+			if (headers == NULL) {
+				return GST_STATE_CHANGE_FAILURE;
 			}
 
-		} else {
-			GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
-					   ("HTTP error: %s", http_status_phrase),
-					   (NULL));
-			ok = FALSE;
-		}
-	} else {
-		GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
-				   ("Unable to parse HTTP response"));
-		ok = FALSE;
-	}
-	g_free (http_status_phrase);
-
-	soup_message_headers_free (header_table);
-
-	end_headers += 4;
-
-	/* copy remaining data into a new buffer */
-	if (ok) {
-		src->buffer_size = readsize - (end_headers - response);
-		src->buffer_base = g_malloc0 (src->buffer_size);
-		src->buffer = src->buffer_base;
-		memcpy (src->buffer_base, response + (readsize - src->buffer_size), src->buffer_size);
-	}
-	g_free (response);
-
-	return ok;
-}
-
-static gboolean
-rb_daap_src_start (GstBaseSrc *bsrc)
-{
-	RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
-	if (src->sock_fd != -1) {
-		close (src->sock_fd);
-	}
-
-	src->curoffset = 0;
+			g_object_set (src->souphttpsrc, "extra-headers", headers, NULL);
+			gst_structure_free (headers);
 
-	if (rb_daap_src_open (src)) {
-		src->buffer = src->buffer_base;
-		src->curoffset = src->seek_bytes;
-		if (src->chunked) {
-			src->first_chunk = TRUE;
-			src->size = 0;
-		}
-		return TRUE;
-	} else {
-		return FALSE;
-	}
-}
+			/* Set daap://... URI as http:// on souphttpsrc to ready connection. */
+			httpuri = g_strdup (src->daap_uri);
+			strncpy (httpuri, http, 4);
 
-static gboolean
-rb_daap_src_stop (GstBaseSrc *bsrc)
-{
-	/* don't do anything - this seems to get called during setup, but
-	 * we don't get started again afterwards.
-	 */
-	return TRUE;
-}
-
-static GstFlowReturn
-rb_daap_src_create (GstPushSrc *psrc, GstBuffer **outbuf)
-{
-	RBDAAPSrc *src;
-	size_t readsize;
-	GstBuffer *buf = NULL;
-
-	src = RB_DAAP_SRC (psrc);
-	if (src->do_seek) {
-		if (src->sock_fd != -1) {
-			close (src->sock_fd);
-			src->sock_fd = -1;
-		}
-		if (!rb_daap_src_start (GST_BASE_SRC (src)))
-			return GST_FLOW_ERROR;
-		src->do_seek = FALSE;
-	}
-
-	/* get a new chunk, if we need one */
-	if (src->chunked && src->size == 0) {
-		if (!rb_daap_src_read_chunk_size (src, src->first_chunk, &src->size)) {
-			return GST_FLOW_ERROR;
-		} else if (src->size == 0) {
-			/* EOS */
-			return GST_FLOW_UNEXPECTED;
+			g_object_set (src->souphttpsrc, "location", httpuri, NULL);
+			g_free (httpuri);
+			break;
 		}
-		src->first_chunk = FALSE;
-	}
 
-	readsize = src->bytes_per_read;
-	if (src->chunked && readsize > src->size)
-		readsize = src->size;
-
-	buf = gst_buffer_new_and_alloc (readsize);
-
-	GST_LOG_OBJECT (src, "Reading %d bytes", readsize);
-	readsize = rb_daap_src_read (src, GST_BUFFER_DATA (buf), readsize);
-	if (readsize < 0) {
-		GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
-		gst_buffer_unref (buf);
-		return GST_FLOW_ERROR;
-	}
-
-	if (readsize == 0) {
-		GST_DEBUG ("blocking read returns 0, EOS");
-		gst_buffer_unref (buf);
-		return GST_FLOW_UNEXPECTED;
-	}
-
-	if (src->chunked)
-		src->size -= readsize;
-
-	GST_BUFFER_OFFSET (buf) = src->curoffset;
-	GST_BUFFER_SIZE (buf) = readsize;
-	GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
-	src->curoffset += readsize;
-
-	GST_LOG_OBJECT (src,
-			"Returning buffer from _get of size %d, ts %"
-			GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
-			", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
-			GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
-			GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
-			GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf));
-	*outbuf = buf;
-	return GST_FLOW_OK;
-}
+		case GST_STATE_CHANGE_READY_TO_PAUSED:
+			break;
 
-gboolean
-rb_daap_src_is_seekable (GstBaseSrc *bsrc)
-{
-	return TRUE;
-}
+		case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+			break;
 
-gboolean
-rb_daap_src_do_seek (GstBaseSrc *bsrc, GstSegment *segment)
-{
-	RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
-	if (segment->format == GST_FORMAT_BYTES) {
-		src->do_seek = TRUE;
-		src->seek_bytes = segment->start;
-		return TRUE;
-	} else {
-		return FALSE;
+		default:
+			break;
 	}
-}
 
-gboolean
-rb_daap_src_get_size (GstBaseSrc *bsrc, guint64 *size)
-{
-	RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
-	if (src->chunked == FALSE && src->size > 0) {
-		*size = src->size;
-		return TRUE;
-	}
-	return FALSE;
+	return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
 }
 
 static gboolean



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]