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);
375
G_OBJECT_CLASS (parent_class)->finalize (object);
379
rb_daap_src_set_property (GObject *object,
384
RBDAAPSrc *src = RB_DAAP_SRC (object);
388
#ifdef HAVE_GSTREAMER_0_8
389
/* the element must be stopped or paused in order to do src */
390
if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) {
394
/* XXX check stuff */
398
g_free (src->daap_uri);
399
src->daap_uri = NULL;
401
src->daap_uri = g_strdup (g_value_get_string (value));
403
#ifdef HAVE_GSTREAMER_0_8
404
case PROP_BYTESPERREAD:
405
src->bytes_per_read = g_value_get_int (value);
409
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
415
rb_daap_src_get_property (GObject *object,
420
RBDAAPSrc *src = RB_DAAP_SRC (object);
424
g_value_set_string (value, src->daap_uri);
426
#ifdef HAVE_GSTREAMER_0_8
428
g_value_set_boolean (value, FALSE);
430
case PROP_BYTESPERREAD:
431
g_value_set_int (value, src->bytes_per_read);
435
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
441
rb_daap_src_write (RBDAAPSrc *src, const guchar *buf, size_t count)
443
size_t bytes_written = 0;
445
while (bytes_written < count) {
446
ssize_t wrote = send (src->sock_fd, buf + bytes_written, count - bytes_written, MSG_NOSIGNAL);
449
GST_WARNING ("error while writing: %s", g_strerror (errno));
455
bytes_written += wrote;
458
GST_DEBUG_OBJECT (src, "wrote %d bytes succesfully", bytes_written);
459
return bytes_written;
463
rb_daap_src_read (RBDAAPSrc *src, guchar *buf, size_t count)
465
size_t bytes_read = 0;
467
if (src->buffer_size > 0) {
469
if (bytes_read > src->buffer_size)
470
bytes_read = src->buffer_size;
472
GST_DEBUG_OBJECT (src, "reading %d bytes from buffer", bytes_read);
473
memcpy (buf, src->buffer, bytes_read);
474
src->buffer += bytes_read;
475
src->buffer_size -= bytes_read;
477
if (src->buffer_size == 0) {
478
g_free (src->buffer_base);
479
src->buffer_base = NULL;
484
while (bytes_read < count) {
485
ssize_t ret = read (src->sock_fd, buf + bytes_read, count - bytes_read);
488
GST_WARNING ("error while reading: %s", g_strerror (errno));
496
GST_DEBUG_OBJECT (src, "read %d bytes succesfully", bytes_read);
501
_expect_char (RBDAAPSrc *src, guchar expected)
504
if (rb_daap_src_read (src, &ch, sizeof (ch)) <= 0)
506
if (ch != expected) {
507
GST_DEBUG_OBJECT (src, "Expected char %d next, but got %d", expected, ch);
514
rb_daap_src_read_chunk_size (RBDAAPSrc *src, gboolean first_chunk, gint64 *chunk_size)
519
memset (&chunk_buf, 0, sizeof (chunk_buf));
521
GST_DEBUG_OBJECT (src, "reading next chunk size; first_chunk = %d", first_chunk);
523
if (!_expect_char (src, '\r') ||
524
!_expect_char (src, '\n')) {
530
if (rb_daap_src_read (src, (guchar *)&ch, sizeof(ch)) <= 0)
534
if (!_expect_char (src, '\n')) {
537
*chunk_size = strtoul (chunk_buf, NULL, 16);
538
if (*chunk_size == 0) {
540
GST_DEBUG_OBJECT (src, "got EOS chunk");
542
} else if (*chunk_size == ULONG_MAX) {
544
GST_DEBUG_OBJECT (src, "HTTP chunk size overflowed");
548
GST_DEBUG_OBJECT (src, "got HTTP chunk size %lu", *chunk_size);
550
} else if (isxdigit (ch)) {
553
GST_DEBUG_OBJECT (src, "HTTP chunk size included illegal character %c", ch);
558
g_assert_not_reached ();
562
_split_uri (const gchar *daap_uri, gchar **host, guint *port, gchar **path)
565
const gchar *pathstart = NULL;
566
const gchar *hostport = NULL;
567
const gchar *portstart = NULL;
569
locationlen = strlen (daap_uri);
570
hostport = daap_uri + 7;
571
pathstart = strchr (hostport, '/');
574
*path = g_strdup (pathstart);
576
*path = g_strdup ("/");
577
pathstart = daap_uri + locationlen;
580
portstart = strrchr (hostport, ':');
582
*host = g_strndup (hostport, portstart - hostport);
583
*port = strtoul (portstart + 1, NULL, 0);
585
*host = g_strndup (hostport, pathstart - hostport);
591
rb_daap_src_open (RBDAAPSrc *src)
594
struct sockaddr_in server;
595
RBDAAPSource *source;
600
GHashTable *header_table;
607
gchar *http_status_phrase = NULL;
609
if (src->buffer_base) {
610
g_free (src->buffer_base);
611
src->buffer_base = NULL;
613
src->buffer_size = 0;
616
rb_debug ("Connecting to DAAP source: %s", src->daap_uri);
619
src->sock_fd = socket (AF_INET, SOCK_STREAM, 0);
620
if (src->sock_fd == -1) {
621
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), GST_ERROR_SYSTEM);
625
_split_uri (src->daap_uri, &host, &port, &path);
627
server.sin_family = AF_INET;
628
server.sin_port = htons (port);
629
server.sin_addr.s_addr = inet_addr (host);
630
memset (&server.sin_zero, 0, sizeof (server.sin_zero));
632
GST_DEBUG_OBJECT (src, "connecting to server %s:%d", host, port);
633
ret = connect (src->sock_fd, (struct sockaddr *) &server, sizeof (struct sockaddr));
635
if (errno == ECONNREFUSED) {
636
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
637
(_("Connection to %s:%d refused."), host, port),
640
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
641
("Connect to %s:%d failed: %s", host, port,
642
g_strerror (errno)));
649
/* construct request */
650
source = rb_daap_plugin_find_source_for_uri (daap_plugin, src->daap_uri);
651
if (source == NULL) {
652
g_warning ("Unable to lookup source for URI: %s", src->daap_uri);
656
/* The following can fail if the source is no longer connected */
657
#ifdef HAVE_GSTREAMER_0_8
658
headers = rb_daap_source_get_headers (source, src->daap_uri, src->seek_time, &src->seek_bytes);
660
headers = rb_daap_source_get_headers (source, src->daap_uri, src->seek_bytes);
662
if (headers == NULL) {
668
request = g_strdup_printf ("GET %s HTTP/1.1\r\nHost: %s\r\n%s\r\n",
669
path, host, headers);
675
GST_DEBUG_OBJECT (src, "Sending HTTP request:\n%s", request);
676
if (rb_daap_src_write (src, (guchar *)request, strlen (request)) <= 0) {
677
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
678
("Sending HTTP request to %s failed: %s",
679
src->daap_uri, g_strerror (errno)));
686
response = g_malloc0 (RESPONSE_BUFFER_SIZE + 1);
687
readsize = rb_daap_src_read (src, (guchar *)response, RESPONSE_BUFFER_SIZE);
690
GST_DEBUG_OBJECT (src, "Error while reading HTTP response header");
693
response[readsize] = '\0';
694
GST_DEBUG_OBJECT (src, "Got HTTP response:\n%s", response);
696
end_headers = strstr (response, "\r\n\r\n");
698
/* this means the DAAP server returned more than 4k of headers.
699
* not terribly likely.
702
GST_DEBUG_OBJECT (src, "HTTP response header way too long");
706
/* libsoup wants the headers null-terminated, despite taking a parameter
707
* specifying how long they are.
709
end_headers[2] = '\0';
712
header_table = g_hash_table_new (soup_str_case_hash, soup_str_case_equal);
713
if (soup_headers_parse_response (response,
714
(end_headers - response),
718
&http_status_phrase)) {
719
if (http_status == 200 || http_status == 206) {
722
val = g_hash_table_lookup (header_table, "Transfer-Encoding");
724
if (g_strcasecmp ((gchar *)val->data, "chunked") == 0) {
727
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
728
("Unknown HTTP transfer encoding \"%s\"", val->data));
731
src->chunked = FALSE;
732
val = g_hash_table_lookup (header_table, "Content-Length");
735
src->size = strtoul ((char *)val->data, &e, 10);
736
if (e == val->data) {
737
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
738
("Couldn't read HTTP content length \"%s\"", val->data));
742
GST_DEBUG_OBJECT (src, "Response doesn't have a content length");
748
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
749
("HTTP error: %s", http_status_phrase),
754
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
755
("Unable to parse HTTP response"));
758
g_free (http_status_phrase);
759
g_hash_table_destroy (header_table);
761
/* copy remaining data into a new buffer */
763
src->buffer_size = readsize - (end_headers - response);
764
src->buffer_base = g_malloc0 (src->buffer_size);
765
src->buffer = src->buffer_base;
766
memcpy (src->buffer_base, response + (readsize - src->buffer_size), src->buffer_size);
774
#ifdef HAVE_GSTREAMER_0_8
775
rb_daap_src_open_file (RBDAAPSrc *src)
778
rb_daap_src_start (GstBaseSrc *bsrc)
780
RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
782
if (src->sock_fd != -1) {
783
close (src->sock_fd);
788
if (rb_daap_src_open (src)) {
789
src->buffer = src->buffer_base;
790
#ifdef HAVE_GSTREAMER_0_8
791
src->seek_time_to_return = src->seek_time;
792
if (src->seek_bytes != 0) {
793
src->need_flush = TRUE;
794
src->send_discont = TRUE;
796
GST_FLAG_SET (src, RB_DAAP_SRC_OPEN);
798
src->curoffset = src->seek_bytes;
801
src->first_chunk = TRUE;
810
#ifdef HAVE_GSTREAMER_0_8
812
rb_daap_src_close_file (RBDAAPSrc *src)
814
if (src->sock_fd != -1) {
815
close (src->sock_fd);
821
src->send_discont = FALSE;
823
GST_FLAG_UNSET (src, RB_DAAP_SRC_OPEN);
827
rb_daap_src_stop (GstBaseSrc *bsrc)
829
/* don't do anything - this seems to get called during setup, but
830
* we don't get started again afterwards.
836
#ifdef HAVE_GSTREAMER_0_8
838
rb_daap_src_get (GstPad *pad)
841
rb_daap_src_create (GstPushSrc *psrc, GstBuffer **outbuf)
846
GstBuffer *buf = NULL;
848
#ifdef HAVE_GSTREAMER_0_8
849
g_return_val_if_fail (pad != NULL, NULL);
850
g_return_val_if_fail (GST_IS_PAD (pad), NULL);
851
src = RB_DAAP_SRC (GST_OBJECT_PARENT (pad));
852
g_return_val_if_fail (GST_FLAG_IS_SET (src, RB_DAAP_SRC_OPEN), NULL);
854
src = RB_DAAP_SRC (psrc);
858
if (src->sock_fd != -1) {
859
close (src->sock_fd);
862
#ifdef HAVE_GSTREAMER_0_8
863
if (!rb_daap_src_open_file (src))
864
return GST_DATA (gst_event_new (GST_EVENT_EOS));
866
if (!rb_daap_src_start (GST_BASE_SRC (src)))
867
return GST_FLOW_ERROR;
869
src->do_seek = FALSE;
872
#ifdef HAVE_GSTREAMER_0_8
873
/* try to negotiate here */
874
if (!gst_pad_is_negotiated (pad)) {
875
if (GST_PAD_LINK_FAILED (gst_pad_renegotiate (pad))) {
876
GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL), GST_ERROR_SYSTEM);
877
gst_buffer_unref (buf);
878
return GST_DATA (gst_event_new (GST_EVENT_EOS));
882
if (src->need_flush) {
883
GstEvent *event = gst_event_new_flush ();
885
src->need_flush = FALSE;
886
return GST_DATA (event);
889
if (src->send_discont) {
892
src->send_discont = FALSE;
893
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset + src->seek_bytes, NULL);
894
return GST_DATA (event);
898
/* get a new chunk, if we need one */
899
if (src->chunked && src->size == 0) {
900
if (!rb_daap_src_read_chunk_size (src, src->first_chunk, &src->size)) {
901
#ifdef HAVE_GSTREAMER_0_8
902
return GST_DATA (gst_event_new (GST_EVENT_EOS));
904
return GST_FLOW_ERROR;
906
} else if (src->size == 0) {
908
#ifdef HAVE_GSTREAMER_0_8
909
gst_element_set_eos (GST_ELEMENT (src));
910
return GST_DATA (gst_event_new (GST_EVENT_EOS));
912
return GST_FLOW_UNEXPECTED;
915
src->first_chunk = FALSE;
918
readsize = src->bytes_per_read;
919
if (src->chunked && readsize > src->size)
920
readsize = src->size;
922
#ifdef HAVE_GSTREAMER_0_8
923
buf = gst_buffer_new ();
924
g_return_val_if_fail (buf, NULL);
925
GST_BUFFER_DATA (buf) = g_malloc0 (readsize);
926
g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
928
buf = gst_buffer_new_and_alloc (readsize);
931
GST_LOG_OBJECT (src, "Reading %d bytes", readsize);
932
readsize = rb_daap_src_read (src, GST_BUFFER_DATA (buf), readsize);
934
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM);
935
gst_buffer_unref (buf);
936
#ifdef HAVE_GSTREAMER_0_8
937
return GST_DATA (gst_event_new (GST_EVENT_EOS));
939
return GST_FLOW_ERROR;
944
GST_DEBUG ("blocking read returns 0, EOS");
945
gst_buffer_unref (buf);
946
#ifdef HAVE_GSTREAMER_0_8
947
gst_element_set_eos (GST_ELEMENT (src));
948
return GST_DATA (gst_event_new (GST_EVENT_EOS));
950
return GST_FLOW_UNEXPECTED;
955
src->size -= readsize;
957
GST_BUFFER_OFFSET (buf) = src->curoffset;
958
GST_BUFFER_SIZE (buf) = readsize;
959
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
960
src->curoffset += readsize;
963
"Returning buffer from _get of size %d, ts %"
964
GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
965
", offset %" G_GINT64_FORMAT ", offset_end %" G_GINT64_FORMAT,
966
GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
967
GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
968
GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET_END (buf));
969
#ifdef HAVE_GSTREAMER_0_8
970
return GST_DATA (buf);
977
#ifdef HAVE_GSTREAMER_0_8
978
static GstElementStateReturn
979
rb_daap_src_change_state (GstElement *element)
981
g_return_val_if_fail (RB_IS_DAAP_SRC (element), GST_STATE_FAILURE);
983
switch (GST_STATE_TRANSITION (element)) {
984
case GST_STATE_READY_TO_PAUSED:
985
if (!GST_FLAG_IS_SET (element, RB_DAAP_SRC_OPEN)) {
986
if (!rb_daap_src_open_file (RB_DAAP_SRC (element))) {
987
return GST_STATE_FAILURE;
991
case GST_STATE_PAUSED_TO_READY:
992
if (GST_FLAG_IS_SET (element, RB_DAAP_SRC_OPEN)) {
993
rb_daap_src_close_file (RB_DAAP_SRC (element));
996
case GST_STATE_NULL_TO_READY:
997
case GST_STATE_READY_TO_NULL:
1002
if (GST_ELEMENT_CLASS (parent_class)->change_state) {
1003
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1006
return GST_STATE_SUCCESS;
1010
rb_daap_src_srcpad_event (GstPad *pad,
1013
RBDAAPSrc *src = RB_DAAP_SRC (GST_PAD_PARENT (pad));
1015
switch (GST_EVENT_TYPE (event)) {
1016
case GST_EVENT_SEEK: {
1017
gint64 desired_offset = 0;
1019
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
1020
gst_event_unref (event);
1024
switch (GST_EVENT_SEEK_METHOD (event)) {
1025
case GST_SEEK_METHOD_SET:
1026
desired_offset = (gint64) GST_EVENT_SEEK_OFFSET (event);
1028
case GST_SEEK_METHOD_CUR:
1029
desired_offset = src->curoffset + GST_EVENT_SEEK_OFFSET (event);
1031
case GST_SEEK_METHOD_END:
1032
if (src->size == 0) {
1035
desired_offset = src->size - ABS (GST_EVENT_SEEK_OFFSET (event));
1038
gst_event_unref (event);
1045
case GST_EVENT_SIZE:
1046
if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) {
1047
gst_event_unref (event);
1050
src->bytes_per_read = GST_EVENT_SIZE_VALUE (event);
1051
g_object_notify (G_OBJECT (src), "bytesperread");
1053
case GST_EVENT_FLUSH:
1054
src->need_flush = TRUE;
1057
gst_event_unref (event);
1062
gst_event_unref (event);
1068
rb_daap_src_srcpad_query (GstPad *pad,
1073
RBDAAPSrc *src = RB_DAAP_SRC (gst_pad_get_parent (pad));
1076
case GST_QUERY_TOTAL:
1077
if (*format != GST_FORMAT_BYTES || src->size == 0) {
1082
case GST_QUERY_POSITION:
1084
case GST_FORMAT_BYTES:
1085
*value = src->curoffset;
1087
case GST_FORMAT_PERCENT:
1088
return FALSE; /* FIXME */
1089
if (src->size == 0) {
1092
*value = src->curoffset * GST_FORMAT_PERCENT_MAX / src->size;
1108
rb_daap_src_is_seekable (GstBaseSrc *bsrc)
1114
rb_daap_src_do_seek (GstBaseSrc *bsrc, GstSegment *segment)
1116
RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
1117
if (segment->format == GST_FORMAT_BYTES) {
1118
src->do_seek = TRUE;
1119
src->seek_bytes = segment->start;
1127
rb_daap_src_get_size (GstBaseSrc *bsrc, guint64 *size)
1129
RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
1130
if (src->chunked == FALSE && src->size > 0) {
1140
plugin_init (GstPlugin *plugin)
1142
gboolean ret = gst_element_register (plugin, "rbdaapsrc", GST_RANK_PRIMARY, RB_TYPE_DAAP_SRC);
1146
GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
1149
"element to access DAAP music share files",
1156
#ifdef HAVE_GSTREAMER_0_8
1157
/*** RB DAAP SEEK INTERFACE **************************************************/
1160
rb_daap_src_set_time (GstElement *element, glong time)
1162
RBDAAPSrc *src = RB_DAAP_SRC (element);
1163
src->seek_time = time;
1164
src->do_seek = TRUE;
1168
rb_daap_src_get_time (GstElement *element)
1170
RBDAAPSrc *src = RB_DAAP_SRC (element);
1171
return src->seek_time_to_return;
1175
/*** GSTURIHANDLER INTERFACE *************************************************/
1178
rb_daap_src_uri_get_type (void)
1184
rb_daap_src_uri_get_protocols (void)
1186
static gchar *protocols[] = {"daap", NULL};
1191
static const gchar *
1192
rb_daap_src_uri_get_uri (GstURIHandler *handler)
1194
RBDAAPSrc *src = RB_DAAP_SRC (handler);
1196
return src->daap_uri;
1200
rb_daap_src_uri_set_uri (GstURIHandler *handler,
1203
RBDAAPSrc *src = RB_DAAP_SRC (handler);
1205
if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) {
1209
g_object_set (G_OBJECT (src), "location", uri, NULL);
1215
rb_daap_src_uri_handler_init (gpointer g_iface,
1216
gpointer iface_data)
1218
GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
1220
iface->get_type = rb_daap_src_uri_get_type;
1221
iface->get_protocols = rb_daap_src_uri_get_protocols;
1222
iface->get_uri = rb_daap_src_uri_get_uri;
1223
iface->set_uri = rb_daap_src_uri_set_uri;