diff options
28 files changed, 2342 insertions, 890 deletions
@@ -1,3 +1,94 @@ +2007-08-18 Mario Torre <neugens@limasoftware.net> + + * examples/gnu/classpath/examples/sound/AudioPlayerSample.java: new file. + * gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java: removed + unused import. + * gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java: likewise. + * gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java: + (gstreamer_get_audio_format_stream): changed signature tu accept a Pointer + object instead of a BufferedInputStream. + (GstHeader): + (getAudioFormat(InputStream, GstHeader)): new private method. + (getAudioFormat(public)): refactored to use the private getAudioFormat + with shared functionality. + (getAudioFormat(GstHeader header)): removed a redundant check. + (init_id_cache): new native method. + * gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java: new file. + * gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java: + (GstDataLine.State): removed enum. + (state): removed local variable. + (isRunning): removed method. + (open): likewise. + (setFormat): new methods. + (setOpen): likewise. + (setBufferSize): likewise. + * gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java: + (createSourcePipeline): new method. + (setup_sink_pipeline): likewise. + (init_id_cache): likewise. Added to the static initializer. + * gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java: + (GstPipeline.State): new enum. + (state): new local variable. + (name): likewise. + (output): likewise. + (source): likewise. + (ready): likewise. + (getState): new method. + (closePipe): likewise. + (create_named_pipe): likewise. + (set_state): likewise. + (available): likewise. + (drain): likewise. + (GstPipeline): likewise. + (close): likewise. + (prepareWrite): likewise. + (flush): likewise. + (write): likewise. + (init_instance): likewise. + (read): likewise. + (createForWrite): likewise. + (setState): likewise. + (getNativeClass): likewise. + (init_id_cache): likewise. + * gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java: + (pipeline): new local variable. + (opne): likewise. + (isActive): method implemented. + (stop): likewise. + (open): likewise. + (flush): likewise. + (isRunning): likewise. + (start): likewise. + (write): likewise. + (available): likewise. + (drain): likewise. + (close): likewise. + * include/Makefile.am: added entry to generate new header file. + * include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h: + regenerated. + * include/gnu_javax_sound_sampled_gstreamer_io_GstInputStream.h: likewise. + * include/gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine.h: + likewise. + * include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h: + likewise. + * native/jni/gstreamer-peer/gstclasspathsrc.c: removed. + * native/jni/gstreamer-peer/gstinputstream.c: likewise. + * native/jni/gstreamer-peer/GStreamerIOPeer.c: likewise. + * native/jni/gstreamer-peer/gstinputstream.h: likewise. + * native/jni/gstreamer-peer/gstclasspathsrc.h: likewise. + * native/jni/gstreamer-peer/Makefile.am: new file added for compilation. + code reformat to keep the 80 columns constraint. + * native/jni/gstreamer-peer/gst_native_pipeline.h: new file. + * native/jni/gstreamer-peer/gst_input_stream.c: likewise. + * native/jni/gstreamer-peer/gst_input_stream.h: likewise. + * native/jni/gstreamer-peer/gst_classpath_src.c: likewise. + * native/jni/gstreamer-peer/gst_native_pipeline.c: likewise. + * native/jni/gstreamer-peer/gst_native_data_line.c: likewise. + * native/jni/gstreamer-peer/gst_classpath_src.h: likewise. + * native/jni/gstreamer-peer/gstreamer_io_peer.c: likewise. + * native/jni/gstreamer-peer/gst_peer.c: likewise. + * native/jni/gstreamer-peer/gst_peer.h: likewise. + 2007-08-16 Andrew John Hughes <gnu_andrew@member.fsf.org> * NEWS: Update with info on VM changes. diff --git a/examples/gnu/classpath/examples/sound/AudioPlayerSample.java b/examples/gnu/classpath/examples/sound/AudioPlayerSample.java new file mode 100644 index 000000000..5c44c9a10 --- /dev/null +++ b/examples/gnu/classpath/examples/sound/AudioPlayerSample.java @@ -0,0 +1,222 @@ +/* AudioPlayerSample.java -- Simple Java Audio Player + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.classpath.examples.sound; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.UnsupportedAudioFileException; + +/** + * A simple demo to show the use of the Java Sound API. + * It plays the given file (up to the end, so don't pass the 26 minutes long + * Pink Floyd's Echoes unless you really want!!). + * + * See: http://jsresources.org/examples/SimpleAudioPlayer.java.html + * + * @author Mario Torre <neugens@limasoftware.net> + */ +public class AudioPlayerSample +{ + private static final int EXTERNAL_BUFFER_SIZE = 128000; + + /** + * @param args + */ + public static void main(String[] args) + { + if (args.length < 1) + { + System.out.println("Radio Classpath -: Usage: " + + "AudioPlayerSample [file]"); + return; + } + + String file = args[0]; + + System.out.println("Welcome to Radio Classpath, only great music for you!"); + System.out.println("Today's DJ Tap The WaterDroplet"); + + // now create the AudioInputStream + AudioInputStream audioInputStream = null; + try + { + audioInputStream = AudioSystem.getAudioInputStream(new File(file)); + } + catch (UnsupportedAudioFileException e) + { + // This happen when the subsystem is unable to parse the kind of + // audio file we are submitting + // See the README for supported audio file types under Classpath + // for the version you are using. + e.printStackTrace(); + return; + } + catch (IOException e) + { + e.printStackTrace(); + return; + } + + // get informations about the kind of file we are about to play + AudioFormat audioFormat = audioInputStream.getFormat(); + + System.out.println("Playing file: " + file); + System.out.println("format: " + audioFormat.toString()); + + System.out.print("Additional properties: "); + + // now, we try to get all the properties we have in this AudioFormat + // and display them + Map<String, Object> properties = audioFormat.properties(); + if (properties.size() < 0) + { + System.out.println("none"); + } + else + { + System.out.println("found #" + properties.size() + " properties"); + for (String key : properties.keySet()) + { + System.out.println(key + ": " + properties.get(key)); + } + } + + // let's setup things for playing + // first, we require a Line. As we are doing playing, we will ask for a + // SourceDataLine + SourceDataLine line = null; + + // To get the source line, we first need to build an Info object + // this is done in one line: + DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat); + + System.out.println("searching line..."); + + // usually, if a backend can parse a file type, it can also + // create a line to handle it, but that's not guaranteed + // so we need to take care and to handle a possible + // LineUnavailableException + try + { + line = (SourceDataLine) AudioSystem.getLine(info); + + System.out.println("line found, opening..."); + + // once created, a line must be opened to let data flow + // though it. + line.open(audioFormat); + } + catch (LineUnavailableException e) + { + // in a real application you should signal that in a kindly way to + // your users + e.printStackTrace(); + return; + } + catch (Exception e) + { + e.printStackTrace(); + return; + } + + // an open line pass data to the backend only when it is in + // a state called "started" ("playing" or "play" in some other + // framework) + System.out.print("starting line... "); + + line.start(); + System.out.println("done"); + + // now we can start reading data from the AudioStream and writing + // data to the pipeline. The Java Sound API is rather low level + // so let you pass up to one byte of data at a time + // (with some constraints, refer to the API documentation to know more) + // We will do some buffering. You may want to check the frame size + // to allow a better buffering, also. + + System.out.println("now playing..."); + + int nBytesRead = 0; + byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; + while (nBytesRead != - 1) + { + try + { + nBytesRead = audioInputStream.read(abData, 0, abData.length); + } + catch (IOException e) + { + e.printStackTrace(); + } + + if (nBytesRead >= 0) + { + // this method returns the number of bytes actuall written + // to the line. You may want to use this number to check + // for events, display the current position (give also a + // look to the API for other ways of doing that) etc.. + line.write(abData, 0, nBytesRead); + } + } + + System.out.print("stream finished, draining line... "); + + // call this method to ensure that all the data in the internal buffer + // reach the audio backend, otherwise your application will + // cut the last frames of audio data (and users will not enjoy the last + // seconds of their precious music) + line.drain(); + + // Once done, we can close the line. Note that a line, once closed + // may not be reopened (depends on the backend, in some cases a "reopen", + // if allowed, really opens a new line, reallocating all the resources) + + System.out.println("line drained, now exiting"); + line.close(); + + System.out.println("We hope you enjoyed Radio Classpath!"); + } + +} diff --git a/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java b/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java index b32db0f35..27a8378e8 100644 --- a/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java +++ b/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java @@ -37,8 +37,6 @@ exception statement from your version. */ package gnu.javax.sound.sampled.gstreamer; -import java.awt.AWTPermission; - import gnu.javax.sound.sampled.gstreamer.lines.GstSourceDataLine; import javax.sound.sampled.AudioFormat; @@ -106,7 +104,7 @@ public class GStreamerMixer /** Mixer Info */ private static final Mixer.Info INFO = new GStreamerMixer.GstInfo(); - + public Line getLine(Line.Info info) throws LineUnavailableException { diff --git a/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java b/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java index 53b2155d8..de872016e 100644 --- a/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java +++ b/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java @@ -59,7 +59,7 @@ import javax.sound.sampled.spi.AudioFileReader; */ public class GstAudioFileReader extends AudioFileReader -{ +{ @Override public AudioFileFormat getAudioFileFormat(File file) throws UnsupportedAudioFileException, IOException diff --git a/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java b/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java index 45ae4ff85..bf40c7da0 100644 --- a/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java +++ b/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.javax.sound.sampled.gstreamer.io; +import gnu.classpath.Pointer; import gnu.javax.sound.sampled.gstreamer.GStreamerMixer; import java.io.BufferedInputStream; @@ -90,8 +91,11 @@ final class GstAudioFileReaderNativePeer public String isSigned = null; public String layer = null; + public String bitrate = null; + public String framed = null; + public String type = null; } @@ -108,18 +112,7 @@ final class GstAudioFileReaderNativePeer public static AudioFormat getAudioFormat(InputStream is) throws Exception { - GstHeader header = new GstHeader(); - - BufferedInputStream stream = new BufferedInputStream(is); - if(!stream.markSupported()) - throw new IOException("Stream must support marking."); - - stream.mark(0); - - if (!gstreamer_get_audio_format_stream(header, stream)) - return null; - - return getAudioFormat(header); + return getAudioFormat(is, new GstHeader()); } public static AudioFormat getAudioFormat(URL url) throws Exception @@ -127,13 +120,20 @@ final class GstAudioFileReaderNativePeer GstHeader header = new GstHeader(); header.file = url.toExternalForm(); - BufferedInputStream stream = new BufferedInputStream(url.openStream()); + return getAudioFormat(url.openStream(), header); + } + + private static AudioFormat getAudioFormat(InputStream is, GstHeader header) + throws Exception + { + BufferedInputStream stream = new BufferedInputStream(is); if(!stream.markSupported()) throw new IOException("Stream must support marking."); stream.mark(0); - if (!gstreamer_get_audio_format_stream(header, stream)) + if (!gstreamer_get_audio_format_stream(header, new GstInputStream(stream). + getNativeClass())) return null; return getAudioFormat(header); @@ -206,8 +206,7 @@ final class GstAudioFileReaderNativePeer // FIXME: frameRate = sampleRate in these cases under all the tests so far // but I'm not sure if this is always correct... - if (lowerCase.contains("law") || lowerCase.contains("au") || - lowerCase.contains("x-au")) + if (lowerCase.contains("law") || lowerCase.contains("au")) { frameSize = (sampleSizeInBits >> 3) * channels; frameRate = sampleRate; @@ -251,14 +250,14 @@ final class GstAudioFileReaderNativePeer /* ***** native methods ***** */ /** - * Retrieve header information about the file being played. + * Retrieve header information about the stream being played. * * @param info * @return */ native static final protected boolean gstreamer_get_audio_format_stream(GstHeader info, - BufferedInputStream istream); + Pointer pointer); /** * Retrieve header information about the file being played. @@ -269,8 +268,15 @@ final class GstAudioFileReaderNativePeer native static final protected boolean gstreamer_get_audio_format_file(GstHeader info); + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + static { System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); } } diff --git a/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java b/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java index 9b395dca2..cef1e0f12 100644 --- a/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java +++ b/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java @@ -36,6 +36,8 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ package gnu.javax.sound.sampled.gstreamer.io; +import gnu.javax.sound.sampled.gstreamer.GStreamerMixer; + import java.io.File; import java.io.IOException; import java.io.OutputStream; diff --git a/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java b/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java new file mode 100644 index 000000000..0702eded7 --- /dev/null +++ b/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java @@ -0,0 +1,119 @@ +/* GstInputStream.java -- Trampoline class for an InputStream, mean to be used + by native code. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.javax.sound.sampled.gstreamer.io; + +import gnu.classpath.Pointer; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Encapsulates the functionality of an InputStream Object. + * + * This class is only meant to be used by the native code, to allow reading + * of the given InputStream as part of a the GStreamer InputStream Source + * Plugin. + * + * <strong>Note:</strong> this class will be not garbage collected as the + * native code contains strong references to internal fields. + * The native layer provides a method that can be called by the C code to + * free the resources and to let the garbage collected to handle this class + * when not needed anymore. + * + * @author Mario Torre <neugens@limasoftware.net> + */ +public class GstInputStream +{ + /** The real InputStream on which to perform reading operations. */ + private InputStream istream; + + /** + * Initialized in the native code, don't change without changes + * in the native layer. + */ + private Pointer gstInputStream = null; + + public GstInputStream(InputStream istream) + { + this.istream = istream; + init_instance(); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + return this.istream.read(buf, off, len); + } + + public int available() throws IOException + { + return this.istream.available(); + } + + /** + * Return a reference to the GstInputStream native class as a Pointer object. + * This method is intended as an helper accessor and the returned pointer + * needs to be casted and used in the native code only. + * + * @return Pointer to the native GstInputStream class. + */ + public Pointer getNativeClass() + { + return this.gstInputStream; + } + + /* native methods */ + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the class constructor. + */ + native private final void init_instance(); + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java b/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java index 0467c9559..33be15c58 100644 --- a/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java +++ b/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java @@ -41,22 +41,13 @@ import javax.sound.sampled.AudioFormat; import javax.sound.sampled.Control; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineListener; -import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.Control.Type; public abstract class GstDataLine implements DataLine { - public static enum State - { - PLAY, PAUSE, STOP - } - public static final int DEFAULT_BUFFER_SIZE = 1024; - /** Represents the playing state of this Line. */ - protected State state = State.STOP; - /** Represents if this Line is opened or not. */ protected Boolean open = false; @@ -90,12 +81,7 @@ public abstract class GstDataLine // TODO Auto-generated method stub return 0; } - - public boolean isRunning() - { - return (state == State.PLAY || state == State.PAUSE); - } - + public void addLineListener(LineListener listener) { // TODO Auto-generated method stub @@ -131,15 +117,35 @@ public abstract class GstDataLine return false; } - public void open() throws LineUnavailableException + public void removeLineListener(LineListener listener) { // TODO Auto-generated method stub } - public void removeLineListener(LineListener listener) + /* protected methods for subclasses */ + + /** + * @param open the open to set + */ + protected void setOpen(Boolean open) { - // TODO Auto-generated method stub + this.open = open; + } + + /** + * @param bufferSize the bufferSize to set + */ + protected void setBufferSize(int bufferSize) + { + this.bufferSize = bufferSize; + } + /** + * @param format the format to set + */ + protected void setFormat(AudioFormat format) + { + this.format = format; } } diff --git a/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java b/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java index 2b41a1186..84007ac97 100644 --- a/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java +++ b/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java @@ -37,12 +37,41 @@ exception statement from your version. */ package gnu.javax.sound.sampled.gstreamer.lines; +import gnu.classpath.Pointer; + +import javax.sound.sampled.LineUnavailableException; + public class GstNativeDataLine -{ +{ + public static final GstPipeline createSourcePipeline(int bufferSize) + throws LineUnavailableException + { + GstPipeline pipeline = new GstPipeline(bufferSize); + + pipeline.createForWrite(); + + if (!setup_sink_pipeline(pipeline.getNativeClass())) + throw new LineUnavailableException("Line unavailable"); + + return pipeline; + } + /* native methods */ + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native static final private void init_id_cache(); + + /** + * Setup a new GStreamer Pipeline + */ + native static final private boolean setup_sink_pipeline(Pointer pipeline); + static { System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); } } diff --git a/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java b/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java index d1460e509..caec48dc5 100644 --- a/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java +++ b/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java @@ -34,8 +34,14 @@ or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ + package gnu.javax.sound.sampled.gstreamer.lines; +import java.io.FileOutputStream; +import java.io.IOException; + +import javax.sound.sampled.LineUnavailableException; + import gnu.classpath.Pointer; /** @@ -44,14 +50,283 @@ import gnu.classpath.Pointer; */ public class GstPipeline { + public static enum State + { + PLAY, PAUSE, STOP, CLOSE + } + + /** Represents the playing state of this Line. */ + protected 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; + + // TODO use nio? + protected FileOutputStream output = null; + + protected boolean source = true; + + protected 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; + + /** + * Creates a new GstPipeline with a capacity of + * {@link GstDataLine#DEFAULT_BUFFER_SIZE}. * - * This field is used by the native code, so any change to it must be - * followed by similar changes in the native peer. + * @see GstDataLine#DEFAULT_BUFFER_SIZE + */ + public GstPipeline() + { + this(GstDataLine.DEFAULT_BUFFER_SIZE); + } + + /** + * Creates a new GstPipeline with a capacity of bufferSize. + * @see GstDataLine#DEFAULT_BUFFER_SIZE */ - private Pointer pipeline; + public GstPipeline(int bufferSize) + { + // bufferSize not needed + init_instance(); + } + + /** + * + */ + public void createForWrite() throws LineUnavailableException + { + // create the named pipe + if (!create_named_pipe(this.pipeline)) + throw new LineUnavailableException("Unable to create filesystem pipe"); + + prepareWrite(); + + this.source = true; + } + + /** + * @return the state + */ + public State getState() + { + return this.state; + } - native private void setState(); + /** + * Closes this pipeline. + * Short hand for #setState(State.STOP). + */ + public void close() + { + setState(State.STOP); + } + + /** + * @param state the state to set + */ + public void setState(final State state) + { + int _state = -1; + switch (state) + { + case PLAY: + _state = 0; + break; + + case PAUSE: + _state = 1; + break; + + case STOP: case CLOSE: + _state = 2; + 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; + } + + /** + * Return a reference to the GstPipeline native class as a Pointer object. + * This method is intended as an helper accessor and the returned pointer + * needs to be casted and used in the native code only. + * + * @return Pointer to the native GstPipeline class. + */ + public Pointer getNativeClass() + { + return this.pipeline; + } + + /** + * Write length bytes from the given buffer into this pipeline, + * starting at offset. + * This method block if the pipeline can't accept more data. + * + * @param buffer + * @param offset + * @param length + * @return + */ + public int write(byte[] buffer, int offset, int length) + { + if (this.state == State.STOP) + return -1; + else if (this.state == State.PAUSE) + return 0; + else if (!ready) + return -1; + + try + { + if (output != null) + { + output.write(buffer, offset, length); + return length; + } + return 0; + } + catch (Exception e) + { + /* nothing to do */ + } + + return -1; + } + + public int read(byte[] buffer, int offset, int length) + { + return 0; + } + + public int available() + { + /* FIXME: not supported yet */ + return -1; + } + + /** + * Wait for remaining data to be enqueued in the pipeline. + */ + public void drain() + { + if (this.state == State.STOP) + return; + + // TODO: ask the native layer if it has finished reading + try + { + Thread.sleep(8000); + } + catch (InterruptedException e) + { + /* nothing to do*/ + } + } + + /** + * Flush all the data currently waiting in the queue. + */ + public void flush() + { + try + { + if (source) + this.output.flush(); + } + catch (IOException e) + { + /* nothing */ + } + } + + private void closePipe() + { + try + { + GstPipeline.this.flush(); + if (source) + GstPipeline.this.output.close(); + } + catch (IOException e) + { + /* nothing to do */ + } + } + + private void prepareWrite() + { + new Thread () + { + public void run () + { + 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; + } + } + }.start(); + } + + /* ***** native ***** */ + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + + /** + * Set the playing state of this pipeline. + */ + native private static final boolean set_state(Pointer jpipeline, int state); + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the class constructor. + */ + native private final void init_instance(); + + /** + * Crates the named pipe used to pass data between the application code + * and gstreamer. + */ + native private final boolean create_named_pipe(Pointer jpipeline); + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } } diff --git a/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java b/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java index d1a0262e5..f7a0f0797 100644 --- a/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java +++ b/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java @@ -38,6 +38,7 @@ exception statement from your version. */ package gnu.javax.sound.sampled.gstreamer.lines; import gnu.javax.sound.AudioSecurityManager; +import gnu.javax.sound.sampled.gstreamer.lines.GstPipeline.State; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.LineUnavailableException; @@ -48,45 +49,61 @@ import static gnu.javax.sound.AudioSecurityManager.Permission; public class GstSourceDataLine extends GstDataLine implements SourceDataLine { + private GstPipeline pipeline = null; + private boolean open = false; + public GstSourceDataLine(AudioFormat format) { super(format); } + public void open() throws LineUnavailableException + { + AudioSecurityManager.checkPermissions(Permission.PLAY); + + if (open) + throw new IllegalStateException("Line already opened"); + + // create the pipeline + pipeline = GstNativeDataLine.createSourcePipeline(getBufferSize()); + + this.open = true; + } + public void open(AudioFormat fmt) throws LineUnavailableException { AudioSecurityManager.checkPermissions(Permission.PLAY); - throw new LineUnavailableException("Line unavailable"); + + setFormat(fmt); + this.open(); } public void open(AudioFormat fmt, int size) throws LineUnavailableException { AudioSecurityManager.checkPermissions(Permission.PLAY); - throw new LineUnavailableException("Line unavailable"); + + setBufferSize(size); + this.open(fmt); } public int write(byte[] buf, int offset, int length) - { - // TODO Auto-generated method stub - return 0; + { + return this.pipeline.write(buf, offset, length); } public int available() { - // TODO Auto-generated method stub - return 0; + return this.pipeline.available(); } public void drain() { - // TODO Auto-generated method stub - + this.pipeline.drain(); } public void flush() { - // TODO Auto-generated method stub - + this.pipeline.flush(); } public int getFramePosition() @@ -109,26 +126,28 @@ public class GstSourceDataLine public boolean isActive() { - // TODO Auto-generated method stub - return false; + State state = pipeline.getState(); + return (state == State.PLAY || state == State.PAUSE); } public void start() { - // TODO Auto-generated method stub - + pipeline.setState(State.PLAY); } public void stop() { - // TODO Auto-generated method stub - + pipeline.setState(State.PAUSE); } public void close() { - // TODO Auto-generated method stub - + pipeline.close(); + this.open = false; + } + + public boolean isRunning() + { + return (pipeline.getState() == State.PLAY); } - } diff --git a/include/Makefile.am b/include/Makefile.am index 33306bce0..eb91a8a6f 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -15,7 +15,10 @@ $(top_srcdir)/include/gnu_javax_sound_midi_dssi_DSSIMidiDeviceProvider.h \ $(top_srcdir)/include/gnu_javax_sound_midi_dssi_DSSISynthesizer.h GST_PEER_H_FILES = \ -$(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h +$(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h \ +$(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_io_GstInputStream.h \ +$(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine.h \ +$(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h XMLJ_H_FILES = \ $(top_srcdir)/include/gnu_xml_libxmlj_dom_GnomeDocument.h \ @@ -354,6 +357,12 @@ $(top_srcdir)/include/gnu_java_util_prefs_gconf_GConfNativePeer.h: $(top_srcdir) $(JAVAH) -o $@ gnu.java.util.prefs.gconf.GConfNativePeer $(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h: $(top_builddir)/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java $(JAVAH) -o $@ gnu.javax.sound.sampled.gstreamer.io.GstAudioFileReaderNativePeer +$(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_io_GstInputStream.h: $(top_builddir)/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java + $(JAVAH) -o $@ gnu.javax.sound.sampled.gstreamer.io.GstInputStream +$(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine.h: $(top_builddir)/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java + $(JAVAH) -o $@ gnu.javax.sound.sampled.gstreamer.lines.GstNativeDataLine +$(top_srcdir)/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h: $(top_builddir)/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java + $(JAVAH) -o $@ gnu.javax.sound.sampled.gstreamer.lines.GstPipeline $(top_srcdir)/include/gnu_java_net_VMPlainSocketImpl.h: $(top_srcdir)/vm/reference/gnu/java/net/VMPlainSocketImpl.java $(JAVAH) -o $@ gnu.java.net.VMPlainSocketImpl $(top_srcdir)/include/gnu_java_net_local_LocalSocketImpl.h: $(top_srcdir)/gnu/java/net/local/LocalSocketImpl.java diff --git a/include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h b/include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h index 509a43cd9..2bb4122e3 100644 --- a/include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h +++ b/include/gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h @@ -1,10 +1,10 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> + #ifndef __gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer__ #define __gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer__ -#include <jni.h> - #ifdef __cplusplus extern "C" { @@ -12,6 +12,7 @@ extern "C" JNIEXPORT jboolean JNICALL Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer_1get_1audio_1format_1stream (JNIEnv *env, jclass, jobject, jobject); JNIEXPORT jboolean JNICALL Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer_1get_1audio_1format_1file (JNIEnv *env, jclass, jobject); +JNIEXPORT void JNICALL Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_init_1id_1cache (JNIEnv *env, jclass); #ifdef __cplusplus } diff --git a/include/gnu_javax_sound_sampled_gstreamer_io_GstInputStream.h b/include/gnu_javax_sound_sampled_gstreamer_io_GstInputStream.h new file mode 100644 index 000000000..15fd94363 --- /dev/null +++ b/include/gnu_javax_sound_sampled_gstreamer_io_GstInputStream.h @@ -0,0 +1,20 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ + +#include <jni.h> + +#ifndef __gnu_javax_sound_sampled_gstreamer_io_GstInputStream__ +#define __gnu_javax_sound_sampled_gstreamer_io_GstInputStream__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +JNIEXPORT void JNICALL Java_gnu_javax_sound_sampled_gstreamer_io_GstInputStream_init_1instance (JNIEnv *env, jobject); +JNIEXPORT void JNICALL Java_gnu_javax_sound_sampled_gstreamer_io_GstInputStream_init_1id_1cache (JNIEnv *env, jclass); + +#ifdef __cplusplus +} +#endif + +#endif /* __gnu_javax_sound_sampled_gstreamer_io_GstInputStream__ */ diff --git a/include/gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine.h b/include/gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine.h new file mode 100644 index 000000000..93910a3f1 --- /dev/null +++ b/include/gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine.h @@ -0,0 +1,20 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ + +#include <jni.h> + +#ifndef __gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine__ +#define __gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +JNIEXPORT void JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine_init_1id_1cache (JNIEnv *env, jclass); +JNIEXPORT jboolean JNICALL Java_gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine_setup_1sink_1pipeline (JNIEnv *env, jclass, jobject); + +#ifdef __cplusplus +} +#endif + +#endif /* __gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine__ */ diff --git a/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h b/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h new file mode 100644 index 000000000..d5893a1f2 --- /dev/null +++ b/include/gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h @@ -0,0 +1,22 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ + +#include <jni.h> + +#ifndef __gnu_javax_sound_sampled_gstreamer_lines_GstPipeline__ +#define __gnu_javax_sound_sampled_gstreamer_lines_GstPipeline__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +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 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); + +#ifdef __cplusplus +} +#endif + +#endif /* __gnu_javax_sound_sampled_gstreamer_lines_GstPipeline__ */ diff --git a/native/jni/gstreamer-peer/Makefile.am b/native/jni/gstreamer-peer/Makefile.am index c40170fc3..17277a698 100644 --- a/native/jni/gstreamer-peer/Makefile.am +++ b/native/jni/gstreamer-peer/Makefile.am @@ -1,12 +1,18 @@ nativeexeclib_LTLIBRARIES = libgstreamerpeer.la -libgstreamerpeer_la_SOURCES = GStreamerIOPeer.c \ - gstinputstream.c \ - gstclasspathsrc.c \ - gstclasspathsrc.h \ - gstinputstream.h +libgstreamerpeer_la_SOURCES = gst_peer.c \ + gstreamer_io_peer.c \ + gst_native_data_line.c \ + gst_input_stream.c \ + gst_native_pipeline.c \ + gst_classpath_src.c \ + gst_peer.h \ + gst_classpath_src.h \ + gst_input_stream.h \ + gst_native_pipeline.h -libgstreamerpeer_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo +libgstreamerpeer_la_LIBADD = $(top_builddir)/native/jni/classpath/jcl.lo \ + $(top_builddir)/native/jni/native-lib/libclasspathnative.la libgstreamerpeer_la_LDFLAGS = $(AM_LDFLAGS) @GST_PLUGIN_LDFLAGS@ -avoid-version @@ -17,6 +23,7 @@ AM_CPPFLAGS = @CLASSPATH_INCLUDES@ # We cannot use -Wwrite-strings and the strict flags since # gstreamer contain broken prototypes (by design). -AM_CFLAGS = @WARNING_CFLAGS@ -Wno-write-strings -Wno-missing-field-initializers \ +AM_CFLAGS = @WARNING_CFLAGS@ -Wno-write-strings \ + -Wno-missing-field-initializers \ @ERROR_CFLAGS@ -Wno-unused-parameter @GSTREAMER_BASE_CFLAGS@ \ @GDK_CFLAGS@ @GSTREAMER_CFLAGS@ @GSTREAMER_PLUGINS_BASE_CFLAGS@ diff --git a/native/jni/gstreamer-peer/gstclasspathsrc.c b/native/jni/gstreamer-peer/gst_classpath_src.c index afce1f1d4..80c679592 100644 --- a/native/jni/gstreamer-peer/gstclasspathsrc.c +++ b/native/jni/gstreamer-peer/gst_classpath_src.c @@ -59,8 +59,8 @@ exception statement from your version. */ #include <gdk/gdk.h> -#include "gstclasspathsrc.h" -#include "gstinputstream.h" +#include "gst_classpath_src.h" +#include "gst_input_stream.h" GST_DEBUG_CATEGORY_STATIC (gst_classpath_src_debug); #define GST_CAT_DEFAULT gst_classpath_src_debug @@ -71,6 +71,12 @@ enum ARG_INPUTSTREAM }; +struct _GstClasspathSrcPrivate +{ + GstInputStream *istream; + GstCaps *caps; +}; + static const GstElementDetails gst_classpath_src_details = GST_ELEMENT_DETAILS ("ClasspathSrc", "Source/Network", @@ -107,7 +113,7 @@ GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR, "classpathsrc", "Java InputStream Reader", plugin_init, CLASSPATH_GST_PLUGIN_VERSION, - GST_LICENSE_UNKNOWN, + GST_LICENSE_UNKNOWN, /* GPL + Exception */ "Classpath", "http://www.classpath.org/") /* ***** public class methods ***** */ @@ -124,6 +130,8 @@ static void gst_classpath_src_get_property (GObject *object, static void gst_classpath_src_finalize (GObject *object); +static GstCaps *gst_classpath_src_getcaps (GstBaseSrc *basesrc); + static gboolean gst_classpath_src_start (GstBaseSrc *basesrc); static gboolean gst_classpath_src_stop (GstBaseSrc *basesrc); @@ -131,6 +139,13 @@ static gboolean gst_classpath_src_stop (GstBaseSrc *basesrc); static GstFlowReturn gst_classpath_src_create (GstPushSrc *src, GstBuffer **buffer); +static GstFlowReturn +gst_classpath_src_create_stream (GstClasspathSrc *src, GstBuffer **buffer); + +static GstFlowReturn +check_read (GstClasspathSrc *src, int read, int buffer_size, + GstBuffer **buffer); + /* ***** public class methods: end ***** */ static void @@ -159,6 +174,8 @@ gst_classpath_src_class_init (GstClasspathSrcClass *klass) gstbasesrc_class = GST_BASE_SRC_CLASS (klass); gstpushsrc_class = GST_PUSH_SRC_CLASS (klass); + g_type_class_add_private (klass, sizeof (GstClasspathSrcPrivate)); + /* getter and setters */ gobject_class->set_property = gst_classpath_src_set_property; @@ -174,6 +191,7 @@ gst_classpath_src_class_init (GstClasspathSrcClass *klass) /* register callbacks */ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_classpath_src_finalize); + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_classpath_src_getcaps); gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_classpath_src_start); gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_classpath_src_stop); @@ -186,8 +204,11 @@ static void gst_classpath_src_init (GstClasspathSrc *src, GstClasspathSrcClass * g_class __attribute__ ((unused))) { - src->istream = NULL; - src->read_position = 0; + src->priv = G_TYPE_INSTANCE_GET_PRIVATE (src, GST_TYPE_CLASSPATH_SRC, + GstClasspathSrcPrivate); + + src->priv->istream = NULL; + src->priv->caps = NULL; } static void @@ -222,21 +243,15 @@ gst_classpath_src_set_property (GObject *object, if (state != GST_STATE_READY && state != GST_STATE_NULL) { - GST_DEBUG_OBJECT (src, "setting location in wrong state"); + GST_DEBUG_OBJECT (src, "setting reader in wrong state"); GST_STATE_UNLOCK (src); break; } } GST_STATE_UNLOCK (src); - if (GST_IS_INPUT_STREAM (g_value_get_pointer (value))) - { - src->istream = g_value_get_pointer (value); - } - else - { - GST_INFO_OBJECT (src, "invalid instance of GstInputStream"); - } + /* FIXME: check if this is a valid instance of GstInputStream */ + src->priv->istream = g_value_get_pointer (value); } break; @@ -254,53 +269,102 @@ gst_classpath_src_get_property (GObject *object, GParamSpec *pspec __attribute__ ((unused))) { /* TODO */ - G_OBJECT_CLASS (parent_class)->finalize (object); } /* ************************************************************************** */ -static GstFlowReturn -gst_classpath_src_create (GstPushSrc *basesrc, - GstBuffer **buffer) +static GstCaps *gst_classpath_src_getcaps (GstBaseSrc *basesrc) { GstClasspathSrc *src; - int read = -1; - + GstCaps *caps = NULL; + src = GST_CLASSPATH_SRC (basesrc); + + if (src->priv->caps) + caps = gst_caps_copy (src->priv->caps); + else + caps = gst_caps_new_any (); - /* create the buffer */ - *buffer = gst_buffer_new_and_alloc (2048); + GST_DEBUG_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps); + g_assert (GST_IS_CAPS (caps)); + + return caps; +} + +static GstFlowReturn +gst_classpath_src_create_stream (GstClasspathSrc *src, GstBuffer **buffer) +{ + int buffer_size = 2048; + int read = -1; + + buffer_size = gst_input_stream_available (src->priv->istream); + if (buffer_size < 0) + return GST_FLOW_ERROR; + else if (buffer_size == 0) + return GST_FLOW_WRONG_STATE; + + *buffer = gst_buffer_new_and_alloc (buffer_size); if (*buffer == NULL) { return GST_FLOW_ERROR; } - GST_BUFFER_SIZE (*buffer) = 0; - - GST_OBJECT_LOCK (src); - read = gst_input_stream_read (src->istream, (int *) GST_BUFFER_DATA (*buffer), 0, - 2048); - GST_OBJECT_UNLOCK (src); + read = gst_input_stream_read (src->priv->istream, + (int *) GST_BUFFER_DATA (*buffer), + 0, + buffer_size); + return check_read (src, read, buffer_size, buffer); +} + +GstFlowReturn +check_read (GstClasspathSrc *src, int read, int buffer_size, GstBuffer **buffer) +{ if (G_UNLIKELY (read < 0)) { + g_warning("GST_FLOW_UNEXPECTED (read < 0)"); + + gst_buffer_unref (*buffer); + *buffer = NULL; + + return GST_FLOW_ERROR; + } + else if (G_UNLIKELY (read == 0)) + { + g_warning("GST_FLOW_WRONG_STATE (read == 0)"); + gst_buffer_unref (*buffer); - return GST_FLOW_UNEXPECTED; + *buffer = NULL; + + return GST_FLOW_WRONG_STATE; } - - GST_OBJECT_LOCK (src); - + else if (G_UNLIKELY (read < buffer_size)) + { + g_warning("shorter read"); + gst_buffer_unref (*buffer); + *buffer = NULL; + + return GST_FLOW_ERROR; + } + GST_BUFFER_SIZE (*buffer) = read; - GST_BUFFER_OFFSET (*buffer) = src->read_position; - GST_BUFFER_OFFSET_END (*buffer) = src->read_position + read; - - src->read_position += read; + gst_buffer_set_caps (*buffer, src->priv->caps); - GST_OBJECT_UNLOCK (src); + return GST_FLOW_OK; +} + +static GstFlowReturn +gst_classpath_src_create (GstPushSrc *basesrc, GstBuffer **buffer) +{ + GstClasspathSrc *src = NULL; + GstFlowReturn ret = GST_FLOW_OK; - gst_buffer_set_caps (*buffer, GST_PAD_CAPS (GST_BASE_SRC_PAD (src))); + src = GST_CLASSPATH_SRC (basesrc); + + /* create the buffer */ + ret = gst_classpath_src_create_stream (src, buffer); - return GST_FLOW_OK; + return ret; } static gboolean @@ -310,23 +374,35 @@ gst_classpath_src_start (GstBaseSrc *basesrc) src = GST_CLASSPATH_SRC (basesrc); - if (src->istream == NULL) + if (src->priv->istream == NULL) { + g_warning("GstInputStream is still null. You need to " \ + "pass a valid InputStream object"); + GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), - ("GstInputStream is still null. you need to pass a valid InputStream")); - + ("GstInputStream is still null. You need to " \ + "pass a valid InputStream")); return FALSE; } - GST_OBJECT_LOCK (src); - src->read_position = 0; - GST_OBJECT_UNLOCK (src); - + return TRUE; } static gboolean -gst_classpath_src_stop (GstBaseSrc *basesrc __attribute__ ((unused))) +gst_classpath_src_stop (GstBaseSrc *basesrc) { - /* nothing to do */ + GstClasspathSrc *src; + + src = GST_CLASSPATH_SRC (basesrc); + + /* clean the stream */ + if (src->priv->istream != NULL) + gst_input_stream_clean (src->priv->istream); + + if (src->priv->caps) { + gst_caps_unref (src->priv->caps); + src->priv->caps = NULL; + } + return TRUE; } diff --git a/native/jni/gstreamer-peer/gstclasspathsrc.h b/native/jni/gstreamer-peer/gst_classpath_src.h index f5fa6c83d..9e2acb0f2 100644 --- a/native/jni/gstreamer-peer/gstclasspathsrc.h +++ b/native/jni/gstreamer-peer/gst_classpath_src.h @@ -41,7 +41,7 @@ exception statement from your version. */ #include <gst/gst.h> #include <gst/base/gstpushsrc.h> -#include "gstinputstream.h" +#include "gst_input_stream.h" G_BEGIN_DECLS @@ -59,7 +59,8 @@ G_BEGIN_DECLS #define GST_IS_CLASSPATH_SRC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLASSPATH_SRC)) - + +typedef struct _GstClasspathSrcPrivate GstClasspathSrcPrivate; typedef struct _GstClasspathSrc GstClasspathSrc; typedef struct _GstClasspathSrcClass GstClasspathSrcClass; @@ -67,9 +68,8 @@ struct _GstClasspathSrc { GstPushSrc element; - /* TODO: move in a private structure */ - GstInputStream *istream; - int read_position; + /* instance members */ + GstClasspathSrcPrivate *priv; }; struct _GstClasspathSrcClass diff --git a/native/jni/gstreamer-peer/gst_input_stream.c b/native/jni/gstreamer-peer/gst_input_stream.c new file mode 100644 index 000000000..c5e512954 --- /dev/null +++ b/native/jni/gstreamer-peer/gst_input_stream.c @@ -0,0 +1,290 @@ +/*GstInputStream.c - Header file for the GstClasspathPlugin + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#include <jni.h> +#include <jcl.h> + +#include <string.h> +#include <stdlib.h> + +#include <gdk/gdk.h> + +#include <glib.h> + +#include "gst_peer.h" + +#include "gnu_javax_sound_sampled_gstreamer_io_GstInputStream.h" +#include "gst_input_stream.h" + +/* for caching */ +static jmethodID readID = NULL; +static jmethodID pointerConstructorID = NULL; +static jmethodID availableID = NULL; + +static jfieldID streamID = NULL; +static jfieldID pointerDataID = NULL; + +struct _GstInputStreamPrivate +{ + JavaVM *vm; + jclass readerClass; + jclass pointerClass; + + jobject reader; +}; + +/* ************************************************************************** */ + +static void init_pointer_IDs (JNIEnv* env); + +/* ************************************************************************** */ + +/* JNI Methods */ + +JNIEXPORT void JNICALL +Java_gnu_javax_sound_sampled_gstreamer_io_GstInputStream_init_1id_1cache + (JNIEnv *env, jclass clazz) +{ + readID = (*env)->GetMethodID(env, clazz, "read", "([BII)I"); + availableID = (*env)->GetMethodID(env, clazz, "available", "()I"); + + streamID = (*env)->GetFieldID(env, clazz, "gstInputStream", + "Lgnu/classpath/Pointer;"); + init_pointer_IDs(env); +} + +JNIEXPORT void JNICALL +Java_gnu_javax_sound_sampled_gstreamer_io_GstInputStream_init_1instance + (JNIEnv *env, jobject reader) +{ + GstInputStream *istream = NULL; + + jclass localReader = NULL; + jclass localPointer = NULL; + jobject _pointer = NULL; + + istream = (GstInputStream *) JCL_malloc (env, sizeof (GstInputStream)); + if (istream == NULL) + return; + + istream->priv = (GstInputStreamPrivate *) + JCL_malloc (env, sizeof (GstInputStreamPrivate)); + if (istream->priv == NULL) + { + JCL_free (env, istream); + return; + } + + /* get a local references first */ + localReader = (*env)->GetObjectClass(env, reader); + if (localReader == NULL) + { + JCL_free (env, istream->priv); + JCL_free (env, istream); + JCL_ThrowException (env, "java/lang/InternalError", + "Class Initialization failed."); + + return; + } + +#if SIZEOF_VOID_P == 8 + localPointer = JCL_FindClass (env, "gnu/classpath/Pointer64"); +#else +# if SIZEOF_VOID_P == 4 + localPointer = JCL_FindClass (env, "gnu/classpath/Pointer32"); +# else +# error "Pointer size is not supported." +# endif /* SIZEOF_VOID_P == 4 */ +#endif /* SIZEOF_VOID_P == 8 */ + + if (localReader == NULL || localPointer == NULL) + { + JCL_free (env, istream->priv); + JCL_free (env, istream); + JCL_ThrowException (env, "java/lang/InternalError", + "Class Initialization failed."); + return; + } + + /* fill out our structure */ + istream->priv->readerClass = (*env)->NewGlobalRef(env, localReader); + istream->priv->pointerClass = (*env)->NewGlobalRef(env, localPointer); + (*env)->GetJavaVM(env, &istream->priv->vm); + istream->priv->reader = (*env)->NewGlobalRef(env, reader); + + _pointer = (*env)->GetObjectField(env, reader, streamID); + + /* this should be always null */ + if (_pointer == NULL) + { +#if SIZEOF_VOID_P == 8 + _pointer = (*env)->NewObject(env, istream->priv->pointerClass, + pointerConstructorID, (jlong) istream); +#else + _pointer = (*env)->NewObject(env, istream->priv->pointerClass, + pointerConstructorID, (jint) istream); +#endif + } + else + { +#if SIZEOF_VOID_P == 8 + (*env)->SetLongField(env, reader, streamID, (jlong) istream); +#else + (*env)->SetIntField(env, reader, streamID, (jint) istream); +#endif + } + + /* store back our pointer into the calling class */ + (*env)->SetObjectField(env, reader, streamID, _pointer); +} + +/* exported library functions */ + +void +gst_input_stream_clean (GstInputStream *self) +{ + JNIEnv *env = NULL; + + env = gst_get_jenv (self->priv->vm); + + (*env)->DeleteGlobalRef (env, self->priv->reader); + (*env)->DeleteGlobalRef (env, self->priv->readerClass); + (*env)->DeleteGlobalRef (env, self->priv->pointerClass); + + JCL_free (env, self->priv); + JCL_free (env, self); +} + +int +gst_input_stream_available (GstInputStream *self) +{ + JNIEnv *env = NULL; + + if (self == NULL || self->priv == NULL || + self->priv->vm == NULL || self->priv->reader == NULL) + { + return -1; + } + + env = gst_get_jenv (self->priv->vm); + if (env == NULL) + { + g_warning("GstInputStream::gst_input_stream_available " \ + "failed to get java env"); + return -1; + } + + return (*env)->CallIntMethod (env, self->priv->reader, availableID); +} + +int +gst_input_stream_read (GstInputStream *self, int *data, int offset, + int length) +{ + JNIEnv *env = NULL; + + int ret = -1; + jbyteArray buffer; + jbyte *bytes = NULL; + + if (self == NULL || self->priv == NULL || + self->priv->vm == NULL || self->priv->reader == NULL) + { + return -1; + } + + env = gst_get_jenv (self->priv->vm); + if (env == NULL) + { + g_warning("GstInputStream::gst_input_stream_read failed to get java env"); + return -1; + } + + buffer = (*env)->NewByteArray (env, length); + if (buffer == NULL) + { + g_warning ("GstInputStream::gst_input_stream_read called, failed"); + return -1; + } + + ret = (*env)->CallIntMethod (env, self->priv->reader, readID, buffer, 0, + length); + if (ret < 0) + { + (*env)->DeleteLocalRef(env, buffer); + return ret; + } + + bytes = (*env)->GetByteArrayElements (env, buffer, NULL); + + /* copy bytes and release */ + memcpy (data + offset, bytes, ret); + + (*env)->ReleaseByteArrayElements (env, buffer, bytes, 0); + (*env)->DeleteLocalRef (env, buffer); + + return ret; +} + +/* private functions */ + +static void init_pointer_IDs (JNIEnv* env) +{ + jclass pointerClass = NULL; + +#if SIZEOF_VOID_P == 8 + pointerClass = JCL_FindClass (env, "gnu/classpath/Pointer64"); + if (pointerClass != NULL) + { + pointerDataID = (*env)->GetFieldID (env, pointerClass, "data", "J"); + pointerConstructorID = (*env)->GetMethodID (env, pointerClass, "<init>", + "(J)V"); + } +#else +# if SIZEOF_VOID_P == 4 + pointerClass = JCL_FindClass (env, "gnu/classpath/Pointer32"); + if (pointerClass != NULL) + { + pointerDataID = (*env)->GetFieldID(env, pointerClass, "data", "I"); + pointerConstructorID = (*env)->GetMethodID(env, pointerClass, + "<init>", "(I)V"); + } +# else +# error "Pointer size is not supported." +# endif /* SIZEOF_VOID_P == 4 */ +#endif /* SIZEOF_VOID_P == 8 */ +} diff --git a/native/jni/gstreamer-peer/gstinputstream.h b/native/jni/gstreamer-peer/gst_input_stream.h index 1930412fe..8e9d3cf42 100644 --- a/native/jni/gstreamer-peer/gstinputstream.h +++ b/native/jni/gstreamer-peer/gst_input_stream.h @@ -38,62 +38,34 @@ exception statement from your version. */ #ifndef __GST_INPUT_STREAM_H__ #define __GST_INPUT_STREAM_H__ -#include <glib-object.h> - -/* TODO: is a gobject overkill for that? */ - -G_BEGIN_DECLS - -/* #defines don't like whitespacey bits */ -#define GST_TYPE_INPUT_STREAM (gst_input_stream_get_type()) - -#define GST_INPUT_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_INPUT_STREAM,GstInputStream)) - -#define GST_INPUT_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_INPUT_STREAM,GstInputStreamClass)) - -#define GST_IS_INPUT_STREAM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_INPUT_STREAM)) - -#define GST_IS_INPUT_STREAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_INPUT_STREAM)) - typedef struct _GstInputStream GstInputStream; -typedef struct _GstInputStreamClass GstInputStreamClass; typedef struct _GstInputStreamPrivate GstInputStreamPrivate; struct _GstInputStream { - GObject parent; - /* instance members */ GstInputStreamPrivate *priv; }; -struct _GstInputStreamClass -{ - GObjectClass parent_class; -}; - -GType gst_input_stream_get_type (void); - +/** + * Clean the given instance of GstInputStream so that the garbage + * collector can collect the cached Java classes. + * Call this fuction when you don't need anymore to use this instance of + * GstInputStream. Note that failure to call this routine will result in + * memroy leaks. + */ +void gst_input_stream_clean (GstInputStream *self); + +/** + * Perform the "read" operation on this GstInputStream. + */ int gst_input_stream_read (GstInputStream *self, int *data, int offset, int length); - -gboolean gst_input_stream_available (GstInputStream *self, guint64 *size); - -gboolean gst_input_stream_can_seek (GstInputStream *self); - -long gst_input_stream_skip (GstInputStream *self, long size); - -void gst_input_stream_reset (GstInputStream *self); - -/* exported properties */ - -#define GST_ISTREAM_JVM "vm" -#define GST_ISTREAM_READER "reader" -G_END_DECLS +/** + * Returns the number of byte currently available for read in this + * GstInputStream. + */ +int gst_input_stream_available (GstInputStream *self); #endif /* __GST_INPUT_STREAM_H__ */ diff --git a/native/jni/gstreamer-peer/gst_native_data_line.c b/native/jni/gstreamer-peer/gst_native_data_line.c new file mode 100644 index 000000000..bc44237b0 --- /dev/null +++ b/native/jni/gstreamer-peer/gst_native_data_line.c @@ -0,0 +1,249 @@ +/*gst_native_data_line.c - Implements the native methods of GstNativeDataLine + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#include <jni.h> + +#include <gst/gst.h> + +#include "jcl.h" +#include "gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine.h" + +#include "gst_peer.h" +#include "gst_classpath_src.h" +#include "gst_native_pipeline.h" + +static jfieldID pointerDataFID = NULL; + +/* ************************************************************************** */ + +static GstElement *setup_pipeline (GstNativePipeline *jpipeline, char *file); +static void +gst_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data); + +/* ************************************************************************** */ + +JNIEXPORT void JNICALL +Java_gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine_init_1id_1cache + (JNIEnv *env __attribute__ ((unused)), jclass clazz __attribute__ ((unused))) +{ + jclass pointerClass = NULL; + +#if SIZEOF_VOID_P == 8 + pointerClass = JCL_FindClass (env, "gnu/classpath/Pointer64"); + if (pointerClass != NULL) + { + pointerDataFID = (*env)->GetFieldID (env, pointerClass, "data", "J"); + } +#else +# if SIZEOF_VOID_P == 4 + pointerClass = JCL_FindClass (env, "gnu/classpath/Pointer32"); + if (pointerClass != NULL) + { + pointerDataFID = (*env)->GetFieldID(env, pointerClass, "data", "I"); + } +# else +# error "Pointer size is not supported." +# endif /* SIZEOF_VOID_P == 4 */ +#endif /* SIZEOF_VOID_P == 8 */ +} + +JNIEXPORT jboolean JNICALL +Java_gnu_javax_sound_sampled_gstreamer_lines_GstNativeDataLine_setup_1sink_1pipeline + (JNIEnv *env, jclass clazz __attribute__ ((unused)), + jobject pointer) +{ + GstNativePipeline *jpipeline = NULL; + + GstElement *pipeline = NULL; + GstElement *sink = NULL; + GstElement *audioconv= NULL; + GstElement *resample = NULL; + GstElement *audio = NULL; + GstElement *decodebin = NULL; + + GstPad *audiopad = NULL; + + gst_init (NULL, NULL); + + /* get the pipeline from the pointer, then create it if needed */ + jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer, + pointerDataFID); + if (jpipeline == NULL) + return JNI_FALSE; + + pipeline = setup_pipeline (jpipeline, + gst_native_pipeline_get_pipeline_name (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"); + if (sink == NULL) + { + gst_object_unref(GST_OBJECT(pipeline)); + gst_object_unref(GST_OBJECT(sink)); + + g_warning ("unable to create sink\n"); + return JNI_FALSE; + } + + audioconv = gst_element_factory_make ("audioconvert", "aconv"); + if (audioconv == NULL) + { + gst_object_unref(GST_OBJECT(pipeline)); + gst_object_unref(GST_OBJECT(sink)); + gst_object_unref(GST_OBJECT(decodebin)); + + g_warning ("unable to create audioconv\n"); + return JNI_FALSE; + } + + audio = gst_bin_new ("audiobin"); + if (audio == NULL) + { + gst_object_unref(GST_OBJECT(pipeline)); + gst_object_unref(GST_OBJECT(sink)); + gst_object_unref(GST_OBJECT(decodebin)); + + g_warning ("unable to create audioconv\n"); + return JNI_FALSE; + } + + resample = gst_element_factory_make ("audioresample", "audioresample"); + if (audioconv == NULL) + { + gst_object_unref(GST_OBJECT(pipeline)); + gst_object_unref(GST_OBJECT(sink)); + gst_object_unref(GST_OBJECT(decodebin)); + gst_object_unref(GST_OBJECT(audio)); + + g_warning ("unable to create resample\n"); + return JNI_FALSE; + } + + audiopad = gst_element_get_pad (audioconv, "sink"); + gst_bin_add_many (GST_BIN (audio), audioconv, resample, sink, NULL); + gst_element_link (audioconv, sink); + + gst_element_add_pad (audio, gst_ghost_pad_new ("sink", audiopad)); + + gst_object_unref (audiopad); + gst_bin_add (GST_BIN (pipeline), audio); + + decodebin = gst_bin_get_by_name (GST_BIN (pipeline), "decodebin"); + g_signal_connect (decodebin, "new-decoded-pad", G_CALLBACK (gst_newpad), + audio); + + gst_native_pipeline_set_pipeline (jpipeline, pipeline); + + return JNI_TRUE; +} + +/* ************************************************************************** */ + +static GstElement *setup_pipeline (GstNativePipeline *jpipeline, char *file) +{ + GstElement *decodebin = NULL; + GstElement *source = NULL; + + GstElement *pipeline = NULL; + + if (file == NULL) + return NULL; + + pipeline = gst_pipeline_new ("java sound pipeline"); + if (pipeline == NULL) + return NULL; + + decodebin = gst_element_factory_make ("decodebin", "decodebin"); + if (decodebin == NULL) + { + gst_object_unref(GST_OBJECT(pipeline)); + gst_object_unref(GST_OBJECT(source)); + + g_warning ("unable to create decodebin\n"); + return NULL; + } + + source = gst_element_factory_make ("filesrc", "source"); + if (source == NULL) + { + gst_object_unref(GST_OBJECT(pipeline)); + gst_object_unref(GST_OBJECT(source)); + gst_object_unref(GST_OBJECT(decodebin)); + + g_warning ("unable to create a source"); + return JNI_FALSE; + } + g_object_set (G_OBJECT (source), "location", file, NULL); + + gst_bin_add_many (GST_BIN (pipeline), source, decodebin, NULL); + gst_element_link (source, decodebin); + + return pipeline; +} + +static void +gst_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data) +{ + GstCaps *caps; + GstStructure *str; + GstPad *audiopad; + + GstElement *audio = (GstElement *) data; + + /* only link once */ + audiopad = gst_element_get_pad (audio, "sink"); + 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; + } + gst_caps_unref (caps); + + /* link'n'play */ + gst_pad_link (pad, audiopad); +} diff --git a/native/jni/gstreamer-peer/gst_native_pipeline.c b/native/jni/gstreamer-peer/gst_native_pipeline.c new file mode 100644 index 000000000..54dbb5ee2 --- /dev/null +++ b/native/jni/gstreamer-peer/gst_native_pipeline.c @@ -0,0 +1,348 @@ +/*gst_native_pipeline.c - Header file for the GstClasspathPlugin + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#include <jni.h> +#include <jcl.h> + +#include <string.h> +#include <stdlib.h> + +#include <gdk/gdk.h> +#include <glib.h> + +#include <gst/gst.h> + +#include "cpio.h" +#include "gst_peer.h" + +#include "gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h" +#include "gst_native_pipeline.h" + +static jmethodID pointerConstructorMID = NULL; + +static jfieldID pipelineFID = NULL; +static jfieldID pointerDataFID = NULL; +static jfieldID nameFID = NULL; + +enum +{ + PLAY, + PAUSE, + STOP +}; + +struct _GstNativePipelinePrivate +{ + JavaVM *vm; + jclass GstPipelineClass; + jclass PointerClass; + + jobject jni_pipeline; + char *name; + GstElement *pipeline; +}; + +/* ************************************************************************** */ + +static void init_pointer_IDs (JNIEnv* env); + +/* ************************************************************************** */ + +/* JNI Methods */ + +JNIEXPORT void JNICALL +Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1id_1cache + (JNIEnv *env, jclass clazz) +{ + pipelineFID = (*env)->GetFieldID (env, clazz, "pipeline", + "Lgnu/classpath/Pointer;"); + nameFID = (*env)->GetFieldID (env, clazz, "name", "Ljava/lang/String;"); + + init_pointer_IDs(env); +} + +JNIEXPORT void JNICALL +Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1instance + (JNIEnv *env, jobject pipeline) +{ + GstNativePipeline *_pipeline = NULL; + + jclass localGstPipelineClass = NULL; + jclass localPointerClass = NULL; + jobject _pointer = NULL; + + _pipeline = + (GstNativePipeline *) JCL_malloc (env, sizeof (GstNativePipeline)); + if (_pipeline == NULL) + return; + + _pipeline->priv = (GstNativePipelinePrivate *) + JCL_malloc (env, sizeof (GstNativePipelinePrivate)); + if (_pipeline->priv == NULL) + { + JCL_free (env, _pipeline); + return; + } + +#if SIZEOF_VOID_P == 8 + localPointerClass = JCL_FindClass (env, "gnu/classpath/Pointer64"); +#else +# if SIZEOF_VOID_P == 4 + localPointerClass = JCL_FindClass (env, "gnu/classpath/Pointer32"); +# else +# error "Pointer size is not supported." +# endif /* SIZEOF_VOID_P == 4 */ +#endif /* SIZEOF_VOID_P == 8 */ + + localGstPipelineClass = (*env)->GetObjectClass(env, pipeline); + if (localGstPipelineClass == NULL || localGstPipelineClass == NULL) + { + JCL_free (env, _pipeline->priv); + JCL_free (env, _pipeline); + JCL_ThrowException (env, "java/lang/InternalError", + "Class Initialization failed."); + return; + } + + /* fill the object */ + (*env)->GetJavaVM(env, &_pipeline->priv->vm); + _pipeline->priv->jni_pipeline = (*env)->NewGlobalRef(env, pipeline); + _pipeline->priv->GstPipelineClass = + (*env)->NewGlobalRef(env, localGstPipelineClass); + _pipeline->priv->PointerClass = (*env)->NewGlobalRef(env, localPointerClass); + _pipeline->priv->pipeline = NULL; + + _pointer = (*env)->GetObjectField(env, pipeline, pipelineFID); + + if (_pointer == NULL) + { +#if SIZEOF_VOID_P == 8 + _pointer = (*env)->NewObject(env, _pipeline->priv->PointerClass, + pointerConstructorMID, (jlong) _pipeline); +#else + _pointer = (*env)->NewObject(env, _pipeline->priv->PointerClass, + pointerConstructorMID, (jint) _pipeline); +#endif + } + else + { +#if SIZEOF_VOID_P == 8 + (*env)->SetLongField(env, pipeline, pipelineFID, (jlong) _pipeline); +#else + (*env)->SetIntField(env, pipeline, pipelineFID, (jint) _pipeline); +#endif + } + + /* store back our pointer into the calling class */ + (*env)->SetObjectField(env, pipeline, pipelineFID, _pointer); +} + +JNIEXPORT jboolean JNICALL +Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_set_1state + (JNIEnv *env, jclass clazz __attribute__ ((unused)), + jobject pointer, jint state) +{ + GstNativePipeline *jpipeline = NULL; + jboolean result = JNI_FALSE; + + if (pointer == NULL) + { + JCL_ThrowException (env, "javax/sound/sampled/LineUnavailableException", + "Can't change pipeline state: " \ + "pipeline not initialized"); + return result; + } + + jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer, + pointerDataFID); + if (jpipeline == NULL) + return JNI_FALSE; + + switch (state) + { + case (PLAY): + gst_element_set_state(GST_ELEMENT(jpipeline->priv->pipeline), + GST_STATE_PLAYING); + result = JNI_TRUE; + break; + + case (PAUSE): + gst_element_set_state(GST_ELEMENT(jpipeline->priv->pipeline), + GST_STATE_PAUSED); + result = JNI_TRUE; + break; + + case (STOP): +#ifndef WITHOUT_FILESYSTEM + /* clean the pipeline and kill named pipe */ + if (jpipeline->priv->name) + { + cpio_removeFile (jpipeline->priv->name); + g_free (jpipeline->priv->name); + } +#endif /* WITHOUT_FILESYSTEM */ + + if (jpipeline->priv->pipeline != NULL) + gst_object_unref (GST_OBJECT(jpipeline->priv->pipeline)); + result = JNI_TRUE; + break; + + default: + /* nothing */ + result = JNI_FALSE; + break; + } + + return result; +} + +JNIEXPORT jboolean JNICALL +Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_create_1named_1pipe + (JNIEnv *env, jobject GstPipeline, jobject pointer) +{ +#ifndef WITHOUT_FILESYSTEM + /* + * We get a temp name for the named pipe, create the named pipe and then + * set the relative field in the java class. + */ + GstNativePipeline *jpipeline = NULL; + jstring *name = NULL; + + jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer, + pointerDataFID); + if (jpipeline == NULL) + return JNI_FALSE; + + jpipeline->priv->name = tempnam (NULL, "cpgst"); + if (jpipeline->priv->name == NULL) + return JNI_FALSE; + + if (mkfifo (jpipeline->priv->name, 0600) < 0) + { + if (jpipeline->priv->name != NULL) + free (jpipeline->priv->name); + return JNI_FALSE; + } + + /* now set the String field */ + name = (*env)->NewStringUTF(env, jpipeline->priv->name); + if (name == NULL) + { + cpio_removeFile (jpipeline->priv->name); + if (jpipeline->priv->name != NULL) + free (jpipeline->priv->name); + + return JNI_FALSE; + } + + (*env)->SetObjectField(env, GstPipeline, nameFID, name); + + return JNI_TRUE; + +#else /* not WITHOUT_FILESYSTEM */ + return JNI_FALSE; +#endif /* not WITHOUT_FILESYSTEM */ + +} + +/* exported library functions */ + +void gst_native_pipeline_clean (GstNativePipeline *self) +{ + JNIEnv *env = NULL; + + env = gst_get_jenv (self->priv->vm); + + (*env)->DeleteGlobalRef (env, self->priv->jni_pipeline); + (*env)->DeleteGlobalRef (env, self->priv->GstPipelineClass); + (*env)->DeleteGlobalRef (env, self->priv->PointerClass); + + if (self->priv->pipeline != NULL) + gst_object_unref (GST_OBJECT (self->priv->pipeline)); + + JCL_free (env, self->priv); + JCL_free (env, self); +} + +void gst_native_pipeline_set_pipeline (GstNativePipeline *self, + GstElement *pipeline) +{ + if (self->priv->pipeline != NULL) + gst_object_unref (GST_OBJECT (self->priv->pipeline)); + + self->priv->pipeline = pipeline; +} + +GstElement *gst_native_pipeline_get_pipeline (GstNativePipeline *self) +{ + return self->priv->pipeline; +} + +char *gst_native_pipeline_get_pipeline_name (GstNativePipeline *self) +{ + return self->priv->name; +} + +/* private functions */ + +static void init_pointer_IDs (JNIEnv* env) +{ + jclass PointerClass = NULL; + +#if SIZEOF_VOID_P == 8 + PointerClass = JCL_FindClass (env, "gnu/classpath/Pointer64"); + if (PointerClass != NULL) + { + PointerDataID = (*env)->GetFieldID (env, PointerClass, "data", "J"); + PointerConstructorID = (*env)->GetMethodID (env, PointerClass, "<init>", + "(J)V"); + } +#else +# if SIZEOF_VOID_P == 4 + PointerClass = JCL_FindClass (env, "gnu/classpath/Pointer32"); + if (PointerClass != NULL) + { + pointerDataFID = (*env)->GetFieldID(env, PointerClass, "data", "I"); + pointerConstructorMID = (*env)->GetMethodID(env, PointerClass, + "<init>", "(I)V"); + } +# else +# error "Pointer size is not supported." +# endif /* SIZEOF_VOID_P == 4 */ +#endif /* SIZEOF_VOID_P == 8 */ +} + diff --git a/native/jni/gstreamer-peer/gst_native_pipeline.h b/native/jni/gstreamer-peer/gst_native_pipeline.h new file mode 100644 index 000000000..4e7f516a3 --- /dev/null +++ b/native/jni/gstreamer-peer/gst_native_pipeline.h @@ -0,0 +1,63 @@ +/*gst_native_pipeline.h - Header file for the GstClasspathPlugin + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#ifndef __GST_NATIVE_PIPELINE_H__ +#define __GST_NATIVE_PIPELINE_H__ + +#include <glib.h> + +#include <gst/gst.h> + +typedef struct _GstNativePipeline GstNativePipeline; +typedef struct _GstNativePipelinePrivate GstNativePipelinePrivate; + +struct _GstNativePipeline +{ + /* instance members */ + GstNativePipelinePrivate *priv; +}; + +void gst_native_pipeline_clean (GstNativePipeline *self); + +void gst_native_pipeline_set_pipeline (GstNativePipeline *self, + GstElement *pipeline); + +GstElement *gst_native_pipeline_get_pipeline (GstNativePipeline *self); + +char *gst_native_pipeline_get_pipeline_name (GstNativePipeline *self); + +#endif /* __GST_NATIVE_PIPELINE_H__ */ diff --git a/native/jni/gstreamer-peer/gst_peer.c b/native/jni/gstreamer-peer/gst_peer.c new file mode 100644 index 000000000..da83b006b --- /dev/null +++ b/native/jni/gstreamer-peer/gst_peer.c @@ -0,0 +1,83 @@ +/*gst_peer.c - Common utility functions for the native peer. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#include <glib.h> + +#include <jni.h> +#include "jcl.h" + +#include "gst_peer.h" + +JNIEnv *gst_get_jenv (JavaVM *vm) +{ + void *env = NULL; + + if ((*vm)->GetEnv(vm, &env, JNI_VERSION_1_2) != JNI_OK) + { + if ((*vm)->AttachCurrentThreadAsDaemon(vm, &env, NULL) < 0) + { + g_warning ("GstNativePipeline:- env not attached"); + return NULL; + } + } + + return (JNIEnv *) env; +} + +void * +get_object_from_pointer (JNIEnv *env, jobject pointer, jfieldID pointerDataFID) +{ + void *_object = NULL; + + if (env == NULL) + return NULL; + + if ((*env)->IsSameObject(env, pointer, NULL) == JNI_TRUE) + return NULL; + +#if SIZEOF_VOID_P == 8 + _object = (void *) (*env)->GetLongField(env, pointer, pointerDataFID); +#else +# if SIZEOF_VOID_P == 4 + _object = (void *) (*env)->GetIntField(env, pointer, pointerDataFID); +# else +# error "Pointer size is not supported." +# endif /* SIZEOF_VOID_P == 4 */ +#endif /* SIZEOF_VOID_P == 8 */ + + return _object; +} diff --git a/native/jni/gstreamer-peer/gst_peer.h b/native/jni/gstreamer-peer/gst_peer.h new file mode 100644 index 000000000..666725419 --- /dev/null +++ b/native/jni/gstreamer-peer/gst_peer.h @@ -0,0 +1,50 @@ +/*gst_peer.h - Common utility functions for the native peer. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#include <jni.h> +#include "jcl.h" + +/** + * Return a reference to the object stored in this Pointer. + */ +void * +get_object_from_pointer (JNIEnv *env, jobject pointer, jfieldID pointerDataFID); + +/** + * Return the JNIEnv valid under the current thread context. + */ +JNIEnv *gst_get_jenv (JavaVM *vm); diff --git a/native/jni/gstreamer-peer/gstinputstream.c b/native/jni/gstreamer-peer/gstinputstream.c deleted file mode 100644 index eb4969682..000000000 --- a/native/jni/gstreamer-peer/gstinputstream.c +++ /dev/null @@ -1,494 +0,0 @@ -/*gstinputstream.c - Header file for the GstClasspathPlugin - Copyright (C) 2007 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -#include <jni.h> -#include <jcl.h> - -#include <string.h> -#include <stdlib.h> - -#include <gdk/gdk.h> - -#include <glib.h> -#include <glib/gprintf.h> - -#include "gstinputstream.h" - -struct _GstInputStreamPrivate -{ - JavaVM *vm; - jobject *reader; - - gboolean eof; - guint8 *buffer; - long size; - long length; - - gboolean disposed; -}; - -#define INPUT_STREAM_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_INPUT_STREAM, GstInputStreamPrivate)) - -/* properties */ - -enum -{ - ARG_0, - ARG_JVM, - ARG_READER -}; - -/* ***** */ - -static JNIEnv *gst_input_stream_get_jenv(GstInputStream *self); - -static void gst_input_stream_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec); - -static void gst_input_stream_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec); - -static void gst_input_stream_instance_init (GTypeInstance *instance, - gpointer g_class); - -static void gst_input_stream_class_init (gpointer g_class, - gpointer g_class_data); - -static GObject * -gst_input_stream_constructor (GType type, guint n_construct_properties, - GObjectConstructParam *construct_properties); - -static void -gst_input_stream_dispose (GObject *obj); - -static void -gst_input_stream_finalize (GObject *obj); - -/* ************************************************************************** */ - -/* class methods */ - -int -gst_input_stream_read (GstInputStream *self, int *data, int offset, - int length) -{ - /* TODO: cache */ - jmethodID _readID = NULL; - jclass InputStream = NULL; - - JNIEnv *env = NULL; - - int ret = -1; - jbyteArray buffer; - jbyte *bytes = NULL; - - if (self->priv->disposed || self->priv->vm == NULL || - self->priv->reader == NULL) - { - return -1; - } - - env = gst_input_stream_get_jenv (self); - if (env == NULL) - { - g_warning("GstInputStream::gst_input_stream_read failed to get java env"); - return -1; - } - - buffer = (*env)->NewByteArray (env, length); - if (buffer == NULL) - { - g_warning ("GstInputStream::gst_input_stream_read called, failed"); - return -1; - } - - InputStream = (*env)->GetObjectClass(env, self->priv->reader); - _readID = (*env)->GetMethodID(env, InputStream, "read", "([BII)I"); - if (_readID == NULL) - { - (*env)->DeleteLocalRef(env, buffer); - return -1; - } - - ret = (*env)->CallIntMethod (env, self->priv->reader, _readID, buffer, 0, - length); - if (ret == -1) - { - (*env)->DeleteLocalRef(env, buffer); - return ret; - } - - bytes = (*env)->GetByteArrayElements (env, buffer, NULL); - - /* copy bytes and release */ - memcpy (data + offset, bytes, ret); - - (*env)->ReleaseByteArrayElements (env, buffer, bytes, 0); - (*env)->DeleteLocalRef (env, buffer); - - return ret; -} - -gboolean -gst_input_stream_available (GstInputStream *self, guint64 *size) -{ - /* TODO: caching */ - - jmethodID _availableID = NULL; - jclass InputStream = NULL; - JNIEnv *env = NULL; - - if (self->priv->disposed || self->priv->vm == NULL || - self->priv->reader == NULL) - { - return FALSE; - } - - env = gst_input_stream_get_jenv(self); - if (env == NULL) - { - g_warning("GstInputStream::gst_input_stream_available failed to get java env"); - return FALSE; - } - - InputStream = (*env)->GetObjectClass(env, self->priv->reader); - _availableID = (*env)->GetMethodID(env, InputStream, "available", "()I"); - if (_availableID == NULL) - { - return FALSE; - } - - *size = (*env)->CallIntMethod (env, self->priv->reader, _availableID); - - return TRUE; -} - -void gst_input_stream_reset (GstInputStream *self) -{ - jmethodID _resetID = NULL; - jclass InputStream = NULL; - JNIEnv *env = NULL; - - if (self->priv->disposed || self->priv->vm == NULL || - self->priv->reader == NULL) - { - return; - } - - env = gst_input_stream_get_jenv(self); - if (env == NULL) - { - g_warning("GstInputStream::gst_input_stream_reset failed to get java env"); - return; - } - - InputStream = (*env)->GetObjectClass(env, self->priv->reader); - _resetID = (*env)->GetMethodID(env, InputStream, "reset", "()V"); - if (_resetID == NULL) - { - return; - } - - (*env)->CallVoidMethod (env, self->priv->reader, _resetID); -} - -long gst_input_stream_skip (GstInputStream *self, long size) -{ - jmethodID _seekID = NULL; - jclass InputStream = NULL; - JNIEnv *env = NULL; - - long skipped = -1; - - if (self->priv->disposed || self->priv->vm == NULL || - self->priv->reader == NULL) - { - return skipped; - } - - env = gst_input_stream_get_jenv(self); - if (env == NULL) - { - g_warning("GstInputStream::gst_input_stream_skip failed to get java env"); - return size; - } - - InputStream = (*env)->GetObjectClass(env, self->priv->reader); - _seekID = (*env)->GetMethodID(env, InputStream, "skip", "(J)J"); - if (_seekID == NULL) - { - return skipped; - } - - size = (*env)->CallIntMethod (env, self->priv->reader, _seekID, size); - if (size != 0) - { - return skipped; - } - - return skipped; -} - -gboolean gst_input_stream_can_seek (GstInputStream *self) -{ - if (gst_input_stream_skip(self, 0) != 0) - { - g_warning ("GstInputStream::gst_input_stream_can_seek CANNOT seek"); - return FALSE; - } - - return TRUE; -} - -/* ************************************************************************** */ - -/* getter and setter */ - -static void -gst_input_stream_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - GstInputStream *self = GST_INPUT_STREAM (object); - - switch (property_id) - { - case ARG_JVM: - { - self->priv->vm = g_value_get_pointer(value); - } - break; - - case ARG_READER: - { - self->priv->reader = g_value_get_pointer(value); - } - break; - - default: - /* We don't have any other property... */ - G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec); - break; - } /* switch */ -} - -static void -gst_input_stream_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - GstInputStream *self = GST_INPUT_STREAM (object); - - switch (property_id) - { - case ARG_JVM: - { - g_value_set_pointer (value, self->priv->vm); - } - break; - - case ARG_READER: - { - g_value_set_pointer (value, self->priv->reader); - } - break; - - default: - /* We don't have any other property... */ - G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec); - break; - } /* switch */ -} - -/* ************************************************************************** */ - -static void -gst_input_stream_instance_init (GTypeInstance *instance, - gpointer g_class __attribute__ ((unused))) -{ - GstInputStream *self = GST_INPUT_STREAM (instance); - - self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GST_TYPE_INPUT_STREAM, - GstInputStreamPrivate); - - self->priv->vm = NULL; - self->priv->reader = NULL; - self->priv->disposed = FALSE; - self->priv->eof = FALSE; - self->priv->buffer = NULL; - self->priv->size = 0; - self->priv->length = 0; -} - -static void -gst_input_stream_class_init (gpointer g_class, - gpointer g_class_data __attribute__ ((unused))) -{ - GObjectClass *gobject_class; - GstInputStreamClass *klass; - GObjectClass *parent_class; - - GParamSpec *pspec; - - gobject_class = G_OBJECT_CLASS (g_class); - klass = GST_INPUT_STREAM_CLASS (g_class); - gobject_class = G_OBJECT_CLASS (g_class); - - g_type_class_add_private (klass, sizeof (GstInputStreamPrivate)); - - gobject_class->set_property = gst_input_stream_set_property; - gobject_class->get_property = gst_input_stream_get_property; - gobject_class->dispose = gst_input_stream_dispose; - gobject_class->finalize = gst_input_stream_finalize; - gobject_class->constructor = gst_input_stream_constructor; - - parent_class = g_type_class_peek_parent (klass); - - /* register properties */ - pspec = g_param_spec_pointer (GST_ISTREAM_JVM, - "Set the java environment property", - "Set the java environment property", - G_PARAM_READWRITE); - g_object_class_install_property (gobject_class, ARG_JVM, pspec); - - pspec = g_param_spec_pointer (GST_ISTREAM_READER, - "Set the java reader property", - "Set the java reader property", - G_PARAM_READWRITE); - g_object_class_install_property (gobject_class, ARG_READER, pspec); - -} - -/* class constructors */ - -static GObject * -gst_input_stream_constructor (GType type, guint n_construct_properties, - GObjectConstructParam *construct_properties) -{ - GObject *obj; - GObjectClass *parent_class; - - /* parent */ - GstInputStreamClass *klass; - klass = GST_INPUT_STREAM_CLASS (g_type_class_peek (GST_TYPE_INPUT_STREAM)); - parent_class = g_type_class_peek_parent (klass); - obj = parent_class->constructor (type, n_construct_properties, - construct_properties); - return obj; -} - -static void -gst_input_stream_dispose (GObject *obj) -{ - GObjectClass *parent_class; - GstInputStream *self = GST_INPUT_STREAM (obj); - if (self->priv->disposed) - { - /* If dispose did already run, return. */ - return; - } - - /* Make sure dispose does not run twice. */ - self->priv->disposed = TRUE; - - if (self->priv->buffer != NULL) - g_free(self->priv->buffer); - - /* Chain up to the parent class */ - parent_class = g_type_class_peek_parent (GST_INPUT_STREAM_CLASS (obj)); - G_OBJECT_CLASS (parent_class)->dispose (obj); -} - -static void -gst_input_stream_finalize (GObject *obj) -{ - /* nothing else to do */ - GObjectClass *parent_class = - g_type_class_peek_parent (GST_INPUT_STREAM_CLASS (obj)); - G_OBJECT_CLASS (parent_class)->finalize (obj); -} - -static JNIEnv * -gst_input_stream_get_jenv(GstInputStream *self) -{ - void *env = NULL; - - if ((*self->priv->vm)->GetEnv(self->priv->vm, &env, JNI_VERSION_1_2) != JNI_OK) - { - if ((*self->priv->vm)->AttachCurrentThreadAsDaemon(self->priv->vm, - &env, NULL) < 0) - { - g_warning ("GstInputStream:- env not attached"); - return NULL; - } - } - - return (JNIEnv *) env; -} - -GType gst_input_stream_get_type (void) -{ - static GType type = 0; - - if (type == 0) - { - static const GTypeInfo info = { - sizeof (GstInputStreamClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - gst_input_stream_class_init, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (GstInputStream), - 0, /* n_preallocs */ - gst_input_stream_instance_init /* instance_init */ - }; - - type = g_type_register_static (G_TYPE_OBJECT, - "GstInputStreamType", - &info, 0); - } - - return type; -} diff --git a/native/jni/gstreamer-peer/GStreamerIOPeer.c b/native/jni/gstreamer-peer/gstreamer_io_peer.c index f5d52e8a4..b3b0d0aa4 100644 --- a/native/jni/gstreamer-peer/GStreamerIOPeer.c +++ b/native/jni/gstreamer-peer/gstreamer_io_peer.c @@ -1,4 +1,5 @@ -/* GStreamerIOPeer.c -- Implements native methods for class GStreamerNativePeer +/* gstreamer_io_peer.c -- Implements native methods for class + GStreamerNativePeer Copyright (C) 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -49,13 +50,32 @@ #include "jcl.h" +#include "gst_peer.h" + #include "gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer.h" -#include "gstclasspathsrc.h" -#include "gstinputstream.h" +#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; + +static jfieldID mimetypeFID = NULL; +static jfieldID endiannessFID = NULL; +static jfieldID channelsFID = NULL; +static jfieldID rateFID = NULL; +static jfieldID widthFID = NULL; +static jfieldID depthFID = NULL; +static jfieldID isSignedFID = NULL; +static jfieldID nameFID = NULL; +static jfieldID layerFID = NULL; +static jfieldID bitrateFID = NULL; +static jfieldID framedFID = NULL; +static jfieldID typeFID = NULL; + typedef struct _AudioProperties AudioProperties; struct _AudioProperties { @@ -116,14 +136,12 @@ struct _AudioProperties const char *type; gboolean done; - }; /* ***** PRIVATE FUNCTIONS DECLARATION ***** */ static gboolean -set_strings (JNIEnv *env, const jclass GstHeader, - const AudioProperties *properties, jobject header); +set_strings (JNIEnv *env, const AudioProperties *properties, jobject header); static gboolean typefind_callback(GstElement *typefind, guint probability, const GstCaps *caps, @@ -134,7 +152,7 @@ element_added (GstBin *bin, GstElement *element, gpointer data); static void new_decoded_pad (GstElement *decoder, GstPad *pad, - gboolean last, GstElement *pipeline); + gboolean last, gpointer data); static gboolean fill_info (GstElement *decoder, AudioProperties *properties); @@ -146,8 +164,8 @@ static gchar * get_boolean_property (const GstStructure *structure, const gchar *property); static gboolean -set_string (JNIEnv *env, const jclass GstHeader, jobject header, - const char *field, const gchar *property); +set_string (JNIEnv *env, jobject header, jfieldID fieldID, + const gchar *property); static void free_properties (AudioProperties *properties); @@ -155,136 +173,97 @@ free_properties (AudioProperties *properties); static void reset_properties (AudioProperties *properties); +static jboolean process_audio (GstElement *source, JNIEnv *env, jobject header); + /* ***** END: PRIVATE FUNCTIONS DECLARATION ***** */ /* ***** NATIVE FUNCTIONS ***** */ -JNIEXPORT jboolean JNICALL -Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer_1get_1audio_1format_1stream - (JNIEnv *env, jclass clazz __attribute__ ((unused)), jobject header __attribute__ ((unused)), - jobject jstream __attribute__ ((unused))) +JNIEXPORT void JNICALL +Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_init_1id_1cache + (JNIEnv *env, jclass clazz __attribute__ ((unused))) { - GstInputStream *istream = NULL; - JavaVM *vm = NULL; + jclass pointerClass = NULL; jclass GstHeader = NULL; + + GstHeader = JCL_FindClass(env, "gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer$GstHeader"); + fileFID = (*env)->GetFieldID(env, GstHeader, "file", "Ljava/lang/String;"); + + mimetypeFID = (*env)->GetFieldID(env, GstHeader, "mimetype", + "Ljava/lang/String;"); + endiannessFID = (*env)->GetFieldID(env, GstHeader, "endianness", + "Ljava/lang/String;"); + channelsFID = (*env)->GetFieldID(env, GstHeader, "channels", + "Ljava/lang/String;"); + rateFID = (*env)->GetFieldID(env, GstHeader, "rate", "Ljava/lang/String;"); + widthFID = (*env)->GetFieldID(env, GstHeader, "width", "Ljava/lang/String;"); + depthFID = (*env)->GetFieldID(env, GstHeader, "depth", "Ljava/lang/String;"); + isSignedFID = (*env)->GetFieldID(env, GstHeader, "isSigned", + "Ljava/lang/String;"); + nameFID = (*env)->GetFieldID(env, GstHeader, "name", "Ljava/lang/String;"); + layerFID = (*env)->GetFieldID(env, GstHeader, "layer", "Ljava/lang/String;"); + bitrateFID = (*env)->GetFieldID(env, GstHeader, "bitrate", + "Ljava/lang/String;"); + framedFID = (*env)->GetFieldID(env, GstHeader, "framed", + "Ljava/lang/String;"); + typeFID = (*env)->GetFieldID(env, GstHeader, "type", "Ljava/lang/String;"); + +#if SIZEOF_VOID_P == 8 + pointerClass = JCL_FindClass (env, "gnu/classpath/Pointer64"); + if (pointerClass != NULL) + { + pointerDataID = (*env)->GetFieldID (env, pointerClass, "data", "J"); + } +#else +# if SIZEOF_VOID_P == 4 + pointerClass = JCL_FindClass (env, "gnu/classpath/Pointer32"); + if (pointerClass != NULL) + { + pointerDataID = (*env)->GetFieldID(env, pointerClass, "data", "I"); + } +# else +# error "Pointer size is not supported." +# endif /* SIZEOF_VOID_P == 4 */ +#endif /* SIZEOF_VOID_P == 8 */ - GstElement *pipeline = NULL; +} - GstElement *typefind = NULL; - GstElement *decodebin = NULL; +JNIEXPORT jboolean JNICALL +Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer_1get_1audio_1format_1stream + (JNIEnv *env, jclass clazz __attribute__ ((unused)), jobject header, + jobject pointer) +{ + GstInputStream *istream = NULL; GstElement *source = NULL; - - AudioProperties *properties = NULL; - - jboolean result = JNI_FALSE; - - GstHeader = (*env)->GetObjectClass(env, header); - + gboolean result = JNI_FALSE; + + if (header == NULL) + return JNI_FALSE; + + if (pointer == NULL) + return JNI_FALSE; + + gst_init (NULL, NULL); + + istream = (GstInputStream *) get_object_from_pointer (env, pointer, + pointerDataID); + if (istream == NULL) + return JNI_FALSE; + + /* init gstreamer */ gst_init (NULL, NULL); - properties = (AudioProperties *) g_malloc0 (sizeof (AudioProperties)); - if (properties == NULL) - { - g_warning ("unable to allocate memory for properties"); - return JNI_FALSE; - } - - /* create the GstInputStream object */ - istream = g_object_new (GST_TYPE_INPUT_STREAM, NULL); - if (istream == NULL) - { - free_properties (properties); - - g_warning ("unable to create an istream"); - return JNI_FALSE; - } - + /* SOURCE */ source = gst_element_factory_make ("classpathsrc", "source"); if (source == NULL) { - free_properties (properties); - g_free ((gpointer) istream); - g_warning ("unable to create a source"); return JNI_FALSE; } - - /* store the vm and the input stream in the gstinputstream class */ - (*env)->GetJavaVM(env, &vm); - g_object_set (G_OBJECT (istream), GST_ISTREAM_JVM, vm, - GST_ISTREAM_READER, jstream, - NULL); g_object_set (G_OBJECT (source), GST_CLASSPATH_SRC_ISTREAM, istream, NULL); - - pipeline = gst_pipeline_new ("pipe"); - if (pipeline == NULL) - { - gst_object_unref (GST_OBJECT (source)); - g_free ((gpointer) istream); - free_properties (properties); - - g_warning ("unable to create the pipeline"); - return JNI_FALSE; - } - - decodebin = gst_element_factory_make ("decodebin", "decodebin"); - if (decodebin == NULL) - { - gst_object_unref (GST_OBJECT (source)); - - g_free ((gpointer) istream); - free_properties(properties); - - gst_object_unref(GST_OBJECT(pipeline)); - - g_warning ("unable to create decodebin"); - return JNI_FALSE; - } - - g_signal_connect (decodebin, "new-decoded-pad", G_CALLBACK (new_decoded_pad), - pipeline); - - gst_bin_add_many (GST_BIN (pipeline), source, decodebin, NULL); - gst_element_link (source, decodebin); - - typefind = gst_bin_get_by_name (GST_BIN (decodebin), "typefind"); - if (typefind == NULL) - { - g_free ((gpointer) istream); - free_properties(properties); - - gst_object_unref(GST_OBJECT(pipeline)); - - g_warning ("unable to create decodebin"); - return JNI_FALSE; - } - - g_signal_connect (G_OBJECT (typefind), "have-type", - G_CALLBACK (typefind_callback), properties); - - gst_element_set_state (GST_ELEMENT(pipeline), GST_STATE_PLAYING); - if (gst_element_get_state (pipeline, NULL, NULL, 100000) == - GST_STATE_CHANGE_FAILURE) - { - g_free ((gpointer) istream); - free_properties(properties); - gst_object_unref(GST_OBJECT(pipeline)); - - g_warning ("Failed to go into PLAYING state"); - return JNI_FALSE; - } - result = JNI_FALSE; - if (fill_info (decodebin, properties)) - { - result = set_strings (env, GstHeader, properties, header); - } + result = process_audio (source, env, header); - gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL); - - gst_object_unref (GST_OBJECT(pipeline)); - free_properties (properties); - return result; } @@ -292,67 +271,71 @@ JNIEXPORT jboolean JNICALL Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer_1get_1audio_1format_1file (JNIEnv *env, jclass clazz __attribute__ ((unused)), jobject header) { - /* will contain the properties we need to put into the given GstHeader */ - AudioProperties *properties = NULL; - /* source file */ const char *file = NULL; /* GStreamer elements */ - GstElement *pipeline = NULL; GstElement *source = NULL; - GstElement *decoder = NULL; - - GstElement *typefind = NULL; - - GstStateChangeReturn res; jboolean result = JNI_FALSE; /* java fields */ - jfieldID _fid = NULL; - jclass GstHeader = NULL; jstring _file = NULL; - GstHeader = (*env)->GetObjectClass(env, header); - _fid = (*env)->GetFieldID(env, GstHeader, "file", "Ljava/lang/String;"); - if (_fid == NULL) - { - return JNI_FALSE; /* failed to find the field */ - } - - _file = (*env)->GetObjectField(env, header, _fid); + _file = (*env)->GetObjectField(env, header, fileFID); file = JCL_jstring_to_cstring (env, _file); if (file == NULL) { return JNI_FALSE; } - - gst_init (NULL, NULL); - - properties = (AudioProperties *) g_malloc0 (sizeof (AudioProperties)); - if (properties == NULL) - { - free_properties (properties); - JCL_free_cstring (env, _file, file); - return JNI_FALSE; - } - - /* this is not really needed */ - reset_properties(properties); + gst_init (NULL, NULL); + /* create the source element, will be used to read the file */ source = gst_element_factory_make ("filesrc", "source"); if (source == NULL) { - free_properties (properties); JCL_free_cstring (env, _file, file); return JNI_FALSE; } /* set the file name */ g_object_set (G_OBJECT (source), "location", file, NULL); + + result = process_audio (source, env, header); + + /* free stuff */ + JCL_free_cstring (env, _file, file); + + return result; +} + +/* ***** END: NATIVE FUNCTIONS ***** */ + +/* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */ + +static jboolean process_audio (GstElement *source, JNIEnv *env, jobject header) +{ + /* will contain the properties we need to put into the given GstHeader */ + AudioProperties *properties = NULL; + + /* GStreamer elements */ + GstElement *pipeline = NULL; + GstElement *decoder = NULL; + + GstElement *typefind = NULL; + GstStateChangeReturn res; + + jboolean result = JNI_FALSE; + + properties = (AudioProperties *) g_malloc0 (sizeof (AudioProperties)); + if (properties == NULL) + { + return result; + } + reset_properties(properties); + /* * create the decoder element, this will decode the stream and retrieve * its properties. @@ -363,30 +346,23 @@ Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer decoder = gst_element_factory_make ("decodebin", "decoder"); if (decoder == NULL) { - gst_object_unref (GST_OBJECT (source)); free_properties(properties); - - JCL_free_cstring (env, _file, file); - return JNI_FALSE; + return result; } - g_signal_connect (decoder, "new-decoded-pad", G_CALLBACK (new_decoded_pad), - pipeline); - g_signal_connect (G_OBJECT (decoder), "element-added", - G_CALLBACK (element_added), properties); - /* now, we create a pipeline and fill it with the other elements */ pipeline = gst_pipeline_new ("pipeline"); if (pipeline == NULL) { - gst_object_unref (GST_OBJECT (source)); gst_object_unref (GST_OBJECT (decoder)); - - free_properties(properties); - - JCL_free_cstring (env, _file, file); - return JNI_FALSE; + free_properties(properties); + return result; } + + g_signal_connect (decoder, "new-decoded-pad", G_CALLBACK (new_decoded_pad), + pipeline); + g_signal_connect (G_OBJECT (decoder), "element-added", + G_CALLBACK (element_added), properties); /* * we get the typefind from the decodebin to catch the additional properties @@ -412,58 +388,51 @@ Java_gnu_javax_sound_sampled_gstreamer_io_GstAudioFileReaderNativePeer_gstreamer * now, we set the pipeline playing state to pause and traverse it * to get the info we need. */ - + res = gst_element_set_state (pipeline, GST_STATE_PAUSED); if (res == GST_STATE_CHANGE_FAILURE) { - JCL_free_cstring (env, _file, file); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); free_properties(properties); - return JNI_FALSE; + return result; } - /* (GstClockTime) 300000000 ? */ res = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); if (res != GST_STATE_CHANGE_SUCCESS) { - JCL_free_cstring (env, _file, file); gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); free_properties(properties); - return JNI_FALSE; + return result; } - result = JNI_FALSE; if (fill_info (decoder, properties)) { - result = set_strings (env, GstHeader, properties, header); + result = set_strings (env, properties, header); } - + /* free stuff */ - JCL_free_cstring (env, _file, file); gst_element_set_state (pipeline, GST_STATE_NULL); + + free_properties (properties); gst_object_unref (GST_OBJECT (pipeline)); - - free_properties (properties); return result; } -/* ***** END: NATIVE FUNCTIONS ***** */ -/* ***** PRIVATE FUNCTIONS IMPLEMENTATION ***** */ static gboolean typefind_callback(GstElement *typefind __attribute__ ((unused)), guint probability __attribute__ ((unused)), const GstCaps *caps, gpointer data) { - GstStructure *structure = NULL; + GstStructure *structure = NULL; AudioProperties *properties = NULL; const char *mpeg = NULL; @@ -494,14 +463,21 @@ static void new_decoded_pad (GstElement *decoder __attribute__ ((unused)), GstPad *pad, gboolean last __attribute__ ((unused)), - GstElement *pipeline) + gpointer data) { + GstElement *pipeline = NULL; GstElement *fakesink = NULL; GstPad *sinkpad = NULL; + pipeline = (GstElement *) data; + if (pipeline == NULL) + return; + fakesink = gst_element_factory_make ("fakesink", NULL); + if (fakesink == NULL) + return; + gst_bin_add (GST_BIN (pipeline), fakesink); - sinkpad = gst_element_get_pad (fakesink, "sink"); if (GST_PAD_LINK_FAILED (gst_pad_link (pad, sinkpad))) { @@ -514,8 +490,7 @@ new_decoded_pad (GstElement *decoder __attribute__ ((unused)), } static gboolean -set_strings (JNIEnv *env, const jclass GstHeader, - const AudioProperties *properties, jobject header) +set_strings (JNIEnv *env, const AudioProperties *properties, jobject header) { gboolean result = FALSE; @@ -525,34 +500,34 @@ set_strings (JNIEnv *env, const jclass GstHeader, */ /* now, map our properties to the java class */ - set_string (env, GstHeader, header, "mimetype", properties->mimetype); + set_string (env, header, mimetypeFID, properties->mimetype); - if (set_string (env, GstHeader, header, "endianness", - properties->endianness)) result = JNI_TRUE; + if (set_string (env, header, endiannessFID, properties->endianness)) + result = JNI_TRUE; - if (set_string (env, GstHeader, header, "channels", - properties->channels)) result = JNI_TRUE; + if (set_string (env, header, channelsFID, properties->channels)) + result = JNI_TRUE; - if (set_string (env, GstHeader, header, "rate", - properties->rate)) result = JNI_TRUE; + if (set_string (env, header, rateFID, properties->rate)) + result = JNI_TRUE; - if (set_string (env, GstHeader, header, "width", - properties->width)) result = JNI_TRUE; + if (set_string (env, header, widthFID, properties->width)) + result = JNI_TRUE; - if (set_string (env, GstHeader, header, "depth", - properties->depth)) result = JNI_TRUE; + if (set_string (env, header, depthFID, properties->depth)) + result = JNI_TRUE; - if (set_string (env, GstHeader, header, "isSigned", - properties->signess)) result = JNI_TRUE; + if (set_string (env, header, isSignedFID, properties->signess)) + result = JNI_TRUE; - if (set_string (env, GstHeader, header, "name", - properties->name)) result = JNI_TRUE; + if (set_string (env, header, nameFID, properties->name)) + result = JNI_TRUE; /* non primary properties */ - set_string (env, GstHeader, header, "layer", properties->layer); - set_string (env, GstHeader, header, "bitrate", properties->bitrate); - set_string (env, GstHeader, header, "framed", properties->framed); - set_string (env, GstHeader, header, "type", properties->type); + set_string (env, header, layerFID, properties->layer); + set_string (env, header, bitrateFID, properties->bitrate); + set_string (env, header, framedFID, properties->framed); + set_string (env, header, typeFID, properties->type); return result; } @@ -562,7 +537,7 @@ static gboolean fill_info (GstElement *decoder, AudioProperties *properties) GstIterator *it = NULL; gpointer data = NULL; gboolean result = FALSE; - + it = gst_element_iterate_src_pads (decoder); while (gst_iterator_next (it, &data) == GST_ITERATOR_OK) { @@ -638,12 +613,15 @@ static gboolean fill_info (GstElement *decoder, AudioProperties *properties) gst_caps_unref (caps); gst_object_unref (pad); } - + return result; } -static void free_properties (AudioProperties *properties) +static void +free_properties (AudioProperties *properties __attribute__ ((unused))) { + /* FIXME this causes a segfault, a string not allocated by us? double free? */ + /* if (properties->name != NULL) g_free((gpointer) properties->name); if (properties->endianness != NULL) g_free((gpointer) properties->endianness); if (properties->channels != NULL) g_free((gpointer) properties->channels); @@ -655,6 +633,7 @@ static void free_properties (AudioProperties *properties) if (properties->framed != NULL) g_free((gpointer) properties->framed); if (properties != NULL) g_free ((gpointer) properties); + */ } static void reset_properties (AudioProperties *properties) @@ -730,38 +709,28 @@ static gchar *get_boolean_property (const GstStructure *structure, return result; } -static gboolean set_string (JNIEnv *env, const jclass GstHeader, - jobject header, - const char *field, +static gboolean set_string (JNIEnv *env, jobject header, jfieldID fieldID, const gchar *property) -{ - jfieldID _fid = NULL; +{ jstring property_string_field = NULL; - if (property == NULL || field == NULL || header == NULL || GstHeader == NULL) + if (property == NULL || header == NULL) { return JNI_FALSE; } - _fid = (*env)->GetFieldID(env, GstHeader, field, "Ljava/lang/String;"); - if (_fid == NULL) - { - return JNI_FALSE; /* failed to find the field */ - } - property_string_field = (*env)->NewStringUTF(env, property); if (property_string_field == NULL) { return JNI_FALSE; } - (*env)->SetObjectField(env, header, _fid, property_string_field); + (*env)->SetObjectField(env, header, fieldID, property_string_field); return JNI_TRUE; } -static void -element_added (GstBin *bin, GstElement *element, gpointer data) +static void element_added (GstBin *bin, GstElement *element, gpointer data) { GstElementFactory *factory; |