--- gstgnomevfssrc.c.orig	2006-03-13 17:42:38.000000000 +0200
+++ gstgnomevfssrc.c	2006-04-25 09:35:06.000000000 +0300
@@ -4,6 +4,7 @@
  *                    2001 Bastien Nocera <hadess@hadess.net>
  *                    2002 Kristian Rietveld <kris@gtk.org>
  *                    2002,2003 Colin Walters <walters@gnu.org>
+ *                    2006 Stefan Kost <ensonic@users.sf.net>
  *
  * gnomevfssrc.c:
  *
@@ -96,6 +97,12 @@
 GST_DEBUG_CATEGORY_STATIC (gnomevfssrc_debug);
 #define GST_CAT_DEFAULT gnomevfssrc_debug
 
+static GstElementDetails gst_gnome_vfs_src_details =
+GST_ELEMENT_DETAILS ("GnomeVFS Source",
+    "Source/File",
+    "Read from any GnomeVFS-supported file",
+    "Bastien Nocera <hadess@hadess.net>\n"
+    "Ronald S. Bultje <rbultje@ronald.bitfreak.net>");
 
 static GStaticMutex count_lock = G_STATIC_MUTEX_INIT;
 static gint ref_count = 0;
@@ -116,7 +123,8 @@
   ARG_IRADIO_NAME,
   ARG_IRADIO_GENRE,
   ARG_IRADIO_URL,
-  ARG_IRADIO_TITLE
+  ARG_IRADIO_TITLE,
+  ARG_TIMEOUT
 };
 
 static void gst_gnome_vfs_src_base_init (gpointer g_class);
@@ -183,12 +191,6 @@
 gst_gnome_vfs_src_base_init (gpointer g_class)
 {
   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-  static GstElementDetails gst_gnome_vfs_src_details =
-      GST_ELEMENT_DETAILS ("GnomeVFS Source",
-      "Source/File",
-      "Read from any GnomeVFS-supported file",
-      "Bastien Nocera <hadess@hadess.net>\n"
-      "Ronald S. Bultje <rbultje@ronald.bitfreak.net>");
 
   gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&srctemplate));
@@ -218,11 +220,17 @@
   /* properties */
   gst_element_class_install_std_props (GST_ELEMENT_CLASS (klass),
       "location", ARG_LOCATION, G_PARAM_READWRITE, NULL);
+  /* FIXME : should be async handle */
   g_object_class_install_property (gobject_class,
       ARG_HANDLE,
       g_param_spec_boxed ("handle",
           "GnomeVFSHandle", "Handle for GnomeVFS",
           GST_TYPE_GNOME_VFS_HANDLE, G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+      ARG_TIMEOUT,
+      g_param_spec_double ("timeout",
+          "timeout", "Async IO Operation timeout in seconds",
+          0.0, 300.0, 10.0, G_PARAM_READWRITE));
 
   /* icecast stuff */
   g_object_class_install_property (gobject_class,
@@ -268,6 +276,9 @@
   gnomevfssrc->handle = NULL;
   gnomevfssrc->curoffset = 0;
   gnomevfssrc->seekable = FALSE;
+  gnomevfssrc->timeout = 10.0; /* 10 second default timeout */
+  gnomevfssrc->async_op_pending = FALSE;
+  gnomevfssrc->async_op_mutex = g_mutex_new ();
 
   gnomevfssrc->icy_metaint = 0;
   gnomevfssrc->iradio_mode = FALSE;
@@ -314,14 +325,26 @@
     src->uri = NULL;
   }
 
-  if (src->uri_name) {
-    g_free (src->uri_name);
-    src->uri_name = NULL;
-  }
+  g_free (src->uri_name);
+  src->uri_name = NULL;
+
+  g_free (src->iradio_name);
+  src->iradio_name = NULL;
+
+  g_free (src->iradio_genre);
+  src->iradio_genre = NULL;
+
+  g_free (src->iradio_url);
+  src->iradio_url = NULL;
+
+  g_free (src->iradio_title);
+  src->iradio_title = NULL;
 
   g_mutex_free (src->audiocast_udpdata_mutex);
   g_mutex_free (src->audiocast_queue_mutex);
 
+  g_mutex_free (src->async_op_mutex);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -384,12 +407,13 @@
     const GValue * value, GParamSpec * pspec)
 {
   GstGnomeVFSSrc *src;
-  gchar cwd[PATH_MAX];
 
   src = GST_GNOME_VFS_SRC (object);
 
   switch (prop_id) {
-    case ARG_LOCATION:
+    case ARG_LOCATION:{
+      const gchar *new_location;
+
       /* the element must be stopped or paused in order to do this */
       if (GST_STATE (src) == GST_STATE_PLAYING ||
           GST_STATE (src) == GST_STATE_PAUSED)
@@ -404,25 +428,13 @@
         src->uri_name = NULL;
       }
 
-      if (g_value_get_string (value)) {
-        const gchar *location = g_value_get_string (value);
-
-        if (!strchr (location, ':')) {
-          gchar *newloc = gnome_vfs_escape_path_string (location);
-
-          if (*newloc == '/')
-            src->uri_name = g_strdup_printf ("file://%s", newloc);
-          else
-            src->uri_name =
-                g_strdup_printf ("file://%s/%s", getcwd (cwd, PATH_MAX),
-                newloc);
-          g_free (newloc);
-        } else
-          src->uri_name = g_strdup (location);
-
+      new_location = g_value_get_string (value);
+      if (new_location) {
+        src->uri_name = gst_gnome_vfs_location_to_uri_string (new_location);
         src->uri = gnome_vfs_uri_new (src->uri_name);
       }
       break;
+    }
     case ARG_HANDLE:
       if (GST_STATE (src) == GST_STATE_NULL ||
           GST_STATE (src) == GST_STATE_READY) {
@@ -437,6 +449,10 @@
         src->handle = g_value_get_boxed (value);
       }
       break;
+    case ARG_TIMEOUT:
+      src->timeout = g_value_get_double (value);
+      GST_INFO ("Timeout changed to %6.3lf", src->timeout);
+      break;
     case ARG_IRADIO_MODE:
       src->iradio_mode = g_value_get_boolean (value);
       break;
@@ -461,6 +477,9 @@
     case ARG_HANDLE:
       g_value_set_boxed (value, src->handle);
       break;
+    case ARG_TIMEOUT:
+      g_value_set_double (value, src->timeout);
+      break;
     case ARG_IRADIO_MODE:
       g_value_set_boolean (value, src->iradio_mode);
       break;
@@ -517,6 +536,156 @@
 }
 
 /*
+ * gnome-vfs async api helpers 
+ */
+
+static gboolean
+gst_gnome_vfs_async_wait(GstGnomeVFSSrc * src)
+{
+  gboolean res = TRUE;
+  GTimer *timer = g_timer_new ();
+
+  /* wait for callback to be called */
+  while (src->async_op_pending) {
+    if (g_main_context_pending (NULL)) {
+      g_main_context_iteration (NULL, FALSE);
+    }
+    else {
+      usleep (100);
+    }
+    if (g_timer_elapsed (timer, NULL) > src->timeout) {
+      gnome_vfs_async_cancel (src->handle);
+      res = FALSE;
+      src->async_op_pending = FALSE;
+      GST_INFO_OBJECT (src, "Timeout occured %6.3lf>%6.3lf", g_timer_elapsed (timer, NULL), src->timeout);
+      break;
+    }
+  }
+  g_timer_destroy (timer);
+  return(res);
+}
+
+static void
+gst_gnome_vfs_async_cancel(GstGnomeVFSSrc * src)
+{
+  /* cancel operation if there is any */
+  if (src->async_op_pending) {
+    gnome_vfs_async_cancel (src->handle);
+    src->async_op_pending = FALSE;
+    g_mutex_unlock (src->async_op_mutex);
+  }
+}
+
+static void
+gst_gnome_vfs_src_async_read_cb (GnomeVFSAsyncHandle *handle,
+                                 GnomeVFSResult result, gpointer buffer,
+                                 GnomeVFSFileSize bytes_requested,
+                                 GnomeVFSFileSize bytes_read,
+                                 gpointer callback_data)
+{
+  GstGnomeVFSSrc * src = GST_GNOME_VFS_SRC (callback_data);
+  GST_DEBUG_OBJECT (src, "Read callback : req=%"G_GUINT64_FORMAT" / read=%"G_GUINT64_FORMAT,bytes_requested,bytes_read);
+  
+  src->bytes_read += bytes_read;
+  src->result = result;
+  src->async_op_pending = FALSE;
+}
+
+static GnomeVFSResult
+gst_gnome_vfs_async_read (GstGnomeVFSSrc * src, guint8 *data, guint size,
+        GnomeVFSFileSize *bytes_read)
+{
+  GnomeVFSResult res = GNOME_VFS_OK;
+  GnomeVFSFileSize bytes_remain = size;
+  
+  src->bytes_read = 0;
+  while (bytes_remain && (res == GNOME_VFS_OK)) {
+    GST_DEBUG_OBJECT (src, "Read chunk : read=%"G_GUINT64_FORMAT" / size=%d",src->bytes_read, size);
+
+    g_mutex_lock (src->async_op_mutex);
+    src->async_op_pending = TRUE;
+    gnome_vfs_async_read (src->handle, &data[src->bytes_read], bytes_remain,
+        gst_gnome_vfs_src_async_read_cb, (gpointer)src);
+      
+    /* wait for callback to be called */
+    res = gst_gnome_vfs_async_wait (src) ? src->result : GNOME_VFS_ERROR_TIMEOUT;
+    g_mutex_unlock (src->async_op_mutex);
+
+    bytes_remain = size - src->bytes_read;
+  }
+  GST_DEBUG_OBJECT (src, "read: res=%s", gnome_vfs_result_to_string (res));
+  *bytes_read = src->bytes_read;
+  return(res);
+}
+
+static void
+gst_gnome_vfs_src_async_default_cb (GnomeVFSAsyncHandle *handle,
+                                    GnomeVFSResult result,
+                                    gpointer callback_data)
+{
+  GstGnomeVFSSrc * src = GST_GNOME_VFS_SRC (callback_data);
+  GST_DEBUG_OBJECT (src, "Default callback : handle=%p", handle);
+  
+  src->result = result;
+  src->async_op_pending = FALSE;
+}
+
+static GnomeVFSResult
+gst_gnome_vfs_async_open_uri (GstGnomeVFSSrc * src)
+{
+  GnomeVFSResult res;
+  
+  g_mutex_lock (src->async_op_mutex);
+  src->async_op_pending = TRUE;
+  gnome_vfs_async_open_uri (&src->handle, src->uri, GNOME_VFS_OPEN_READ,
+                            GNOME_VFS_PRIORITY_DEFAULT,
+                            gst_gnome_vfs_src_async_default_cb,
+                            (gpointer)src);
+
+  /* wait for callback to be called */
+  res = gst_gnome_vfs_async_wait (src) ? src->result : GNOME_VFS_ERROR_TIMEOUT;
+  g_mutex_unlock (src->async_op_mutex);
+
+  GST_DEBUG_OBJECT (src, "open uri: handle = %p, res=%s", src->handle,
+      gnome_vfs_result_to_string (res));
+  return(res);
+}
+
+static void
+gst_gnome_vfs_async_close (GstGnomeVFSSrc * src)
+{
+  gst_gnome_vfs_async_cancel (src);
+
+  GST_DEBUG_OBJECT (src, "close uri: handle = %p", src->handle);
+  g_mutex_lock (src->async_op_mutex);
+  src->async_op_pending = TRUE;
+  gnome_vfs_async_close (src->handle,
+                         gst_gnome_vfs_src_async_default_cb,
+                         (gpointer)src);
+  /* wait for callback to be called */
+  gst_gnome_vfs_async_wait (src);
+  g_mutex_unlock (src->async_op_mutex);
+}
+
+static GnomeVFSResult
+gst_gnome_vfs_seek_async (GstGnomeVFSSrc *src, GnomeVFSSeekPosition whence,
+                          GnomeVFSFileOffset offset)
+{
+  GnomeVFSResult res;
+  
+  gst_gnome_vfs_async_cancel (src);
+  g_mutex_lock (src->async_op_mutex);
+  src->async_op_pending = TRUE;
+  gnome_vfs_async_seek (src->handle, whence, offset,
+                            gst_gnome_vfs_src_async_default_cb,
+                            (gpointer)src);
+  /* wait for callback to be called */
+  res = gst_gnome_vfs_async_wait (src) ? src->result : GNOME_VFS_ERROR_TIMEOUT;
+  g_mutex_unlock (src->async_op_mutex);
+  return(res);  
+}
+
+/*
  * icecast/audiocast metadata extraction support code
  */
 
@@ -771,7 +940,7 @@
 
   if (!src->iradio_mode)
     return;
-  GST_DEBUG_OBJECT (src, "sending headers\n");
+  GST_DEBUG_OBJECT (src, "sending headers");
 
   out_args->headers = g_list_append (out_args->headers,
       g_strdup ("icy-metadata:1\r\n"));
@@ -872,6 +1041,8 @@
       (GNOME_VFS_MODULE_CALLBACK_HTTP_SEND_ADDITIONAL_HEADERS);
   gnome_vfs_module_callback_pop
       (GNOME_VFS_MODULE_CALLBACK_HTTP_RECEIVED_HEADERS);
+
+  src->http_callbacks_pushed = FALSE;
 }
 
 static void
@@ -884,12 +1055,14 @@
   guchar *data;
   guchar *pos;
   gchar **tags;
-  int i;
+  guint i, size;
 
   GST_DEBUG_OBJECT (src, "reading icecast metadata");
 
   while (length == 0) {
-    res = gnome_vfs_read (src->handle, &foobyte, 1, &length);
+    //res = gnome_vfs_read (src->handle, &foobyte, 1, &length);
+    res = gst_gnome_vfs_async_read (src, &foobyte, 1, &length);
+    
     if (res != GNOME_VFS_OK)
       return;
   }
@@ -903,8 +1076,11 @@
   pos = data;
 
   while (pos - data < metadata_length) {
-    res = gnome_vfs_read (src->handle, pos,
-        metadata_length - (pos - data), &length);
+    size = metadata_length - (pos - data);
+    //res = gnome_vfs_read (src->handle, pos, size, &length);
+    res = gst_gnome_vfs_async_read (src, data, size, &length);
+        
+        
     /* FIXME: better error handling here? */
     if (res != GNOME_VFS_OK) {
       g_free (data);
@@ -942,6 +1118,7 @@
   }
 
   g_strfreev (tags);
+  g_free (data);
 }
 
 /* end of icecast/audiocast metadata extraction support code */
@@ -956,7 +1133,7 @@
 {
   GnomeVFSResult res;
   GstBuffer *buf;
-  GnomeVFSFileSize readbytes;
+  GnomeVFSFileSize bytes_read;
   guint8 *data;
   GstGnomeVFSSrc *src;
 
@@ -970,7 +1147,9 @@
     GST_DEBUG ("need to seek");
     if (src->seekable) {
       GST_DEBUG ("seeking to %lld", offset);
-      res = gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_START, offset);
+      //res = gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_START, offset);
+      res = gst_gnome_vfs_seek_async (src, GNOME_VFS_SEEK_START, offset);
+      
       if (res != GNOME_VFS_OK)
         goto seek_failed;
       src->curoffset = offset;
@@ -982,6 +1161,8 @@
   audiocast_do_notifications (src);
 
   if (src->iradio_mode && src->icy_metaint > 0) {
+    guint isize = src->icy_metaint - src->icy_count;
+    
     buf = gst_buffer_new_and_alloc (src->icy_metaint);
 
     data = GST_BUFFER_DATA (buf);
@@ -990,41 +1171,43 @@
     GST_DEBUG_OBJECT (src, "doing read: icy_count: %" G_GINT64_FORMAT,
         src->icy_count);
 
-    res = gnome_vfs_read (src->handle, data,
-        src->icy_metaint - src->icy_count, &readbytes);
+    //res = gnome_vfs_read (src->handle, data, isize, &bytes_read);
+    res = gst_gnome_vfs_async_read (src, data, isize, &bytes_read);
 
-    if (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK && readbytes == 0))
+    if (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK && bytes_read == 0))
       goto eos;
 
     if (res != GNOME_VFS_OK)
       goto read_failed;
 
-    src->icy_count += readbytes;
+    src->icy_count += bytes_read;
     GST_BUFFER_OFFSET (buf) = src->curoffset;
-    GST_BUFFER_SIZE (buf) = readbytes;
-    src->curoffset += readbytes;
+    GST_BUFFER_SIZE (buf) = bytes_read;
+    src->curoffset += bytes_read;
 
     if (src->icy_count == src->icy_metaint) {
       gst_gnome_vfs_src_get_icy_metadata (src);
       src->icy_count = 0;
     }
-  } else {
+  } else {    
     buf = gst_buffer_new_and_alloc (size);
 
     data = GST_BUFFER_DATA (buf);
-    GST_BUFFER_OFFSET (buf) = src->curoffset;
 
-    res = gnome_vfs_read (src->handle, data, size, &readbytes);
+    GST_DEBUG_OBJECT (src, "doing read");
 
-    if (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK && readbytes == 0))
-      goto eos;
+    //res = gnome_vfs_read (src->handle, data, size, &bytes_read);
+    res = gst_gnome_vfs_async_read (src, data, size, &bytes_read);
 
-    GST_BUFFER_SIZE (buf) = readbytes;
+    if (res == GNOME_VFS_ERROR_EOF || (res == GNOME_VFS_OK && bytes_read == 0))
+      goto eos;
 
     if (res != GNOME_VFS_OK)
       goto read_failed;
 
-    src->curoffset += readbytes;
+    GST_BUFFER_OFFSET (buf) = src->curoffset;
+    GST_BUFFER_SIZE (buf) = bytes_read;
+    src->curoffset += bytes_read;
   }
 
   /* we're done, return the buffer */
@@ -1148,12 +1331,16 @@
 
   gst_gnome_vfs_src_push_callbacks (src);
 
+  GST_DEBUG_OBJECT (src, "before open uri : handle = %s", src->uri_name);
+
   if (src->uri != NULL) {
     /* this can block... */
-    if ((res = gnome_vfs_open_uri (&src->handle, src->uri,
-                GNOME_VFS_OPEN_READ)) != GNOME_VFS_OK)
+    //if ((res = gnome_vfs_open_uri (&src->handle, src->uri,
+    //            GNOME_VFS_OPEN_READ)) != GNOME_VFS_OK)
+    if ((res = gst_gnome_vfs_async_open_uri (src)) != GNOME_VFS_OK)
       goto open_failed;
     src->own_handle = TRUE;
+    GST_DEBUG_OBJECT (src, "open uri okay : handle = %p", src->handle);
   } else if (!src->handle) {
     goto no_filename;
   } else {
@@ -1162,7 +1349,10 @@
 
   src->size = (GnomeVFSFileSize) - 1;
   info = gnome_vfs_file_info_new ();
-  if ((res = gnome_vfs_get_file_info_from_handle (src->handle,
+  /* TODO: port to async API */
+  //if ((res = gnome_vfs_get_file_info_from_handle (src->handle,
+  //            info, GNOME_VFS_FILE_INFO_DEFAULT)) == GNOME_VFS_OK) {
+  if ((res = gnome_vfs_get_file_info_uri (src->uri,
               info, GNOME_VFS_FILE_INFO_DEFAULT)) == GNOME_VFS_OK) {
     if (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
       src->size = info->size;
@@ -1177,13 +1367,17 @@
 
   audiocast_do_notifications (src);
 
-  if (gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_CURRENT, 0)
-      == GNOME_VFS_OK) {
+  //if (gnome_vfs_seek (src->handle, GNOME_VFS_SEEK_CURRENT, 0)
+  if (gst_gnome_vfs_seek_async (src, GNOME_VFS_SEEK_CURRENT, 0)
+    == GNOME_VFS_OK) {
     src->seekable = TRUE;
+    GST_DEBUG_OBJECT (src, "is seekable");
   } else {
     src->seekable = FALSE;
+    GST_DEBUG_OBJECT (src, "is not seekable");
   }
 
+  GST_DEBUG_OBJECT (src, "open uri still okay : handle = %p", src->handle);
   return TRUE;
 
   /* ERRORS */
@@ -1226,7 +1420,8 @@
   audiocast_thread_kill (src);
 
   if (src->own_handle) {
-    gnome_vfs_close (src->handle);
+    //gnome_vfs_close (src->handle);
+    gst_gnome_vfs_async_close (src);
     src->handle = NULL;
   }
   src->size = (GnomeVFSFileSize) - 1;
--- gstgnomevfssrc.h.orig	2006-04-25 09:47:14.000000000 +0300
+++ gstgnomevfssrc.h	2006-04-25 09:35:14.000000000 +0300
@@ -58,11 +58,17 @@
   /* uri, file, ... */
   GnomeVFSURI *uri;
   gchar *uri_name;
-  GnomeVFSHandle *handle;
+  //GnomeVFSHandle *handle;
+  GnomeVFSAsyncHandle *handle;
   gboolean own_handle;
   GnomeVFSFileSize size;        /* -1 = unknown */
   GnomeVFSFileOffset curoffset; /* current offset in file */
+  GnomeVFSResult result;
   gboolean seekable;
+  gboolean async_op_pending;
+  GMutex *async_op_mutex;
+  GnomeVFSFileSize bytes_read;
+  gdouble timeout;
 
   /* icecast/audiocast metadata extraction handling */
   gboolean iradio_mode;
