The changelog is long, but this time the patch is not huge as always :)
Few fixlets and some addition to the GStreamer peer. The next thing to
do is to implement the still missing event handling.

The peers are still not enabled by default, but if you help me test them
this would be great.

I'm committing.
Mario

2007-09-27  Mario Torre  <[EMAIL PROTECTED]>

        *
gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java:
        (gstreamer_get_audio_format_stream): Removed parameter from javadoc.
        (gstreamer_get_audio_format_file): likewise.
        * gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java:
        Added class javadoc and implementation notes.
        (READ): new constant.
        (WRITE): likewise.
        (QUEUED): likewise.
        (CAPACITY_KEY): likewise.
        (lock): likewise.
        (prefs): new variable.
        (GstPipeline constructor): added OS independent rutines to detect
        filesystem pipes size plus save and restores this information via
        preferences. Now closes open pipe on user abort at VM exit.
        (open_native_pipe): new native method.
        (close_native_pipe): likewise.
        (detect_pipe_size): likewise.
        (createForWrite): update to use new native methods.
        (setState): removed hack to synchronize reading and writing of the
        filesystme named pipe.
        (available): implemented.
        (drain): new implementation, now correctly waits for data to be
consumed
        in the pipeline.
        (prepareWrite): removed hack to synchronize reading and writing of the
        filesystme named pipe.
        (CleanPipeline): new inner class, used for cleaning of native pipelines
        still opened at VM exit.
        * gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine:
        (getFramePosition): method still stubbed, now output "implement me"
        note when called (used for testing).
        (getLongFramePosition): likewise.
        (getMicrosecondPosition): likewise.
        * include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h:
        regenerated.
        * native/jni/gstreamer-peer/gst_native_data_line.c:
        (setup_pipeline): Changed signature, now uses a file descriptor instead
of
        char with the name of the native pipeline. Also changed to use "fdsrc"
        when creating the GStreamer pipeline.

(Java_gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine_setup_1sink_1pipeline):
        now uses gst_native_pipeline_get_pipeline_fd to get the file descriptor
        of the native pipeline, instead of
gst_native_pipeline_get_pipeline_name.
        Chaged to use "autoaudiosink" as GStreamer audio sink.
        (gst_newpad): fix indentation.
        * native/jni/gstreamer-peer/gst_native_pipeline.c: include new headers
for
        compilation.
        (capacityFID): new filed for caching.
        (GST_DETECTED_PIPE_CAPACITY): new field.
        (enum): maps READ and WRITE in GstPipeline class.
        (_GstNativePipelinePrivate.fd): new field.
        (create_name): new function.
        (init_pointer_IDs): likewise.
        (get_free_space): likewise.

(Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1id_1cache):
        cache capacityFID.

(Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1instance):
        get value for GST_DETECTED_PIPE_CAPACITY from mapped class.
        (Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_set_1state):
        removed "unused" attribute from parameters, clean pipeline name on
exit.

(Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_open_1native_1pipe):
        new function.

(Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_close_1native_1pipe):
        likewise.

(Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_create_1named_1pipe):
        pipe name created with a dedicated function.
        (Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_available):
new
        function.
        * native/jni/gstreamer-peer/gst_native_pipeline.h:
        (gst_native_pipeline_clean): removed.
        (gst_native_pipeline_get_pipeline_fd): new function.
        * native/jni/gstreamer-peer/gst_peer.h: new defines used by the peer.
        * native/jni/gstreamer-peer/gstreamer_io_peer.c: (_GST_MALLOC_SIZE_):
moved
        in gst_peer.h.
-- 
Lima Software - http://www.limasoftware.net/
GNU Classpath Developer - http://www.classpath.org/
Fedora Ambassador - http://fedoraproject.org/wiki/MarioTorre
Jabber: [EMAIL PROTECTED]
pgp key: http://subkeys.pgp.net/ PGP Key ID: 80F240CF
Fingerprint: BA39 9666 94EC 8B73 27FA  FC7C 4086 63E3 80F2 40CF

Please, support open standards:
http://opendocumentfellowship.org/petition/
http://www.nosoftwarepatents.com/
### Eclipse Workspace Patch 1.0
#P classpath
Index: native/jni/gstreamer-peer/gst_peer.h
===================================================================
RCS file: /sources/classpath/classpath/native/jni/gstreamer-peer/gst_peer.h,v
retrieving revision 1.1
diff -u -r1.1 gst_peer.h
--- native/jni/gstreamer-peer/gst_peer.h	18 Aug 2007 15:23:14 -0000	1.1
+++ native/jni/gstreamer-peer/gst_peer.h	27 Sep 2007 19:02:19 -0000
@@ -38,6 +38,15 @@
 #include <jni.h>
 #include "jcl.h"
 
+#ifdef MAXPATHLEN
+# define _GST_MALLOC_SIZE_ MAXPATHLEN
+#else
+# define _GST_MALLOC_SIZE_ 1024
+#endif
+
+#define _GST_PIPELINE_PREFIX_ "cp-"
+#define _GST_PIPELINE_SUFFIX_ "-classpath-gst-audio"
+
 /**
  * Return a reference to the object stored in this Pointer.
  */
Index: native/jni/gstreamer-peer/gst_native_pipeline.c
===================================================================
RCS file: /sources/classpath/classpath/native/jni/gstreamer-peer/gst_native_pipeline.c,v
retrieving revision 1.2
diff -u -r1.2 gst_native_pipeline.c
--- native/jni/gstreamer-peer/gst_native_pipeline.c	19 Aug 2007 16:11:14 -0000	1.2
+++ native/jni/gstreamer-peer/gst_native_pipeline.c	27 Sep 2007 19:02:19 -0000
@@ -41,6 +41,24 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <unistd.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif /* HAVE_FCNTL_H */
+
+#if defined(HAVE_SYS_IOCTL_H)
+#define BSD_COMP /* Get FIONREAD on Solaris2 */
+#include <sys/ioctl.h>
+#endif
+#if defined(HAVE_SYS_FILIO_H) /* Get FIONREAD on Solaris 2.5 */
+#include <sys/filio.h>
+#endif
+
 #include <gdk/gdk.h>
 #include <glib.h>
 
@@ -57,7 +75,20 @@
 static jfieldID pipelineFID = NULL;
 static jfieldID pointerDataFID = NULL;
 static jfieldID nameFID = NULL;
+static jfieldID capacityFID = NULL;
 
+/*
+ * Needed to compute the size of the data still available for processing in the
+ * pipeline. We give a default here but this will be overwritten by the
+ * detection routines.
+ */
+static long GST_DETECTED_PIPE_CAPACITY = 65536;
+
+/*
+ * Note: the Java code uses enum classes, these are not mapped into constants
+ * by the javah tool, changes to these values should be reflected in the Java
+ * side.
+ */
 enum
 {
   PLAY,
@@ -65,6 +96,15 @@
   STOP
 };
 
+/*
+ * Defined as constants in the Java code, hence mapped by javah.
+ */
+enum
+{
+  READ = gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_READ,
+  WRITE = gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_WRITE
+};
+
 struct _GstNativePipelinePrivate
 {
   JavaVM *vm;
@@ -72,13 +112,20 @@
   jclass PointerClass;
   
   jobject jni_pipeline;
+
   char *name;
+  int fd;
+ 
   GstElement *pipeline;
 };
 
 /* ************************************************************************** */
-
+/*
+static void gst_native_pipeline_clean (GstNativePipeline *self);*/
+static char *create_name (void);
 static void init_pointer_IDs (JNIEnv* env);
+static jint get_free_space (int fd);
+static void detect_pipe_max (void);
 
 /* ************************************************************************** */
 
@@ -91,8 +138,9 @@
   pipelineFID = (*env)->GetFieldID (env, clazz, "pipeline",
                                     "Lgnu/classpath/Pointer;");
   nameFID = (*env)->GetFieldID (env, clazz, "name", "Ljava/lang/String;");
+  capacityFID = (*env)->GetFieldID (env, clazz, "capacity", "J");
 
-  init_pointer_IDs(env);
+  init_pointer_IDs (env);
 }
 
 JNIEXPORT void JNICALL
@@ -138,6 +186,9 @@
       return;
     }
 
+  GST_DETECTED_PIPE_CAPACITY = (long) (*env)->GetLongField(env, pipeline,
+                                                           capacityFID);
+  
   /* fill the object */
   (*env)->GetJavaVM(env, &_pipeline->priv->vm);
   _pipeline->priv->jni_pipeline = (*env)->NewGlobalRef(env, pipeline);
@@ -173,8 +224,7 @@
 
 JNIEXPORT jboolean JNICALL
 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_set_1state
-  (JNIEnv *env, jclass clazz __attribute__ ((unused)), 
-   jobject pointer, jint state)
+  (JNIEnv *env, jclass clazz, jobject pointer, jint state)
 {
   GstNativePipeline *jpipeline = NULL;
   jboolean result = JNI_FALSE;
@@ -213,6 +263,7 @@
           {
             cpio_removeFile (jpipeline->priv->name);
             g_free (jpipeline->priv->name);
+            jpipeline->priv->name = NULL;
           }
 #endif /* WITHOUT_FILESYSTEM */
   
@@ -230,6 +281,45 @@
   return result;
 }
 
+JNIEXPORT void JNICALL
+Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_open_1native_1pipe
+  (JNIEnv *env, jclass clazz, jobject pointer, jint mode)
+{
+  GstNativePipeline *jpipeline = NULL;
+  
+  jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer,
+                                                             pointerDataFID);
+  switch (mode)
+    {
+      case (READ):
+        jpipeline->priv->fd =
+            open (jpipeline->priv->name, O_RDONLY | O_NONBLOCK);
+        break;
+      
+      case (WRITE):
+        /* TODO: no-op currently */
+        break;
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_close_1native_1pipe
+  (JNIEnv *env, jclass clazz, jobject pointer)
+{
+#ifndef WITHOUT_FILESYSTEM
+  GstNativePipeline *jpipeline = NULL;
+  jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer,
+                                                             pointerDataFID);
+  /* kill the named pipe */
+  if (jpipeline->priv->name)
+    {
+      cpio_removeFile (jpipeline->priv->name);
+      g_free (jpipeline->priv->name);
+      jpipeline->priv->name = NULL;
+    }
+#endif /* WITHOUT_FILESYSTEM */
+}
+
 JNIEXPORT jboolean JNICALL
 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_create_1named_1pipe
   (JNIEnv *env, jobject GstPipeline, jobject pointer)
@@ -247,10 +337,10 @@
   if (jpipeline == NULL)
     return JNI_FALSE;                                                        
   
-  jpipeline->priv->name = tempnam (NULL, "cpgst");
+  jpipeline->priv->name = create_name ();
   if (jpipeline->priv->name == NULL)
     return JNI_FALSE;
-    
+   
   if (mkfifo (jpipeline->priv->name, 0600) < 0)
     {
       if (jpipeline->priv->name != NULL)
@@ -270,18 +360,59 @@
     }
   
   (*env)->SetObjectField(env, GstPipeline, nameFID, name);
-  
+    
   return JNI_TRUE;
   
 #else /* not WITHOUT_FILESYSTEM */
   return JNI_FALSE;
 #endif /* not WITHOUT_FILESYSTEM */
+}
+
+JNIEXPORT jint JNICALL
+Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_available
+  (JNIEnv *env, jclass clazz, jobject pointer, jint mode)
+{
+  jint result = -1;
+ 
+#ifndef WITHOUT_FILESYSTEM
+  
+  GstNativePipeline *jpipeline = NULL;
+  jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer,
+                                                             pointerDataFID);
+                                                                                                         
+  if (mode == READ)
+    {
+      result = get_free_space (jpipeline->priv->fd);
+    }
+  else
+    {
+# if defined (FIONREAD)      
+      if (ioctl (jpipeline->priv->fd, FIONREAD, &result) == -1)
+        g_warning("IMPLEMENT ME: ioctl failed");
+        
+# else /* not defined (FIONREAD) */
+      g_warning("IMPLEMENT ME: !defined (FIONREAD");
+# endif /* defined (FIONREAD) */
+    
+    } /* if (mode == READ) */
+    
+#endif  /* not WITHOUT_FILESYSTEM */
 
+  return result;
 }
 
-/* exported library functions */
+JNIEXPORT jlong JNICALL
+Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_detect_1pipe_1size
+  (JNIEnv *env, jobject GstPipeline)
+{
+  detect_pipe_max ();
+  
+  return GST_DETECTED_PIPE_CAPACITY;
+}
 
-void gst_native_pipeline_clean (GstNativePipeline *self)
+/* exported library functions */
+/*
+static void gst_native_pipeline_clean (GstNativePipeline *self)
 {
   JNIEnv *env = NULL;
   
@@ -294,10 +425,17 @@
   if (self->priv->pipeline != NULL)
     gst_object_unref (GST_OBJECT (self->priv->pipeline));
   
+  if (self->priv->name)
+    {
+      cpio_removeFile (self->priv->name);
+      g_free (self->priv->name);
+      self->priv->name = NULL;
+    }
+    
   JCL_free (env, self->priv);
   JCL_free (env, self);
 }
-
+*/
 void gst_native_pipeline_set_pipeline (GstNativePipeline *self,
                                        GstElement *pipeline)
 {
@@ -317,6 +455,11 @@
   return self->priv->name;
 }
 
+int gst_native_pipeline_get_pipeline_fd (GstNativePipeline *self)
+{
+  return self->priv->fd;
+}
+
 /* private functions */
 
 static void init_pointer_IDs (JNIEnv* env)
@@ -346,3 +489,123 @@
 #endif /* SIZEOF_VOID_P == 8 */
 }
 
+static jint get_free_space (int fd)
+{
+  jint result = -1;
+  
+#if defined (FIONSPACE)
+
+  if (ioctl (fd, FIONSPACE, &result) == -1)
+    {
+      g_warning("IMPLEMENT ME: ioctl failed");
+    }
+    
+#elif defined (FIONREAD)
+
+  if (ioctl (fd, FIONREAD, &result) == -1)
+    {
+      g_warning("IMPLEMENT ME: ioctl failed");
+    }
+
+  result = GST_DETECTED_PIPE_CAPACITY - result;
+  
+#elif
+   g_warning("IMPLEMENT ME!!! - !defined (FIONSPACE), !defined (FIONREAD");
+ 
+#endif
+
+  return result;
+}
+
+static char *create_name (void)
+{
+  char *buffer = NULL;
+  char *tmp = NULL;
+  
+  buffer = (char *) g_malloc0 (_GST_MALLOC_SIZE_);
+  if (buffer == NULL)
+    {
+      /* huston, we have a problem... */
+      return NULL;
+    }
+    
+  tmp = tempnam (NULL, _GST_PIPELINE_PREFIX_);
+  if (tmp == NULL)
+    {
+      g_free (buffer);
+      return NULL;
+    }
+  
+  g_snprintf (buffer, _GST_MALLOC_SIZE_, "%s%s", tmp, _GST_PIPELINE_SUFFIX_);
+  g_free (tmp);
+  
+  return buffer;
+}
+
+static void detect_pipe_max (void)
+{
+  int read_fd;
+  int write_fd;
+  
+  /* can be anything! */
+  char *character = "a";
+  char *pipe = NULL;
+  
+  gboolean available = TRUE;
+  int w = 0;
+  long wrote = 0;
+  
+  pipe = create_name ();
+  if (pipe == NULL)
+    {
+      g_warning ("can't create test pipe name");
+      return;
+    }
+ 
+  if (mkfifo (pipe, 0600) < 0)
+    {
+      g_warning ("unable to create test pipe...");
+      g_free (pipe);
+      
+      return;
+    }
+ 
+  /* open both end of the pipe */
+  read_fd = open (pipe, O_RDONLY | O_NONBLOCK);
+  if (read_fd < 0)
+    {
+      cpio_removeFile (pipe);
+      g_free (pipe);
+      
+      return;
+    }
+    
+  write_fd = open (pipe, O_WRONLY | O_NONBLOCK);
+  if (write_fd < 0)
+    {
+      cpio_closeFile (write_fd);
+      cpio_removeFile (pipe);
+      g_free (pipe);
+      
+      return;
+    }
+
+  while (available)
+    {
+      w = 0;
+          
+      cpio_write (write_fd, character, 1, &w);
+      if (w < 0)
+        available = FALSE;
+      else
+        wrote += w;
+    }
+    
+  GST_DETECTED_PIPE_CAPACITY = wrote;
+    
+  cpio_closeFile (write_fd);    
+  cpio_closeFile (read_fd);
+  cpio_removeFile (pipe);
+      
+  g_free (pipe);  
+}
Index: native/jni/gstreamer-peer/gstreamer_io_peer.c
===================================================================
RCS file: /sources/classpath/classpath/native/jni/gstreamer-peer/gstreamer_io_peer.c,v
retrieving revision 1.1
diff -u -r1.1 gstreamer_io_peer.c
--- native/jni/gstreamer-peer/gstreamer_io_peer.c	18 Aug 2007 15:23:13 -0000	1.1
+++ native/jni/gstreamer-peer/gstreamer_io_peer.c	27 Sep 2007 19:02:19 -0000
@@ -57,8 +57,6 @@
 #include "gst_classpath_src.h"
 #include "gst_input_stream.h"
 
-#define _GST_MALLOC_SIZE_ 256
-
 /* for caching */
 static jfieldID fileFID = NULL;
 static jfieldID pointerDataID = NULL;
@@ -418,11 +416,11 @@
  
   /* free stuff */
   gst_element_set_state (pipeline, GST_STATE_NULL);
-
+   
   free_properties (properties);
   
   gst_object_unref (GST_OBJECT (pipeline));
-
+ 
   return result;
 }
 
Index: native/jni/gstreamer-peer/gst_native_data_line.c
===================================================================
RCS file: /sources/classpath/classpath/native/jni/gstreamer-peer/gst_native_data_line.c,v
retrieving revision 1.1
diff -u -r1.1 gst_native_data_line.c
--- native/jni/gstreamer-peer/gst_native_data_line.c	18 Aug 2007 15:23:13 -0000	1.1
+++ native/jni/gstreamer-peer/gst_native_data_line.c	27 Sep 2007 19:02:19 -0000
@@ -50,7 +50,7 @@
 
 /* ************************************************************************** */
 
-static GstElement *setup_pipeline (GstNativePipeline *jpipeline, char *file);
+static GstElement *setup_pipeline (GstNativePipeline *jpipeline, int fd);
 static void
 gst_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data);
 
@@ -106,13 +106,13 @@
     return JNI_FALSE;
  
   pipeline = setup_pipeline (jpipeline,
-                             gst_native_pipeline_get_pipeline_name (jpipeline));
+                             gst_native_pipeline_get_pipeline_fd (jpipeline));
   if (pipeline == NULL)
     return JNI_FALSE;
    
   /* add the audio sink to the pipeline */
   /* TODO: hardcoded values */
-  sink = gst_element_factory_make ("alsasink", "alsa-output");
+  sink = gst_element_factory_make ("autoaudiosink", "alsa-output");
   if (sink == NULL)
     {
       gst_object_unref(GST_OBJECT(pipeline));
@@ -176,14 +176,14 @@
 
 /* ************************************************************************** */
 
-static GstElement *setup_pipeline (GstNativePipeline *jpipeline, char *file)
+static GstElement *setup_pipeline (GstNativePipeline *jpipeline, int fd)
 {
   GstElement *decodebin = NULL;
   GstElement *source = NULL;
   
   GstElement *pipeline = NULL;
   
-  if (file == NULL)
+  if (fd < 0)
     return NULL;
   
   pipeline = gst_pipeline_new ("java sound pipeline");
@@ -200,7 +200,7 @@
       return NULL;
     }
     
-  source = gst_element_factory_make ("filesrc", "source");
+  source = gst_element_factory_make ("fdsrc", "source");
   if (source == NULL)
     {
       gst_object_unref(GST_OBJECT(pipeline));
@@ -210,7 +210,7 @@
       g_warning ("unable to create a source");
       return JNI_FALSE;
     }
-  g_object_set (G_OBJECT (source), "location", file, NULL);
+  g_object_set (G_OBJECT (source), "fd", fd, NULL);
   
   gst_bin_add_many (GST_BIN (pipeline), source, decodebin, NULL);
   gst_element_link (source, decodebin);
@@ -229,19 +229,21 @@
 
   /* only link once */
   audiopad = gst_element_get_pad (audio, "sink");
-  if (GST_PAD_IS_LINKED (audiopad)) {
-    g_object_unref (audiopad);
-    return;
-  } 
+  if (GST_PAD_IS_LINKED (audiopad))
+    {
+      g_object_unref (audiopad);
+      return;
+    } 
   
   /* check media type */
   caps = gst_pad_get_caps (pad);
   str = gst_caps_get_structure (caps, 0);
-  if (!g_strrstr (gst_structure_get_name (str), "audio")) {
-    gst_caps_unref (caps);
-    gst_object_unref (audiopad);
-    return;
-  } 
+  if (!g_strrstr (gst_structure_get_name (str), "audio"))
+    {
+      gst_caps_unref (caps);
+      gst_object_unref (audiopad);
+      return;
+    } 
   gst_caps_unref (caps);
   
   /* link'n'play */
Index: native/jni/gstreamer-peer/gst_native_pipeline.h
===================================================================
RCS file: /sources/classpath/classpath/native/jni/gstreamer-peer/gst_native_pipeline.h,v
retrieving revision 1.1
diff -u -r1.1 gst_native_pipeline.h
--- native/jni/gstreamer-peer/gst_native_pipeline.h	18 Aug 2007 15:23:14 -0000	1.1
+++ native/jni/gstreamer-peer/gst_native_pipeline.h	27 Sep 2007 19:02:19 -0000
@@ -51,8 +51,6 @@
   GstNativePipelinePrivate *priv;
 };
 
-void gst_native_pipeline_clean (GstNativePipeline *self);
-
 void gst_native_pipeline_set_pipeline (GstNativePipeline *self,
                                        GstElement *pipeline);
 
@@ -60,4 +58,6 @@
 
 char *gst_native_pipeline_get_pipeline_name (GstNativePipeline *self);
 
+int gst_native_pipeline_get_pipeline_fd (GstNativePipeline *self);
+
 #endif /* __GST_NATIVE_PIPELINE_H__ */
Index: include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h
===================================================================
RCS file: /sources/classpath/classpath/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h,v
retrieving revision 1.1
diff -u -r1.1 gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h
--- include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h	18 Aug 2007 15:23:13 -0000	1.1
+++ include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h	27 Sep 2007 19:02:18 -0000
@@ -12,8 +12,19 @@
 
 JNIEXPORT void JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1id_1cache (JNIEnv *env, jclass);
 JNIEXPORT jboolean JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_set_1state (JNIEnv *env, jclass, jobject, jint);
+JNIEXPORT jint JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_available (JNIEnv *env, jclass, jobject, jint);
+JNIEXPORT void JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_open_1native_1pipe (JNIEnv *env, jclass, jobject, jint);
+JNIEXPORT void JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_close_1native_1pipe (JNIEnv *env, jclass, jobject);
 JNIEXPORT void JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1instance (JNIEnv *env, jobject);
 JNIEXPORT jboolean JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_create_1named_1pipe (JNIEnv *env, jobject, jobject);
+JNIEXPORT jlong JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_detect_1pipe_1size (JNIEnv *env, jobject);
+
+#undef gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_READ
+#define gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_READ 0L
+#undef gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_WRITE
+#define gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_WRITE 1L
+#undef gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_QUEUED
+#define gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_QUEUED 1L
 
 #ifdef __cplusplus
 }
Index: gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java,v
retrieving revision 1.3
diff -u -r1.3 GstAudioFileReaderNativePeer.java
--- gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java	19 Aug 2007 19:08:12 -0000	1.3
+++ gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java	27 Sep 2007 19:02:16 -0000
@@ -259,9 +259,6 @@
   
   /**
    * Retrieve header information about the stream being played.
-   * 
-   * @param info
-   * @return
    */
   native static final
   protected boolean gstreamer_get_audio_format_stream(GstHeader info,
@@ -269,9 +266,6 @@
   
   /**
    * Retrieve header information about the file being played.
-   * 
-   * @param info
-   * @return
    */
   native static final
   protected boolean gstreamer_get_audio_format_file(GstHeader info);
Index: gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java,v
retrieving revision 1.2
diff -u -r1.2 GstPipeline.java
--- gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java	18 Aug 2007 15:23:15 -0000	1.2
+++ gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java	27 Sep 2007 19:02:17 -0000
@@ -39,44 +39,88 @@
 
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.prefs.Preferences;
 
 import javax.sound.sampled.LineUnavailableException;
 
 import gnu.classpath.Pointer;
 
 /**
+ * This class represent a GStreamer pipeline and is resposible to handle the
+ * flow of data to and from the GStreamer native backend.
  * 
  * @author Mario Torre <[EMAIL PROTECTED]>
  */
 public class GstPipeline
 {
+  /*
+   * Implementation note:
+   * This class is at first a bit confusing as it serves as a gateway
+   * to a real filesystem named pipe.
+   * The pipelines is shared by the gstreamer backend and by the java code.
+   * If the operation we are performing is to play a given stream of bytes,
+   * we need to open the java side of the pipeline for writing, which is done
+   * in the prepareWrite method. At the same time, the native side of the code
+   * need to open the pipeline in read mode, to get access to the data,
+   * and hence, act as a source element. This is why you will see terms
+   * like "read" or "source" in methods that are used to write in the pipeline,
+   * in other words, each the native operation is the opposite of the java
+   * side operation.
+   * Opening the pipe to record audio data from the sound card works the same
+   * except that all the operation are inverted.
+   */
+  
+  // These enums are used in the native code also, changes here must reflect
+  // changes in the native code.
   public static enum State
   {
     PLAY, PAUSE, STOP, CLOSE
   }
   
+  private static final int READ = 0;
+  private static final int WRITE = 1;
+  private static final int QUEUED = 1;
+  
+  private static final String CAPACITY_KEY = "Capacity"; 
+  
+  private static final Object [] lock = new Object[0];
+  
+  /*
+   * Preference subsystem. We use this to store some system specific settings.
+   */
+  protected Preferences prefs =
+    Preferences.userNodeForPackage(GstPipeline.class).node("GStreamer");
+  
+  // used by the native code, stores the size of the named pipeline
+  // created by the operating system.
+  private long capacity = -1;
+  
   /** Represents the playing state of this Line. */
-  protected State state = State.STOP;
+  private State state = State.STOP;
   
-  /** The name of the named pipe */
-  // will be setup and filled in the native code. See the native library
-  // for details
-  protected String name = null;
+  /** The name of the named pipe. */
+  // Will be setup and filled in the native code. See the native library
+  // for details.
+  private String name = null;
   
-  // TODO use nio?
-  protected FileOutputStream output = null;
+  /** This is the named pipe that will be read by the gstreamer backend. */
+  private FileOutputStream output = null;
   
-  protected boolean source = true;
+  /**
+   * Defines if we are getting data from a sink pipe
+   * or writing to a source pipe.
+   */
+  private boolean source = true;
   
-  protected boolean ready = false;
+  /** Indicate that we are ready to process audio data to/from the pipe. */
+  private boolean ready = false;
   
   /**
    * This is the native GStreamer Pipeline.
    */
   // This field is used by the native code, so any change to it must be
-  // followed by similar changes in the native peer;
-  // package private because it is actually used by lines.
-  protected Pointer pipeline = null;
+  // followed by similar changes in the native peer.
+  private Pointer pipeline = null;
 
   /**
    * Creates a new GstPipeline with a capacity of
@@ -94,13 +138,34 @@
    * @see GstDataLine#DEFAULT_BUFFER_SIZE
    */
   public GstPipeline(int bufferSize)
-  {
-    // bufferSize not needed    
+  { 
+    // see if we need to detect the size of the named pipe or we can use
+    // an already computet default for this system.
+    // Note that this is very different from the bufferSize parameter,
+    // see below.
+    capacity = prefs.getLong(CAPACITY_KEY, -1);
+    if (capacity == -1)
+      {
+        synchronized (lock)
+          {
+            capacity = detect_pipe_size();
+          }
+        
+        prefs.putLong(CAPACITY_KEY, capacity);
+      }
+    
+    // FIXME: bufferSize actually not used nor needed by the backend.
+    // Applications that expects a buffer of different size will be a
+    // bit disappointed by that..
     init_instance();
+    
+    // need to remove the named pipe in case of abnormal termination
+    Runtime.getRuntime().addShutdownHook(new CleanPipeline());
   }
   
   /**
-   * 
+   * Creates a source pipeline. A source pipeline is a pipe you send data for
+   * processing using the write method.
    */
   public void createForWrite() throws LineUnavailableException
   { 
@@ -108,6 +173,7 @@
     if (!create_named_pipe(this.pipeline))
       throw new LineUnavailableException("Unable to create filesystem pipe");
    
+    open_native_pipe(this.pipeline, READ);
     prepareWrite();
     
     this.source = true;
@@ -151,20 +217,7 @@
           closePipe();
           break;
       }
-    
-    // FIXME: bad hack, this pipeline needs to be started by the same thread
-    // that opens the gstreamer side of the pipe, but need to ensure that
-    // the writing side has been opened too. Waiting half second seem to be fine
-    // for now. The native code needs a little refactoring to fix that.
-    try
-      {
-        Thread.sleep(500);
-      }
-    catch (InterruptedException e)
-      {
-        /* nothing to do*/
-      }
-      
+
     if (set_state(pipeline, _state))
       GstPipeline.this.state = state;
   }
@@ -192,7 +245,7 @@
    * @return
    */
   public int write(byte[] buffer, int offset, int length)
-  {
+  { 
     if (this.state == State.STOP)
       return -1;
     else if (this.state == State.PAUSE)
@@ -224,8 +277,10 @@
   
   public int available()
   {
-    /* FIXME: not supported yet */
-    return -1;
+    if (this.source)
+      return available(this.pipeline, READ);
+    else
+      return available(this.pipeline, WRITE);
   }
   
   /**
@@ -236,10 +291,14 @@
     if (this.state == State.STOP)
       return;
     
-    // TODO: ask the native layer if it has finished reading
     try
       {
-        Thread.sleep(8000);
+        // wait untill there is anymore data in the pipe
+        while (available(this.pipeline, QUEUED) > 0)
+          Thread.sleep(3000);
+        
+        // plus a bit to allow data to be processed
+        Thread.sleep(1000);
       }
     catch (InterruptedException e)
       {
@@ -248,7 +307,7 @@
   }
   
   /**
-   * Flush all the data currently waiting in the queue.
+   * Flush all the data currently waiting to be processed.
    */
   public void flush()
   {
@@ -279,24 +338,18 @@
   
   private void prepareWrite()
   {
-    new Thread ()
-    {  
-      public void run ()
+    try
       {
-        try
-          {
-            // if this is not completed for some reason, we will catch
-            // in the write method. As this call can block, we assume we will
-            // succed and that the dataline can get data.
-            GstPipeline.this.ready = true;
-            GstPipeline.this.output = new FileOutputStream(name);
-          }
-        catch (Exception e)
-          {
-            GstPipeline.this.ready = false;
-          }
+        // if this is not completed for some reason, we will catch
+        // in the write method. As this call can block, we assume we will
+        // succeed and that the dataline can get data.
+        GstPipeline.this.ready = true;
+        GstPipeline.this.output = new FileOutputStream(name);
+      }
+    catch (Exception e)
+      {
+        GstPipeline.this.ready = false;
       }
-    }.start();
   }
   
   /* ***** native ***** */
@@ -310,7 +363,24 @@
   /**
    * Set the playing state of this pipeline.
    */
-  native private static final boolean set_state(Pointer jpipeline, int state);
+  native private static final boolean set_state(Pointer pipeline, int state);
+  
+  /**
+   * Get the number of bytes currently available for reading or writing
+   * from the pipeline.
+   */
+  native private static final int available(Pointer pipeline, int mode);
+  
+  /**
+   * Open the native pipeline with the given mode.
+   */
+  native private static final void open_native_pipe(Pointer jpipeline,
+                                                    int mode);
+  
+  /**
+   * Close the native pipeline.
+   */
+  native private static final void close_native_pipe(Pointer jpipeline);
   
   /**
    * Initialize the native peer and enables the object cache.
@@ -324,6 +394,19 @@
    */
   native private final boolean create_named_pipe(Pointer jpipeline);
   
+  /**
+   * Detect and return the size of the filesystem named pipe.
+   */
+  native private final long detect_pipe_size();
+  
+  private class CleanPipeline extends Thread
+  {
+    public void run()
+    {
+      GstPipeline.close_native_pipe(GstPipeline.this.pipeline);
+    }
+  }
+  
   static
   {
     System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$
Index: gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java,v
retrieving revision 1.2
diff -u -r1.2 GstSourceDataLine.java
--- gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java	18 Aug 2007 15:23:15 -0000	1.2
+++ gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java	27 Sep 2007 19:02:18 -0000
@@ -108,19 +108,19 @@
 
   public int getFramePosition()
   {
-    // TODO Auto-generated method stub
+    System.out.println("getFramePosition -: IMPLEMENT ME!!");
     return 0;
   }
 
   public long getLongFramePosition()
   {
-    // TODO Auto-generated method stub
+    System.out.println("getLongFramePosition -: IMPLEMENT ME!!");
     return 0;
   }
 
   public long getMicrosecondPosition()
   {
-    // TODO Auto-generated method stub
+    System.out.println("getMicrosecondPosition -: IMPLEMENT ME!!");
     return 0;
   }
 

Reply via email to