2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
4 * 2001 Bastien Nocera <hadess@hadess.net>
5 * 2002 Kristian Rietveld <kris@gtk.org>
6 * 2002,2003 Colin Walters <walters@gnu.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
27 * SECTION:element-gnomevfssrc
28 * @short_description: Read from any GnomeVFS-supported location
29 * @see_also: #GstFileSrc, #GstGnomeVFSSink
33 * This plugin reads data from a local or remote location specified
34 * by an URI. This location can be specified using any protocol supported by
35 * the GnomeVFS library. Common protocols are 'file', 'http', 'ftp', or 'smb'.
40 * gst-launch -v gnomevfssrc location=file:///home/joe/foo.xyz ! fakesink
42 * The above pipeline will simply read a local file and do nothing with the
43 * data read. Instead of gnomevfssrc, we could just as well have used the
44 * filesrc element here.
47 * Another example pipeline:
49 * gst-launch -v gnomevfssrc location=smb://othercomputer/foo.xyz ! filesink location=/home/joe/foo.xyz
51 * The above pipeline will copy a file from a remote host to the local file
52 * system using the Samba protocol.
55 * Yet another example pipeline:
57 * gst-launch -v gnomevfssrc location=http://music.foobar.com/demo.mp3 ! mad ! audioconvert ! audioresample ! alsasink
59 * The above pipeline will read and decode and play an mp3 file from a
60 * web server using the http protocol.
68 /*#undef BROKEN_SIG */
74 #include "gst/gst-i18n-plugin.h"
76 #include "gstgnomevfssrc.h"
79 #include <sys/types.h>
80 #include <sys/socket.h>
82 #include <netinet/in.h>
83 #include <arpa/inet.h>
93 /* gnome-vfs.h doesn't include the following header, which we need: */
94 #include <libgnomevfs/gnome-vfs-standard-callbacks.h>
96 GST_DEBUG_CATEGORY_STATIC (gnomevfssrc_debug);
97 #define GST_CAT_DEFAULT gnomevfssrc_debug
100 static GStaticMutex count_lock = G_STATIC_MUTEX_INIT;
101 static gint ref_count = 0;
102 static gboolean vfs_owner = FALSE;
105 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
108 GST_STATIC_CAPS_ANY);
122 static void gst_gnome_vfs_src_base_init (gpointer g_class);
123 static void gst_gnome_vfs_src_class_init (GstGnomeVFSSrcClass * klass);
124 static void gst_gnome_vfs_src_init (GstGnomeVFSSrc * gnomevfssrc);
125 static void gst_gnome_vfs_src_finalize (GObject * object);
126 static void gst_gnome_vfs_src_uri_handler_init (gpointer g_iface,
127 gpointer iface_data);
129 static void gst_gnome_vfs_src_set_property (GObject * object, guint prop_id,
130 const GValue * value, GParamSpec * pspec);
131 static void gst_gnome_vfs_src_get_property (GObject * object, guint prop_id,
132 GValue * value, GParamSpec * pspec);
134 static gboolean gst_gnome_vfs_src_stop (GstBaseSrc * src);
135 static gboolean gst_gnome_vfs_src_start (GstBaseSrc * src);
136 static gboolean gst_gnome_vfs_src_is_seekable (GstBaseSrc * src);
137 static gboolean gst_gnome_vfs_src_get_size (GstBaseSrc * src, guint64 * size);
138 static GstFlowReturn gst_gnome_vfs_src_create (GstBaseSrc * basesrc,
139 guint64 offset, guint size, GstBuffer ** buffer);
141 static int audiocast_init (GstGnomeVFSSrc * src);
142 static int audiocast_register_listener (gint * port, gint * fd);
143 static void audiocast_do_notifications (GstGnomeVFSSrc * src);
144 static gpointer audiocast_thread_run (GstGnomeVFSSrc * src);
145 static void audiocast_thread_kill (GstGnomeVFSSrc * src);
147 static GstElementClass *parent_class = NULL;
150 gst_gnome_vfs_src_get_type (void)
152 static GType gnomevfssrc_type = 0;
154 if (!gnomevfssrc_type) {
155 static const GTypeInfo gnomevfssrc_info = {
156 sizeof (GstGnomeVFSSrcClass),
157 gst_gnome_vfs_src_base_init,
159 (GClassInitFunc) gst_gnome_vfs_src_class_init,
162 sizeof (GstGnomeVFSSrc),
164 (GInstanceInitFunc) gst_gnome_vfs_src_init,
166 static const GInterfaceInfo urihandler_info = {
167 gst_gnome_vfs_src_uri_handler_init,
173 g_type_register_static (GST_TYPE_BASE_SRC,
174 "GstGnomeVFSSrc", &gnomevfssrc_info, 0);
175 g_type_add_interface_static (gnomevfssrc_type, GST_TYPE_URI_HANDLER,
178 return gnomevfssrc_type;
182 gst_gnome_vfs_src_base_init (gpointer g_class)
184 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
185 static GstElementDetails gst_gnome_vfs_src_details =
186 GST_ELEMENT_DETAILS ("GnomeVFS Source",
188 "Read from any GnomeVFS-supported file",
189 "Bastien Nocera <hadess@hadess.net>\n"
190 "Ronald S. Bultje <rbultje@ronald.bitfreak.net>");
192 gst_element_class_add_pad_template (element_class,
193 gst_static_pad_template_get (&srctemplate));
194 gst_element_class_set_details (element_class, &gst_gnome_vfs_src_details);
196 GST_DEBUG_CATEGORY_INIT (gnomevfssrc_debug, "gnomevfssrc", 0,
201 gst_gnome_vfs_src_class_init (GstGnomeVFSSrcClass * klass)
203 GObjectClass *gobject_class;
204 GstElementClass *gstelement_class;
205 GstBaseSrcClass *gstbasesrc_class;
207 gobject_class = G_OBJECT_CLASS (klass);
208 gstelement_class = GST_ELEMENT_CLASS (klass);
209 gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
211 parent_class = g_type_class_peek_parent (klass);
213 gobject_class->finalize = gst_gnome_vfs_src_finalize;
214 gobject_class->set_property = gst_gnome_vfs_src_set_property;
215 gobject_class->get_property = gst_gnome_vfs_src_get_property;
218 gst_element_class_install_std_props (GST_ELEMENT_CLASS (klass),
219 "location", ARG_LOCATION, G_PARAM_READWRITE, NULL);
220 g_object_class_install_property (gobject_class,
222 g_param_spec_boxed ("handle",
223 "GnomeVFSHandle", "Handle for GnomeVFS",
224 GST_TYPE_GNOME_VFS_HANDLE, G_PARAM_READWRITE));
227 g_object_class_install_property (gobject_class,
229 g_param_spec_boolean ("iradio-mode",
231 "Enable internet radio mode (extraction of icecast/audiocast metadata)",
232 FALSE, G_PARAM_READWRITE));
233 g_object_class_install_property (gobject_class,
235 g_param_spec_string ("iradio-name",
236 "iradio-name", "Name of the stream", NULL, G_PARAM_READABLE));
237 g_object_class_install_property (gobject_class,
239 g_param_spec_string ("iradio-genre",
240 "iradio-genre", "Genre of the stream", NULL, G_PARAM_READABLE));
241 g_object_class_install_property (gobject_class,
243 g_param_spec_string ("iradio-url",
245 "Homepage URL for radio stream", NULL, G_PARAM_READABLE));
246 g_object_class_install_property (gobject_class,
248 g_param_spec_string ("iradio-title",
250 "Name of currently playing song", NULL, G_PARAM_READABLE));
252 gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_start);
253 gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_stop);
254 gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_get_size);
255 gstbasesrc_class->is_seekable =
256 GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_is_seekable);
257 gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_gnome_vfs_src_create);
261 gst_gnome_vfs_src_init (GstGnomeVFSSrc * gnomevfssrc)
263 gnomevfssrc->uri = NULL;
264 gnomevfssrc->uri_name = NULL;
265 gnomevfssrc->handle = NULL;
266 gnomevfssrc->curoffset = 0;
267 gnomevfssrc->seekable = FALSE;
269 gnomevfssrc->icy_metaint = 0;
270 gnomevfssrc->iradio_mode = FALSE;
271 gnomevfssrc->http_callbacks_pushed = FALSE;
272 gnomevfssrc->icy_count = 0;
273 gnomevfssrc->iradio_name = NULL;
274 gnomevfssrc->iradio_genre = NULL;
275 gnomevfssrc->iradio_url = NULL;
276 gnomevfssrc->iradio_title = NULL;
278 gnomevfssrc->audiocast_udpdata_mutex = g_mutex_new ();
279 gnomevfssrc->audiocast_queue_mutex = g_mutex_new ();
280 gnomevfssrc->audiocast_notify_queue = NULL;
281 gnomevfssrc->audiocast_thread = NULL;
283 g_static_mutex_lock (&count_lock);
284 if (ref_count == 0) {
285 /* gnome vfs engine init */
286 if (gnome_vfs_initialized () == FALSE) {
292 g_static_mutex_unlock (&count_lock);
296 gst_gnome_vfs_src_finalize (GObject * object)
298 GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (object);
300 g_static_mutex_lock (&count_lock);
302 if (ref_count == 0 && vfs_owner) {
303 if (gnome_vfs_initialized () == TRUE) {
304 gnome_vfs_shutdown ();
307 g_static_mutex_unlock (&count_lock);
310 gnome_vfs_uri_unref (src->uri);
315 g_free (src->uri_name);
316 src->uri_name = NULL;
319 g_mutex_free (src->audiocast_udpdata_mutex);
320 g_mutex_free (src->audiocast_queue_mutex);
322 G_OBJECT_CLASS (parent_class)->finalize (object);
326 * URI interface support.
330 gst_gnome_vfs_src_uri_get_type (void)
336 gst_gnome_vfs_src_uri_get_protocols (void)
338 static gchar **protocols = NULL;
341 protocols = gst_gnomevfs_get_supported_uris ();
347 gst_gnome_vfs_src_uri_get_uri (GstURIHandler * handler)
349 GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (handler);
351 return src->uri_name;
355 gst_gnome_vfs_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
357 GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (handler);
359 if (GST_STATE (src) == GST_STATE_PLAYING ||
360 GST_STATE (src) == GST_STATE_PAUSED)
363 g_object_set (G_OBJECT (src), "location", uri, NULL);
369 gst_gnome_vfs_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
371 GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
373 iface->get_type = gst_gnome_vfs_src_uri_get_type;
374 iface->get_protocols = gst_gnome_vfs_src_uri_get_protocols;
375 iface->get_uri = gst_gnome_vfs_src_uri_get_uri;
376 iface->set_uri = gst_gnome_vfs_src_uri_set_uri;
380 gst_gnome_vfs_src_set_property (GObject * object, guint prop_id,
381 const GValue * value, GParamSpec * pspec)
386 src = GST_GNOME_VFS_SRC (object);
390 /* the element must be stopped or paused in order to do this */
391 if (GST_STATE (src) == GST_STATE_PLAYING ||
392 GST_STATE (src) == GST_STATE_PAUSED)
396 gnome_vfs_uri_unref (src->uri);
400 g_free (src->uri_name);
401 src->uri_name = NULL;
404 if (g_value_get_string (value)) {
405 const gchar *location = g_value_get_string (value);
407 if (!strchr (location, ':')) {
408 gchar *newloc = gnome_vfs_escape_path_string (location);
411 src->uri_name = g_strdup_printf ("file://%s", newloc);
414 g_strdup_printf ("file://%s/%s", getcwd (cwd, PATH_MAX),
418 src->uri_name = g_strdup (location);
420 src->uri = gnome_vfs_uri_new (src->uri_name);
424 if (GST_STATE (src) == GST_STATE_NULL ||
425 GST_STATE (src) == GST_STATE_READY) {
427 gnome_vfs_uri_unref (src->uri);
431 g_free (src->uri_name);
432 src->uri_name = NULL;
434 src->handle = g_value_get_boxed (value);
437 case ARG_IRADIO_MODE:
438 src->iradio_mode = g_value_get_boolean (value);
441 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
447 gst_gnome_vfs_src_get_property (GObject * object, guint prop_id, GValue * value,
452 src = GST_GNOME_VFS_SRC (object);
456 g_value_set_string (value, src->uri_name);
459 g_value_set_boxed (value, src->handle);
461 case ARG_IRADIO_MODE:
462 g_value_set_boolean (value, src->iradio_mode);
464 case ARG_IRADIO_NAME:
465 g_value_set_string (value, src->iradio_name);
467 case ARG_IRADIO_GENRE:
468 g_value_set_string (value, src->iradio_genre);
471 g_value_set_string (value, src->iradio_url);
473 case ARG_IRADIO_TITLE:
474 g_mutex_lock (src->audiocast_udpdata_mutex);
475 g_value_set_string (value, src->iradio_title);
476 g_mutex_unlock (src->audiocast_udpdata_mutex);
479 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
485 unicodify (const char *str, int len, ...)
487 char *ret = NULL, *cset;
489 gsize bytes_read, bytes_written;
491 if (g_utf8_validate (str, len, NULL))
492 return g_strndup (str, len >= 0 ? len : strlen (str));
494 va_start (args, len);
495 while ((cset = va_arg (args, char *)) != NULL)
497 if (!strcmp (cset, "locale"))
498 ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL);
500 ret = g_convert (str, len, "UTF-8", cset,
501 &bytes_read, &bytes_written, NULL);
511 gst_gnome_vfs_src_unicodify (const char *str)
513 return unicodify (str, -1, "locale", "ISO-8859-1", NULL);
517 * icecast/audiocast metadata extraction support code
521 audiocast_init (GstGnomeVFSSrc * src)
524 GError *error = NULL;
526 if (!src->iradio_mode)
528 GST_DEBUG_OBJECT (src, "audiocast: registering listener");
529 if (audiocast_register_listener (&src->audiocast_port,
530 &src->audiocast_fd) < 0) {
531 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
532 ("Unable to listen on UDP port %d", src->audiocast_port));
533 close (src->audiocast_fd);
536 GST_DEBUG_OBJECT (src, "audiocast: creating pipe");
537 src->audiocast_notify_queue = NULL;
538 if (pipe (pipefds) < 0) {
539 close (src->audiocast_fd);
542 src->audiocast_thread_die_infd = pipefds[0];
543 src->audiocast_thread_die_outfd = pipefds[1];
544 GST_DEBUG_OBJECT (src, "audiocast: creating audiocast thread");
545 src->audiocast_thread =
546 g_thread_create ((GThreadFunc) audiocast_thread_run, src, TRUE, &error);
548 GST_ELEMENT_ERROR (src, RESOURCE, TOO_LAZY, (NULL),
549 ("Unable to create thread: %s", error->message));
550 close (src->audiocast_fd);
557 audiocast_register_listener (gint * port, gint * fd)
559 struct sockaddr_in sin;
561 socklen_t sinlen = sizeof (struct sockaddr_in);
563 GST_DEBUG ("audiocast: establishing UDP listener");
565 if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
568 memset (&sin, 0, sinlen);
569 sin.sin_family = AF_INET;
570 sin.sin_addr.s_addr = g_htonl (INADDR_ANY);
572 if (bind (sock, (struct sockaddr *) &sin, sinlen) < 0)
575 memset (&sin, 0, sinlen);
576 if (getsockname (sock, (struct sockaddr *) &sin, &sinlen) < 0)
579 GST_DEBUG ("audiocast: listening on local %s:%d", inet_ntoa (sin.sin_addr),
580 g_ntohs (sin.sin_port));
582 *port = g_ntohs (sin.sin_port);
593 audiocast_do_notifications (GstGnomeVFSSrc * src)
595 /* Send any pending notifications we got from the UDP thread. */
596 if (src->iradio_mode) {
599 g_mutex_lock (src->audiocast_queue_mutex);
600 for (entry = src->audiocast_notify_queue; entry; entry = entry->next)
601 g_object_notify (G_OBJECT (src), (const gchar *) entry->data);
602 g_list_free (src->audiocast_notify_queue);
603 src->audiocast_notify_queue = NULL;
604 g_mutex_unlock (src->audiocast_queue_mutex);
609 audiocast_thread_run (GstGnomeVFSSrc * src)
611 char buf[1025], **lines;
613 fd_set fdset, readset;
614 struct sockaddr_in from;
615 socklen_t fromlen = sizeof (struct sockaddr_in);
619 FD_SET (src->audiocast_fd, &fdset);
620 FD_SET (src->audiocast_thread_die_infd, &fdset);
623 GST_DEBUG ("audiocast thread: dropping into select");
625 if (select (FD_SETSIZE, &readset, NULL, NULL, NULL) < 0) {
629 if (FD_ISSET (src->audiocast_thread_die_infd, &readset)) {
632 GST_DEBUG ("audiocast thread: got die character");
633 if (read (src->audiocast_thread_die_infd, buf, 1) != 1)
634 g_warning ("gnomevfssrc: could not read from audiocast fd");
635 close (src->audiocast_thread_die_infd);
636 close (src->audiocast_fd);
639 GST_DEBUG ("audiocast thread: reading data");
641 recvfrom (src->audiocast_fd, buf, sizeof (buf) - 1, 0,
642 (struct sockaddr *) &from, &fromlen);
643 if (len < 0 && errno == EAGAIN)
647 char *valptr, *value;
650 lines = g_strsplit (buf, "\n", 0);
654 for (i = 0; lines[i]; i++) {
655 while ((lines[i][strlen (lines[i]) - 1] == '\n') ||
656 (lines[i][strlen (lines[i]) - 1] == '\r'))
657 lines[i][strlen (lines[i]) - 1] = '\0';
659 valptr = strchr (lines[i], ':');
667 if (!strlen (valptr))
670 value = gst_gnome_vfs_src_unicodify (valptr);
672 g_print ("Unable to convert \"%s\" to UTF-8!\n", valptr);
676 if (!strncmp (lines[i], "x-audiocast-streamtitle", 23)) {
677 g_mutex_lock (src->audiocast_udpdata_mutex);
678 g_free (src->iradio_title);
679 src->iradio_title = value;
680 g_mutex_unlock (src->audiocast_udpdata_mutex);
682 g_mutex_lock (src->audiocast_queue_mutex);
683 src->audiocast_notify_queue =
684 g_list_append (src->audiocast_notify_queue, "iradio-title");
685 GST_DEBUG_OBJECT (src, "audiocast title: %s\n", src->iradio_title);
686 g_mutex_unlock (src->audiocast_queue_mutex);
687 } else if (!strncmp (lines[i], "x-audiocast-streamurl", 21)) {
688 g_mutex_lock (src->audiocast_udpdata_mutex);
689 g_free (src->iradio_url);
690 src->iradio_url = value;
691 g_mutex_unlock (src->audiocast_udpdata_mutex);
693 g_mutex_lock (src->audiocast_queue_mutex);
694 src->audiocast_notify_queue =
695 g_list_append (src->audiocast_notify_queue, "iradio-url");
696 GST_DEBUG_OBJECT (src, "audiocast url: %s\n", src->iradio_title);
697 g_mutex_unlock (src->audiocast_queue_mutex);
698 } else if (!strncmp (lines[i], "x-audiocast-udpseqnr", 20)) {
701 sprintf (outbuf, "x-audiocast-ack: %ld \r\n", atol (value));
704 if (sendto (src->audiocast_fd, outbuf, strlen (outbuf), 0,
705 (struct sockaddr *) &from, fromlen) <= 0) {
706 g_print ("Error sending response to server: %s\n",
710 GST_DEBUG_OBJECT (src, "sent audiocast ack: %s\n", outbuf);
720 audiocast_thread_kill (GstGnomeVFSSrc * src)
722 if (!src->audiocast_thread)
726 We rely on this hack to kill the
727 audiocast thread. If we get icecast
728 metadata, then we don't need the
729 audiocast metadata too.
731 GST_DEBUG ("audiocast: writing die character");
732 if (write (src->audiocast_thread_die_outfd, "q", 1) != 1)
733 g_critical ("gnomevfssrc: could not write to audiocast thread fd");
734 close (src->audiocast_thread_die_outfd);
735 GST_DEBUG ("audiocast: joining thread");
736 g_thread_join (src->audiocast_thread);
737 src->audiocast_thread = NULL;
741 gst_gnome_vfs_src_send_additional_headers_callback (gconstpointer in,
742 gsize in_size, gpointer out, gsize out_size, gpointer callback_data)
744 GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (callback_data);
745 GnomeVFSModuleCallbackAdditionalHeadersOut *out_args =
746 (GnomeVFSModuleCallbackAdditionalHeadersOut *) out;
748 if (!src->iradio_mode)
750 GST_DEBUG_OBJECT (src, "sending headers\n");
752 out_args->headers = g_list_append (out_args->headers,
753 g_strdup ("icy-metadata:1\r\n"));
754 out_args->headers = g_list_append (out_args->headers,
755 g_strdup_printf ("x-audiocast-udpport: %d\r\n", src->audiocast_port));
759 gst_gnome_vfs_src_received_headers_callback (gconstpointer in,
760 gsize in_size, gpointer out, gsize out_size, gpointer callback_data)
764 GstGnomeVFSSrc *src = GST_GNOME_VFS_SRC (callback_data);
765 GnomeVFSModuleCallbackReceivedHeadersIn *in_args =
766 (GnomeVFSModuleCallbackReceivedHeadersIn *) in;
768 /* This is only used for internet radio stuff right now */
769 if (!src->iradio_mode)
772 for (i = in_args->headers; i; i = i->next) {
773 char *data = (char *) i->data;
775 char *value = strchr (data, ':');
786 if (strncmp (data, "icy-metaint:", 12) == 0) { /* ugh */
787 if (sscanf (data + 12, "%d", &icy_metaint) == 1) {
788 src->icy_metaint = icy_metaint;
789 GST_DEBUG_OBJECT (src, "got icy-metaint %d, killing audiocast thread",
791 audiocast_thread_kill (src);
796 if (!strncmp (data, "icy-", 4))
798 else if (!strncmp (data, "x-audiocast-", 12))
803 GST_DEBUG_OBJECT (src, "key: %s", key);
804 if (!strncmp (key, "name", 4)) {
805 g_free (src->iradio_name);
806 src->iradio_name = gst_gnome_vfs_src_unicodify (value);
807 if (src->iradio_name)
808 g_object_notify (G_OBJECT (src), "iradio-name");
809 } else if (!strncmp (key, "genre", 5)) {
810 g_free (src->iradio_genre);
811 src->iradio_genre = gst_gnome_vfs_src_unicodify (value);
812 if (src->iradio_genre)
813 g_object_notify (G_OBJECT (src), "iradio-genre");
814 } else if (!strncmp (key, "url", 3)) {
815 g_free (src->iradio_url);
816 src->iradio_url = gst_gnome_vfs_src_unicodify (value);
818 g_object_notify (G_OBJECT (src), "iradio-url");
824 gst_gnome_vfs_src_push_callbacks (GstGnomeVFSSrc * src)
826 if (src->http_callbacks_pushed)
829 GST_DEBUG_OBJECT (src, "pushing callbacks");
830 gnome_vfs_module_callback_push
831 (GNOME_VFS_MODULE_CALLBACK_HTTP_SEND_ADDITIONAL_HEADERS,
832 gst_gnome_vfs_src_send_additional_headers_callback, src, NULL);
833 gnome_vfs_module_callback_push
834 (GNOME_VFS_MODULE_CALLBACK_HTTP_RECEIVED_HEADERS,
835 gst_gnome_vfs_src_received_headers_callback, src, NULL);
837 src->http_callbacks_pushed = TRUE;
841 gst_gnome_vfs_src_pop_callbacks (GstGnomeVFSSrc * src)
843 if (!src->http_callbacks_pushed)
846 GST_DEBUG_OBJECT (src, "popping callbacks");
847 gnome_vfs_module_callback_pop
848 (GNOME_VFS_MODULE_CALLBACK_HTTP_SEND_ADDITIONAL_HEADERS);
849 gnome_vfs_module_callback_pop
850 (GNOME_VFS_MODULE_CALLBACK_HTTP_RECEIVED_HEADERS);
854 gst_gnome_vfs_src_get_icy_metadata (GstGnomeVFSSrc * src)
856 GnomeVFSFileSize length = 0;
858 gint metadata_length;
865 GST_DEBUG_OBJECT (src, "reading icecast metadata");
867 while (length == 0) {
868 res = gnome_vfs_read (src->handle, &foobyte, 1, &length);
869 if (res != GNOME_VFS_OK)
873 metadata_length = foobyte * 16;
875 if (metadata_length == 0)
878 data = g_new (guchar, metadata_length + 1);
881 while (pos - data < metadata_length) {
882 res = gnome_vfs_read (src->handle, pos,
883 metadata_length - (pos - data), &length);
884 /* FIXME: better error handling here? */
885 if (res != GNOME_VFS_OK) {
893 data[metadata_length] = 0;
894 tags = g_strsplit ((gchar *) data, "';", 0);
896 for (i = 0; tags[i]; i++) {
897 if (!g_ascii_strncasecmp (tags[i], "StreamTitle=", 12)) {
898 g_free (src->iradio_title);
899 src->iradio_title = gst_gnome_vfs_src_unicodify (tags[i] + 13);
900 if (src->iradio_title) {
901 GST_DEBUG_OBJECT (src, "sending notification on icecast title");
902 g_object_notify (G_OBJECT (src), "iradio-title");
904 g_print ("Unable to convert icecast title \"%s\" to UTF-8!\n",
908 if (!g_ascii_strncasecmp (tags[i], "StreamUrl=", 10)) {
909 g_free (src->iradio_url);
910 src->iradio_url = gst_gnome_vfs_src_unicodify (tags[i] + 11);
911 if (src->iradio_url) {
912 GST_DEBUG_OBJECT (src, "sending notification on icecast url");
913 g_object_notify (G_OBJECT (src), "iradio-url");
915 g_print ("Unable to convert icecast url \"%s\" to UTF-8!\n",
923 /* end of icecast/audiocast metadata extraction support code */
926 * Read a new buffer from src->reqoffset, takes care of events
927 * and seeking and such.
930 gst_gnome_vfs_src_create (GstBaseSrc * basesrc, guint64 offset, guint size,
935 GnomeVFSFileSize readbytes;
939 src = GST_GNOME_VFS_SRC (basesrc);
941 GST_DEBUG ("now at %llu, reading %lld, size %u", src->curoffset, offset,
944 /* seek if required */
945 if (src->curoffset != offset) {
946 GST_DEBUG ("need to seek");
948 GST_DEBUG ("seeking to %lld", offset);
949 res = gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_START, offset);
950 if (res != GNOME_VFS_OK)
952 src->curoffset = offset;
958 audiocast_do_notifications (src);
960 if (src->iradio_mode && src->icy_metaint > 0) {
961 buf = gst_buffer_new_and_alloc (src->icy_metaint);
963 data = GST_BUFFER_DATA (buf);
966 GST_DEBUG_OBJECT (src, "doing read: icy_count: %" G_GINT64_FORMAT,
969 res = gnome_vfs_read (src->handle, data,
970 src->icy_metaint - src->icy_count, &readbytes);
972 if (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK && readbytes == 0))
975 if (res != GNOME_VFS_OK)
978 src->icy_count += readbytes;
979 GST_BUFFER_OFFSET (buf) = src->curoffset;
980 GST_BUFFER_SIZE (buf) = readbytes;
981 src->curoffset += readbytes;
983 if (src->icy_count == src->icy_metaint) {
984 gst_gnome_vfs_src_get_icy_metadata (src);
988 buf = gst_buffer_new_and_alloc (size);
990 data = GST_BUFFER_DATA (buf);
991 GST_BUFFER_OFFSET (buf) = src->curoffset;
993 res = gnome_vfs_read (src->handle, data, size, &readbytes);
995 if (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK && readbytes == 0))
998 GST_BUFFER_SIZE (buf) = readbytes;
1000 if (res != GNOME_VFS_OK)
1003 src->curoffset += readbytes;
1006 /* we're done, return the buffer */
1013 GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL),
1014 ("Failed to seek to requested position %" G_GINT64_FORMAT ": %s",
1015 offset, gnome_vfs_result_to_string (res)));
1016 return GST_FLOW_ERROR;
1020 GST_ELEMENT_ERROR (src, RESOURCE, SEEK, (NULL),
1021 ("Requested seek from %" G_GINT64_FORMAT " to %" G_GINT64_FORMAT
1022 "on non-seekable stream", src->curoffset, offset));
1023 return GST_FLOW_ERROR;
1027 gst_buffer_unref (buf);
1028 GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
1029 ("Failed to read data: %s", gnome_vfs_result_to_string (res)));
1030 return GST_FLOW_ERROR;
1034 gst_buffer_unref (buf);
1035 GST_DEBUG_OBJECT (src, "Reading data gave EOS");
1036 gst_pad_push_event (basesrc->srcpad, gst_event_new_eos ());
1037 return GST_FLOW_UNEXPECTED;
1042 gst_gnome_vfs_src_is_seekable (GstBaseSrc * basesrc)
1044 GstGnomeVFSSrc *src;
1046 src = GST_GNOME_VFS_SRC (basesrc);
1048 return src->seekable;
1052 gst_gnome_vfs_src_get_size (GstBaseSrc * basesrc, guint64 * size)
1054 GstGnomeVFSSrc *src;
1056 src = GST_GNOME_VFS_SRC (basesrc);
1058 GST_DEBUG_OBJECT (src, "size %" G_GUINT64_FORMAT, src->size);
1060 if (src->size == (GnomeVFSFileSize) - 1)
1068 /* open the file, do stuff necessary to go to READY state */
1070 gst_gnome_vfs_src_start (GstBaseSrc * basesrc)
1073 GnomeVFSFileInfo *info;
1074 GstGnomeVFSSrc *src;
1076 src = GST_GNOME_VFS_SRC (basesrc);
1078 if (!audiocast_init (src))
1081 gst_gnome_vfs_src_push_callbacks (src);
1083 if (src->uri != NULL) {
1084 if ((res = gnome_vfs_open_uri (&src->handle, src->uri,
1085 GNOME_VFS_OPEN_READ)) != GNOME_VFS_OK) {
1086 gchar *filename = gnome_vfs_uri_to_string (src->uri,
1087 GNOME_VFS_URI_HIDE_PASSWORD);
1089 gst_gnome_vfs_src_pop_callbacks (src);
1090 audiocast_thread_kill (src);
1092 if (res == GNOME_VFS_ERROR_NOT_FOUND ||
1093 res == GNOME_VFS_ERROR_SERVICE_NOT_AVAILABLE) {
1094 GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL),
1095 ("Could not open vfs file \"%s\" for reading: %s",
1096 filename, gnome_vfs_result_to_string (res)));
1098 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL),
1099 ("Could not open vfs file \"%s\" for reading: %s",
1100 filename, gnome_vfs_result_to_string (res)));
1105 src->own_handle = TRUE;
1106 } else if (!src->handle) {
1107 GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("No filename given"));
1110 src->own_handle = FALSE;
1113 src->size = (GnomeVFSFileSize) - 1;
1114 info = gnome_vfs_file_info_new ();
1115 if ((res = gnome_vfs_get_file_info_from_handle (src->handle,
1116 info, GNOME_VFS_FILE_INFO_DEFAULT)) == GNOME_VFS_OK) {
1117 if (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
1118 src->size = info->size;
1119 GST_DEBUG_OBJECT (src, "size: %llu bytes", src->size);
1121 GST_LOG_OBJECT (src, "filesize not known");
1123 GST_WARNING_OBJECT (src, "getting info failed: %s",
1124 gnome_vfs_result_to_string (res));
1126 gnome_vfs_file_info_unref (info);
1128 audiocast_do_notifications (src);
1130 if (gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_CURRENT, 0)
1132 src->seekable = TRUE;
1134 src->seekable = FALSE;
1141 gst_gnome_vfs_src_stop (GstBaseSrc * basesrc)
1143 GstGnomeVFSSrc *src;
1145 src = GST_GNOME_VFS_SRC (basesrc);
1147 gst_gnome_vfs_src_pop_callbacks (src);
1148 audiocast_thread_kill (src);
1150 if (src->own_handle) {
1151 gnome_vfs_close (src->handle);
1154 src->size = (GnomeVFSFileSize) - 1;