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"
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
61 RB_DAAP_SRC_OPEN
= GST_ELEMENT_FLAG_LAST
,
63 RB_DAAP_SRC_FLAG_LAST
= GST_ELEMENT_FLAG_LAST
+ 2
67 typedef struct _RBDAAPSrc RBDAAPSrc
;
68 typedef struct _RBDAAPSrcClass RBDAAPSrcClass
;
72 #ifdef HAVE_GSTREAMER_0_8
87 guint32 bytes_per_read
;
97 #ifdef HAVE_GSTREAMER_0_8
99 gboolean send_discont
;
100 glong seek_time_to_return
;
105 struct _RBDAAPSrcClass
107 #ifdef HAVE_GSTREAMER_0_8
108 GstElementClass parent_class
;
110 GstPushSrcClass parent_class
;
114 #ifdef HAVE_GSTREAMER_0_10
115 static GstStaticPadTemplate srctemplate
= GST_STATIC_PAD_TEMPLATE ("src",
118 GST_STATIC_CAPS_ANY
);
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",
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
);
133 _do_init (GType daap_src_type
)
135 static const GInterfaceInfo urihandler_info
= {
136 rb_daap_src_uri_handler_init
,
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
,
148 #ifdef HAVE_GSTREAMER_0_8
149 GST_BOILERPLATE_FULL (RBDAAPSrc
, rb_daap_src
, GstElement
, GST_TYPE_ELEMENT
, _do_init
);
151 GST_BOILERPLATE_FULL (RBDAAPSrc
, rb_daap_src
, GstElement
, GST_TYPE_PUSH_SRC
, _do_init
);
154 static void rb_daap_src_finalize (GObject
*object
);
155 static void rb_daap_src_set_property (GObject
*object
,
159 static void rb_daap_src_get_property (GObject
*object
,
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
,
175 static gboolean
rb_daap_src_srcpad_query (GstPad
*pad
,
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
);
188 #ifdef HAVE_GSTREAMER_0_8
190 static const GstFormat
*
191 rb_daap_src_get_formats (GstPad
*pad
)
193 static const GstFormat formats
[] = {
201 static const GstQueryType
*
202 rb_daap_src_get_query_types (GstPad
*pad
)
204 static const GstQueryType 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},
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
));
244 gst_element_class_set_details (element_class
, &rb_daap_src_details
);
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
,
267 g_param_spec_boolean ("seekable",
269 "TRUE if stream is seekable",
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
;
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",
297 "location of the file to read",
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
);
311 #ifdef HAVE_GSTREAMER_0_8
313 rb_daap_src_init (RBDAAPSrc
*src
)
316 rb_daap_src_init (RBDAAPSrc
*src
, RBDAAPSrcClass
*klass
)
319 src
->daap_uri
= NULL
;
322 src
->bytes_per_read
= 4096 * 2;
324 #ifdef HAVE_GSTREAMER_0_8
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
,
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
);
350 rb_daap_src_finalize (GObject
*object
)
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
);
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
);
371 rb_daap_src_set_property (GObject
*object
,
376 RBDAAPSrc
*src
= RB_DAAP_SRC (object
);
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
) {
386 /* XXX check stuff */
390 g_free (src
->daap_uri
);
391 src
->daap_uri
= NULL
;
393 src
->daap_uri
= g_strdup (g_value_get_string (value
));
395 #ifdef HAVE_GSTREAMER_0_8
396 case PROP_BYTESPERREAD
:
397 src
->bytes_per_read
= g_value_get_int (value
);
401 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
407 rb_daap_src_get_property (GObject
*object
,
412 RBDAAPSrc
*src
= RB_DAAP_SRC (object
);
416 g_value_set_string (value
, src
->daap_uri
);
418 #ifdef HAVE_GSTREAMER_0_8
420 g_value_set_boolean (value
, FALSE
);
422 case PROP_BYTESPERREAD
:
423 g_value_set_int (value
, src
->bytes_per_read
);
427 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
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
);
441 GST_WARNING ("error while writing: %s", g_strerror (errno
));
447 bytes_written
+= wrote
;
450 GST_DEBUG_OBJECT (src
, "wrote %d bytes succesfully", bytes_written
);
451 return bytes_written
;
455 rb_daap_src_read (RBDAAPSrc
*src
, guchar
*buf
, size_t count
)
457 size_t bytes_read
= 0;
459 if (src
->buffer_size
> 0) {
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
;
476 while (bytes_read
< count
) {
477 ssize_t ret
= read (src
->sock_fd
, buf
+ bytes_read
, count
- bytes_read
);
480 GST_WARNING ("error while reading: %s", g_strerror (errno
));
488 GST_DEBUG_OBJECT (src
, "read %d bytes succesfully", bytes_read
);
493 _expect_char (RBDAAPSrc
*src
, guchar expected
)
496 if (rb_daap_src_read (src
, &ch
, sizeof (ch
)) <= 0)
498 if (ch
!= expected
) {
499 GST_DEBUG_OBJECT (src
, "Expected char %d next, but got %d", expected
, ch
);
506 rb_daap_src_read_chunk_size (RBDAAPSrc
*src
, gboolean first_chunk
, gint64
*chunk_size
)
511 memset (&chunk_buf
, 0, sizeof (chunk_buf
));
513 GST_DEBUG_OBJECT (src
, "reading next chunk size; first_chunk = %d", first_chunk
);
515 if (!_expect_char (src
, '\r') ||
516 !_expect_char (src
, '\n')) {
522 if (rb_daap_src_read (src
, (guchar
*)&ch
, sizeof(ch
)) <= 0)
526 if (!_expect_char (src
, '\n')) {
529 *chunk_size
= strtoul (chunk_buf
, NULL
, 16);
530 if (*chunk_size
== 0) {
532 GST_DEBUG_OBJECT (src
, "got EOS chunk");
534 } else if (*chunk_size
== ULONG_MAX
) {
536 GST_DEBUG_OBJECT (src
, "HTTP chunk size overflowed");
540 GST_DEBUG_OBJECT (src
, "got HTTP chunk size %lu", *chunk_size
);
542 } else if (isxdigit (ch
)) {
545 GST_DEBUG_OBJECT (src
, "HTTP chunk size included illegal character %c", ch
);
550 g_assert_not_reached ();
554 _split_uri (const gchar
*daap_uri
, gchar
**host
, guint
*port
, gchar
**path
)
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
, '/');
566 *path
= g_strdup (pathstart
);
568 *path
= g_strdup ("/");
569 pathstart
= daap_uri
+ locationlen
;
572 portstart
= strrchr (hostport
, ':');
574 *host
= g_strndup (hostport
, portstart
- hostport
);
575 *port
= strtoul (portstart
+ 1, NULL
, 0);
577 *host
= g_strndup (hostport
, pathstart
- hostport
);
583 rb_daap_src_open (RBDAAPSrc
*src
)
586 struct sockaddr_in server
;
587 RBDAAPSource
*source
;
592 GHashTable
*header_table
;
599 gchar
*http_status_phrase
= NULL
;
601 if (src
->buffer_base
) {
602 g_free (src
->buffer_base
);
603 src
->buffer_base
= NULL
;
605 src
->buffer_size
= 0;
608 rb_debug ("Connecting to DAAP source: %s", src
->daap_uri
);
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
);
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
));
627 if (errno
== ECONNREFUSED
) {
628 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
,
629 (_("Connection to %s:%d refused."), host
, port
),
632 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
),
633 ("Connect to %s:%d failed: %s", host
, port
,
634 g_strerror (errno
)));
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
);
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
);
652 headers
= rb_daap_source_get_headers (source
, src
->daap_uri
, src
->seek_bytes
);
654 if (headers
== NULL
) {
660 request
= g_strdup_printf ("GET %s HTTP/1.1\r\nHost: %s\r\n%s\r\n",
661 path
, host
, headers
);
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
)));
678 response
= g_malloc0 (RESPONSE_BUFFER_SIZE
+ 1);
679 readsize
= rb_daap_src_read (src
, (guchar
*)response
, RESPONSE_BUFFER_SIZE
);
682 GST_DEBUG_OBJECT (src
, "Error while reading HTTP response header");
685 response
[readsize
] = '\0';
686 GST_DEBUG_OBJECT (src
, "Got HTTP response:\n%s", response
);
688 end_headers
= strstr (response
, "\r\n\r\n");
690 /* this means the DAAP server returned more than 4k of headers.
691 * not terribly likely.
694 GST_DEBUG_OBJECT (src
, "HTTP response header way too long");
698 /* libsoup wants the headers null-terminated, despite taking a parameter
699 * specifying how long they are.
701 end_headers
[2] = '\0';
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
),
710 &http_status_phrase
)) {
711 if (http_status
== 200 || http_status
== 206) {
714 val
= g_hash_table_lookup (header_table
, "Transfer-Encoding");
716 if (g_strcasecmp ((gchar
*)val
->data
, "chunked") == 0) {
719 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
),
720 ("Unknown HTTP transfer encoding \"%s\"", val
->data
));
723 src
->chunked
= FALSE
;
724 val
= g_hash_table_lookup (header_table
, "Content-Length");
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
));
737 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
,
738 ("HTTP error: %s", http_status_phrase
),
743 GST_ELEMENT_ERROR (src
, RESOURCE
, OPEN_READ
, (NULL
),
744 ("Unable to parse HTTP response"));
747 g_free (http_status_phrase
);
748 g_hash_table_destroy (header_table
);
750 /* copy remaining data into a new buffer */
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
);
763 #ifdef HAVE_GSTREAMER_0_8
764 rb_daap_src_open_file (RBDAAPSrc
*src
)
767 rb_daap_src_start (GstBaseSrc
*bsrc
)
769 RBDAAPSrc
*src
= RB_DAAP_SRC (bsrc
);
771 if (src
->sock_fd
!= -1) {
772 close (src
->sock_fd
);
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
);
787 src
->curoffset
= src
->seek_bytes
;
790 src
->first_chunk
= TRUE
;
799 #ifdef HAVE_GSTREAMER_0_8
801 rb_daap_src_close_file (RBDAAPSrc
*src
)
803 if (src
->sock_fd
!= -1) {
804 close (src
->sock_fd
);
810 src
->send_discont
= FALSE
;
812 GST_FLAG_UNSET (src
, RB_DAAP_SRC_OPEN
);
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.
825 #ifdef HAVE_GSTREAMER_0_8
827 rb_daap_src_get (GstPad
*pad
)
830 rb_daap_src_create (GstPushSrc
*psrc
, GstBuffer
**outbuf
)
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
);
843 src
= RB_DAAP_SRC (psrc
);
847 if (src
->sock_fd
!= -1) {
848 close (src
->sock_fd
);
851 #ifdef HAVE_GSTREAMER_0_8
852 if (!rb_daap_src_open_file (src
))
853 return GST_DATA (gst_event_new (GST_EVENT_EOS
));
855 if (!rb_daap_src_start (GST_BASE_SRC (src
)))
856 return GST_FLOW_ERROR
;
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
) {
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
);
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
));
893 return GST_FLOW_ERROR
;
895 } else if (src
->size
== 0) {
897 #ifdef HAVE_GSTREAMER_0_8
898 gst_element_set_eos (GST_ELEMENT (src
));
899 return GST_DATA (gst_event_new (GST_EVENT_EOS
));
901 return GST_FLOW_UNEXPECTED
;
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
);
917 buf
= gst_buffer_new_and_alloc (readsize
);
920 GST_LOG_OBJECT (src
, "Reading %d bytes", readsize
);
921 readsize
= rb_daap_src_read (src
, GST_BUFFER_DATA (buf
), readsize
);
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
));
928 return GST_FLOW_ERROR
;
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
));
939 return GST_FLOW_UNEXPECTED
;
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
;
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
);
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
;
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
));
985 case GST_STATE_NULL_TO_READY
:
986 case GST_STATE_READY_TO_NULL
:
991 if (GST_ELEMENT_CLASS (parent_class
)->change_state
) {
992 return GST_ELEMENT_CLASS (parent_class
)->change_state (element
);
995 return GST_STATE_SUCCESS
;
999 rb_daap_src_srcpad_event (GstPad
*pad
,
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
);
1013 switch (GST_EVENT_SEEK_METHOD (event
)) {
1014 case GST_SEEK_METHOD_SET
:
1015 desired_offset
= (gint64
) GST_EVENT_SEEK_OFFSET (event
);
1017 case GST_SEEK_METHOD_CUR
:
1018 desired_offset
= src
->curoffset
+ GST_EVENT_SEEK_OFFSET (event
);
1020 case GST_SEEK_METHOD_END
:
1021 if (src
->size
== 0) {
1024 desired_offset
= src
->size
- ABS (GST_EVENT_SEEK_OFFSET (event
));
1027 gst_event_unref (event
);
1034 case GST_EVENT_SIZE
:
1035 if (GST_EVENT_SIZE_FORMAT (event
) != GST_FORMAT_BYTES
) {
1036 gst_event_unref (event
);
1039 src
->bytes_per_read
= GST_EVENT_SIZE_VALUE (event
);
1040 g_object_notify (G_OBJECT (src
), "bytesperread");
1042 case GST_EVENT_FLUSH
:
1043 src
->need_flush
= TRUE
;
1046 gst_event_unref (event
);
1051 gst_event_unref (event
);
1057 rb_daap_src_srcpad_query (GstPad
*pad
,
1062 RBDAAPSrc
*src
= RB_DAAP_SRC (gst_pad_get_parent (pad
));
1065 case GST_QUERY_TOTAL
:
1066 if (*format
!= GST_FORMAT_BYTES
|| src
->size
== 0) {
1071 case GST_QUERY_POSITION
:
1073 case GST_FORMAT_BYTES
:
1074 *value
= src
->curoffset
;
1076 case GST_FORMAT_PERCENT
:
1077 return FALSE
; /* FIXME */
1078 if (src
->size
== 0) {
1081 *value
= src
->curoffset
* GST_FORMAT_PERCENT_MAX
/ src
->size
;
1097 rb_daap_src_is_seekable (GstBaseSrc
*bsrc
)
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
;
1116 rb_daap_src_get_size (GstBaseSrc
*bsrc
, guint64
*size
)
1118 RBDAAPSrc
*src
= RB_DAAP_SRC (bsrc
);
1119 if (!src
->chunked
) {
1129 plugin_init (GstPlugin
*plugin
)
1131 gboolean ret
= gst_element_register (plugin
, "rbdaapsrc", GST_RANK_PRIMARY
, RB_TYPE_DAAP_SRC
);
1135 GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR
,
1138 "element to access DAAP music share files",
1145 #ifdef HAVE_GSTREAMER_0_8
1146 /*** RB DAAP SEEK INTERFACE **************************************************/
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
;
1157 rb_daap_src_get_time (GstElement
*element
)
1159 RBDAAPSrc
*src
= RB_DAAP_SRC (element
);
1160 return src
->seek_time_to_return
;
1164 /*** GSTURIHANDLER INTERFACE *************************************************/
1167 rb_daap_src_uri_get_type (void)
1173 rb_daap_src_uri_get_protocols (void)
1175 static gchar
*protocols
[] = {"daap", NULL
};
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
;
1189 rb_daap_src_uri_set_uri (GstURIHandler
*handler
,
1192 RBDAAPSrc
*src
= RB_DAAP_SRC (handler
);
1194 if (GST_STATE (src
) == GST_STATE_PLAYING
|| GST_STATE (src
) == GST_STATE_PAUSED
) {
1198 g_object_set (G_OBJECT (src
), "location", uri
, NULL
);
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
;