changeset 30:f05acd4ee58b

merging changes committer: Omair Majid <omajid@redhat.com>
author Omair Majid <omajid@redhat.com>
date Fri, 01 Aug 2008 11:22:31 -0400
parents b9836224602b (current diff) dbffaa5c4944 (diff)
children 70d51e08abbb
files src/org/openjdk/sound/PulseAudioSourceDataLine.java src/org_openjdk_sound_PulseAudioSourceDataLine.c
diffstat 5 files changed, 177 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jni-common.c	Fri Aug 01 11:22:31 2008 -0400
@@ -0,0 +1,4 @@
+#include "jni-common.h"
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jni-common.h	Fri Aug 01 11:22:31 2008 -0400
@@ -0,0 +1,15 @@
+#ifndef _JNI_COMMON_H
+#define _JNI_COMMON_H
+
+
+/*
+ * This file contains some commonly used functions 
+ * 
+ */
+
+
+
+
+
+
+#endif
\ No newline at end of file
--- a/src/org/openjdk/sound/EventLoop.java	Fri Aug 01 10:59:19 2008 -0400
+++ b/src/org/openjdk/sound/EventLoop.java	Fri Aug 01 11:22:31 2008 -0400
@@ -49,7 +49,16 @@
 	private native void native_set_sink_volume(int contextPointer,
 			int streamPointer, int volume);
 
-	// pointers
+	/*
+	 * These fields hold pointers
+	 * 
+	 * When going from 32 bit to 64 bit, these will have to be changed to longs,
+	 * but not otherwise
+	 * 
+	 * Pointer sizes change from 32 bit to 64 bit, but java data types's sizes
+	 * dont
+	 * 
+	 */
 	@SuppressWarnings("unused")
 	private int contextPointer;
 	@SuppressWarnings("unused")
@@ -76,8 +85,6 @@
 		contextListeners = new ArrayList<ContextListener>();
 	}
 
-
-
 	public void setAppName(String name) {
 		this.name = name;
 	}
--- a/src/org/openjdk/sound/PulseAudioSourceDataLine.java	Fri Aug 01 10:59:19 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioSourceDataLine.java	Fri Aug 01 11:22:31 2008 -0400
@@ -18,13 +18,10 @@
 
 public class PulseAudioSourceDataLine implements SourceDataLine {
 
-	
-	
 	private static final int DEFAULT_BUFFER_SIZE = 1000;
 	private String streamName = "Java Stream";
 	private List<StreamListener> streamListeners = new ArrayList();
 
-	
 	private EventLoop eventLoop = null;
 
 	private boolean isOpen = false;
@@ -34,30 +31,36 @@
 	
 	private ArrayList<LineListener> listeners;
 
+	/*
+	 * When moving from 32bit platform to 64 bit platform, these variables that
+	 * hold pointers will need their sizes changed
+	 * 
+	 */
 	@SuppressWarnings("unused")
 	private int streamPointer;
 
-	private native void native_open(int contextPointer, String name, String encoding, float rate, int size,
-			int channels, boolean bigEndian, int bufferSize);
+	private native void native_open(int contextPointer, String name,
+			String encoding, float rate, int size, int channels,
+			boolean bigEndian, int bufferSize);
 
 	private native void native_write(byte[] data, int offset, int length);
 
 	private native int native_get_writable_size();
 
 	private native void native_flush();
-	
+
 	private native void native_start();
-	
+
 	private native void native_pause();
 
 	private native void native_resume();
-	
+
 	private native void native_drain();
 
 	private native void native_close();
 
 
-	/*static {
+	static {
 		try {
 			String library = new java.io.File(".").getCanonicalPath()
 					+ java.io.File.separatorChar + "lib"
@@ -68,7 +71,7 @@
 		} catch (IOException e) {
 			assert ("Loading failed".endsWith("library"));
 		}
-	}*/
+    }
 
 	public PulseAudioSourceDataLine(EventLoop eventLoop) {
 		this.eventLoop = eventLoop;
@@ -83,9 +86,10 @@
 		int sampleSize = format.getSampleSizeInBits();
 		String encoding = format.getEncoding().toString();
 		boolean bigEndian = format.isBigEndian();
-		
+
 		synchronized (eventLoop.threadLock) {
-			native_open(eventLoop.getContextPointer(), streamName, encoding, rate, sampleSize, channels, bigEndian, bufferSize);
+			native_open(eventLoop.getContextPointer(), streamName, encoding,
+					rate, sampleSize, channels, bigEndian, bufferSize);
 		}
 	}
 
@@ -97,22 +101,42 @@
 	public void open() throws LineUnavailableException {
 		format = new AudioFormat(44100, 16, 2, true, false);
 		open(format, DEFAULT_BUFFER_SIZE);
-		
 	}
 
-	public int write(byte[] data, int off, int len) {
-		// FIXME
-		
-		
-		synchronized (eventLoop.threadLock) {
-			native_write(data, off, len);
+	@Override
+	public int write(byte[] data, int offset, int length) {
+
+		int position = offset;
+		int remainingLength = length;
+		int availableSize;
+
+		int sizeWritten = 0;
+
+		while (remainingLength != 0) {
+
+			synchronized (eventLoop.threadLock) {
+				availableSize = native_get_writable_size();
+				if (availableSize < 0) {
+					return sizeWritten;
+				}
+				if (availableSize > remainingLength) {
+					availableSize = remainingLength;
+				}
+				/* write a little bit of the buffer */
+				native_write(data, position, availableSize);
+
+				sizeWritten += availableSize;
+				position += availableSize;
+				remainingLength -= availableSize;
+
+			}
 		}
 
-		/*
-		 * FIXME when the stream is flushed() etc, instead of returning length
-		 * this should unblock and return the the size of data written so far
-		 */
-		return len;
+		// all the data should have been played by now
+		assert (sizeWritten == length);
+
+		return sizeWritten;
+
 	}
 
 	public void start() {
@@ -189,15 +213,13 @@
 		synchronized (eventLoop.threadLock) {
 			native_close();
 		}
-		
-		
+
 		for (LineListener l : this.listeners) {
 			l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0));
 		}
 
 	}
 
-
 	public int getBufferSize() {
 		// TODO Auto-generated method stub
 		return 0;
--- a/src/org_openjdk_sound_PulseAudioSourceDataLine.c	Fri Aug 01 10:59:19 2008 -0400
+++ b/src/org_openjdk_sound_PulseAudioSourceDataLine.c	Fri Aug 01 11:22:31 2008 -0400
@@ -10,15 +10,14 @@
 	jlong value = (int) ptr;
 	jfieldID fid =(*env)->GetFieldID(env, cls, fieldName, "I");
 	(*env)->SetIntField(env, obj, fid, value);
-	//CHECK No DeleteLocalReference Method?
-	//(*env)->DeleteLocalReference(cls);
+	(*env)->DeleteLocalReference(cls);
 }
 
 void *getJavaIntField(JNIEnv *env, jobject obj, char *fieldName) {
-jclass cls = (*env)->GetObjectClass(env, obj);
+    jclass cls = (*env)->GetObjectClass(env, obj);
 	jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "I");
 	jlong value = (*env)->GetIntField(env, obj, fid);
-	//(*env)->DeleteLocalReference(cls);
+	(*env)->DeleteLocalReference(cls);
 	return (void *) value;
 }
 
@@ -86,6 +85,66 @@
 
 
 
+typedef struct java_context_t {
+	JNIEnv* env;
+	jobject obj;
+} java_context_t;
+
+
+/* defined in EventLoop.c */
+extern JNIEnv* pulse_thread_env;
+
+
+
+static void stream_state_change_callback(pa_stream* stream, void* userdata) {
+	assert(stream);
+	assert(userdata);
+
+	printf("entering stream_state_change_callback\n");
+
+	java_context_t* java_context = (java_context_t*)userdata;
+	JNIEnv* env;
+	
+	/* needed so we can create a stream from another thread
+	 */
+	if (pa_stream_get_state(stream) == PA_STREAM_CREATING) {
+		printf("java thread\n");
+		env = java_context->env;
+	} else {
+		env = pulse_thread_env;
+	}
+
+	jobject obj = java_context->obj;
+
+	printf("stream state changed to %d\n", pa_stream_get_state(stream));
+
+	/* Call the 'update' method in java
+	 * to handle all java-side events
+	 */
+	jclass cls = (*env)->GetObjectClass(env, obj);
+	if (cls == NULL) {
+		printf("unable to get class of object");
+		return;
+	}
+	jmethodID mid = (*env)->GetMethodID(env, cls, "update", "(I)V");
+	if (mid == NULL) {
+		printf("unable to get callback method\n");
+		return;
+
+	}
+	printf("calling update on java\n");
+	(*env)->CallVoidMethod(env, obj, mid, pa_stream_get_state(stream));
+
+	printf("returning form stream_state_change_callback\n");
+	return;
+
+}
+
+
+
+
+
+
 /*
  * Class:     org_openjdk_sound_PulseAudioSourceDataLine
  * Method:    native_open
@@ -94,12 +153,16 @@
 JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1open
 (JNIEnv* env, jobject obj, jint contextPointer, jstring name, jstring encodingString, jfloat rate, jint size, jint channels, jboolean bigEndian, jint bufferSize) {
 
+	//TODO: Need to deal with the buffer size. Currently ignored
+
+	printf("entering native_open\n");
 	java_context_t* java_context = malloc(sizeof(java_context));
 	java_context->env = env;
-;
 	java_context->obj = (*env)->NewGlobalRef(env, obj);
-;
-	    
+
+	pa_context* context = (pa_context*) contextPointer;
+	assert(context != NULL);
+
     pa_sample_spec sample_spec;
     
     char *encoding = (*env)->GetStringUTFChars(env, encodingString, NULL);
@@ -120,20 +183,28 @@
 	sample_spec.format = PA_SAMPLE_S32LE;
      } else {
      	printf("error in open");
-     	//TO DO: Invalid format :throw Exception;
+     	//TODO: Invalid format :throw Exception;
      }
     
     sample_spec.rate = rate;
     sample_spec.channels = channels;
 
-    
-    pa_stream *stream = pa_stream_new(contextPointer, "default stream", &sample_spec, NULL);
+	/* obtain the server from the caller */
+	const jbyte* stream_name = NULL;
+	stream_name = (*env)->GetStringUTFChars(env, name, NULL);
+	if (stream_name == NULL) {
+		return; /* OutOfMemoryError */
+	}
+	printf("About to create stream: %s\n", stream_name);
+	pa_stream* stream = pa_stream_new(context, stream_name, &sample_spec, NULL);
+	assert(stream != NULL);
+	(*env)->ReleaseStringUTFChars(env, name, stream_name);
 
     pa_stream_set_state_callback(stream, stream_state_change_callback, java_context);
   
-
+    setJavaIntField(env, obj, stream, "streamPointer");    
+	printf("returning from native_open\n");
 
-    setJavaIntField(env, obj, stream, "streamPointer");    
 }
 
 /*
@@ -142,14 +213,18 @@
  * Signature: ([BII)V
  */
 JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1write
-(JNIEnv* env, jobject obj, jbyteArray arr, jint int1, jint int2) {
+(JNIEnv* env, jobject obj, jbyteArray buffer, jint offset, jint length) {
 
-//	pa_stream* stream = (pa_stream*) streamPointer;
-//	jbyte* data_buffer = (*env)->GetByteArrayElements(env, data, NULL);
-//
-//	pa_stream_write(stream, data_buffer, data_length, NULL, 0, PA_SEEK_RELATIVE);
-//	(*env)->ReleaseByteArrayElements(env, data, data_buffer, 0);
+	jclass cls = (*env)->GetObjectClass(env, obj);
+	jfieldID fid = (*env)->GetFieldID(env, cls, "streamPointer", "I");
+	assert(fid);
 	
+	pa_stream* stream = (pa_stream*) (*env)->GetIntField(env, obj, fid);
+	jbyte* data_buffer = (*env)->GetByteArrayElements(env, data, NULL);
+
+	pa_stream_write(stream, data_buffer, data_length, NULL, 0, PA_SEEK_RELATIVE);
+	(*env)->ReleaseByteArrayElements(env, data, data_buffer, 0);
+
 }
 
 /*
@@ -159,12 +234,12 @@
  */
 JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1get_1writable_1size
 (JNIEnv* env, jobject obj) {
-	
-//	jfieldID fid = (*env)->GetIntField
-//	
-//	pa_stream* stream = (pa_stream*)streamPointer;
-//	return pa_stream_writable_size(stream);
-	
+
+	//	jfieldID fid = (*env)->GetIntField
+	//	
+	//	pa_stream* stream = (pa_stream*)streamPointer;
+	//	return pa_stream_writable_size(stream);
+
 }
 
 /*