ext/neon/gstneonhttpsrc.*: added iradio-mode support as in gnomevfssrc to enable...
authorSébastien Moutte <sebastien@moutte.net>
Sat, 29 Apr 2006 15:36:16 +0000 (15:36 +0000)
committerSébastien Moutte <sebastien@moutte.net>
Sat, 29 Apr 2006 15:36:16 +0000 (15:36 +0000)
Original commit message from CVS:
* ext/neon/gstneonhttpsrc.c:
* ext/neon/gstneonhttpsrc.h:
added iradio-mode support as in gnomevfssrc to enable
connections with icydemux that will send title tag messages on
shoutcast/icecast streams. I've also added iradio properties
iradio-name, iradio-genre, iradio-url.
added user-agent property because some shoutcast streams don't return
data if the GET requests don't have a User-Agent.
* win32/common/libgstneon.dsp:
use debug version of libneon in debug mode

ChangeLog
common
ext/neon/gstneonhttpsrc.c
ext/neon/gstneonhttpsrc.h
win32/vs6/libgstneon.dsp

index 89401d0..3bd37d0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2006-04-29  Sebastien Moutte  <sebastien@moutte.net>
+
+       * ext/neon/gstneonhttpsrc.c:
+       * ext/neon/gstneonhttpsrc.h:
+         added iradio-mode support as in gnomevfssrc to enable 
+         connections with icydemux that will send title tag messages on 
+         shoutcast/icecast streams. I've also added iradio properties
+         iradio-name, iradio-genre, iradio-url.
+         added user-agent property because some shoutcast streams don't return 
+         data if the GET requests don't have a User-Agent.
+       * win32/common/libgstneon.dsp:
+         use debug version of libneon in debug mode
 2006-04-28  Thomas Vander Stichele  <thomas at apestaart dot org>
 
        * configure.ac:
diff --git a/common b/common
index a6710e6..6b67aa6 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit a6710e67fd82147e32a18f1b63177583faffd498
+Subproject commit 6b67aa6dd111fb139e1be0f6a386e3ff84cce091
index b8932e4..356da9a 100644 (file)
@@ -22,7 +22,7 @@
 
 #define HTTP_DEFAULT_HOST        "localhost"
 #define HTTP_DEFAULT_PORT        80
-#define HTTPS_DEFAULT_PORT        443
+#define HTTPS_DEFAULT_PORT       443
 
 GST_DEBUG_CATEGORY (neonhttpsrc_debug);
 #define GST_CAT_DEFAULT neonhttpsrc_debug
@@ -41,13 +41,17 @@ static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_ALWAYS,
     GST_STATIC_CAPS_ANY);
 
-
 enum
 {
   PROP_0,
   PROP_LOCATION,
   PROP_URI,
-  PROP_PROXY
+  PROP_PROXY,
+  PROP_USER_AGENT,
+  PROP_IRADIO_MODE,
+  PROP_IRADIO_NAME,
+  PROP_IRADIO_GENRE,
+  PROP_IRADIO_URL
 };
 
 static void oom_callback ();
@@ -119,7 +123,7 @@ gst_neonhttp_src_class_init (GstNeonhttpSrcClass * klass)
   gobject_class->finalize = gst_neonhttp_src_finalize;
 
   g_object_class_install_property
-      (G_OBJECT_CLASS (klass), PROP_LOCATION,
+      (gobject_class, PROP_LOCATION,
       g_param_spec_string ("location", "Location",
           "The location. In the form:"
           "\n\t\t\thttp://a.com/file.txt - default port '80' "
@@ -130,19 +134,47 @@ gst_neonhttp_src_class_init (GstNeonhttpSrcClass * klass)
           "", G_PARAM_READWRITE));
 
   g_object_class_install_property
-      (G_OBJECT_CLASS (klass), PROP_URI,
+      (gobject_class, PROP_URI,
       g_param_spec_string ("uri", "Uri",
           "The location in form of a URI (deprecated; use location)",
           "", G_PARAM_READWRITE));
 
   g_object_class_install_property
-      (G_OBJECT_CLASS (klass), PROP_PROXY,
+      (gobject_class, PROP_PROXY,
       g_param_spec_string ("proxy", "Proxy",
           "The proxy. In the form myproxy.mycompany.com:8080. "
           "\n\t\t\tIf nothing is passed g_getenv(\"http_proxy\") will be used "
           "\n\t\t\tIf that http_proxy enviroment var isn't define no proxy is used",
           "", G_PARAM_READWRITE));
 
+  g_object_class_install_property
+      (gobject_class, PROP_USER_AGENT,
+      g_param_spec_string ("user-agent", "User-Agent",
+          "The User-Agent used for connection.",
+          "neonhttpsrc", G_PARAM_READWRITE));
+
+  g_object_class_install_property
+      (gobject_class, PROP_IRADIO_MODE,
+      g_param_spec_boolean ("iradio-mode", "iradio-mode",
+          "Enable internet radio mode (extraction of shoutcast/icecast metadata)",
+          FALSE, G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+      PROP_IRADIO_NAME,
+      g_param_spec_string ("iradio-name",
+          "iradio-name", "Name of the stream", NULL, G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class,
+      PROP_IRADIO_GENRE,
+      g_param_spec_string ("iradio-genre",
+          "iradio-genre", "Genre of the stream", NULL, G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class,
+      PROP_IRADIO_URL,
+      g_param_spec_string ("iradio-url",
+          "iradio-url",
+          "Homepage URL for radio stream", NULL, G_PARAM_READABLE));
+
   gstbasesrc_class->start = gst_neonhttp_src_start;
   gstbasesrc_class->stop = gst_neonhttp_src_stop;
   gstbasesrc_class->unlock = gst_neonhttp_src_unlock;
@@ -171,6 +203,15 @@ gst_neonhttp_src_init (GstNeonhttpSrc * this, GstNeonhttpSrcClass * g_class)
 
   this->adapter = gst_adapter_new ();
 
+  this->user_agent = g_strdup ("neonhttpsrc");
+
+  this->iradio_mode = FALSE;
+  this->iradio_name = NULL;
+  this->iradio_genre = NULL;
+  this->iradio_url = NULL;
+  this->icy_caps = NULL;
+  this->icy_metaint = 0;
+
   GST_OBJECT_FLAG_UNSET (this, GST_NEONHTTP_SRC_OPEN);
 }
 
@@ -182,6 +223,30 @@ gst_neonhttp_src_finalize (GObject * gobject)
   ne_uri_free (&this->uri);
   ne_uri_free (&this->proxy);
 
+  if (this->user_agent) {
+    g_free (this->user_agent);
+    this->user_agent = NULL;
+  }
+
+  if (this->iradio_name) {
+    g_free (this->iradio_name);
+    this->iradio_name = NULL;
+  }
+
+  if (this->iradio_genre) {
+    g_free (this->iradio_genre);
+    this->iradio_genre = NULL;
+  }
+
+  if (this->iradio_url) {
+    g_free (this->iradio_url);
+    this->iradio_url = NULL;
+  }
+
+  if (this->icy_caps) {
+    gst_caps_unref (this->icy_caps);
+    this->icy_caps = NULL;
+  }
 
   if (this->request) {
     ne_request_destroy (this->request);
@@ -288,7 +353,11 @@ gst_neonhttp_src_create (GstPushSrc * psrc, GstBuffer ** outbuf)
   if (read > 0) {
 
     if (*outbuf) {
-      gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
+      if (src->icy_caps) {
+        gst_buffer_set_caps (*outbuf, src->icy_caps);
+      } else {
+        gst_buffer_set_caps (*outbuf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
+      }
     }
 
   } else if (read < 0) {
@@ -316,6 +385,42 @@ wrong_state:
 
 }
 
+/* The following two charset mangling functions were copied from gnomevfssrc.
+ * Preserve them under the unverified assumption that they do something vaguely
+ * worthwhile.
+ */
+static char *
+unicodify (const char *str, int len, ...)
+{
+  char *ret = NULL, *cset;
+  va_list args;
+  gsize bytes_read, bytes_written;
+
+  if (g_utf8_validate (str, len, NULL))
+    return g_strndup (str, len >= 0 ? len : strlen (str));
+
+  va_start (args, len);
+  while ((cset = va_arg (args, char *)) != NULL)
+  {
+    if (!strcmp (cset, "locale"))
+      ret = g_locale_to_utf8 (str, len, &bytes_read, &bytes_written, NULL);
+    else
+      ret = g_convert (str, len, "UTF-8", cset,
+          &bytes_read, &bytes_written, NULL);
+    if (ret)
+      break;
+  }
+  va_end (args);
+
+  return ret;
+}
+
+static char *
+gst_neonhttp_src_unicodify (const char *str)
+{
+  return unicodify (str, -1, "locale", "ISO-8859-1", NULL);
+}
+
 /* create a socket for connecting to remote server */
 static gboolean
 gst_neonhttp_src_start (GstBaseSrc * bsrc)
@@ -344,6 +449,14 @@ gst_neonhttp_src_start (GstBaseSrc * bsrc)
 
   src->request = ne_request_create (src->session, "GET", src->uri.path);
 
+  if (src->user_agent) {
+    ne_add_request_header (src->request, "User-Agent", src->user_agent);
+  }
+
+  if (src->iradio_mode) {
+    ne_add_request_header (src->request, "icy-metadata", "1");
+  }
+
   if (NE_OK != ne_begin_request (src->request)) {
     ret = FALSE;
     goto done;
@@ -357,6 +470,50 @@ gst_neonhttp_src_start (GstBaseSrc * bsrc)
     src->content_size = -1;
   }
 
+  if (src->iradio_mode) {
+    /* Icecast stuff */
+    const char *str_value;
+    gint gint_value;
+
+    str_value = ne_get_response_header (src->request, "icy-metaint");
+    if (str_value) {
+      if (sscanf (str_value, "%d", &gint_value) == 1) {
+        if (src->icy_caps) {
+          gst_caps_unref (src->icy_caps);
+          src->icy_caps = NULL;
+        }
+        src->icy_metaint = gint_value;
+        src->icy_caps = gst_caps_new_simple ("application/x-icy",
+            "metadata-interval", G_TYPE_INT, src->icy_metaint, NULL);
+      }
+    }
+
+    str_value = ne_get_response_header (src->request, "icy-name");
+    if (str_value) {
+      if (src->iradio_name) {
+        g_free (src->iradio_name);
+        src->iradio_name = NULL;
+      }
+      src->iradio_name = gst_neonhttp_src_unicodify (str_value);
+    }
+    str_value = ne_get_response_header (src->request, "icy-genre");
+    if (str_value) {
+      if (src->iradio_genre) {
+        g_free (src->iradio_genre);
+        src->iradio_genre = NULL;
+      }
+      src->iradio_genre = gst_neonhttp_src_unicodify (str_value);
+    }
+    str_value = ne_get_response_header (src->request, "icy-url");
+    if (str_value) {
+      if (src->iradio_url) {
+        g_free (src->iradio_url);
+        src->iradio_url = NULL;
+      }
+      src->iradio_url = gst_neonhttp_src_unicodify (str_value);
+    }
+  }
+
   GST_OBJECT_FLAG_SET (src, GST_NEONHTTP_SRC_OPEN);
 
 done:
@@ -405,6 +562,26 @@ gst_neonhttp_src_stop (GstBaseSrc * bsrc)
 
   src = GST_NEONHTTP_SRC (bsrc);
 
+  if (src->iradio_name) {
+    g_free (src->iradio_name);
+    src->iradio_name = NULL;
+  }
+
+  if (src->iradio_genre) {
+    g_free (src->iradio_genre);
+    src->iradio_genre = NULL;
+  }
+
+  if (src->iradio_url) {
+    g_free (src->iradio_url);
+    src->iradio_url = NULL;
+  }
+
+  if (src->icy_caps) {
+    gst_caps_unref (src->icy_caps);
+    src->icy_caps = NULL;
+  }
+
   if (src->request) {
     ne_request_destroy (src->request);
     src->request = NULL;
@@ -575,7 +752,24 @@ gst_neonhttp_src_set_property (GObject * object, guint prop_id,
       }
     }
       break;
+    case PROP_USER_AGENT:
+    {
+      if (this->user_agent) {
+        g_free (this->user_agent);
+        this->user_agent = NULL;
+      }
+
+      if (g_value_get_string (value)) {
+        this->user_agent = g_strdup (g_value_get_string (value));
+      }
 
+      break;
+    }
+    case PROP_IRADIO_MODE:
+    {
+      this->iradio_mode = g_value_get_boolean (value);
+      break;
+    }
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -626,7 +820,23 @@ gst_neonhttp_src_get_property (GObject * object, guint prop_id,
       }
     }
       break;
-
+    case PROP_USER_AGENT:
+    {
+      g_value_set_string (value, neonhttpsrc->user_agent);
+      break;
+    }
+    case PROP_IRADIO_MODE:
+      g_value_set_boolean (value, neonhttpsrc->iradio_mode);
+      break;
+    case PROP_IRADIO_NAME:
+      g_value_set_string (value, neonhttpsrc->iradio_name);
+      break;
+    case PROP_IRADIO_GENRE:
+      g_value_set_string (value, neonhttpsrc->iradio_genre);
+      break;
+    case PROP_IRADIO_URL:
+      g_value_set_string (value, neonhttpsrc->iradio_url);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index ce749cc..4f20e0e 100644 (file)
@@ -55,6 +55,7 @@ struct _GstNeonhttpSrc {
   ne_uri uri;
   gchar *uristr;
   ne_uri proxy;
+  gchar *user_agent;
 
   gboolean ishttps;
 
@@ -64,6 +65,13 @@ struct _GstNeonhttpSrc {
 
   gboolean eos;
 
+  /* icecast/audiocast metadata extraction handling */
+  gboolean iradio_mode;
+  gchar *iradio_name;
+  gchar *iradio_genre;
+  gchar *iradio_url;
+  GstCaps *icy_caps;
+  gint icy_metaint;
 };
 
 struct _GstNeonhttpSrcClass {
index 9800060..3c4399f 100644 (file)
@@ -84,7 +84,7 @@ BSC32=bscmake.exe
 # ADD BSC32 /nologo
 LINK32=link.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 ws2_32.lib libneon.lib libgstreamer-0.10.lib libgstbase-0.10.lib glib-2.0D.lib gobject-2.0D.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../gstreamer/win32/vs6/debug" /libpath:"../../../gst-plugins-base/win32/vs6/debug" /libpath:"./debug"
+# ADD LINK32 ws2_32.lib libneonD.lib libgstreamer-0.10.lib libgstbase-0.10.lib glib-2.0D.lib gobject-2.0D.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../gstreamer/win32/vs6/debug" /libpath:"../../../gst-plugins-base/win32/vs6/debug" /libpath:"./debug"
 # Begin Special Build Tool
 TargetPath=.\Debug\libgstneon.dll
 SOURCE="$(InputPath)"