Updated Finnish translation
[rhythmbox.git] / daapsharing / rb-daap-src.c
blob7b1c85dfa77487471450a81552b5f0444a1d3ead
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * Implementatin of DAAP (iTunes Music Sharing) GStreamer source
5 * Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "config.h"
25 #include <string.h>
26 #include <netdb.h>
27 #include <netinet/in.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <sys/ioctl.h>
33 #include <netdb.h>
34 #include <unistd.h>
35 #include <ctype.h>
37 #include <libsoup/soup-headers.h>
38 #include <libsoup/soup-misc.h>
40 #include <glib/gi18n.h>
41 #include <gst/gst.h>
42 #ifdef HAVE_GSTREAMER_0_10
43 #include <gst/base/gstbasesrc.h>
44 #include <gst/base/gstpushsrc.h>
45 #endif
47 #include "rb-daap-source.h"
48 #include "rb-daap-src.h"
49 #include "rb-debug.h"
51 #define RB_TYPE_DAAP_SRC (rb_daap_src_get_type())
52 #define RB_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RB_TYPE_DAAP_SRC,RBDAAPSrc))
53 #define RB_DAAP_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RB_TYPE_DAAP_SRC,RBDAAPSrcClass))
54 #define RB_IS_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RB_TYPE_DAAP_SRC))
55 #define RB_IS_DAAP_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),RB_TYPE_DAAP_SRC))
57 #define RESPONSE_BUFFER_SIZE (4096)
59 #ifdef HAVE_GSTREAMER_0_8
60 typedef enum {
61 RB_DAAP_SRC_OPEN = GST_ELEMENT_FLAG_LAST,
63 RB_DAAP_SRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
64 } RBDAAPSrcFlags;
65 #endif
67 typedef struct _RBDAAPSrc RBDAAPSrc;
68 typedef struct _RBDAAPSrcClass RBDAAPSrcClass;
70 struct _RBDAAPSrc
72 #ifdef HAVE_GSTREAMER_0_8
73 GstElement element;
74 GstPad *srcpad;
75 #else
76 GstPushSrc parent;
77 #endif
79 /* uri */
80 gchar *daap_uri;
82 /* connection */
83 int sock_fd;
84 gchar *buffer_base;
85 gchar *buffer;
86 guint buffer_size;
87 guint32 bytes_per_read;
88 gboolean chunked;
89 gboolean first_chunk;
91 gint64 size;
93 /* Seek stuff */
94 gint64 curoffset;
95 gint64 seek_bytes;
96 gboolean do_seek;
97 #ifdef HAVE_GSTREAMER_0_8
98 gboolean need_flush;
99 gboolean send_discont;
100 glong seek_time_to_return;
101 glong seek_time;
102 #endif
105 struct _RBDAAPSrcClass
107 #ifdef HAVE_GSTREAMER_0_8
108 GstElementClass parent_class;
109 #else
110 GstPushSrcClass parent_class;
111 #endif
114 #ifdef HAVE_GSTREAMER_0_10
115 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
116 GST_PAD_SRC,
117 GST_PAD_ALWAYS,
118 GST_STATIC_CAPS_ANY);
119 #endif
121 GST_DEBUG_CATEGORY_STATIC (rb_daap_src_debug);
122 #define GST_CAT_DEFAULT rb_daap_src_debug
124 static GstElementDetails rb_daap_src_details =
125 GST_ELEMENT_DETAILS ("RBDAAP Source",
126 "Source/File",
127 "Read a DAAP (music share) file",
128 "Charles Schmidt <cschmidt2@emich.edu");
130 static void rb_daap_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
132 static void
133 _do_init (GType daap_src_type)
135 static const GInterfaceInfo urihandler_info = {
136 rb_daap_src_uri_handler_init,
137 NULL,
138 NULL
140 GST_DEBUG_CATEGORY_INIT (rb_daap_src_debug,
141 "daapsrc", GST_DEBUG_FG_WHITE,
142 "Rhythmbox built in DAAP source element");
144 g_type_add_interface_static (daap_src_type, GST_TYPE_URI_HANDLER,
145 &urihandler_info);
148 #ifdef HAVE_GSTREAMER_0_8
149 GST_BOILERPLATE_FULL (RBDAAPSrc, rb_daap_src, GstElement, GST_TYPE_ELEMENT, _do_init);
150 #else
151 GST_BOILERPLATE_FULL (RBDAAPSrc, rb_daap_src, GstElement, GST_TYPE_PUSH_SRC, _do_init);
152 #endif
154 static void rb_daap_src_finalize (GObject *object);
155 static void rb_daap_src_set_property (GObject *object,
156 guint prop_id,
157 const GValue *value,
158 GParamSpec *pspec);
159 static void rb_daap_src_get_property (GObject *object,
160 guint prop_id,
161 GValue *value,
162 GParamSpec *pspec);
164 #ifdef HAVE_GSTREAMER_0_8
165 static GstCaps *rb_daap_src_getcaps (GstPad *pad);
167 static GstData *rb_daap_src_get (GstPad *pad);
169 static GstElementStateReturn rb_daap_src_change_state (GstElement *element);
171 static void rb_daap_src_close_file (RBDAAPSrc *src);
172 static gboolean rb_daap_src_open_file (RBDAAPSrc *src);
173 static gboolean rb_daap_src_srcpad_event (GstPad *pad,
174 GstEvent *event);
175 static gboolean rb_daap_src_srcpad_query (GstPad *pad,
176 GstQueryType type,
177 GstFormat *format,
178 gint64 *value);
179 #else
180 static gboolean rb_daap_src_start (GstBaseSrc *bsrc);
181 static gboolean rb_daap_src_stop (GstBaseSrc *bsrc);
182 static gboolean rb_daap_src_is_seekable (GstBaseSrc *bsrc);
183 static gboolean rb_daap_src_get_size (GstBaseSrc *src, guint64 *size);
184 static gboolean rb_daap_src_do_seek (GstBaseSrc *src, GstSegment *segment);
185 static GstFlowReturn rb_daap_src_create (GstPushSrc *psrc, GstBuffer **outbuf);
186 #endif
188 #ifdef HAVE_GSTREAMER_0_8
190 static const GstFormat *
191 rb_daap_src_get_formats (GstPad *pad)
193 static const GstFormat formats[] = {
194 GST_FORMAT_BYTES,
198 return formats;
201 static const GstQueryType *
202 rb_daap_src_get_query_types (GstPad *pad)
204 static const GstQueryType types[] = {
205 GST_QUERY_TOTAL,
206 GST_QUERY_POSITION,
210 return types;
213 static const GstEventMask *
214 rb_daap_src_get_event_mask (GstPad *pad)
216 static const GstEventMask masks[] = {
217 // {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
218 {GST_EVENT_FLUSH, 0},
219 {GST_EVENT_SIZE, 0},
220 {0, 0},
223 return masks;
226 #endif
228 enum
230 PROP_0,
231 PROP_LOCATION,
232 PROP_SEEKABLE,
233 PROP_BYTESPERREAD
236 static void
237 rb_daap_src_base_init (gpointer g_class)
239 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
240 #ifdef HAVE_GSTREAMER_0_10
241 gst_element_class_add_pad_template (element_class,
242 gst_static_pad_template_get (&srctemplate));
243 #endif
244 gst_element_class_set_details (element_class, &rb_daap_src_details);
247 static void
248 rb_daap_src_class_init (RBDAAPSrcClass *klass)
250 #ifdef HAVE_GSTREAMER_0_8
251 GObjectClass *gobject_class;
252 GstElementClass *gstelement_class;
254 gobject_class = (GObjectClass *) klass;
255 gstelement_class = (GstElementClass *) klass;
257 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
259 gst_element_class_install_std_props (GST_ELEMENT_CLASS (klass),
260 "bytesperread", PROP_BYTESPERREAD, G_PARAM_READWRITE,
261 "location", PROP_LOCATION, G_PARAM_READWRITE, NULL);
263 gobject_class->finalize = rb_daap_src_finalize;
265 g_object_class_install_property (gobject_class,
266 PROP_SEEKABLE,
267 g_param_spec_boolean ("seekable",
268 "seekable",
269 "TRUE if stream is seekable",
270 TRUE,
271 G_PARAM_READABLE));
273 gstelement_class->set_property = rb_daap_src_set_property;
274 gstelement_class->get_property = rb_daap_src_get_property;
276 gstelement_class->change_state = rb_daap_src_change_state;
277 #else
278 GObjectClass *gobject_class;
279 GstElementClass *gstelement_class;
280 GstBaseSrcClass *gstbasesrc_class;
281 GstPushSrcClass *gstpushsrc_class;
283 gobject_class = G_OBJECT_CLASS (klass);
284 gstelement_class = GST_ELEMENT_CLASS (klass);
285 gstbasesrc_class = (GstBaseSrcClass *) klass;
286 gstpushsrc_class = (GstPushSrcClass *) klass;
288 parent_class = g_type_class_ref (GST_TYPE_PUSH_SRC);
290 gobject_class->set_property = rb_daap_src_set_property;
291 gobject_class->get_property = rb_daap_src_get_property;
292 gobject_class->finalize = rb_daap_src_finalize;
294 g_object_class_install_property (gobject_class, PROP_LOCATION,
295 g_param_spec_string ("location",
296 "file location",
297 "location of the file to read",
298 NULL,
299 G_PARAM_READWRITE));
301 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (rb_daap_src_start);
302 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (rb_daap_src_stop);
303 gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (rb_daap_src_is_seekable);
304 gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (rb_daap_src_get_size);
305 gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (rb_daap_src_do_seek);
307 gstpushsrc_class->create = GST_DEBUG_FUNCPTR (rb_daap_src_create);
308 #endif
311 #ifdef HAVE_GSTREAMER_0_8
312 static void
313 rb_daap_src_init (RBDAAPSrc *src)
314 #else
315 static void
316 rb_daap_src_init (RBDAAPSrc *src, RBDAAPSrcClass *klass)
317 #endif
319 src->daap_uri = NULL;
320 src->sock_fd = -1;
321 src->curoffset = 0;
322 src->bytes_per_read = 4096 * 2;
324 #ifdef HAVE_GSTREAMER_0_8
325 src->seek_bytes = 0;
327 src->send_discont = FALSE;
328 src->need_flush = FALSE;
330 src->srcpad = gst_pad_new ("src", GST_PAD_SRC);
331 gst_pad_set_getcaps_function (src->srcpad,
332 rb_daap_src_getcaps);
333 gst_pad_set_get_function (src->srcpad,
334 rb_daap_src_get);
335 gst_pad_set_event_mask_function (src->srcpad,
336 rb_daap_src_get_event_mask);
337 gst_pad_set_event_function (src->srcpad,
338 rb_daap_src_srcpad_event);
339 gst_pad_set_query_type_function (src->srcpad,
340 rb_daap_src_get_query_types);
341 gst_pad_set_query_function (src->srcpad,
342 rb_daap_src_srcpad_query);
343 gst_pad_set_formats_function (src->srcpad,
344 rb_daap_src_get_formats);
345 gst_element_add_pad (GST_ELEMENT (src), src->srcpad);
346 #endif
349 static void
350 rb_daap_src_finalize (GObject *object)
352 RBDAAPSrc *src;
353 src = RB_DAAP_SRC (object);
355 #ifdef HAVE_GSTREAMER_0_8
356 if (GST_FLAG_IS_SET (src, RB_DAAP_SRC_OPEN)) {
357 rb_daap_src_close_file (src);
359 #endif
361 g_free (src->daap_uri);
362 src->daap_uri = NULL;
364 if (src->sock_fd != -1)
365 close (src->sock_fd);
367 G_OBJECT_CLASS (parent_class)->finalize (object);
370 static void
371 rb_daap_src_set_property (GObject *object,
372 guint prop_id,
373 const GValue *value,
374 GParamSpec *pspec)
376 RBDAAPSrc *src = RB_DAAP_SRC (object);
378 switch (prop_id) {
379 case PROP_LOCATION:
380 #ifdef HAVE_GSTREAMER_0_8
381 /* the element must be stopped or paused in order to do src */
382 if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) {
383 break;
385 #else
386 /* XXX check stuff */
387 #endif
389 if (src->daap_uri) {
390 g_free (src->daap_uri);
391 src->daap_uri = NULL;
393 src->daap_uri = g_strdup (g_value_get_string (value));
394 break;
395 #ifdef HAVE_GSTREAMER_0_8
396 case PROP_BYTESPERREAD:
397 src->bytes_per_read = g_value_get_int (value);
398 break;
399 #endif
400 default:
401 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
402 break;
406 static void
407 rb_daap_src_get_property (GObject *object,
408 guint prop_id,
409 GValue *value,
410 GParamSpec *pspec)
412 RBDAAPSrc *src = RB_DAAP_SRC (object);
414 switch (prop_id) {
415 case PROP_LOCATION:
416 g_value_set_string (value, src->daap_uri);
417 break;
418 #ifdef HAVE_GSTREAMER_0_8
419 case PROP_SEEKABLE:
420 g_value_set_boolean (value, FALSE);
421 break;
422 case PROP_BYTESPERREAD:
423 g_value_set_int (value, src->bytes_per_read);
424 break;
425 #endif
426 default:
427 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
428 break;
432 static gint
433 rb_daap_src_write (RBDAAPSrc *src, const guchar *buf, size_t count)
435 size_t bytes_written = 0;
437 while (bytes_written < count) {
438 ssize_t wrote = send (src->sock_fd, buf + bytes_written, count - bytes_written, MSG_NOSIGNAL);
440 if (wrote < 0) {
441 GST_WARNING ("error while writing: %s", g_strerror (errno));
442 return wrote;
444 if (wrote == 0)
445 break;
447 bytes_written += wrote;
450 GST_DEBUG_OBJECT (src, "wrote %d bytes succesfully", bytes_written);
451 return bytes_written;
454 static gint
455 rb_daap_src_read (RBDAAPSrc *src, guchar *buf, size_t count)
457 size_t bytes_read = 0;
459 if (src->buffer_size > 0) {
460 bytes_read = count;
461 if (bytes_read > src->buffer_size)
462 bytes_read = src->buffer_size;
464 GST_DEBUG_OBJECT (src, "reading %d bytes from buffer", bytes_read);
465 memcpy (buf, src->buffer, bytes_read);
466 src->buffer += bytes_read;
467 src->buffer_size -= bytes_read;
469 if (src->buffer_size == 0) {
470 g_free (src->buffer_base);
471 src->buffer_base = NULL;
472 src->buffer = NULL;
476 while (bytes_read < count) {
477 ssize_t ret = read (src->sock_fd, buf + bytes_read, count - bytes_read);
479 if (ret < 0) {
480 GST_WARNING ("error while reading: %s", g_strerror (errno));
481 return ret;
483 if (ret == 0)
484 break;
485 bytes_read += ret;
488 GST_DEBUG_OBJECT (src, "read %d bytes succesfully", bytes_read);
489 return bytes_read;
492 static gboolean
493 _expect_char (RBDAAPSrc *src, guchar expected)
495 guchar ch;
496 if (rb_daap_src_read (src, &ch, sizeof (ch)) <= 0)
497 return FALSE;
498 if (ch != expected) {
499 GST_DEBUG_OBJECT (src, "Expected char %d next, but got %d", expected, ch);
500 return FALSE;
502 return TRUE;
505 static gboolean
506 rb_daap_src_read_chunk_size (RBDAAPSrc *src, gboolean first_chunk, gint64 *chunk_size)
508 gchar chunk_buf[30];
509 gchar ch;
510 gint i = 0;
511 memset (&chunk_buf, 0, sizeof (chunk_buf));
513 GST_DEBUG_OBJECT (src, "reading next chunk size; first_chunk = %d", first_chunk);
514 if (!first_chunk) {
515 if (!_expect_char (src, '\r') ||
516 !_expect_char (src, '\n')) {
517 return FALSE;
521 while (1) {
522 if (rb_daap_src_read (src, (guchar *)&ch, sizeof(ch)) <= 0)
523 return FALSE;
525 if (ch == '\r') {
526 if (!_expect_char (src, '\n')) {
527 return FALSE;
529 *chunk_size = strtoul (chunk_buf, NULL, 16);
530 if (*chunk_size == 0) {
531 /* EOS */
532 GST_DEBUG_OBJECT (src, "got EOS chunk");
533 return TRUE;
534 } else if (*chunk_size == ULONG_MAX) {
535 /* overflow */
536 GST_DEBUG_OBJECT (src, "HTTP chunk size overflowed");
537 return FALSE;
540 GST_DEBUG_OBJECT (src, "got HTTP chunk size %lu", *chunk_size);
541 return TRUE;
542 } else if (isxdigit (ch)) {
543 chunk_buf[i++] = ch;
544 } else {
545 GST_DEBUG_OBJECT (src, "HTTP chunk size included illegal character %c", ch);
546 return FALSE;
550 g_assert_not_reached ();
553 static void
554 _split_uri (const gchar *daap_uri, gchar **host, guint *port, gchar **path)
556 gint locationlen;
557 const gchar *pathstart = NULL;
558 const gchar *hostport = NULL;
559 const gchar *portstart = NULL;
561 locationlen = strlen (daap_uri);
562 hostport = daap_uri + 7;
563 pathstart = strchr (hostport, '/');
565 if (pathstart) {
566 *path = g_strdup (pathstart);
567 } else {
568 *path = g_strdup ("/");
569 pathstart = daap_uri + locationlen;
572 portstart = strrchr (hostport, ':');
573 if (portstart) {
574 *host = g_strndup (hostport, portstart - hostport);
575 *port = strtoul (portstart + 1, NULL, 0);
576 } else {
577 *host = g_strndup (hostport, pathstart - hostport);
578 *port = 3869;
582 static gboolean
583 rb_daap_src_open (RBDAAPSrc *src)
585 int ret;
586 struct sockaddr_in server;
587 RBDAAPSource *source;
588 gchar *headers;
589 gchar *host;
590 guint port;
591 gchar *path;
592 GHashTable *header_table;
593 gchar *request;
594 gchar *response;
595 gchar *end_headers;
596 size_t readsize;
597 gboolean ok = TRUE;
598 guint http_status;
599 gchar *http_status_phrase = NULL;
601 if (src->buffer_base) {
602 g_free (src->buffer_base);
603 src->buffer_base = NULL;
604 src->buffer = NULL;
605 src->buffer_size = 0;
608 rb_debug ("Connecting to DAAP source: %s", src->daap_uri);
610 /* connect */
611 src->sock_fd = socket (AF_INET, SOCK_STREAM, 0);
612 if (src->sock_fd == -1) {
613 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
614 return FALSE;
617 _split_uri (src->daap_uri, &host, &port, &path);
619 server.sin_family = AF_INET;
620 server.sin_port = htons (port);
621 server.sin_addr.s_addr = inet_addr (host);
622 memset (&server.sin_zero, 0, sizeof (server.sin_zero));
624 GST_DEBUG_OBJECT (src, "connecting to server %s:%d", host, port);
625 ret = connect (src->sock_fd, (struct sockaddr *) &server, sizeof (struct sockaddr));
626 if (ret) {
627 if (errno == ECONNREFUSED) {
628 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
629 (_("Connection to %s:%d refused."), host, port),
630 (NULL));
631 } else {
632 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
633 ("Connect to %s:%d failed: %s", host, port,
634 g_strerror (errno)));
636 g_free (host);
637 g_free (path);
638 return FALSE;
641 /* construct request */
642 source = rb_daap_source_find_for_uri (src->daap_uri);
643 if (source == NULL) {
644 g_warning ("Unable to lookup source for URI: %s", src->daap_uri);
645 return FALSE;
648 /* The following can fail if the source is no longer connected */
649 #ifdef HAVE_GSTREAMER_0_8
650 headers = rb_daap_source_get_headers (source, src->daap_uri, src->seek_time, &src->seek_bytes);
651 #else
652 headers = rb_daap_source_get_headers (source, src->daap_uri, src->seek_bytes);
653 #endif
654 if (headers == NULL) {
655 g_free (host);
656 g_free (path);
657 return FALSE;
660 request = g_strdup_printf ("GET %s HTTP/1.1\r\nHost: %s\r\n%s\r\n",
661 path, host, headers);
662 g_free (headers);
663 g_free (host);
664 g_free (path);
666 /* send request */
667 GST_DEBUG_OBJECT (src, "Sending HTTP request:\n%s", request);
668 if (rb_daap_src_write (src, (guchar *)request, strlen (request)) <= 0) {
669 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
670 ("Sending HTTP request to %s failed: %s",
671 src->daap_uri, g_strerror (errno)));
672 g_free (request);
673 return FALSE;
675 g_free (request);
677 /* read response */
678 response = g_malloc0 (RESPONSE_BUFFER_SIZE + 1);
679 readsize = rb_daap_src_read (src, (guchar *)response, RESPONSE_BUFFER_SIZE);
680 if (readsize <= 0) {
681 g_free (response);
682 GST_DEBUG_OBJECT (src, "Error while reading HTTP response header");
683 return FALSE;
685 response[readsize] = '\0';
686 GST_DEBUG_OBJECT (src, "Got HTTP response:\n%s", response);
688 end_headers = strstr (response, "\r\n\r\n");
689 if (!end_headers) {
690 /* this means the DAAP server returned more than 4k of headers.
691 * not terribly likely.
693 g_free (response);
694 GST_DEBUG_OBJECT (src, "HTTP response header way too long");
695 return FALSE;
698 /* libsoup wants the headers null-terminated, despite taking a parameter
699 * specifying how long they are.
701 end_headers[2] = '\0';
702 end_headers += 4;
704 header_table = g_hash_table_new (soup_str_case_hash, soup_str_case_equal);
705 if (soup_headers_parse_response (response,
706 (end_headers - response),
707 header_table,
708 NULL,
709 &http_status,
710 &http_status_phrase)) {
711 if (http_status == 200 || http_status == 206) {
712 GSList *val;
714 val = g_hash_table_lookup (header_table, "Transfer-Encoding");
715 if (val) {
716 if (g_strcasecmp ((gchar *)val->data, "chunked") == 0) {
717 src->chunked = TRUE;
718 } else {
719 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
720 ("Unknown HTTP transfer encoding \"%s\"", val->data));
722 } else {
723 src->chunked = FALSE;
724 val = g_hash_table_lookup (header_table, "Content-Length");
725 if (val) {
726 char *e;
727 src->size = strtoul ((char *)val->data, &e, 10);
728 if (e == val->data) {
729 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
730 ("Couldn't read HTTP content length \"%s\"", val->data));
731 ok = FALSE;
736 } else {
737 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
738 ("HTTP error: %s", http_status_phrase),
739 (NULL));
740 ok = FALSE;
742 } else {
743 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
744 ("Unable to parse HTTP response"));
745 ok = FALSE;
747 g_free (http_status_phrase);
748 g_hash_table_destroy (header_table);
750 /* copy remaining data into a new buffer */
751 if (ok) {
752 src->buffer_size = readsize - (end_headers - response);
753 src->buffer_base = g_malloc0 (src->buffer_size);
754 src->buffer = src->buffer_base;
755 memcpy (src->buffer_base, response + (readsize - src->buffer_size), src->buffer_size);
757 g_free (response);
759 return ok;
762 static gboolean
763 #ifdef HAVE_GSTREAMER_0_8
764 rb_daap_src_open_file (RBDAAPSrc *src)
766 #else
767 rb_daap_src_start (GstBaseSrc *bsrc)
769 RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
770 #endif
771 if (src->sock_fd != -1) {
772 close (src->sock_fd);
775 src->curoffset = 0;
777 if (rb_daap_src_open (src)) {
778 src->buffer = src->buffer_base;
779 #ifdef HAVE_GSTREAMER_0_8
780 src->seek_time_to_return = src->seek_time;
781 if (src->seek_bytes != 0) {
782 src->need_flush = TRUE;
783 src->send_discont = TRUE;
785 GST_FLAG_SET (src, RB_DAAP_SRC_OPEN);
786 #else
787 src->curoffset = src->seek_bytes;
788 #endif
789 if (src->chunked) {
790 src->first_chunk = TRUE;
791 src->size = 0;
793 return TRUE;
794 } else {
795 return FALSE;
799 #ifdef HAVE_GSTREAMER_0_8
800 static void
801 rb_daap_src_close_file (RBDAAPSrc *src)
803 if (src->sock_fd != -1) {
804 close (src->sock_fd);
805 src->sock_fd = -1;
807 src->seek_bytes = 0;
808 src->curoffset = 0;
809 src->size = 0;
810 src->send_discont = FALSE;
812 GST_FLAG_UNSET (src, RB_DAAP_SRC_OPEN);
814 #else
815 static gboolean
816 rb_daap_src_stop (GstBaseSrc *bsrc)
818 /* don't do anything - this seems to get called during setup, but
819 * we don't get started again afterwards.
821 return TRUE;
823 #endif
825 #ifdef HAVE_GSTREAMER_0_8
826 static GstData *
827 rb_daap_src_get (GstPad *pad)
828 #else
829 static GstFlowReturn
830 rb_daap_src_create (GstPushSrc *psrc, GstBuffer **outbuf)
831 #endif
833 RBDAAPSrc *src;
834 size_t readsize;
835 GstBuffer *buf = NULL;
837 #ifdef HAVE_GSTREAMER_0_8
838 g_return_val_if_fail (pad != NULL, NULL);
839 g_return_val_if_fail (GST_IS_PAD (pad), NULL);
840 src = RB_DAAP_SRC (GST_OBJECT_PARENT (pad));
841 g_return_val_if_fail (GST_FLAG_IS_SET (src, RB_DAAP_SRC_OPEN), NULL);
842 #else
843 src = RB_DAAP_SRC (psrc);
844 #endif
846 if (src->do_seek) {
847 if (src->sock_fd != -1) {
848 close (src->sock_fd);
849 src->sock_fd = -1;
851 #ifdef HAVE_GSTREAMER_0_8
852 if (!rb_daap_src_open_file (src))
853 return GST_DATA (gst_event_new (GST_EVENT_EOS));
854 #else
855 if (!rb_daap_src_start (GST_BASE_SRC (src)))
856 return GST_FLOW_ERROR;
857 #endif
858 src->do_seek = FALSE;
861 #ifdef HAVE_GSTREAMER_0_8
862 /* try to negotiate here */
863 if (!gst_pad_is_negotiated (pad)) {
864 if (GST_PAD_LINK_FAILED (gst_pad_renegotiate (pad))) {
865 GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL), GST_ERROR_SYSTEM);
866 gst_buffer_unref (buf);
867 return GST_DATA (gst_event_new (GST_EVENT_EOS));
871 if (src->need_flush) {
872 GstEvent *event = gst_event_new_flush ();
874 src->need_flush = FALSE;
875 return GST_DATA (event);
878 if (src->send_discont) {
879 GstEvent *event;
881 src->send_discont = FALSE;
882 event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset + src->seek_bytes, NULL);
883 return GST_DATA (event);
885 #endif
887 /* get a new chunk, if we need one */
888 if (src->chunked && src->size == 0) {
889 if (!rb_daap_src_read_chunk_size (src, src->first_chunk, &src->size)) {
890 #ifdef HAVE_GSTREAMER_0_8
891 return GST_DATA (gst_event_new (GST_EVENT_EOS));
892 #else
893 return GST_FLOW_ERROR;
894 #endif
895 } else if (src->size == 0) {
896 /* EOS */
897 #ifdef HAVE_GSTREAMER_0_8
898 gst_element_set_eos (GST_ELEMENT (src));
899 return GST_DATA (gst_event_new (GST_EVENT_EOS));
900 #else
901 return GST_FLOW_UNEXPECTED;
902 #endif
904 src->first_chunk = FALSE;
907 readsize = src->bytes_per_read;
908 if (src->chunked && readsize > src->size)
909 readsize = src->size;
911 #ifdef HAVE_GSTREAMER_0_8
912 buf = gst_buffer_new ();
913 g_return_val_if_fail (buf, NULL);
914 GST_BUFFER_DATA (buf) = g_malloc0 (readsize);
915 g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
916 #else
917 buf = gst_buffer_new_and_alloc (readsize);
918 #endif
920 GST_LOG_OBJECT (src, "Reading %d bytes", readsize);
921 readsize = rb_daap_src_read (src, GST_BUFFER_DATA (buf), readsize);
922 if (readsize < 0) {
923 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
924 gst_buffer_unref (buf);
925 #ifdef HAVE_GSTREAMER_0_8
926 return GST_DATA (gst_event_new (GST_EVENT_EOS));
927 #else
928 return GST_FLOW_ERROR;
929 #endif
932 if (readsize == 0) {
933 GST_DEBUG ("blocking read returns 0, EOS");
934 gst_buffer_unref (buf);
935 #ifdef HAVE_GSTREAMER_0_8
936 gst_element_set_eos (GST_ELEMENT (src));
937 return GST_DATA (gst_event_new (GST_EVENT_EOS));
938 #else
939 return GST_FLOW_UNEXPECTED;
940 #endif
943 if (src->chunked)
944 src->size -= readsize;
946 GST_BUFFER_OFFSET (buf) = src->curoffset;
947 GST_BUFFER_SIZE (buf) = readsize;
948 GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
949 src->curoffset += readsize;
951 GST_LOG_OBJECT (src,
952 "Returning buffer from _get of size %d, ts %"
953 GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
954 ", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
955 GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
956 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
957 GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf));
958 #ifdef HAVE_GSTREAMER_0_8
959 return GST_DATA (buf);
960 #else
961 *outbuf = buf;
962 return GST_FLOW_OK;
963 #endif
966 #ifdef HAVE_GSTREAMER_0_8
967 static GstElementStateReturn
968 rb_daap_src_change_state (GstElement *element)
970 g_return_val_if_fail (RB_IS_DAAP_SRC (element), GST_STATE_FAILURE);
972 switch (GST_STATE_TRANSITION (element)) {
973 case GST_STATE_READY_TO_PAUSED:
974 if (!GST_FLAG_IS_SET (element, RB_DAAP_SRC_OPEN)) {
975 if (!rb_daap_src_open_file (RB_DAAP_SRC (element))) {
976 return GST_STATE_FAILURE;
979 break;
980 case GST_STATE_PAUSED_TO_READY:
981 if (GST_FLAG_IS_SET (element, RB_DAAP_SRC_OPEN)) {
982 rb_daap_src_close_file (RB_DAAP_SRC (element));
984 break;
985 case GST_STATE_NULL_TO_READY:
986 case GST_STATE_READY_TO_NULL:
987 default:
988 break;
991 if (GST_ELEMENT_CLASS (parent_class)->change_state) {
992 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
995 return GST_STATE_SUCCESS;
998 static gboolean
999 rb_daap_src_srcpad_event (GstPad *pad,
1000 GstEvent *event)
1002 RBDAAPSrc *src = RB_DAAP_SRC (GST_PAD_PARENT (pad));
1004 switch (GST_EVENT_TYPE (event)) {
1005 case GST_EVENT_SEEK: {
1006 gint64 desired_offset = 0;
1008 if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
1009 gst_event_unref (event);
1010 return FALSE;
1013 switch (GST_EVENT_SEEK_METHOD (event)) {
1014 case GST_SEEK_METHOD_SET:
1015 desired_offset = (gint64) GST_EVENT_SEEK_OFFSET (event);
1016 break;
1017 case GST_SEEK_METHOD_CUR:
1018 desired_offset = src->curoffset + GST_EVENT_SEEK_OFFSET (event);
1019 break;
1020 case GST_SEEK_METHOD_END:
1021 if (src->size == 0) {
1022 return FALSE;
1024 desired_offset = src->size - ABS (GST_EVENT_SEEK_OFFSET (event));
1025 break;
1026 default:
1027 gst_event_unref (event);
1028 return FALSE;
1031 return FALSE;
1032 break;
1034 case GST_EVENT_SIZE:
1035 if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) {
1036 gst_event_unref (event);
1037 return FALSE;
1039 src->bytes_per_read = GST_EVENT_SIZE_VALUE (event);
1040 g_object_notify (G_OBJECT (src), "bytesperread");
1041 break;
1042 case GST_EVENT_FLUSH:
1043 src->need_flush = TRUE;
1044 break;
1045 default:
1046 gst_event_unref (event);
1047 return FALSE;
1048 break;
1051 gst_event_unref (event);
1053 return TRUE;
1056 static gboolean
1057 rb_daap_src_srcpad_query (GstPad *pad,
1058 GstQueryType type,
1059 GstFormat *format,
1060 gint64 *value)
1062 RBDAAPSrc *src = RB_DAAP_SRC (gst_pad_get_parent (pad));
1064 switch (type) {
1065 case GST_QUERY_TOTAL:
1066 if (*format != GST_FORMAT_BYTES || src->size == 0) {
1067 return FALSE;
1069 *value = src->size;
1070 break;
1071 case GST_QUERY_POSITION:
1072 switch (*format) {
1073 case GST_FORMAT_BYTES:
1074 *value = src->curoffset;
1075 break;
1076 case GST_FORMAT_PERCENT:
1077 return FALSE; /* FIXME */
1078 if (src->size == 0) {
1079 return FALSE;
1081 *value = src->curoffset * GST_FORMAT_PERCENT_MAX / src->size;
1082 break;
1083 default:
1084 return FALSE;
1086 break;
1087 default:
1088 return FALSE;
1089 break;
1092 return TRUE;
1094 #else
1096 gboolean
1097 rb_daap_src_is_seekable (GstBaseSrc *bsrc)
1099 return TRUE;
1102 gboolean
1103 rb_daap_src_do_seek (GstBaseSrc *bsrc, GstSegment *segment)
1105 RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
1106 if (segment->format == GST_FORMAT_BYTES) {
1107 src->do_seek = TRUE;
1108 src->seek_bytes = segment->start;
1109 return TRUE;
1110 } else {
1111 return FALSE;
1115 gboolean
1116 rb_daap_src_get_size (GstBaseSrc *bsrc, guint64 *size)
1118 RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
1119 if (!src->chunked) {
1120 *size = src->size;
1121 return TRUE;
1123 return FALSE;
1126 #endif
1128 static gboolean
1129 plugin_init (GstPlugin *plugin)
1131 gboolean ret = gst_element_register (plugin, "rbdaapsrc", GST_RANK_PRIMARY, RB_TYPE_DAAP_SRC);
1132 return ret;
1135 GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
1136 GST_VERSION_MINOR,
1137 "rbdaap",
1138 "element to access DAAP music share files",
1139 plugin_init,
1140 VERSION,
1141 "GPL",
1142 PACKAGE,
1143 "");
1145 #ifdef HAVE_GSTREAMER_0_8
1146 /*** RB DAAP SEEK INTERFACE **************************************************/
1148 void
1149 rb_daap_src_set_time (GstElement *element, glong time)
1151 RBDAAPSrc *src = RB_DAAP_SRC (element);
1152 src->seek_time = time;
1153 src->do_seek = TRUE;
1156 glong
1157 rb_daap_src_get_time (GstElement *element)
1159 RBDAAPSrc *src = RB_DAAP_SRC (element);
1160 return src->seek_time_to_return;
1163 #endif
1164 /*** GSTURIHANDLER INTERFACE *************************************************/
1166 static guint
1167 rb_daap_src_uri_get_type (void)
1169 return GST_URI_SRC;
1172 static gchar **
1173 rb_daap_src_uri_get_protocols (void)
1175 static gchar *protocols[] = {"daap", NULL};
1177 return protocols;
1180 static const gchar *
1181 rb_daap_src_uri_get_uri (GstURIHandler *handler)
1183 RBDAAPSrc *src = RB_DAAP_SRC (handler);
1185 return src->daap_uri;
1188 static gboolean
1189 rb_daap_src_uri_set_uri (GstURIHandler *handler,
1190 const gchar *uri)
1192 RBDAAPSrc *src = RB_DAAP_SRC (handler);
1194 if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) {
1195 return FALSE;
1198 g_object_set (G_OBJECT (src), "location", uri, NULL);
1200 return TRUE;
1203 static void
1204 rb_daap_src_uri_handler_init (gpointer g_iface,
1205 gpointer iface_data)
1207 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
1209 iface->get_type = rb_daap_src_uri_get_type;
1210 iface->get_protocols = rb_daap_src_uri_get_protocols;
1211 iface->get_uri = rb_daap_src_uri_get_uri;
1212 iface->set_uri = rb_daap_src_uri_set_uri;