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.
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>
37 #include <libsoup/soup-headers.h>
38 #include <libsoup/soup-misc.h>
40 #include <glib/gi18n.h>
42 #ifdef HAVE_GSTREAMER_0_10
43 #include <gst/base/gstbasesrc.h>
44 #include <gst/base/gstpushsrc.h>
47 #include "rb-daap-source.h"
48 #include "rb-daap-src.h"
50 #include "rb-daap-plugin.h"
52 #define RB_TYPE_DAAP_SRC (rb_daap_src_get_type())
53 #define RB_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),RB_TYPE_DAAP_SRC,RBDAAPSrc))
54 #define RB_DAAP_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),RB_TYPE_DAAP_SRC,RBDAAPSrcClass))
55 #define RB_IS_DAAP_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),RB_TYPE_DAAP_SRC))
56 #define RB_IS_DAAP_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),RB_TYPE_DAAP_SRC))
58 #define RESPONSE_BUFFER_SIZE (4096)
60 #ifdef HAVE_GSTREAMER_0_8
62 RB_DAAP_SRC_OPEN
= GST_ELEMENT_FLAG_LAST
,
64 RB_DAAP_SRC_FLAG_LAST
= GST_ELEMENT_FLAG_LAST
+ 2
68 typedef struct _RBDAAPSrc RBDAAPSrc
;
69 typedef struct _RBDAAPSrcClass RBDAAPSrcClass
;
73 #ifdef HAVE_GSTREAMER_0_8
88 guint32 bytes_per_read
;
98 #ifdef HAVE_GSTREAMER_0_8
100 gboolean send_discont
;
101 glong seek_time_to_return
;
106 struct _RBDAAPSrcClass
108 #ifdef HAVE_GSTREAMER_0_8
109 GstElementClass parent_class
;
111 GstPushSrcClass parent_class
;
115 #ifdef HAVE_GSTREAMER_0_10
116 static GstStaticPadTemplate srctemplate
= GST_STATIC_PAD_TEMPLATE ("src",
119 GST_STATIC_CAPS_ANY
);
122 GST_DEBUG_CATEGORY_STATIC (rb_daap_src_debug
);
123 #define GST_CAT_DEFAULT rb_daap_src_debug
125 static GstElementDetails rb_daap_src_details
=
126 GST_ELEMENT_DETAILS ("RBDAAP Source",
128 "Read a DAAP (music share) file",
129 "Charles Schmidt <cschmidt2@emich.edu");
131 static RBDaapPlugin
*daap_plugin
= NULL
;
133 static void rb_daap_src_uri_handler_init (gpointer g_iface
, gpointer iface_data
);
136 _do_init (GType daap_src_type
)
138 static const GInterfaceInfo urihandler_info
= {
139 rb_daap_src_uri_handler_init
,
143 GST_DEBUG_CATEGORY_INIT (rb_daap_src_debug
,
144 "daapsrc", GST_DEBUG_FG_WHITE
,
145 "Rhythmbox built in DAAP source element");
147 g_type_add_interface_static (daap_src_type
, GST_TYPE_URI_HANDLER
,
151 #ifdef HAVE_GSTREAMER_0_8
152 GST_BOILERPLATE_FULL (RBDAAPSrc
, rb_daap_src
, GstElement
, GST_TYPE_ELEMENT
, _do_init
);
154 GST_BOILERPLATE_FULL (RBDAAPSrc
, rb_daap_src
, GstElement
, GST_TYPE_PUSH_SRC
, _do_init
);
157 static void rb_daap_src_finalize (GObject
*object
);
158 static void rb_daap_src_set_property (GObject
*object
,
162 static void rb_daap_src_get_property (GObject
*object
,
167 #ifdef HAVE_GSTREAMER_0_8
168 static GstData
*rb_daap_src_get (GstPad
*pad
);
170 static GstElementStateReturn
rb_daap_src_change_state (GstElement
*element
);
172 static void rb_daap_src_close_file (RBDAAPSrc
*src
);
173 static gboolean
rb_daap_src_open_file (RBDAAPSrc
*src
);
174 static gboolean
rb_daap_src_srcpad_event (GstPad
*pad
,
176 static gboolean
rb_daap_src_srcpad_query (GstPad
*pad
,
181 static gboolean
rb_daap_src_start (GstBaseSrc
*bsrc
);
182 static gboolean
rb_daap_src_stop (GstBaseSrc
*bsrc
);
183 static gboolean
rb_daap_src_is_seekable (GstBaseSrc
*bsrc
);
184 static gboolean
rb_daap_src_get_size (GstBaseSrc
*src
, guint64
*size
);
185 static gboolean
rb_daap_src_do_seek (GstBaseSrc
*src
, GstSegment
*segment
);
186 static GstFlowReturn
rb_daap_src_create (GstPushSrc
*psrc
, GstBuffer
**outbuf
);
190 rb_daap_src_set_plugin (RBPlugin
*plugin
)
192 g_assert (RB_IS_DAAP_PLUGIN (plugin
));
193 daap_plugin
= RB_DAAP_PLUGIN (plugin
);
196 #ifdef HAVE_GSTREAMER_0_8
198 static const GstFormat
*
199 rb_daap_src_get_formats (GstPad
*pad
)
201 static const GstFormat formats
[] = {
209 static const GstQueryType
*
210 rb_daap_src_get_query_types (GstPad
*pad
)
212 static const GstQueryType types
[] = {
221 static const GstEventMask
*
222 rb_daap_src_get_event_mask (GstPad
*pad
)
224 static const GstEventMask masks
[] = {
225 // {GST_EVENT_SEEK, GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
226 {GST_EVENT_FLUSH
, 0},
245 rb_daap_src_base_init (gpointer g_class
)
247 GstElementClass
*element_class
= GST_ELEMENT_CLASS (g_class
);
248 #ifdef HAVE_GSTREAMER_0_10
249 gst_element_class_add_pad_template (element_class
,
250 gst_static_pad_template_get (&srctemplate
));
252 gst_element_class_set_details (element_class
, &rb_daap_src_details
);
256 rb_daap_src_class_init (RBDAAPSrcClass
*klass
)
258 #ifdef HAVE_GSTREAMER_0_8
259 GObjectClass
*gobject_class
;
260 GstElementClass
*gstelement_class
;
262 gobject_class
= (GObjectClass
*) klass
;
263 gstelement_class
= (GstElementClass
*) klass
;
265 parent_class
= g_type_class_ref (GST_TYPE_ELEMENT
);
267 gst_element_class_install_std_props (GST_ELEMENT_CLASS (klass
),
268 "bytesperread", PROP_BYTESPERREAD
, G_PARAM_READWRITE
,
269 "location", PROP_LOCATION
, G_PARAM_READWRITE
, NULL
);
271 gobject_class
->finalize
= rb_daap_src_finalize
;
273 g_object_class_install_property (gobject_class
,
275 g_param_spec_boolean ("seekable",
277 "TRUE if stream is seekable",
281 gstelement_class
->set_property
= rb_daap_src_set_property
;
282 gstelement_class
->get_property
= rb_daap_src_get_property
;
284 gstelement_class
->change_state
= rb_daap_src_change_state
;
286 GObjectClass
*gobject_class
;
287 GstElementClass
*gstelement_class
;
288 GstBaseSrcClass
*gstbasesrc_class
;
289 GstPushSrcClass
*gstpushsrc_class
;
291 gobject_class
= G_OBJECT_CLASS (klass
);
292 gstelement_class
= GST_ELEMENT_CLASS (klass
);
293 gstbasesrc_class
= (GstBaseSrcClass
*) klass
;
294 gstpushsrc_class
= (GstPushSrcClass
*) klass
;
296 parent_class
= g_type_class_ref (GST_TYPE_PUSH_SRC
);
298 gobject_class
->set_property
= rb_daap_src_set_property
;
299 gobject_class
->get_property
= rb_daap_src_get_property
;
300 gobject_class
->finalize
= rb_daap_src_finalize
;
302 g_object_class_install_property (gobject_class
, PROP_LOCATION
,
303 g_param_spec_string ("location",
305 "location of the file to read",
309 gstbasesrc_class
->start
= GST_DEBUG_FUNCPTR (rb_daap_src_start
);
310 gstbasesrc_class
->stop
= GST_DEBUG_FUNCPTR (rb_daap_src_stop
);
311 gstbasesrc_class
->is_seekable
= GST_DEBUG_FUNCPTR (rb_daap_src_is_seekable
);
312 gstbasesrc_class
->get_size
= GST_DEBUG_FUNCPTR (rb_daap_src_get_size
);
313 gstbasesrc_class
->do_seek
= GST_DEBUG_FUNCPTR (rb_daap_src_do_seek
);
315 gstpushsrc_class
->create
= GST_DEBUG_FUNCPTR (rb_daap_src_create
);
319 #ifdef HAVE_GSTREAMER_0_8
321 rb_daap_src_init (RBDAAPSrc
*src
)
324 rb_daap_src_init (RBDAAPSrc
*src
, RBDAAPSrcClass
*klass
)
327 src
->daap_uri
= NULL
;
330 src
->bytes_per_read
= 4096 * 2;
332 #ifdef HAVE_GSTREAMER_0_8
335 src
->send_discont
= FALSE
;
336 src
->need_flush
= FALSE
;
338 src
->srcpad
= gst_pad_new ("src", GST_PAD_SRC
);
339 gst_pad_set_get_function (src
->srcpad
,
341 gst_pad_set_event_mask_function (src
->srcpad
,
342 rb_daap_src_get_event_mask
);
343 gst_pad_set_event_function (src
->srcpad
,
344 rb_daap_src_srcpad_event
);
345 gst_pad_set_query_type_function (src
->srcpad
,
346 rb_daap_src_get_query_types
);
347 gst_pad_set_query_function (src
->srcpad
,
348 rb_daap_src_srcpad_query
);
349 gst_pad_set_formats_function (src
->srcpad
,
350 rb_daap_src_get_formats
);
351 gst_element_add_pad (GST_ELEMENT (src
), src
->srcpad
);
356 rb_daap_src_finalize (GObject
*object
)
359 src
= RB_DAAP_SRC (object
);
361 #ifdef HAVE_GSTREAMER_0_8
362 if (GST_FLAG_IS_SET (src
, RB_DAAP_SRC_OPEN
)) {
363 rb_daap_src_close_file (src
);
367 g_free (src
->daap_uri
);
368 src
->daap_uri
= NULL
;
370 if (src
->sock_fd
!= -1)
371 close (src
->sock_fd
);
373 G_OBJECT_CLASS (parent_class
)->finalize (object
);
377 rb_daap_src_set_property (GObject
*object
,
382 RBDAAPSrc
*src
= RB_DAAP_SRC (object
);
386 #ifdef HAVE_GSTREAMER_0_8
387 /* the element must be stopped or paused in order to do src */
388 if (GST_STATE (src
) == GST_STATE_PLAYING
|| GST_STATE (src
) == GST_STATE_PAUSED
) {
392 /* XXX check stuff */
396 g_free (src
->daap_uri
);
397 src
->daap_uri
= NULL
;
399 src
->daap_uri
= g_strdup (g_value_get_string (value
));
401 #ifdef HAVE_GSTREAMER_0_8
402 case PROP_BYTESPERREAD
:
403 src
->bytes_per_read
= g_value_get_int (value
);
407 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
413 rb_daap_src_get_property (GObject
*object
,
418 RBDAAPSrc
*src
= RB_DAAP_SRC (object
);
422 g_value_set_string (value
, src
->daap_uri
);
424 #ifdef HAVE_GSTREAMER_0_8
426 g_value_set_boolean (value
, FALSE
);
428 case PROP_BYTESPERREAD
:
429 g_value_set_int (value
, src
->bytes_per_read
);
433 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
439 rb_daap_src_write (RBDAAPSrc
*src
, const guchar
*buf
, size_t count
)
441 size_t bytes_written
= 0;
443 while (bytes_written
< count
) {
444 ssize_t wrote
= send (src
->sock_fd
, buf
+ bytes_written
, count
- bytes_written
, MSG_NOSIGNAL
);
447 GST_WARNING ("error while writing: %s", g_strerror (errno
));
453 bytes_written
+= wrote
;
456 GST_DEBUG_OBJECT (src
, "wrote %d bytes succesfully", bytes_written
);
457 return bytes_written
;
461 rb_daap_src_read (RBDAAPSrc
*src
, guchar
*buf
, size_t count
)
463 size_t bytes_read
= 0;
465 if (src
->buffer_size
> 0) {
467 if (bytes_read
> src
->buffer_size
)
468 bytes_read
= src
->buffer_size
;
470 GST_DEBUG_OBJECT (src
, "reading %d bytes from buffer", bytes_read
);
471 memcpy (buf
, src
->buffer
, bytes_read
);
472 src
->buffer
+= bytes_read
;
473 src
->buffer_size
-= bytes_read
;
475 if (src
->buffer_size
== 0) {
476 g_free (src
->buffer_base
);
477 src
->buffer_base
= NULL
;
482 while (bytes_read
< count
) {
483 ssize_t ret
= read (src
->sock_fd
, buf
+ bytes_read
, count
- bytes_read
);
486 GST_WARNING ("error while reading: %s", g_strerror (errno
));
494 GST_DEBUG_OBJECT (src
, "read %d bytes succesfully", bytes_read
);
499 _expect_char (RBDAAPSrc
*src
, guchar expected
)
502 if (rb_daap_src_read (src
, &ch
, sizeof (ch
)) <= 0)
504 if (ch
!= expected
) {
505 GST_DEBUG_OBJECT (src
, "Expected char %d next, but got %d", expected
, ch
);
512 rb_daap_src_read_chunk_size (RBDAAPSrc
*src
, gboolean first_chunk
, gint64
*chunk_size
)
517 memset (&chunk_buf
, 0, sizeof (chunk_buf
));
519 GST_DEBUG_OBJECT (src
, "reading next chunk size; first_chunk = %d", first_chunk
);
521 if (!_expect_char (src
, '\r') ||
522 !_expect_char (src
, '\n')) {
528 if (rb_daap_src_read (src
, (guchar
*)&ch
, sizeof(ch
)) <= 0)
532 if (!_expect_char (src
, '\n')) {
535 *chunk_size
= strtoul (chunk_buf
, NULL
, 16);
536 if (*chunk_size
== 0) {
538 GST_DEBUG_OBJECT (src
, "got EOS chunk");
540 } else if (*chunk_size
== ULONG_MAX
) {
542 GST_DEBUG_OBJECT (src
, "HTTP chunk size overflowed");
546 GST_DEBUG_OBJECT (src
, "got HTTP chunk size %lu", *chunk_size
);
548 } else if (isxdigit (ch
)) {
551 GST_DEBUG_OBJECT (src
, "HTTP chunk size included illegal character %c", ch
);
556 g_assert_not_reached ();
560 _split_uri (const gchar
*daap_uri
, gchar
**host
, guint
*port
, gchar
**path
)
563 const gchar
*pathstart
= NULL
;
564 const gchar
*hostport
= NULL
;
565 const gchar
*portstart
= NULL
;
567 locationlen
= strlen (daap_uri
);
568 hostport
= daap_uri
+ 7;
569 pathstart
= strchr (hostport
, '/');
572 *path
= g_strdup (pathstart
);
574 *path
= g_strdup ("/");
575 pathstart
= daap_uri
+ locationlen
;
578 portstart
= strrchr (hostport
, ':');
580 *host
= g_strndup (hostport
, portstart
- hostport
);
581 *port
= strtoul (portstart
+ 1, NULL
, 0);
583 *host
= g_strndup (hostport
, pathstart
- hostport
);
589 rb_daap_src_open (RBDAAPSrc
*src
)
592 struct sockaddr_in server
;
593 RBDAAPSource
*source
;
598 GHashTable
*header_table
;
605 gchar
*http_status_phrase
= NULL
;
607 if (src
->buffer_base
) {
608 g_free (src
->buffer_base
);
609 src
->buffer_base
= NULL
;
611 src
->buffer_size
= 0;
614 rb_debug ("Connecting to DAAP source: %s", src
->daap_uri
);
617 src
->sock_fd
= socket (AF_INET
, SOCK_STREAM
, 0);
618 if (src
->sock_fd
== -1) {
619 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
), GST_ERROR_SYSTEM
);
623 _split_uri (src
->daap_uri
, &host
, &port
, &path
);
625 server
.sin_family
= AF_INET
;
626 server
.sin_port
= htons (port
);
627 server
.sin_addr
.s_addr
= inet_addr (host
);
628 memset (&server
.sin_zero
, 0, sizeof (server
.sin_zero
));
630 GST_DEBUG_OBJECT (src
, "connecting to server %s:%d", host
, port
);
631 ret
= connect (src
->sock_fd
, (struct sockaddr
*) &server
, sizeof (struct sockaddr
));
633 if (errno
== ECONNREFUSED
) {
634 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
,
635 (_("Connection to %s:%d refused."), host
, port
),
638 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
),
639 ("Connect to %s:%d failed: %s", host
, port
,
640 g_strerror (errno
)));
647 /* construct request */
648 source
= rb_daap_plugin_find_source_for_uri (daap_plugin
, src
->daap_uri
);
649 if (source
== NULL
) {
650 g_warning ("Unable to lookup source for URI: %s", src
->daap_uri
);
654 /* The following can fail if the source is no longer connected */
655 #ifdef HAVE_GSTREAMER_0_8
656 headers
= rb_daap_source_get_headers (source
, src
->daap_uri
, src
->seek_time
, &src
->seek_bytes
);
658 headers
= rb_daap_source_get_headers (source
, src
->daap_uri
, src
->seek_bytes
);
660 if (headers
== NULL
) {
666 request
= g_strdup_printf ("GET %s HTTP/1.1\r\nHost: %s\r\n%s\r\n",
667 path
, host
, headers
);
673 GST_DEBUG_OBJECT (src
, "Sending HTTP request:\n%s", request
);
674 if (rb_daap_src_write (src
, (guchar
*)request
, strlen (request
)) <= 0) {
675 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
),
676 ("Sending HTTP request to %s failed: %s",
677 src
->daap_uri
, g_strerror (errno
)));
684 response
= g_malloc0 (RESPONSE_BUFFER_SIZE
+ 1);
685 readsize
= rb_daap_src_read (src
, (guchar
*)response
, RESPONSE_BUFFER_SIZE
);
688 GST_DEBUG_OBJECT (src
, "Error while reading HTTP response header");
691 response
[readsize
] = '\0';
692 GST_DEBUG_OBJECT (src
, "Got HTTP response:\n%s", response
);
694 end_headers
= strstr (response
, "\r\n\r\n");
696 /* this means the DAAP server returned more than 4k of headers.
697 * not terribly likely.
700 GST_DEBUG_OBJECT (src
, "HTTP response header way too long");
704 /* libsoup wants the headers null-terminated, despite taking a parameter
705 * specifying how long they are.
707 end_headers
[2] = '\0';
710 header_table
= g_hash_table_new (soup_str_case_hash
, soup_str_case_equal
);
711 if (soup_headers_parse_response (response
,
712 (end_headers
- response
),
716 &http_status_phrase
)) {
717 if (http_status
== 200 || http_status
== 206) {
720 val
= g_hash_table_lookup (header_table
, "Transfer-Encoding");
722 if (g_strcasecmp ((gchar
*)val
->data
, "chunked") == 0) {
725 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
),
726 ("Unknown HTTP transfer encoding \"%s\"", val
->data
));
729 src
->chunked
= FALSE
;
730 val
= g_hash_table_lookup (header_table
, "Content-Length");
733 src
->size
= strtoul ((char *)val
->data
, &e
, 10);
734 if (e
== val
->data
) {
735 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
),
736 ("Couldn't read HTTP content length \"%s\"", val
->data
));
740 GST_DEBUG_OBJECT (src
, "Response doesn't have a content length");
746 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
,
747 ("HTTP error: %s", http_status_phrase
),
752 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
),
753 ("Unable to parse HTTP response"));
756 g_free (http_status_phrase
);
757 g_hash_table_destroy (header_table
);
759 /* copy remaining data into a new buffer */
761 src
->buffer_size
= readsize
- (end_headers
- response
);
762 src
->buffer_base
= g_malloc0 (src
->buffer_size
);
763 src
->buffer
= src
->buffer_base
;
764 memcpy (src
->buffer_base
, response
+ (readsize
- src
->buffer_size
), src
->buffer_size
);
772 #ifdef HAVE_GSTREAMER_0_8
773 rb_daap_src_open_file (RBDAAPSrc
*src
)
776 rb_daap_src_start (GstBaseSrc
*bsrc
)
778 RBDAAPSrc
*src
= RB_DAAP_SRC (bsrc
);
780 if (src
->sock_fd
!= -1) {
781 close (src
->sock_fd
);
786 if (rb_daap_src_open (src
)) {
787 src
->buffer
= src
->buffer_base
;
788 #ifdef HAVE_GSTREAMER_0_8
789 src
->seek_time_to_return
= src
->seek_time
;
790 if (src
->seek_bytes
!= 0) {
791 src
->need_flush
= TRUE
;
792 src
->send_discont
= TRUE
;
794 GST_FLAG_SET (src
, RB_DAAP_SRC_OPEN
);
796 src
->curoffset
= src
->seek_bytes
;
799 src
->first_chunk
= TRUE
;
808 #ifdef HAVE_GSTREAMER_0_8
810 rb_daap_src_close_file (RBDAAPSrc
*src
)
812 if (src
->sock_fd
!= -1) {
813 close (src
->sock_fd
);
819 src
->send_discont
= FALSE
;
821 GST_FLAG_UNSET (src
, RB_DAAP_SRC_OPEN
);
825 rb_daap_src_stop (GstBaseSrc
*bsrc
)
827 /* don't do anything - this seems to get called during setup, but
828 * we don't get started again afterwards.
834 #ifdef HAVE_GSTREAMER_0_8
836 rb_daap_src_get (GstPad
*pad
)
839 rb_daap_src_create (GstPushSrc
*psrc
, GstBuffer
**outbuf
)
844 GstBuffer
*buf
= NULL
;
846 #ifdef HAVE_GSTREAMER_0_8
847 g_return_val_if_fail (pad
!= NULL
, NULL
);
848 g_return_val_if_fail (GST_IS_PAD (pad
), NULL
);
849 src
= RB_DAAP_SRC (GST_OBJECT_PARENT (pad
));
850 g_return_val_if_fail (GST_FLAG_IS_SET (src
, RB_DAAP_SRC_OPEN
), NULL
);
852 src
= RB_DAAP_SRC (psrc
);
856 if (src
->sock_fd
!= -1) {
857 close (src
->sock_fd
);
860 #ifdef HAVE_GSTREAMER_0_8
861 if (!rb_daap_src_open_file (src
))
862 return GST_DATA (gst_event_new (GST_EVENT_EOS
));
864 if (!rb_daap_src_start (GST_BASE_SRC (src
)))
865 return GST_FLOW_ERROR
;
867 src
->do_seek
= FALSE
;
870 #ifdef HAVE_GSTREAMER_0_8
871 /* try to negotiate here */
872 if (!gst_pad_is_negotiated (pad
)) {
873 if (GST_PAD_LINK_FAILED (gst_pad_renegotiate (pad
))) {
874 GST_ELEMENT_ERROR (src
, CORE
, NEGOTIATION
, (NULL
), GST_ERROR_SYSTEM
);
875 gst_buffer_unref (buf
);
876 return GST_DATA (gst_event_new (GST_EVENT_EOS
));
880 if (src
->need_flush
) {
881 GstEvent
*event
= gst_event_new_flush ();
883 src
->need_flush
= FALSE
;
884 return GST_DATA (event
);
887 if (src
->send_discont
) {
890 src
->send_discont
= FALSE
;
891 event
= gst_event_new_discontinuous (FALSE
, GST_FORMAT_BYTES
, src
->curoffset
+ src
->seek_bytes
, NULL
);
892 return GST_DATA (event
);
896 /* get a new chunk, if we need one */
897 if (src
->chunked
&& src
->size
== 0) {
898 if (!rb_daap_src_read_chunk_size (src
, src
->first_chunk
, &src
->size
)) {
899 #ifdef HAVE_GSTREAMER_0_8
900 return GST_DATA (gst_event_new (GST_EVENT_EOS
));
902 return GST_FLOW_ERROR
;
904 } else if (src
->size
== 0) {
906 #ifdef HAVE_GSTREAMER_0_8
907 gst_element_set_eos (GST_ELEMENT (src
));
908 return GST_DATA (gst_event_new (GST_EVENT_EOS
));
910 return GST_FLOW_UNEXPECTED
;
913 src
->first_chunk
= FALSE
;
916 readsize
= src
->bytes_per_read
;
917 if (src
->chunked
&& readsize
> src
->size
)
918 readsize
= src
->size
;
920 #ifdef HAVE_GSTREAMER_0_8
921 buf
= gst_buffer_new ();
922 g_return_val_if_fail (buf
, NULL
);
923 GST_BUFFER_DATA (buf
) = g_malloc0 (readsize
);
924 g_return_val_if_fail (GST_BUFFER_DATA (buf
) != NULL
, NULL
);
926 buf
= gst_buffer_new_and_alloc (readsize
);
929 GST_LOG_OBJECT (src
, "Reading %d bytes", readsize
);
930 readsize
= rb_daap_src_read (src
, GST_BUFFER_DATA (buf
), readsize
);
932 GST_ELEMENT_ERROR (src
, RESOURCE
, READ
, (NULL
), GST_ERROR_SYSTEM
);
933 gst_buffer_unref (buf
);
934 #ifdef HAVE_GSTREAMER_0_8
935 return GST_DATA (gst_event_new (GST_EVENT_EOS
));
937 return GST_FLOW_ERROR
;
942 GST_DEBUG ("blocking read returns 0, EOS");
943 gst_buffer_unref (buf
);
944 #ifdef HAVE_GSTREAMER_0_8
945 gst_element_set_eos (GST_ELEMENT (src
));
946 return GST_DATA (gst_event_new (GST_EVENT_EOS
));
948 return GST_FLOW_UNEXPECTED
;
953 src
->size
-= readsize
;
955 GST_BUFFER_OFFSET (buf
) = src
->curoffset
;
956 GST_BUFFER_SIZE (buf
) = readsize
;
957 GST_BUFFER_TIMESTAMP (buf
) = GST_CLOCK_TIME_NONE
;
958 src
->curoffset
+= readsize
;
961 "Returning buffer from _get of size %d, ts %"
962 GST_TIME_FORMAT
", dur %" GST_TIME_FORMAT
963 ", offset %" G_GINT64_FORMAT
", offset_end %" G_GINT64_FORMAT
,
964 GST_BUFFER_SIZE (buf
), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf
)),
965 GST_TIME_ARGS (GST_BUFFER_DURATION (buf
)),
966 GST_BUFFER_OFFSET (buf
), GST_BUFFER_OFFSET_END (buf
));
967 #ifdef HAVE_GSTREAMER_0_8
968 return GST_DATA (buf
);
975 #ifdef HAVE_GSTREAMER_0_8
976 static GstElementStateReturn
977 rb_daap_src_change_state (GstElement
*element
)
979 g_return_val_if_fail (RB_IS_DAAP_SRC (element
), GST_STATE_FAILURE
);
981 switch (GST_STATE_TRANSITION (element
)) {
982 case GST_STATE_READY_TO_PAUSED
:
983 if (!GST_FLAG_IS_SET (element
, RB_DAAP_SRC_OPEN
)) {
984 if (!rb_daap_src_open_file (RB_DAAP_SRC (element
))) {
985 return GST_STATE_FAILURE
;
989 case GST_STATE_PAUSED_TO_READY
:
990 if (GST_FLAG_IS_SET (element
, RB_DAAP_SRC_OPEN
)) {
991 rb_daap_src_close_file (RB_DAAP_SRC (element
));
994 case GST_STATE_NULL_TO_READY
:
995 case GST_STATE_READY_TO_NULL
:
1000 if (GST_ELEMENT_CLASS (parent_class
)->change_state
) {
1001 return GST_ELEMENT_CLASS (parent_class
)->change_state (element
);
1004 return GST_STATE_SUCCESS
;
1008 rb_daap_src_srcpad_event (GstPad
*pad
,
1011 RBDAAPSrc
*src
= RB_DAAP_SRC (GST_PAD_PARENT (pad
));
1013 switch (GST_EVENT_TYPE (event
)) {
1014 case GST_EVENT_SEEK
: {
1015 gint64 desired_offset
= 0;
1017 if (GST_EVENT_SEEK_FORMAT (event
) != GST_FORMAT_BYTES
) {
1018 gst_event_unref (event
);
1022 switch (GST_EVENT_SEEK_METHOD (event
)) {
1023 case GST_SEEK_METHOD_SET
:
1024 desired_offset
= (gint64
) GST_EVENT_SEEK_OFFSET (event
);
1026 case GST_SEEK_METHOD_CUR
:
1027 desired_offset
= src
->curoffset
+ GST_EVENT_SEEK_OFFSET (event
);
1029 case GST_SEEK_METHOD_END
:
1030 if (src
->size
== 0) {
1033 desired_offset
= src
->size
- ABS (GST_EVENT_SEEK_OFFSET (event
));
1036 gst_event_unref (event
);
1043 case GST_EVENT_SIZE
:
1044 if (GST_EVENT_SIZE_FORMAT (event
) != GST_FORMAT_BYTES
) {
1045 gst_event_unref (event
);
1048 src
->bytes_per_read
= GST_EVENT_SIZE_VALUE (event
);
1049 g_object_notify (G_OBJECT (src
), "bytesperread");
1051 case GST_EVENT_FLUSH
:
1052 src
->need_flush
= TRUE
;
1055 gst_event_unref (event
);
1060 gst_event_unref (event
);
1066 rb_daap_src_srcpad_query (GstPad
*pad
,
1071 RBDAAPSrc
*src
= RB_DAAP_SRC (gst_pad_get_parent (pad
));
1074 case GST_QUERY_TOTAL
:
1075 if (*format
!= GST_FORMAT_BYTES
|| src
->size
== 0) {
1080 case GST_QUERY_POSITION
:
1082 case GST_FORMAT_BYTES
:
1083 *value
= src
->curoffset
;
1085 case GST_FORMAT_PERCENT
:
1086 return FALSE
; /* FIXME */
1087 if (src
->size
== 0) {
1090 *value
= src
->curoffset
* GST_FORMAT_PERCENT_MAX
/ src
->size
;
1106 rb_daap_src_is_seekable (GstBaseSrc
*bsrc
)
1112 rb_daap_src_do_seek (GstBaseSrc
*bsrc
, GstSegment
*segment
)
1114 RBDAAPSrc
*src
= RB_DAAP_SRC (bsrc
);
1115 if (segment
->format
== GST_FORMAT_BYTES
) {
1116 src
->do_seek
= TRUE
;
1117 src
->seek_bytes
= segment
->start
;
1125 rb_daap_src_get_size (GstBaseSrc
*bsrc
, guint64
*size
)
1127 RBDAAPSrc
*src
= RB_DAAP_SRC (bsrc
);
1128 if (src
->chunked
== FALSE
&& src
->size
> 0) {
1138 plugin_init (GstPlugin
*plugin
)
1140 gboolean ret
= gst_element_register (plugin
, "rbdaapsrc", GST_RANK_PRIMARY
, RB_TYPE_DAAP_SRC
);
1144 GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR
,
1147 "element to access DAAP music share files",
1154 #ifdef HAVE_GSTREAMER_0_8
1155 /*** RB DAAP SEEK INTERFACE **************************************************/
1158 rb_daap_src_set_time (GstElement
*element
, glong time
)
1160 RBDAAPSrc
*src
= RB_DAAP_SRC (element
);
1161 src
->seek_time
= time
;
1162 src
->do_seek
= TRUE
;
1166 rb_daap_src_get_time (GstElement
*element
)
1168 RBDAAPSrc
*src
= RB_DAAP_SRC (element
);
1169 return src
->seek_time_to_return
;
1173 /*** GSTURIHANDLER INTERFACE *************************************************/
1176 rb_daap_src_uri_get_type (void)
1182 rb_daap_src_uri_get_protocols (void)
1184 static gchar
*protocols
[] = {"daap", NULL
};
1189 static const gchar
*
1190 rb_daap_src_uri_get_uri (GstURIHandler
*handler
)
1192 RBDAAPSrc
*src
= RB_DAAP_SRC (handler
);
1194 return src
->daap_uri
;
1198 rb_daap_src_uri_set_uri (GstURIHandler
*handler
,
1201 RBDAAPSrc
*src
= RB_DAAP_SRC (handler
);
1203 if (GST_STATE (src
) == GST_STATE_PLAYING
|| GST_STATE (src
) == GST_STATE_PAUSED
) {
1207 g_object_set (G_OBJECT (src
), "location", uri
, NULL
);
1213 rb_daap_src_uri_handler_init (gpointer g_iface
,
1214 gpointer iface_data
)
1216 GstURIHandlerInterface
*iface
= (GstURIHandlerInterface
*) g_iface
;
1218 iface
->get_type
= rb_daap_src_uri_get_type
;
1219 iface
->get_protocols
= rb_daap_src_uri_get_protocols
;
1220 iface
->get_uri
= rb_daap_src_uri_get_uri
;
1221 iface
->set_uri
= rb_daap_src_uri_set_uri
;