~snaggen/rhythmbox/bpm

« back to all changes in this revision

Viewing changes to plugins/daap/rb-daap-src.c

  • Committer: Jonathan Matthew
  • Author(s): Jonathan Matthew
  • Date: 2007-01-07 12:16:12 UTC
  • Revision ID: git-v1:5b6958ea3cf24f2c8bcfa15b9cab1fc7798b7305
Moved lots of files around. Now everything should be in the directory it's

2007-01-07  Jonathan Matthew  <jonathan@kaolin.wh9.net>

        Moved lots of files around.  Now everything should be in the directory
        it's built in and all plugin-specific files should be installed into
        the plugin directory.

        * plugins/audioscrobbler/rb-audioscrobbler-plugin.c:
        (impl_create_configure_dialog):
        * plugins/audioscrobbler/rb-audioscrobbler.c:
        (rb_audioscrobbler_class_init), (rb_audioscrobbler_dispose),
        (rb_audioscrobbler_finalize),
        (rb_audioscrobbler_get_config_widget):
        * plugins/audioscrobbler/rb-audioscrobbler.h:
        Use rb_plugin_find_file where needed.

        * widgets/rb-uri-dialog.c: (rb_uri_dialog_class_init),
        (rb_uri_dialog_init), (rb_uri_dialog_finalize),
        (rb_uri_dialog_new), (rb_uri_dialog_response_cb),
        (rb_uri_dialog_text_changed):
        * widgets/rb-uri-dialog.h:
        New common 'enter a URI' dialog, used by iradio and podcast code.

        * plugins/iradio/rb-iradio-plugin.c: (impl_activate):
        * plugins/iradio/rb-iradio-source.c:
        (rb_iradio_source_constructor), (rb_iradio_source_new),
        (impl_song_properties), (rb_iradio_source_first_time_changed),
        (new_station_location_added), (rb_iradio_source_cmd_new_station):
        * plugins/iradio/rb-iradio-source.h:
        * plugins/iradio/rb-station-properties-dialog.c:
        (rb_station_properties_dialog_class_init),
        (rb_station_properties_dialog_init),
        (rb_station_properties_dialog_constructor),
        (rb_station_properties_dialog_set_property),
        (rb_station_properties_dialog_get_property),
        (rb_station_properties_dialog_new):
        * plugins/iradio/rb-station-properties-dialog.h:
        Use the common URI dialog, use rb_plugin_find_file where needed.

        * sources/rb-podcast-source.c:
        (rb_podcast_source_location_added_cb),
        (rb_podcast_source_cmd_new_podcast):
        Use the common URI dialog.

svn path=/trunk/; revision=4725

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 *  Implementatin of DAAP (iTunes Music Sharing) GStreamer source
 
4
 *
 
5
 *  Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
 
6
 *
 
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.
 
11
 *
 
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.
 
16
 *
 
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.
 
20
 *
 
21
 */
 
22
 
 
23
#include "config.h"
 
24
 
 
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>
 
36
 
 
37
#include <libsoup/soup-headers.h>
 
38
#include <libsoup/soup-misc.h>
 
39
 
 
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
 
46
 
 
47
#include "rb-daap-source.h"
 
48
#include "rb-daap-src.h"
 
49
#include "rb-debug.h"
 
50
#include "rb-daap-plugin.h"
 
51
 
 
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))
 
57
 
 
58
#define RESPONSE_BUFFER_SIZE    (4096)
 
59
 
 
60
#ifdef HAVE_GSTREAMER_0_8
 
61
typedef enum {
 
62
        RB_DAAP_SRC_OPEN = GST_ELEMENT_FLAG_LAST,
 
63
 
 
64
        RB_DAAP_SRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
 
65
} RBDAAPSrcFlags;
 
66
#endif
 
67
 
 
68
typedef struct _RBDAAPSrc RBDAAPSrc;
 
69
typedef struct _RBDAAPSrcClass RBDAAPSrcClass;
 
70
 
 
71
struct _RBDAAPSrc
 
72
{
 
73
#ifdef HAVE_GSTREAMER_0_8
 
74
        GstElement element;
 
75
        GstPad *srcpad;
 
76
#else
 
77
        GstPushSrc parent;
 
78
#endif
 
79
 
 
80
        /* uri */
 
81
        gchar *daap_uri;
 
82
 
 
83
        /* connection */
 
84
        int sock_fd;
 
85
        gchar *buffer_base;
 
86
        gchar *buffer;
 
87
        guint buffer_size;
 
88
        guint32 bytes_per_read;
 
89
        gboolean chunked;
 
90
        gboolean first_chunk;
 
91
 
 
92
        gint64 size;
 
93
 
 
94
        /* Seek stuff */
 
95
        gint64 curoffset;
 
96
        gint64 seek_bytes;
 
97
        gboolean do_seek;
 
98
#ifdef HAVE_GSTREAMER_0_8
 
99
        gboolean need_flush;
 
100
        gboolean send_discont;
 
101
        glong seek_time_to_return;
 
102
        glong seek_time;
 
103
#endif
 
104
};
 
105
 
 
106
struct _RBDAAPSrcClass
 
107
{
 
108
#ifdef HAVE_GSTREAMER_0_8
 
109
        GstElementClass parent_class;
 
110
#else
 
111
        GstPushSrcClass parent_class;
 
112
#endif
 
113
};
 
114
 
 
115
#ifdef HAVE_GSTREAMER_0_10
 
116
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
 
117
        GST_PAD_SRC,
 
118
        GST_PAD_ALWAYS,
 
119
        GST_STATIC_CAPS_ANY);
 
120
#endif
 
121
 
 
122
GST_DEBUG_CATEGORY_STATIC (rb_daap_src_debug);
 
123
#define GST_CAT_DEFAULT rb_daap_src_debug
 
124
 
 
125
static GstElementDetails rb_daap_src_details =
 
126
GST_ELEMENT_DETAILS ("RBDAAP Source",
 
127
        "Source/File",
 
128
        "Read a DAAP (music share) file",
 
129
        "Charles Schmidt <cschmidt2@emich.edu");
 
130
 
 
131
static RBDaapPlugin *daap_plugin = NULL;
 
132
 
 
133
static void rb_daap_src_uri_handler_init (gpointer g_iface, gpointer iface_data);
 
134
 
 
135
static void
 
136
_do_init (GType daap_src_type)
 
137
{
 
138
        static const GInterfaceInfo urihandler_info = {
 
139
                rb_daap_src_uri_handler_init,
 
140
                NULL,
 
141
                NULL
 
142
        };
 
143
        GST_DEBUG_CATEGORY_INIT (rb_daap_src_debug,
 
144
                                 "daapsrc", GST_DEBUG_FG_WHITE,
 
145
                                 "Rhythmbox built in DAAP source element");
 
146
 
 
147
        g_type_add_interface_static (daap_src_type, GST_TYPE_URI_HANDLER,
 
148
                        &urihandler_info);
 
149
}
 
150
 
 
151
#ifdef HAVE_GSTREAMER_0_8
 
152
GST_BOILERPLATE_FULL (RBDAAPSrc, rb_daap_src, GstElement, GST_TYPE_ELEMENT, _do_init);
 
153
#else
 
154
GST_BOILERPLATE_FULL (RBDAAPSrc, rb_daap_src, GstElement, GST_TYPE_PUSH_SRC, _do_init);
 
155
#endif
 
156
 
 
157
static void rb_daap_src_finalize (GObject *object);
 
158
static void rb_daap_src_set_property (GObject *object,
 
159
                          guint prop_id,
 
160
                          const GValue *value,
 
161
                          GParamSpec *pspec);
 
162
static void rb_daap_src_get_property (GObject *object,
 
163
                          guint prop_id,
 
164
                          GValue *value,
 
165
                          GParamSpec *pspec);
 
166
 
 
167
#ifdef HAVE_GSTREAMER_0_8
 
168
static GstData *rb_daap_src_get (GstPad *pad);
 
169
 
 
170
static GstElementStateReturn rb_daap_src_change_state (GstElement *element);
 
171
 
 
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,
 
175
                          GstEvent *event);
 
176
static gboolean rb_daap_src_srcpad_query (GstPad *pad,
 
177
                          GstQueryType type,
 
178
                          GstFormat *format,
 
179
                          gint64 *value);
 
180
#else
 
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);
 
187
#endif
 
188
 
 
189
void
 
190
rb_daap_src_set_plugin (RBPlugin *plugin)
 
191
{
 
192
        g_assert (RB_IS_DAAP_PLUGIN (plugin));
 
193
        daap_plugin = RB_DAAP_PLUGIN (plugin);
 
194
}
 
195
 
 
196
#ifdef HAVE_GSTREAMER_0_8
 
197
 
 
198
static const GstFormat *
 
199
rb_daap_src_get_formats (GstPad *pad)
 
200
{
 
201
        static const GstFormat formats[] = {
 
202
                GST_FORMAT_BYTES,
 
203
                0,
 
204
        };
 
205
 
 
206
        return formats;
 
207
}
 
208
 
 
209
static const GstQueryType *
 
210
rb_daap_src_get_query_types (GstPad *pad)
 
211
{
 
212
        static const GstQueryType types[] = {
 
213
                GST_QUERY_TOTAL,
 
214
                GST_QUERY_POSITION,
 
215
                0,
 
216
        };
 
217
 
 
218
        return types;
 
219
}
 
220
 
 
221
static const GstEventMask *
 
222
rb_daap_src_get_event_mask (GstPad *pad)
 
223
{
 
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},
 
227
                {GST_EVENT_SIZE, 0},
 
228
                {0, 0},
 
229
        };
 
230
 
 
231
        return masks;
 
232
}
 
233
 
 
234
#endif
 
235
 
 
236
enum
 
237
{
 
238
        PROP_0,
 
239
        PROP_LOCATION,
 
240
        PROP_SEEKABLE,
 
241
        PROP_BYTESPERREAD
 
242
};
 
243
 
 
244
static void
 
245
rb_daap_src_base_init (gpointer g_class)
 
246
{
 
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));
 
251
#endif
 
252
        gst_element_class_set_details (element_class, &rb_daap_src_details);
 
253
}
 
254
 
 
255
static void
 
256
rb_daap_src_class_init (RBDAAPSrcClass *klass)
 
257
{
 
258
#ifdef HAVE_GSTREAMER_0_8
 
259
        GObjectClass *gobject_class;
 
260
        GstElementClass *gstelement_class;
 
261
 
 
262
        gobject_class = (GObjectClass *) klass;
 
263
        gstelement_class = (GstElementClass *) klass;
 
264
 
 
265
        parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
 
266
 
 
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);
 
270
 
 
271
        gobject_class->finalize = rb_daap_src_finalize;
 
272
 
 
273
        g_object_class_install_property (gobject_class,
 
274
                                         PROP_SEEKABLE,
 
275
                                         g_param_spec_boolean ("seekable",
 
276
                                                               "seekable",
 
277
                                                               "TRUE if stream is seekable",
 
278
                                                               TRUE,
 
279
                                                               G_PARAM_READABLE));
 
280
 
 
281
        gstelement_class->set_property = rb_daap_src_set_property;
 
282
        gstelement_class->get_property = rb_daap_src_get_property;
 
283
 
 
284
        gstelement_class->change_state = rb_daap_src_change_state;
 
285
#else
 
286
        GObjectClass *gobject_class;
 
287
        GstElementClass *gstelement_class;
 
288
        GstBaseSrcClass *gstbasesrc_class;
 
289
        GstPushSrcClass *gstpushsrc_class;
 
290
 
 
291
        gobject_class = G_OBJECT_CLASS (klass);
 
292
        gstelement_class = GST_ELEMENT_CLASS (klass);
 
293
        gstbasesrc_class = (GstBaseSrcClass *) klass;
 
294
        gstpushsrc_class = (GstPushSrcClass *) klass;
 
295
 
 
296
        parent_class = g_type_class_ref (GST_TYPE_PUSH_SRC);
 
297
 
 
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;
 
301
 
 
302
        g_object_class_install_property (gobject_class, PROP_LOCATION,
 
303
                        g_param_spec_string ("location",
 
304
                                             "file location",
 
305
                                             "location of the file to read",
 
306
                                             NULL,
 
307
                                             G_PARAM_READWRITE));
 
308
 
 
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);
 
314
 
 
315
        gstpushsrc_class->create = GST_DEBUG_FUNCPTR (rb_daap_src_create);
 
316
#endif
 
317
}
 
318
 
 
319
#ifdef HAVE_GSTREAMER_0_8
 
320
static void
 
321
rb_daap_src_init (RBDAAPSrc *src)
 
322
#else
 
323
static void
 
324
rb_daap_src_init (RBDAAPSrc *src, RBDAAPSrcClass *klass)
 
325
#endif
 
326
{
 
327
        src->daap_uri = NULL;
 
328
        src->sock_fd = -1;
 
329
        src->curoffset = 0;
 
330
        src->bytes_per_read = 4096 * 2;
 
331
 
 
332
#ifdef HAVE_GSTREAMER_0_8
 
333
        src->seek_bytes = 0;
 
334
 
 
335
        src->send_discont = FALSE;
 
336
        src->need_flush = FALSE;
 
337
 
 
338
        src->srcpad = gst_pad_new ("src", GST_PAD_SRC);
 
339
        gst_pad_set_get_function (src->srcpad,
 
340
                                  rb_daap_src_get);
 
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);
 
352
#endif
 
353
}
 
354
 
 
355
static void
 
356
rb_daap_src_finalize (GObject *object)
 
357
{
 
358
        RBDAAPSrc *src;
 
359
        src = RB_DAAP_SRC (object);
 
360
 
 
361
#ifdef HAVE_GSTREAMER_0_8
 
362
        if (GST_FLAG_IS_SET (src, RB_DAAP_SRC_OPEN)) {
 
363
                rb_daap_src_close_file (src);
 
364
        }
 
365
#endif
 
366
 
 
367
        g_free (src->daap_uri);
 
368
        src->daap_uri = NULL;
 
369
 
 
370
        if (src->sock_fd != -1) {
 
371
                close (src->sock_fd);
 
372
                src->sock_fd = -1;
 
373
        }
 
374
 
 
375
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
376
}
 
377
 
 
378
static void
 
379
rb_daap_src_set_property (GObject *object,
 
380
                          guint prop_id,
 
381
                          const GValue *value,
 
382
                          GParamSpec *pspec)
 
383
{
 
384
        RBDAAPSrc *src = RB_DAAP_SRC (object);
 
385
 
 
386
        switch (prop_id) {
 
387
                case PROP_LOCATION:
 
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) {
 
391
                                break;
 
392
                        }
 
393
#else
 
394
                        /* XXX check stuff */
 
395
#endif
 
396
 
 
397
                        if (src->daap_uri) {
 
398
                                g_free (src->daap_uri);
 
399
                                src->daap_uri = NULL;
 
400
                        }
 
401
                        src->daap_uri = g_strdup (g_value_get_string (value));
 
402
                        break;
 
403
#ifdef HAVE_GSTREAMER_0_8
 
404
                case PROP_BYTESPERREAD:
 
405
                        src->bytes_per_read = g_value_get_int (value);
 
406
                        break;
 
407
#endif
 
408
                default:
 
409
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
410
                        break;
 
411
        }
 
412
}
 
413
 
 
414
static void
 
415
rb_daap_src_get_property (GObject *object,
 
416
                          guint prop_id,
 
417
                          GValue *value,
 
418
                          GParamSpec *pspec)
 
419
{
 
420
        RBDAAPSrc *src = RB_DAAP_SRC (object);
 
421
 
 
422
        switch (prop_id) {
 
423
                case PROP_LOCATION:
 
424
                        g_value_set_string (value, src->daap_uri);
 
425
                        break;
 
426
#ifdef HAVE_GSTREAMER_0_8
 
427
                case PROP_SEEKABLE:
 
428
                        g_value_set_boolean (value, FALSE);
 
429
                        break;
 
430
                case PROP_BYTESPERREAD:
 
431
                        g_value_set_int (value, src->bytes_per_read);
 
432
                        break;
 
433
#endif
 
434
                default:
 
435
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
436
                        break;
 
437
        }
 
438
}
 
439
 
 
440
static gint
 
441
rb_daap_src_write (RBDAAPSrc *src, const guchar *buf, size_t count)
 
442
{
 
443
        size_t bytes_written = 0;
 
444
 
 
445
        while (bytes_written < count) {
 
446
                ssize_t wrote = send (src->sock_fd, buf + bytes_written, count - bytes_written, MSG_NOSIGNAL);
 
447
 
 
448
                if (wrote < 0) {
 
449
                        GST_WARNING ("error while writing: %s", g_strerror (errno));
 
450
                        return wrote;
 
451
                }
 
452
                if (wrote == 0)
 
453
                        break;
 
454
 
 
455
                bytes_written += wrote;
 
456
        }
 
457
 
 
458
        GST_DEBUG_OBJECT (src, "wrote %d bytes succesfully", bytes_written);
 
459
        return bytes_written;
 
460
}
 
461
 
 
462
static gint
 
463
rb_daap_src_read (RBDAAPSrc *src, guchar *buf, size_t count)
 
464
{
 
465
        size_t bytes_read = 0;
 
466
 
 
467
        if (src->buffer_size > 0) {
 
468
                bytes_read = count;
 
469
                if (bytes_read > src->buffer_size)
 
470
                        bytes_read = src->buffer_size;
 
471
 
 
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;
 
476
 
 
477
                if (src->buffer_size == 0) {
 
478
                        g_free (src->buffer_base);
 
479
                        src->buffer_base = NULL;
 
480
                        src->buffer = NULL;
 
481
                }
 
482
        }
 
483
 
 
484
        while (bytes_read < count) {
 
485
                ssize_t ret = read (src->sock_fd, buf + bytes_read, count - bytes_read);
 
486
 
 
487
                if (ret < 0) {
 
488
                        GST_WARNING ("error while reading: %s", g_strerror (errno));
 
489
                        return ret;
 
490
                }
 
491
                if (ret == 0)
 
492
                        break;
 
493
                bytes_read += ret;
 
494
        }
 
495
 
 
496
        GST_DEBUG_OBJECT (src, "read %d bytes succesfully", bytes_read);
 
497
        return bytes_read;
 
498
}
 
499
 
 
500
static gboolean
 
501
_expect_char (RBDAAPSrc *src, guchar expected)
 
502
{
 
503
        guchar ch;
 
504
        if (rb_daap_src_read (src, &ch, sizeof (ch)) <= 0)
 
505
                return FALSE;
 
506
        if (ch != expected) {
 
507
                GST_DEBUG_OBJECT (src, "Expected char %d next, but got %d", expected, ch);
 
508
                return FALSE;
 
509
        }
 
510
        return TRUE;
 
511
}
 
512
 
 
513
static gboolean
 
514
rb_daap_src_read_chunk_size (RBDAAPSrc *src, gboolean first_chunk, gint64 *chunk_size)
 
515
{
 
516
        gchar chunk_buf[30];
 
517
        gchar ch;
 
518
        gint i = 0;
 
519
        memset (&chunk_buf, 0, sizeof (chunk_buf));
 
520
 
 
521
        GST_DEBUG_OBJECT (src, "reading next chunk size; first_chunk = %d", first_chunk);
 
522
        if (!first_chunk) {
 
523
                if (!_expect_char (src, '\r') ||
 
524
                    !_expect_char (src, '\n')) {
 
525
                        return FALSE;
 
526
                }
 
527
        }
 
528
 
 
529
        while (1) {
 
530
                if (rb_daap_src_read (src, (guchar *)&ch, sizeof(ch)) <= 0)
 
531
                        return FALSE;
 
532
 
 
533
                if (ch == '\r') {
 
534
                        if (!_expect_char (src, '\n')) {
 
535
                                return FALSE;
 
536
                        }
 
537
                        *chunk_size = strtoul (chunk_buf, NULL, 16);
 
538
                        if (*chunk_size == 0) {
 
539
                                /* EOS */
 
540
                                GST_DEBUG_OBJECT (src, "got EOS chunk");
 
541
                                return TRUE;
 
542
                        } else if (*chunk_size == ULONG_MAX) {
 
543
                                /* overflow */
 
544
                                GST_DEBUG_OBJECT (src, "HTTP chunk size overflowed");
 
545
                                return FALSE;
 
546
                        }
 
547
 
 
548
                        GST_DEBUG_OBJECT (src, "got HTTP chunk size %lu", *chunk_size);
 
549
                        return TRUE;
 
550
                } else if (isxdigit (ch)) {
 
551
                        chunk_buf[i++] = ch;
 
552
                } else {
 
553
                        GST_DEBUG_OBJECT (src, "HTTP chunk size included illegal character %c", ch);
 
554
                        return FALSE;
 
555
                }
 
556
        }
 
557
 
 
558
        g_assert_not_reached ();
 
559
}
 
560
 
 
561
static void
 
562
_split_uri (const gchar *daap_uri, gchar **host, guint *port, gchar **path)
 
563
{
 
564
        gint locationlen;
 
565
        const gchar *pathstart = NULL;
 
566
        const gchar *hostport = NULL;
 
567
        const gchar *portstart = NULL;
 
568
 
 
569
        locationlen = strlen (daap_uri);
 
570
        hostport = daap_uri + 7;
 
571
        pathstart = strchr (hostport, '/');
 
572
 
 
573
        if (pathstart) {
 
574
                *path = g_strdup (pathstart);
 
575
        } else {
 
576
                *path = g_strdup ("/");
 
577
                pathstart = daap_uri + locationlen;
 
578
        }
 
579
 
 
580
        portstart = strrchr (hostport, ':');
 
581
        if (portstart) {
 
582
                *host = g_strndup (hostport, portstart - hostport);
 
583
                *port = strtoul (portstart + 1, NULL, 0);
 
584
        } else {
 
585
                *host = g_strndup (hostport, pathstart - hostport);
 
586
                *port = 3869;
 
587
        }
 
588
}
 
589
 
 
590
static gboolean
 
591
rb_daap_src_open (RBDAAPSrc *src)
 
592
{
 
593
        int ret;
 
594
        struct sockaddr_in server;
 
595
        RBDAAPSource *source;
 
596
        gchar *headers;
 
597
        gchar *host;
 
598
        guint port;
 
599
        gchar *path;
 
600
        GHashTable *header_table;
 
601
        gchar *request;
 
602
        gchar *response;
 
603
        gchar *end_headers;
 
604
        size_t readsize;
 
605
        gboolean ok = TRUE;
 
606
        guint http_status;
 
607
        gchar *http_status_phrase = NULL;
 
608
 
 
609
        if (src->buffer_base) {
 
610
                g_free (src->buffer_base);
 
611
                src->buffer_base = NULL;
 
612
                src->buffer = NULL;
 
613
                src->buffer_size = 0;
 
614
        }
 
615
 
 
616
        rb_debug ("Connecting to DAAP source: %s", src->daap_uri);
 
617
 
 
618
        /* connect */
 
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);
 
622
                return FALSE;
 
623
        }
 
624
 
 
625
        _split_uri (src->daap_uri, &host, &port, &path);
 
626
 
 
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));
 
631
 
 
632
        GST_DEBUG_OBJECT (src, "connecting to server %s:%d", host, port);
 
633
        ret = connect (src->sock_fd, (struct sockaddr *) &server, sizeof (struct sockaddr));
 
634
        if (ret) {
 
635
                if (errno == ECONNREFUSED) {
 
636
                        GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
 
637
                                           (_("Connection to %s:%d refused."), host, port),
 
638
                                           (NULL));
 
639
                } else {
 
640
                        GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
 
641
                                           ("Connect to %s:%d failed: %s", host, port,
 
642
                                            g_strerror (errno)));
 
643
                }
 
644
                g_free (host);
 
645
                g_free (path);
 
646
                return FALSE;
 
647
        }
 
648
 
 
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);
 
653
                return FALSE;
 
654
        }
 
655
 
 
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);
 
659
#else
 
660
        headers = rb_daap_source_get_headers (source, src->daap_uri, src->seek_bytes);
 
661
#endif
 
662
        if (headers == NULL) {
 
663
                g_free (host);
 
664
                g_free (path);
 
665
                return FALSE;
 
666
        }
 
667
 
 
668
        request = g_strdup_printf ("GET %s HTTP/1.1\r\nHost: %s\r\n%s\r\n",
 
669
                                   path, host, headers);
 
670
        g_free (headers);
 
671
        g_free (host);
 
672
        g_free (path);
 
673
 
 
674
        /* send request */
 
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)));
 
680
                g_free (request);
 
681
                return FALSE;
 
682
        }
 
683
        g_free (request);
 
684
 
 
685
        /* read response */
 
686
        response = g_malloc0 (RESPONSE_BUFFER_SIZE + 1);
 
687
        readsize = rb_daap_src_read (src, (guchar *)response, RESPONSE_BUFFER_SIZE);
 
688
        if (readsize <= 0) {
 
689
                g_free (response);
 
690
                GST_DEBUG_OBJECT (src, "Error while reading HTTP response header");
 
691
                return FALSE;
 
692
        }
 
693
        response[readsize] = '\0';
 
694
        GST_DEBUG_OBJECT (src, "Got HTTP response:\n%s", response);
 
695
 
 
696
        end_headers = strstr (response, "\r\n\r\n");
 
697
        if (!end_headers) {
 
698
                /* this means the DAAP server returned more than 4k of headers.
 
699
                 * not terribly likely.
 
700
                 */
 
701
                g_free (response);
 
702
                GST_DEBUG_OBJECT (src, "HTTP response header way too long");
 
703
                return FALSE;
 
704
        }
 
705
 
 
706
        /* libsoup wants the headers null-terminated, despite taking a parameter
 
707
         * specifying how long they are.
 
708
         */
 
709
        end_headers[2] = '\0';
 
710
        end_headers += 4;
 
711
 
 
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),
 
715
                                         header_table,
 
716
                                         NULL,
 
717
                                         &http_status,
 
718
                                         &http_status_phrase)) {
 
719
                if (http_status == 200 || http_status == 206) {
 
720
                        GSList *val;
 
721
 
 
722
                        val = g_hash_table_lookup (header_table, "Transfer-Encoding");
 
723
                        if (val) {
 
724
                                if (g_strcasecmp ((gchar *)val->data, "chunked") == 0) {
 
725
                                        src->chunked = TRUE;
 
726
                                } else {
 
727
                                        GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
 
728
                                                           ("Unknown HTTP transfer encoding \"%s\"", val->data));
 
729
                                }
 
730
                        } else {
 
731
                                src->chunked = FALSE;
 
732
                                val = g_hash_table_lookup (header_table, "Content-Length");
 
733
                                if (val) {
 
734
                                        char *e;
 
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));
 
739
                                                ok = FALSE;
 
740
                                        }
 
741
                                } else {
 
742
                                        GST_DEBUG_OBJECT (src, "Response doesn't have a content length");
 
743
                                        src->size = 0;
 
744
                                }
 
745
                        }
 
746
 
 
747
                } else {
 
748
                        GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
 
749
                                           ("HTTP error: %s", http_status_phrase),
 
750
                                           (NULL));
 
751
                        ok = FALSE;
 
752
                }
 
753
        } else {
 
754
                GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
 
755
                                   ("Unable to parse HTTP response"));
 
756
                ok = FALSE;
 
757
        }
 
758
        g_free (http_status_phrase);
 
759
        g_hash_table_destroy (header_table);
 
760
 
 
761
        /* copy remaining data into a new buffer */
 
762
        if (ok) {
 
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);
 
767
        }
 
768
        g_free (response);
 
769
 
 
770
        return ok;
 
771
}
 
772
 
 
773
static gboolean
 
774
#ifdef HAVE_GSTREAMER_0_8
 
775
rb_daap_src_open_file (RBDAAPSrc *src)
 
776
{
 
777
#else
 
778
rb_daap_src_start (GstBaseSrc *bsrc)
 
779
{
 
780
        RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
 
781
#endif
 
782
        if (src->sock_fd != -1) {
 
783
                close (src->sock_fd);
 
784
        }
 
785
 
 
786
        src->curoffset = 0;
 
787
 
 
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;
 
795
                }
 
796
                GST_FLAG_SET (src, RB_DAAP_SRC_OPEN);
 
797
#else
 
798
                src->curoffset = src->seek_bytes;
 
799
#endif
 
800
                if (src->chunked) {
 
801
                        src->first_chunk = TRUE;
 
802
                        src->size = 0;
 
803
                }
 
804
                return TRUE;
 
805
        } else {
 
806
                return FALSE;
 
807
        }
 
808
}
 
809
 
 
810
#ifdef HAVE_GSTREAMER_0_8
 
811
static void
 
812
rb_daap_src_close_file (RBDAAPSrc *src)
 
813
{
 
814
        if (src->sock_fd != -1) {
 
815
                close (src->sock_fd);
 
816
                src->sock_fd = -1;
 
817
        }
 
818
        src->seek_bytes = 0;
 
819
        src->curoffset = 0;
 
820
        src->size = 0;
 
821
        src->send_discont = FALSE;
 
822
 
 
823
        GST_FLAG_UNSET (src, RB_DAAP_SRC_OPEN);
 
824
}
 
825
#else
 
826
static gboolean
 
827
rb_daap_src_stop (GstBaseSrc *bsrc)
 
828
{
 
829
        /* don't do anything - this seems to get called during setup, but
 
830
         * we don't get started again afterwards.
 
831
         */
 
832
        return TRUE;
 
833
}
 
834
#endif
 
835
 
 
836
#ifdef HAVE_GSTREAMER_0_8
 
837
static GstData *
 
838
rb_daap_src_get (GstPad *pad)
 
839
#else
 
840
static GstFlowReturn
 
841
rb_daap_src_create (GstPushSrc *psrc, GstBuffer **outbuf)
 
842
#endif
 
843
{
 
844
        RBDAAPSrc *src;
 
845
        size_t readsize;
 
846
        GstBuffer *buf = NULL;
 
847
 
 
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);
 
853
#else
 
854
        src = RB_DAAP_SRC (psrc);
 
855
#endif
 
856
 
 
857
        if (src->do_seek) {
 
858
                if (src->sock_fd != -1) {
 
859
                        close (src->sock_fd);
 
860
                        src->sock_fd = -1;
 
861
                }
 
862
#ifdef HAVE_GSTREAMER_0_8
 
863
                if (!rb_daap_src_open_file (src))
 
864
                        return GST_DATA (gst_event_new (GST_EVENT_EOS));
 
865
#else
 
866
                if (!rb_daap_src_start (GST_BASE_SRC (src)))
 
867
                        return GST_FLOW_ERROR;
 
868
#endif
 
869
                src->do_seek = FALSE;
 
870
        }
 
871
 
 
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));
 
879
                }
 
880
        }
 
881
 
 
882
        if (src->need_flush) {
 
883
                GstEvent *event = gst_event_new_flush ();
 
884
 
 
885
                src->need_flush = FALSE;
 
886
                return GST_DATA (event);
 
887
        }
 
888
 
 
889
        if (src->send_discont) {
 
890
                GstEvent *event;
 
891
 
 
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);
 
895
        }
 
896
#endif
 
897
 
 
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));
 
903
#else
 
904
                        return GST_FLOW_ERROR;
 
905
#endif
 
906
                } else if (src->size == 0) {
 
907
                        /* EOS */
 
908
#ifdef HAVE_GSTREAMER_0_8
 
909
                        gst_element_set_eos (GST_ELEMENT (src));
 
910
                        return GST_DATA (gst_event_new (GST_EVENT_EOS));
 
911
#else
 
912
                        return GST_FLOW_UNEXPECTED;
 
913
#endif
 
914
                }
 
915
                src->first_chunk = FALSE;
 
916
        }
 
917
 
 
918
        readsize = src->bytes_per_read;
 
919
        if (src->chunked && readsize > src->size)
 
920
                readsize = src->size;
 
921
 
 
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);
 
927
#else
 
928
        buf = gst_buffer_new_and_alloc (readsize);
 
929
#endif
 
930
 
 
931
        GST_LOG_OBJECT (src, "Reading %d bytes", readsize);
 
932
        readsize = rb_daap_src_read (src, GST_BUFFER_DATA (buf), readsize);
 
933
        if (readsize < 0) {
 
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));
 
938
#else
 
939
                return GST_FLOW_ERROR;
 
940
#endif
 
941
        }
 
942
 
 
943
        if (readsize == 0) {
 
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));
 
949
#else
 
950
                return GST_FLOW_UNEXPECTED;
 
951
#endif
 
952
        }
 
953
 
 
954
        if (src->chunked)
 
955
                src->size -= readsize;
 
956
 
 
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;
 
961
 
 
962
        GST_LOG_OBJECT (src,
 
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);
 
971
#else
 
972
        *outbuf = buf;
 
973
        return GST_FLOW_OK;
 
974
#endif
 
975
}
 
976
 
 
977
#ifdef HAVE_GSTREAMER_0_8
 
978
static GstElementStateReturn
 
979
rb_daap_src_change_state (GstElement *element)
 
980
{
 
981
        g_return_val_if_fail (RB_IS_DAAP_SRC (element), GST_STATE_FAILURE);
 
982
 
 
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;
 
988
                                }
 
989
                        }
 
990
                        break;
 
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));
 
994
                        }
 
995
                        break;
 
996
                case GST_STATE_NULL_TO_READY:
 
997
                case GST_STATE_READY_TO_NULL:
 
998
                default:
 
999
                        break;
 
1000
        }
 
1001
 
 
1002
        if (GST_ELEMENT_CLASS (parent_class)->change_state) {
 
1003
                return GST_ELEMENT_CLASS (parent_class)->change_state (element);
 
1004
        }
 
1005
 
 
1006
        return GST_STATE_SUCCESS;
 
1007
}
 
1008
 
 
1009
static gboolean
 
1010
rb_daap_src_srcpad_event (GstPad *pad,
 
1011
                          GstEvent *event)
 
1012
{
 
1013
        RBDAAPSrc *src = RB_DAAP_SRC (GST_PAD_PARENT (pad));
 
1014
 
 
1015
        switch (GST_EVENT_TYPE (event)) {
 
1016
                case GST_EVENT_SEEK: {
 
1017
                        gint64 desired_offset = 0;
 
1018
 
 
1019
                        if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
 
1020
                                gst_event_unref (event);
 
1021
                                return FALSE;
 
1022
                        }
 
1023
 
 
1024
                        switch (GST_EVENT_SEEK_METHOD (event)) {
 
1025
                                case GST_SEEK_METHOD_SET:
 
1026
                                        desired_offset = (gint64) GST_EVENT_SEEK_OFFSET (event);
 
1027
                                        break;
 
1028
                                case GST_SEEK_METHOD_CUR:
 
1029
                                        desired_offset = src->curoffset + GST_EVENT_SEEK_OFFSET (event);
 
1030
                                        break;
 
1031
                                case GST_SEEK_METHOD_END:
 
1032
                                        if (src->size == 0) {
 
1033
                                                return FALSE;
 
1034
                                        }
 
1035
                                        desired_offset = src->size - ABS (GST_EVENT_SEEK_OFFSET (event));
 
1036
                                        break;
 
1037
                                default:
 
1038
                                        gst_event_unref (event);
 
1039
                                        return FALSE;
 
1040
                        }
 
1041
 
 
1042
                        return FALSE;
 
1043
                        break;
 
1044
                }
 
1045
                case GST_EVENT_SIZE:
 
1046
                        if (GST_EVENT_SIZE_FORMAT (event) != GST_FORMAT_BYTES) {
 
1047
                                gst_event_unref (event);
 
1048
                                return FALSE;
 
1049
                        }
 
1050
                        src->bytes_per_read = GST_EVENT_SIZE_VALUE (event);
 
1051
                        g_object_notify (G_OBJECT (src), "bytesperread");
 
1052
                        break;
 
1053
                case GST_EVENT_FLUSH:
 
1054
                        src->need_flush = TRUE;
 
1055
                        break;
 
1056
                default:
 
1057
                        gst_event_unref (event);
 
1058
                        return FALSE;
 
1059
                        break;
 
1060
        }
 
1061
 
 
1062
        gst_event_unref (event);
 
1063
 
 
1064
        return TRUE;
 
1065
}
 
1066
 
 
1067
static gboolean
 
1068
rb_daap_src_srcpad_query (GstPad *pad,
 
1069
                          GstQueryType type,
 
1070
                          GstFormat *format,
 
1071
                          gint64 *value)
 
1072
{
 
1073
        RBDAAPSrc *src = RB_DAAP_SRC (gst_pad_get_parent (pad));
 
1074
 
 
1075
        switch (type) {
 
1076
                case GST_QUERY_TOTAL:
 
1077
                        if (*format != GST_FORMAT_BYTES || src->size == 0) {
 
1078
                                return FALSE;
 
1079
                        }
 
1080
                        *value = src->size;
 
1081
                        break;
 
1082
                case GST_QUERY_POSITION:
 
1083
                        switch (*format) {
 
1084
                                case GST_FORMAT_BYTES:
 
1085
                                        *value = src->curoffset;
 
1086
                                        break;
 
1087
                                case GST_FORMAT_PERCENT:
 
1088
                                        return FALSE; /* FIXME */
 
1089
                                        if (src->size == 0) {
 
1090
                                                return FALSE;
 
1091
                                        }
 
1092
                                        *value = src->curoffset * GST_FORMAT_PERCENT_MAX / src->size;
 
1093
                                        break;
 
1094
                                default:
 
1095
                                        return FALSE;
 
1096
                        }
 
1097
                        break;
 
1098
                default:
 
1099
                        return FALSE;
 
1100
                        break;
 
1101
        }
 
1102
 
 
1103
        return TRUE;
 
1104
}
 
1105
#else
 
1106
 
 
1107
gboolean
 
1108
rb_daap_src_is_seekable (GstBaseSrc *bsrc)
 
1109
{
 
1110
        return TRUE;
 
1111
}
 
1112
 
 
1113
gboolean
 
1114
rb_daap_src_do_seek (GstBaseSrc *bsrc, GstSegment *segment)
 
1115
{
 
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;
 
1120
                return TRUE;
 
1121
        } else {
 
1122
                return FALSE;
 
1123
        }
 
1124
}
 
1125
 
 
1126
gboolean
 
1127
rb_daap_src_get_size (GstBaseSrc *bsrc, guint64 *size)
 
1128
{
 
1129
        RBDAAPSrc *src = RB_DAAP_SRC (bsrc);
 
1130
        if (src->chunked == FALSE && src->size > 0) {
 
1131
                *size = src->size;
 
1132
                return TRUE;
 
1133
        }
 
1134
        return FALSE;
 
1135
}
 
1136
 
 
1137
#endif
 
1138
 
 
1139
static gboolean
 
1140
plugin_init (GstPlugin *plugin)
 
1141
{
 
1142
        gboolean ret = gst_element_register (plugin, "rbdaapsrc", GST_RANK_PRIMARY, RB_TYPE_DAAP_SRC);
 
1143
        return ret;
 
1144
}
 
1145
 
 
1146
GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
 
1147
                          GST_VERSION_MINOR,
 
1148
                          "rbdaap",
 
1149
                          "element to access DAAP music share files",
 
1150
                          plugin_init,
 
1151
                          VERSION,
 
1152
                          "GPL",
 
1153
                          PACKAGE,
 
1154
                          "");
 
1155
 
 
1156
#ifdef HAVE_GSTREAMER_0_8
 
1157
/*** RB DAAP SEEK INTERFACE **************************************************/
 
1158
 
 
1159
void
 
1160
rb_daap_src_set_time (GstElement *element, glong time)
 
1161
{
 
1162
        RBDAAPSrc *src = RB_DAAP_SRC (element);
 
1163
        src->seek_time = time;
 
1164
        src->do_seek = TRUE;
 
1165
}
 
1166
 
 
1167
glong
 
1168
rb_daap_src_get_time (GstElement *element)
 
1169
{
 
1170
        RBDAAPSrc *src = RB_DAAP_SRC (element);
 
1171
        return src->seek_time_to_return;
 
1172
}
 
1173
 
 
1174
#endif
 
1175
/*** GSTURIHANDLER INTERFACE *************************************************/
 
1176
 
 
1177
static guint
 
1178
rb_daap_src_uri_get_type (void)
 
1179
{
 
1180
        return GST_URI_SRC;
 
1181
}
 
1182
 
 
1183
static gchar **
 
1184
rb_daap_src_uri_get_protocols (void)
 
1185
{
 
1186
        static gchar *protocols[] = {"daap", NULL};
 
1187
 
 
1188
        return protocols;
 
1189
}
 
1190
 
 
1191
static const gchar *
 
1192
rb_daap_src_uri_get_uri (GstURIHandler *handler)
 
1193
{
 
1194
        RBDAAPSrc *src = RB_DAAP_SRC (handler);
 
1195
 
 
1196
        return src->daap_uri;
 
1197
}
 
1198
 
 
1199
static gboolean
 
1200
rb_daap_src_uri_set_uri (GstURIHandler *handler,
 
1201
                         const gchar *uri)
 
1202
{
 
1203
        RBDAAPSrc *src = RB_DAAP_SRC (handler);
 
1204
 
 
1205
        if (GST_STATE (src) == GST_STATE_PLAYING || GST_STATE (src) == GST_STATE_PAUSED) {
 
1206
                return FALSE;
 
1207
        }
 
1208
 
 
1209
        g_object_set (G_OBJECT (src), "location", uri, NULL);
 
1210
 
 
1211
        return TRUE;
 
1212
}
 
1213
 
 
1214
static void
 
1215
rb_daap_src_uri_handler_init (gpointer g_iface,
 
1216
                              gpointer iface_data)
 
1217
{
 
1218
        GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
 
1219
 
 
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;
 
1224
}