summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMario Torre <neugens@limasoftware.net>2007-09-27 19:22:01 +0000
committerMario Torre <neugens@limasoftware.net>2007-09-27 19:22:01 +0000
commit91c61c786867c976411b86646f5a87244c0d1137 (patch)
tree812cf5e724aac2d805fa588e50a6dd7ad2e8165c
parent03111edb686175e342c6275b7ac60732e16b03f5 (diff)
downloadclasspath-91c61c786867c976411b86646f5a87244c0d1137.tar.gz
2007-09-27 Mario Torre <neugens@limasoftware.net>
* 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.
-rw-r--r--ChangeLog75
-rw-r--r--gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java6
-rw-r--r--gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java187
-rw-r--r--gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java6
-rw-r--r--include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h11
-rw-r--r--native/jni/gstreamer-peer/gst_native_data_line.c34
-rw-r--r--native/jni/gstreamer-peer/gst_native_pipeline.c285
-rw-r--r--native/jni/gstreamer-peer/gst_native_pipeline.h4
-rw-r--r--native/jni/gstreamer-peer/gst_peer.h9
-rw-r--r--native/jni/gstreamer-peer/gstreamer_io_peer.c6
10 files changed, 529 insertions, 94 deletions
diff --git a/ChangeLog b/ChangeLog
index ecb4c5e12..b09f24abc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,78 @@
+2007-09-27 Mario Torre <neugens@limasoftware.net>
+
+ * 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.
+
2007-09-27 Dalibor Topic <robilad@kaffe.org>
* native/fdlibm/dtoa.c: Include mprec.h after system includes.
diff --git a/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java b/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java
index 3ac17f1f7..761720fee 100644
--- a/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java
+++ b/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java
@@ -259,9 +259,6 @@ final class GstAudioFileReaderNativePeer
/**
* 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 @@ final class GstAudioFileReaderNativePeer
/**
* Retrieve header information about the file being played.
- *
- * @param info
- * @return
*/
native static final
protected boolean gstreamer_get_audio_format_file(GstHeader info);
diff --git a/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java b/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java
index caec48dc5..f561f71c2 100644
--- a/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java
+++ b/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java
@@ -39,44 +39,88 @@ package gnu.javax.sound.sampled.gstreamer.lines;
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 <neugens@limasoftware.net>
*/
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 @@ public class GstPipeline
* @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 @@ public class GstPipeline
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 @@ public class GstPipeline
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 @@ public class GstPipeline
* @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 class GstPipeline
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 @@ public class GstPipeline
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 @@ public class GstPipeline
}
/**
- * 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 @@ public class GstPipeline
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 @@ public class GstPipeline
/**
* 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 @@ public class GstPipeline
*/
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$
diff --git a/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java b/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java
index f7a0f0797..f149ab39d 100644
--- a/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java
+++ b/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java
@@ -108,19 +108,19 @@ public class GstSourceDataLine
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;
}
diff --git a/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h b/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h
index d5893a1f2..dbf13b0fd 100644
--- a/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h
+++ b/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h
@@ -12,8 +12,19 @@ extern "C"
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
}
diff --git a/native/jni/gstreamer-peer/gst_native_data_line.c b/native/jni/gstreamer-peer/gst_native_data_line.c
index bc44237b0..84e76a1dc 100644
--- a/native/jni/gstreamer-peer/gst_native_data_line.c
+++ b/native/jni/gstreamer-peer/gst_native_data_line.c
@@ -50,7 +50,7 @@ static jfieldID pointerDataFID = NULL;
/* ************************************************************************** */
-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 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine_setup_1sink_1pipe
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 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine_setup_1sink_1pipe
/* ************************************************************************** */
-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 @@ static GstElement *setup_pipeline (GstNativePipeline *jpipeline, char *file)
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 @@ static GstElement *setup_pipeline (GstNativePipeline *jpipeline, char *file)
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 @@ gst_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data)
/* 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 */
diff --git a/native/jni/gstreamer-peer/gst_native_pipeline.c b/native/jni/gstreamer-peer/gst_native_pipeline.c
index 9c5a3f0dd..3e3256897 100644
--- a/native/jni/gstreamer-peer/gst_native_pipeline.c
+++ b/native/jni/gstreamer-peer/gst_native_pipeline.c
@@ -41,6 +41,24 @@ exception statement from your version. */
#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 jmethodID pointerConstructorMID = NULL;
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 @@ enum
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 @@ struct _GstNativePipelinePrivate
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 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1id_1cache
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 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1instance
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 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1instance
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 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_set_1state
{
cpio_removeFile (jpipeline->priv->name);
g_free (jpipeline->priv->name);
+ jpipeline->priv->name = NULL;
}
#endif /* WITHOUT_FILESYSTEM */
@@ -230,6 +281,45 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_set_1state
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 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_create_1named_1pipe
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 @@ Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_create_1named_1pipe
}
(*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 @@ void gst_native_pipeline_clean (GstNativePipeline *self)
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 @@ char *gst_native_pipeline_get_pipeline_name (GstNativePipeline *self)
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 @@ static void init_pointer_IDs (JNIEnv* env)
#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);
+}
diff --git a/native/jni/gstreamer-peer/gst_native_pipeline.h b/native/jni/gstreamer-peer/gst_native_pipeline.h
index 4e7f516a3..b5a45b40a 100644
--- a/native/jni/gstreamer-peer/gst_native_pipeline.h
+++ b/native/jni/gstreamer-peer/gst_native_pipeline.h
@@ -51,8 +51,6 @@ struct _GstNativePipeline
GstNativePipelinePrivate *priv;
};
-void gst_native_pipeline_clean (GstNativePipeline *self);
-
void gst_native_pipeline_set_pipeline (GstNativePipeline *self,
GstElement *pipeline);
@@ -60,4 +58,6 @@ GstElement *gst_native_pipeline_get_pipeline (GstNativePipeline *self);
char *gst_native_pipeline_get_pipeline_name (GstNativePipeline *self);
+int gst_native_pipeline_get_pipeline_fd (GstNativePipeline *self);
+
#endif /* __GST_NATIVE_PIPELINE_H__ */
diff --git a/native/jni/gstreamer-peer/gst_peer.h b/native/jni/gstreamer-peer/gst_peer.h
index 666725419..4500001b0 100644
--- a/native/jni/gstreamer-peer/gst_peer.h
+++ b/native/jni/gstreamer-peer/gst_peer.h
@@ -38,6 +38,15 @@ exception statement from your version. */
#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.
*/
diff --git a/native/jni/gstreamer-peer/gstreamer_io_peer.c b/native/jni/gstreamer-peer/gstreamer_io_peer.c
index b3b0d0aa4..7e38b91f8 100644
--- a/native/jni/gstreamer-peer/gstreamer_io_peer.c
+++ b/native/jni/gstreamer-peer/gstreamer_io_peer.c
@@ -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 @@ static jboolean process_audio (GstElement *source, JNIEnv *env, jobject header)
/* free stuff */
gst_element_set_state (pipeline, GST_STATE_NULL);
-
+
free_properties (properties);
gst_object_unref (GST_OBJECT (pipeline));
-
+
return result;
}