Merge with trank @ 137446
[official-gcc.git] / libjava / classpath / native / jni / gstreamer-peer / gst_native_pipeline.c
blob3e32568974676c6a5328f57285d0ba32a6cb846b
1 /*gst_native_pipeline.c - Header file for the GstClasspathPlugin
2 Copyright (C) 2007 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 #include <jni.h>
39 #include <jcl.h>
41 #include <string.h>
42 #include <stdlib.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <sys/wait.h>
48 #include <unistd.h>
50 #ifdef HAVE_FCNTL_H
51 #include <fcntl.h>
52 #endif /* HAVE_FCNTL_H */
54 #if defined(HAVE_SYS_IOCTL_H)
55 #define BSD_COMP /* Get FIONREAD on Solaris2 */
56 #include <sys/ioctl.h>
57 #endif
58 #if defined(HAVE_SYS_FILIO_H) /* Get FIONREAD on Solaris 2.5 */
59 #include <sys/filio.h>
60 #endif
62 #include <gdk/gdk.h>
63 #include <glib.h>
65 #include <gst/gst.h>
67 #include "cpio.h"
68 #include "gst_peer.h"
70 #include "gnu_javax_sound_sampled_gstreamer_lines_GstPipeline.h"
71 #include "gst_native_pipeline.h"
73 static jmethodID pointerConstructorMID = NULL;
75 static jfieldID pipelineFID = NULL;
76 static jfieldID pointerDataFID = NULL;
77 static jfieldID nameFID = NULL;
78 static jfieldID capacityFID = NULL;
81 * Needed to compute the size of the data still available for processing in the
82 * pipeline. We give a default here but this will be overwritten by the
83 * detection routines.
85 static long GST_DETECTED_PIPE_CAPACITY = 65536;
88 * Note: the Java code uses enum classes, these are not mapped into constants
89 * by the javah tool, changes to these values should be reflected in the Java
90 * side.
92 enum
94 PLAY,
95 PAUSE,
96 STOP
100 * Defined as constants in the Java code, hence mapped by javah.
102 enum
104 READ = gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_READ,
105 WRITE = gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_WRITE
108 struct _GstNativePipelinePrivate
110 JavaVM *vm;
111 jclass GstPipelineClass;
112 jclass PointerClass;
114 jobject jni_pipeline;
116 char *name;
117 int fd;
119 GstElement *pipeline;
122 /* ************************************************************************** */
124 static void gst_native_pipeline_clean (GstNativePipeline *self);*/
125 static char *create_name (void);
126 static void init_pointer_IDs (JNIEnv* env);
127 static jint get_free_space (int fd);
128 static void detect_pipe_max (void);
130 /* ************************************************************************** */
132 /* JNI Methods */
134 JNIEXPORT void JNICALL
135 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1id_1cache
136 (JNIEnv *env, jclass clazz)
138 pipelineFID = (*env)->GetFieldID (env, clazz, "pipeline",
139 "Lgnu/classpath/Pointer;");
140 nameFID = (*env)->GetFieldID (env, clazz, "name", "Ljava/lang/String;");
141 capacityFID = (*env)->GetFieldID (env, clazz, "capacity", "J");
143 init_pointer_IDs (env);
146 JNIEXPORT void JNICALL
147 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_init_1instance
148 (JNIEnv *env, jobject pipeline)
150 GstNativePipeline *_pipeline = NULL;
152 jclass localGstPipelineClass = NULL;
153 jclass localPointerClass = NULL;
154 jobject _pointer = NULL;
156 _pipeline =
157 (GstNativePipeline *) JCL_malloc (env, sizeof (GstNativePipeline));
158 if (_pipeline == NULL)
159 return;
161 _pipeline->priv = (GstNativePipelinePrivate *)
162 JCL_malloc (env, sizeof (GstNativePipelinePrivate));
163 if (_pipeline->priv == NULL)
165 JCL_free (env, _pipeline);
166 return;
169 #if SIZEOF_VOID_P == 8
170 localPointerClass = JCL_FindClass (env, "gnu/classpath/Pointer64");
171 #else
172 # if SIZEOF_VOID_P == 4
173 localPointerClass = JCL_FindClass (env, "gnu/classpath/Pointer32");
174 # else
175 # error "Pointer size is not supported."
176 # endif /* SIZEOF_VOID_P == 4 */
177 #endif /* SIZEOF_VOID_P == 8 */
179 localGstPipelineClass = (*env)->GetObjectClass(env, pipeline);
180 if (localGstPipelineClass == NULL || localGstPipelineClass == NULL)
182 JCL_free (env, _pipeline->priv);
183 JCL_free (env, _pipeline);
184 JCL_ThrowException (env, "java/lang/InternalError",
185 "Class Initialization failed.");
186 return;
189 GST_DETECTED_PIPE_CAPACITY = (long) (*env)->GetLongField(env, pipeline,
190 capacityFID);
192 /* fill the object */
193 (*env)->GetJavaVM(env, &_pipeline->priv->vm);
194 _pipeline->priv->jni_pipeline = (*env)->NewGlobalRef(env, pipeline);
195 _pipeline->priv->GstPipelineClass =
196 (*env)->NewGlobalRef(env, localGstPipelineClass);
197 _pipeline->priv->PointerClass = (*env)->NewGlobalRef(env, localPointerClass);
198 _pipeline->priv->pipeline = NULL;
200 _pointer = (*env)->GetObjectField(env, pipeline, pipelineFID);
202 if (_pointer == NULL)
204 #if SIZEOF_VOID_P == 8
205 _pointer = (*env)->NewObject(env, _pipeline->priv->PointerClass,
206 pointerConstructorMID, (jlong) _pipeline);
207 #else
208 _pointer = (*env)->NewObject(env, _pipeline->priv->PointerClass,
209 pointerConstructorMID, (jint) _pipeline);
210 #endif
212 else
214 #if SIZEOF_VOID_P == 8
215 (*env)->SetLongField(env, pipeline, pipelineFID, (jlong) _pipeline);
216 #else
217 (*env)->SetIntField(env, pipeline, pipelineFID, (jint) _pipeline);
218 #endif
221 /* store back our pointer into the calling class */
222 (*env)->SetObjectField(env, pipeline, pipelineFID, _pointer);
225 JNIEXPORT jboolean JNICALL
226 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_set_1state
227 (JNIEnv *env, jclass clazz, jobject pointer, jint state)
229 GstNativePipeline *jpipeline = NULL;
230 jboolean result = JNI_FALSE;
232 if (pointer == NULL)
234 JCL_ThrowException (env, "javax/sound/sampled/LineUnavailableException",
235 "Can't change pipeline state: " \
236 "pipeline not initialized");
237 return result;
240 jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer,
241 pointerDataFID);
242 if (jpipeline == NULL)
243 return JNI_FALSE;
245 switch (state)
247 case (PLAY):
248 gst_element_set_state(GST_ELEMENT(jpipeline->priv->pipeline),
249 GST_STATE_PLAYING);
250 result = JNI_TRUE;
251 break;
253 case (PAUSE):
254 gst_element_set_state(GST_ELEMENT(jpipeline->priv->pipeline),
255 GST_STATE_PAUSED);
256 result = JNI_TRUE;
257 break;
259 case (STOP):
260 #ifndef WITHOUT_FILESYSTEM
261 /* clean the pipeline and kill named pipe */
262 if (jpipeline->priv->name)
264 cpio_removeFile (jpipeline->priv->name);
265 g_free (jpipeline->priv->name);
266 jpipeline->priv->name = NULL;
268 #endif /* WITHOUT_FILESYSTEM */
270 if (jpipeline->priv->pipeline != NULL)
271 gst_object_unref (GST_OBJECT(jpipeline->priv->pipeline));
272 result = JNI_TRUE;
273 break;
275 default:
276 /* nothing */
277 result = JNI_FALSE;
278 break;
281 return result;
284 JNIEXPORT void JNICALL
285 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_open_1native_1pipe
286 (JNIEnv *env, jclass clazz, jobject pointer, jint mode)
288 GstNativePipeline *jpipeline = NULL;
290 jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer,
291 pointerDataFID);
292 switch (mode)
294 case (READ):
295 jpipeline->priv->fd =
296 open (jpipeline->priv->name, O_RDONLY | O_NONBLOCK);
297 break;
299 case (WRITE):
300 /* TODO: no-op currently */
301 break;
305 JNIEXPORT void JNICALL
306 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_close_1native_1pipe
307 (JNIEnv *env, jclass clazz, jobject pointer)
309 #ifndef WITHOUT_FILESYSTEM
310 GstNativePipeline *jpipeline = NULL;
311 jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer,
312 pointerDataFID);
313 /* kill the named pipe */
314 if (jpipeline->priv->name)
316 cpio_removeFile (jpipeline->priv->name);
317 g_free (jpipeline->priv->name);
318 jpipeline->priv->name = NULL;
320 #endif /* WITHOUT_FILESYSTEM */
323 JNIEXPORT jboolean JNICALL
324 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_create_1named_1pipe
325 (JNIEnv *env, jobject GstPipeline, jobject pointer)
327 #ifndef WITHOUT_FILESYSTEM
329 * We get a temp name for the named pipe, create the named pipe and then
330 * set the relative field in the java class.
332 GstNativePipeline *jpipeline = NULL;
333 jstring *name = NULL;
335 jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer,
336 pointerDataFID);
337 if (jpipeline == NULL)
338 return JNI_FALSE;
340 jpipeline->priv->name = create_name ();
341 if (jpipeline->priv->name == NULL)
342 return JNI_FALSE;
344 if (mkfifo (jpipeline->priv->name, 0600) < 0)
346 if (jpipeline->priv->name != NULL)
347 free (jpipeline->priv->name);
348 return JNI_FALSE;
351 /* now set the String field */
352 name = (*env)->NewStringUTF(env, jpipeline->priv->name);
353 if (name == NULL)
355 cpio_removeFile (jpipeline->priv->name);
356 if (jpipeline->priv->name != NULL)
357 free (jpipeline->priv->name);
359 return JNI_FALSE;
362 (*env)->SetObjectField(env, GstPipeline, nameFID, name);
364 return JNI_TRUE;
366 #else /* not WITHOUT_FILESYSTEM */
367 return JNI_FALSE;
368 #endif /* not WITHOUT_FILESYSTEM */
371 JNIEXPORT jint JNICALL
372 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_available
373 (JNIEnv *env, jclass clazz, jobject pointer, jint mode)
375 jint result = -1;
377 #ifndef WITHOUT_FILESYSTEM
379 GstNativePipeline *jpipeline = NULL;
380 jpipeline = (GstNativePipeline *) get_object_from_pointer (env, pointer,
381 pointerDataFID);
383 if (mode == READ)
385 result = get_free_space (jpipeline->priv->fd);
387 else
389 # if defined (FIONREAD)
390 if (ioctl (jpipeline->priv->fd, FIONREAD, &result) == -1)
391 g_warning("IMPLEMENT ME: ioctl failed");
393 # else /* not defined (FIONREAD) */
394 g_warning("IMPLEMENT ME: !defined (FIONREAD");
395 # endif /* defined (FIONREAD) */
397 } /* if (mode == READ) */
399 #endif /* not WITHOUT_FILESYSTEM */
401 return result;
404 JNIEXPORT jlong JNICALL
405 Java_gnu_javax_sound_sampled_gstreamer_lines_GstPipeline_detect_1pipe_1size
406 (JNIEnv *env, jobject GstPipeline)
408 detect_pipe_max ();
410 return GST_DETECTED_PIPE_CAPACITY;
413 /* exported library functions */
415 static void gst_native_pipeline_clean (GstNativePipeline *self)
417 JNIEnv *env = NULL;
419 env = gst_get_jenv (self->priv->vm);
421 (*env)->DeleteGlobalRef (env, self->priv->jni_pipeline);
422 (*env)->DeleteGlobalRef (env, self->priv->GstPipelineClass);
423 (*env)->DeleteGlobalRef (env, self->priv->PointerClass);
425 if (self->priv->pipeline != NULL)
426 gst_object_unref (GST_OBJECT (self->priv->pipeline));
428 if (self->priv->name)
430 cpio_removeFile (self->priv->name);
431 g_free (self->priv->name);
432 self->priv->name = NULL;
435 JCL_free (env, self->priv);
436 JCL_free (env, self);
439 void gst_native_pipeline_set_pipeline (GstNativePipeline *self,
440 GstElement *pipeline)
442 if (self->priv->pipeline != NULL)
443 gst_object_unref (GST_OBJECT (self->priv->pipeline));
445 self->priv->pipeline = pipeline;
448 GstElement *gst_native_pipeline_get_pipeline (GstNativePipeline *self)
450 return self->priv->pipeline;
453 char *gst_native_pipeline_get_pipeline_name (GstNativePipeline *self)
455 return self->priv->name;
458 int gst_native_pipeline_get_pipeline_fd (GstNativePipeline *self)
460 return self->priv->fd;
463 /* private functions */
465 static void init_pointer_IDs (JNIEnv* env)
467 jclass PointerClass = NULL;
469 #if SIZEOF_VOID_P == 8
470 PointerClass = JCL_FindClass (env, "gnu/classpath/Pointer64");
471 if (PointerClass != NULL)
473 pointerDataFID = (*env)->GetFieldID (env, PointerClass, "data", "J");
474 pointerConstructorMID = (*env)->GetMethodID (env, PointerClass, "<init>",
475 "(J)V");
477 #else
478 # if SIZEOF_VOID_P == 4
479 PointerClass = JCL_FindClass (env, "gnu/classpath/Pointer32");
480 if (PointerClass != NULL)
482 pointerDataFID = (*env)->GetFieldID(env, PointerClass, "data", "I");
483 pointerConstructorMID = (*env)->GetMethodID(env, PointerClass,
484 "<init>", "(I)V");
486 # else
487 # error "Pointer size is not supported."
488 # endif /* SIZEOF_VOID_P == 4 */
489 #endif /* SIZEOF_VOID_P == 8 */
492 static jint get_free_space (int fd)
494 jint result = -1;
496 #if defined (FIONSPACE)
498 if (ioctl (fd, FIONSPACE, &result) == -1)
500 g_warning("IMPLEMENT ME: ioctl failed");
503 #elif defined (FIONREAD)
505 if (ioctl (fd, FIONREAD, &result) == -1)
507 g_warning("IMPLEMENT ME: ioctl failed");
510 result = GST_DETECTED_PIPE_CAPACITY - result;
512 #elif
513 g_warning("IMPLEMENT ME!!! - !defined (FIONSPACE), !defined (FIONREAD");
515 #endif
517 return result;
520 static char *create_name (void)
522 char *buffer = NULL;
523 char *tmp = NULL;
525 buffer = (char *) g_malloc0 (_GST_MALLOC_SIZE_);
526 if (buffer == NULL)
528 /* huston, we have a problem... */
529 return NULL;
532 tmp = tempnam (NULL, _GST_PIPELINE_PREFIX_);
533 if (tmp == NULL)
535 g_free (buffer);
536 return NULL;
539 g_snprintf (buffer, _GST_MALLOC_SIZE_, "%s%s", tmp, _GST_PIPELINE_SUFFIX_);
540 g_free (tmp);
542 return buffer;
545 static void detect_pipe_max (void)
547 int read_fd;
548 int write_fd;
550 /* can be anything! */
551 char *character = "a";
552 char *pipe = NULL;
554 gboolean available = TRUE;
555 int w = 0;
556 long wrote = 0;
558 pipe = create_name ();
559 if (pipe == NULL)
561 g_warning ("can't create test pipe name");
562 return;
565 if (mkfifo (pipe, 0600) < 0)
567 g_warning ("unable to create test pipe...");
568 g_free (pipe);
570 return;
573 /* open both end of the pipe */
574 read_fd = open (pipe, O_RDONLY | O_NONBLOCK);
575 if (read_fd < 0)
577 cpio_removeFile (pipe);
578 g_free (pipe);
580 return;
583 write_fd = open (pipe, O_WRONLY | O_NONBLOCK);
584 if (write_fd < 0)
586 cpio_closeFile (write_fd);
587 cpio_removeFile (pipe);
588 g_free (pipe);
590 return;
593 while (available)
595 w = 0;
597 cpio_write (write_fd, character, 1, &w);
598 if (w < 0)
599 available = FALSE;
600 else
601 wrote += w;
604 GST_DETECTED_PIPE_CAPACITY = wrote;
606 cpio_closeFile (write_fd);
607 cpio_closeFile (read_fd);
608 cpio_removeFile (pipe);
610 g_free (pipe);