diff options
-rw-r--r-- | ChangeLog | 75 | ||||
-rw-r--r-- | gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java | 6 | ||||
-rw-r--r-- | gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java | 187 | ||||
-rw-r--r-- | gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java | 6 | ||||
-rw-r--r-- | include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h | 11 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gst_native_data_line.c | 34 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gst_native_pipeline.c | 285 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gst_native_pipeline.h | 4 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gst_peer.h | 9 | ||||
-rw-r--r-- | native/jni/gstreamer-peer/gstreamer_io_peer.c | 6 |
10 files changed, 529 insertions, 94 deletions
@@ -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; } |