changeset 28:dbffaa5c4944

its coming along committer: Omair Majid <omajid@redhat.com>
author Omair Majid <omajid@redhat.com>
date Fri, 01 Aug 2008 11:03:52 -0400
parents f1a1eaa0f610
children f05acd4ee58b
files src/jni-common.c src/jni-common.h src/org/openjdk/sound/EventLoop.java src/org/openjdk/sound/PulseAudioSourceDataLine.java src/org_openjdk_sound_PulseAudioSourceDataLine.c
diffstat 5 files changed, 224 insertions(+), 51 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:03:52 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:03:52 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	Thu Jul 31 17:29:47 2008 -0400
+++ b/src/org/openjdk/sound/EventLoop.java	Fri Aug 01 11:03:52 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	Thu Jul 31 17:29:47 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioSourceDataLine.java	Fri Aug 01 11:03:52 2008 -0400
@@ -15,43 +15,46 @@
 
 public class PulseAudioSourceDataLine implements SourceDataLine {
 
-	
-	
 	private static final int DEFAULT_BUFFER_SIZE = 1000;
 	private String streamName = "Java Stream";
-	
+
 	private EventLoop eventLoop = null;
 
 	private boolean isOpen = false;
 	private boolean isPaused = false;
 
-	private final AudioFormat format = null;
-	
+	private final AudioFormat lineFormat = null;
+
 	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 {
 		try {
 			String library = new java.io.File(".").getCanonicalPath()
@@ -78,9 +81,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);
 		}
 	}
 
@@ -90,30 +94,51 @@
 	}
 
 	public void open() throws LineUnavailableException {
-//		format = new AudioFormat(Encoding.PCM_SIGNED, 44100, 16, 2, );
-		
-//		synchronized (eventLoop.threadLock) {
-//			openStream("PCM_SIGNED", 44100, 16, 2, false, DEFAULT_BUFFER_SIZE);
-//
-//		}
-		
+		// format = new AudioFormat(Encoding.PCM_SIGNED, 44100, 16, 2, );
+
+		// synchronized (eventLoop.threadLock) {
+		// openStream("PCM_SIGNED", 44100, 16, 2, false, DEFAULT_BUFFER_SIZE);
+		//
+		// }
+
 		open(null);
-		
+
 	}
 
-	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() {
@@ -156,15 +181,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	Thu Jul 31 17:29:47 2008 -0400
+++ b/src/org_openjdk_sound_PulseAudioSourceDataLine.c	Fri Aug 01 11:03:52 2008 -0400
@@ -2,13 +2,133 @@
 
 #include <pulse/pulseaudio.h>
 
+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
  * Signature: (ILjava/lang/String;Ljava/lang/String;FIIZI)V
  */
 JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_native_1open
-(JNIEnv* env, jobject obj, jint arg, jstring arg1, jstring arg2, jfloat arg3, jint arg4, jint arg5, jboolean arg6, jint arg7) {
+(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");
+
+	pa_context* context = (pa_context*) contextPointer;
+	assert(context != NULL);
+
+	obj = (*env)->NewGlobalRef(env, obj);
+
+	java_context_t* java_context = malloc(sizeof(java_context));
+	java_context->env = env;
+	java_context->obj = obj;
+
+	pa_sample_spec sample_spec;
+
+	const char* encoding = (*env)->GetStringUTFChars(env, encodingString, NULL);
+
+	if( (strcmp(encoding, "PCM_UNSIGNED") == 0) && (size == 8)) {
+		sample_spec.format = PA_SAMPLE_U8;
+	} else if( (strcmp(encoding, "ALAW") == 0) && (size == 8)) {
+		sample_spec.format = PA_SAMPLE_ALAW;
+	} else if( (strcmp(encoding, "ULAW") == 0) && (size == 8)) {
+		sample_spec.format = PA_SAMPLE_ULAW;
+	} else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 1)) {
+		sample_spec.format = PA_SAMPLE_S16BE;
+	} else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 16) && (bigEndian == 0)) {
+		sample_spec.format = PA_SAMPLE_S16LE;
+	} else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 1)) {
+		sample_spec.format = PA_SAMPLE_S32BE;
+	} else if ( (strcmp(encoding, "PCM_SIGNED") == 0) && (size == 32) && (bigEndian == 0)) {
+		sample_spec.format = PA_SAMPLE_S32LE;
+	} else {
+		printf("error in open");
+		(*env)->Throw
+	}
+
+	sample_spec.rate = rate;
+	sample_spec.channels = channels;
+
+	/* 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);
+
+	pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL);
+
+	jclass cls = (*env)->GetObjectClass(env,obj);
+	jfieldID fid = (*env)->GetFieldID(env, cls, "streamPointer", "I");
+	(*env)->SetIntField(env, obj, fid, (jint) stream);
+
+	printf("returning from native_open\n");
 
 }
 
@@ -18,14 +138,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);
+
 }
 
 /*
@@ -35,12 +159,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);
+
 }
 
 /*