changeset 24:03101556665f

fixed errors committer: Ioana Ivan <iivan@redhat.com>
author Ioana Ivan <iivan@redhat.com>
date Tue, 29 Jul 2008 11:46:39 -0400
parents 9ce846af2c4d
children 7fc1bc131b7e
files src/org/openjdk/sound/PulseAudioTargetDataLine.java src/org_openjdk_sound_PulseAudioTargetDataLine.c
diffstat 2 files changed, 361 insertions(+), 106 deletions(-) [+]
line wrap: on
line diff
--- a/src/org/openjdk/sound/PulseAudioTargetDataLine.java	Tue Jul 29 11:29:44 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioTargetDataLine.java	Tue Jul 29 11:46:39 2008 -0400
@@ -1,75 +1,84 @@
 package org.openjdk.sound;
-import java.io.File;
+import java.util.ArrayList;
+
+import javax.sound.sampled.*;
+import javax.sound.sampled.Control.Type;
+
+
 
-import javax.sound.sampled.AudioFormat;
-import javax.sound.sampled.AudioInputStream;
-import javax.sound.sampled.AudioSystem;
-import javax.sound.sampled.Control;
-import javax.sound.sampled.LineListener;
-import javax.sound.sampled.LineUnavailableException;
-import javax.sound.sampled.TargetDataLine;
-import javax.sound.sampled.Control.Type;
-public class PulseAudioTargetDataLine implements TargetDataLine {
+public class PulseAudioTargetDataLine  implements TargetDataLine {
+	
+	protected long contextPointer;
+	protected long mainLoopPointer;
+	protected long streamPointer;
+	protected boolean isOpen = false;
+	protected boolean isPaused = false;
+	protected int defaultBufferSize;
+	protected ArrayList<LineListener> listeners;
 	
-	private boolean isOpen = false;
-	private long nativeObject;
-	
-	public boolean isOpen() {
-		return isOpen;
+	public void open(AudioFormat format, int bufferSize) throws LineUnavailableException {
+		isOpen = true;
+		
+		int channels = format.getChannels();
+		float rate = format.getSampleRate();
+		int sampleSize = format.getSampleSizeInBits();
+		String encoding = format.getEncoding().toString();
+		boolean bigEndian = format.isBigEndian();
+		openStream(encoding, rate, sampleSize, channels, bigEndian, bufferSize);
+	}
+
+	public void open(AudioFormat format) throws LineUnavailableException {
+		open(format, defaultBufferSize);
+		
 	}
 	
-	public void open(AudioFormat format) {
-		int channels = format.getChannels();
-		float rate = format.getFrameRate();
-		boolean bigEndian = format.isBigEndian();
-		AudioFormat.Encoding encoding = format.getEncoding();
-		openConnection(channels, rate);
+
+	public void open() throws LineUnavailableException {
+		openStream("PCM_SIGNED", 44100, 16, 2, false, defaultBufferSize);
 	}
-	
-	private native void openConnection(int channels, float rate);
-	private native void write(byte[]data, int bytes, int index);
-	private native void closeConnection();
-	
-	public static void main(String[] args)throws Exception{
-		File	soundFile = new File("/home/yyz/iivan/pulse-test/sound.wav");
-		AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile);
-		AudioFormat	audioFormat = audioInputStream.getFormat();
-		PulseAudioSourceDataLine line = new PulseAudioSourceDataLine(1,1);
-		line.open(audioFormat);
-		byte[]	abData = new byte[10000];
-		int bytesRead = 0;
 
-		while ( bytesRead >= 0) {
-			bytesRead = audioInputStream.read(abData, 0, abData.length);
-			if (bytesRead > 0) {
-		    		line.write(abData, bytesRead, 0);
-		    	}
-	    }
-	    line.closeConnection();
-    }
-	
+	private native void openStream(String encoding, float rate, int size, int channels, boolean bigEndian, int bufferSize);
+
 	static {
 		System.loadLibrary("PulseAudioSourceDataLine");
 	}
 
-	@Override
-	public void open(AudioFormat format, int bufferSize)
-			throws LineUnavailableException {
-		// TODO Auto-generated method stub
-		
-	}
+
 
 	@Override
 	public int read(byte[] b, int off, int len) {
-		// TODO Auto-generated method stub
-		return 0;
+		readFromStream(b, off, len);
+		return len;
 	}
+	
+	private native void readFromStream(byte[] b, int off, int len);
+
+
 
-	@Override
-	public int available() {
-		// TODO Auto-generated method stub
-		return 0;
+	public void start() {
+		if (isPaused) {
+			resumeStream();
+			isPaused = false;
+		} else {
+			startStream();
+		}
+		
+		for(LineListener l :listeners) {
+			l.update(new LineEvent(this, LineEvent.Type.START, 0));
+		}
 	}
+	
+	public void stop() {
+		pauseStream();
+		isPaused = true;
+		
+		
+	}
+	
+	private native void startStream();
+	private native void pauseStream();
+	private native void resumeStream();
+	
 
 	@Override
 	public void drain() {
@@ -82,114 +91,101 @@
 		// TODO Auto-generated method stub
 		
 	}
-
-	@Override
+	
+	public void addLineListener(LineListener listener){
+		listeners.add(listener);
+	}
+	
+	public void removeLineListener(LineListener listener){
+		listeners.remove(listener);
+	}
+	
+	public boolean isOpen() {
+		return isOpen;
+	}
+	
+	public native int available();
+	
+	public void close() {
+		closeStream();
+		for (LineListener l : listeners) {
+			l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0));
+		}
+		
+	}
+	
+	private native void closeStream();
+	
 	public int getBufferSize() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-	@Override
+
 	public AudioFormat getFormat() {
 		// TODO Auto-generated method stub
 		return null;
 	}
 
-	@Override
+
 	public int getFramePosition() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-	@Override
+	
 	public float getLevel() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-	@Override
+	
 	public long getLongFramePosition() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-	@Override
+
 	public long getMicrosecondPosition() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-	@Override
+
 	public boolean isActive() {
 		// TODO Auto-generated method stub
 		return false;
 	}
 
-	@Override
 	public boolean isRunning() {
 		// TODO Auto-generated method stub
 		return false;
 	}
-
-	@Override
-	public void start() {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public void stop() {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public void addLineListener(LineListener listener) {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public void close() {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
+	
 	public Control getControl(Type control) {
 		// TODO Auto-generated method stub
 		return null;
 	}
 
-	@Override
+
 	public Control[] getControls() {
 		// TODO Auto-generated method stub
 		return null;
 	}
 
-	@Override
+
 	public javax.sound.sampled.Line.Info getLineInfo() {
-		// TODO Auto-generated method stub
-		return null;
+		return new Line.Info(SourceDataLine.class);
 	}
 
-	@Override
+
 	public boolean isControlSupported(Type control) {
 		// TODO Auto-generated method stub
 		return false;
 	}
 
-	@Override
-	public void open() throws LineUnavailableException {
-		// TODO Auto-generated method stub
-		
-	}
-
-	@Override
-	public void removeLineListener(LineListener listener) {
-		// TODO Auto-generated method stub
-		
-	}
 	
 
+
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org_openjdk_sound_PulseAudioTargetDataLine.c	Tue Jul 29 11:46:39 2008 -0400
@@ -0,0 +1,259 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <pulse/pulseaudio.h>
+#include <string.h>
+#include "org_openjdk_sound_PulseAudioTargetDataLine.h"
+
+
+
+
+
+
+void setJavaLongField(JNIEnv *env, jobject obj, void *ptr, char *fieldName) {
+	jclass cls = (*env)->GetObjectClass(env, obj);
+	jlong value = (long) ptr;
+	jfieldID fid =(*env)->GetFieldID(env, cls, fieldName, "J");
+	(*env)->SetLongField(env, obj, fid, value);
+	//CHECK No DeleteLocalReference Method?
+	//(*env)->DeleteLocalReference(cls);
+}
+
+void *getJavaLongField(JNIEnv *env, jobject obj, char *fieldName) {
+jclass cls = (*env)->GetObjectClass(env, obj);
+	jfieldID fid = (*env)->GetFieldID(env, cls, fieldName, "J");
+	jlong value = (*env)->GetLongField(env, obj, fid);
+	//(*env)->DeleteLocalReference(cls);
+	return (void *) value;
+}
+
+
+
+static void stream_read_cb(pa_stream* stream, size_t length, void* userdata) {
+    pa_threaded_mainloop *mainloop = userdata;
+    pa_threaded_mainloop_signal(mainloop,0);
+}
+
+static void stream_operation_complete_cb(pa_stream* stream, int success, void* userdata) {
+  pa_threaded_mainloop *mainloop = userdata;
+   pa_threaded_mainloop_signal(mainloop,0);
+}
+
+
+
+static void stream_state_cb(pa_stream* stream, void* userdata) {
+    assert(stream);
+    pa_threaded_mainloop *mainloop = userdata;
+    printf("stream state changed to %d\n", pa_stream_get_state(stream));
+    switch (pa_stream_get_state(stream)) {
+        case PA_STREAM_READY:
+        case PA_STREAM_FAILED:
+        case PA_STREAM_TERMINATED:
+            pa_threaded_mainloop_signal(mainloop, 0);
+            break;
+
+        default:
+            /* do nothing */
+            break;
+    }
+ }
+
+
+
+
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_openStream
+  (JNIEnv * env, jobject obj, jstring string, jfloat rate, jint size, jint channels, jboolean bigEndian, jint bufferSize){
+  
+    //TO DO: Need to deal with the buffer size. Currently ignored
+
+    pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); 
+    pa_context *context = getJavaLongField(env, obj, "contextPointer");
+    
+   
+    pa_sample_spec sample_spec;
+    
+    char *encoding = GetStringUTFChars(env, string, 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 {
+     	//TO DO: Invalid format :throw Exception;
+     }
+    
+    sample_spec.rate = rate;
+    sample_spec.channels = channels;
+
+    pa_threaded_mainloop_lock(mainloop);
+    
+    pa_stream *stream = pa_stream_new(context, "default stream", &sample_spec, NULL);
+
+    pa_stream_set_state_callback(stream, stream_state_cb, mainloop);
+    pa_stream_set_read_callback(stream, stream_read_cb, mainloop);
+    
+  
+    pa_threaded_mainloop_unlock(mainloop);
+
+
+    setJavaLongField(env, obj, stream, "streamPointer");    
+    return;
+
+unlock_and_fail:
+    pa_threaded_mainloop_unlock(mainloop);
+
+fail:
+    return;
+}
+
+JNIEXPORT void JNICALL
+Java_org_openjdk_sound_PulseAudioSourceDataLine_startStream(JNIEnv *env, jobject obj) {
+    pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); 
+    pa_stream *stream = getJavaLongField(env, obj, "streamPointer");
+    pa_threaded_mainloop_lock(mainloop);
+    pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL);
+    pa_threaded_mainloop_wait(mainloop);
+    if ( pa_stream_get_state(stream) != PA_STREAM_READY ) {
+        printf("stream initialization failed\n");
+    }
+    pa_threaded_mainloop_unlock(mainloop);
+}
+
+JNIEXPORT void Java_org_openjdk_sound_PulseAudioSourceDataLine_resumeStream(JNIEnv *env, jobject obj) {
+  	 pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); 
+  	 pa_stream *stream = getJavaLongField(env, obj, "streamPointer");
+  	 pa_threaded_mainloop_lock(mainloop);
+    	 pa_operation *o = pa_stream_cork(stream, 0, stream_operation_complete_cb, mainloop);
+    	 while(pa_operation_get_state(o) != PA_OPERATION_DONE) {
+    		pa_threaded_mainloop_wait(mainloop);
+    	 }
+    	 pa_operation_unref(o);
+    	 pa_threaded_mainloop_unlock(mainloop);
+
+}
+
+JNIEXPORT void Java_org_openjdk_sound_PulseAudioSourceDataLine__pauseStream(JNIEnv *env, jobject obj) {
+	 pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer"); 
+  	 pa_stream *stream = getJavaLongField(env, obj, "streamPointer");
+  	 pa_threaded_mainloop_lock(mainloop);
+    	 pa_operation *o = pa_stream_cork(stream, 1, stream_operation_complete_cb, mainloop);
+    	 while(pa_operation_get_state(o) != PA_OPERATION_DONE) {
+    		pa_threaded_mainloop_wait(mainloop);
+    	 }
+    	 pa_operation_unref(o);
+    	 pa_threaded_mainloop_unlock(mainloop);
+}
+  
+
+
+J
+
+JNIEXPORT void JNICALL
+Java_org_openjdk_sound_PulseAudioSourceDataLine__closeStream(JNIEnv *env, jobject obj, jint channels, jfloat rate) {
+
+    
+ 
+  	pa_stream *stream = getJavaLongField(env, obj, "streamPointer");
+  	pa_strean_disconnect(stream);
+}
+
+JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_available
+  (JNIEnv *env, jobject obj) {
+  	pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer");
+  	pa_stream *stream = getJavaLongField(env, obj, "streamPointer");
+  	pa_threaded_mainloop_lock(mainloop);
+	int available = pa_stream_writable_size(stream);
+    	pa_threaded_mainloop_unlock(mainloop);
+    	return available;
+ }
+
+
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_drain
+  (JNIEnv *env, jobject obj) {
+  	pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer");
+  	pa_stream *stream = getJavaLongField(env, obj, "streamPointer");
+  	pa_threaded_mainloop_lock(mainloop);
+	pa_operation *o = pa_stream_drain(stream, stream_operation_complete_cb, mainloop);
+    	while(pa_operation_get_state(o) != PA_OPERATION_DONE) {
+    		pa_threaded_mainloop_wait(mainloop);
+    	}
+    	pa_operation_unref(o);
+    	pa_threaded_mainloop_unlock(mainloop);
+ }
+
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_flush
+  (JNIEnv *env, jobject obj) {
+  	pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer");
+  	pa_stream *stream = getJavaLongField(env, obj, "streamPointer");
+  	pa_threaded_mainloop_lock(mainloop);
+	pa_operation *o = pa_stream_flush(stream, stream_operation_complete_cb, mainloop);
+    	while(pa_operation_get_state(o) != PA_OPERATION_DONE) {
+    		pa_threaded_mainloop_wait(mainloop);
+    	}
+    	pa_operation_unref(o);
+    	pa_threaded_mainloop_unlock(mainloop);
+ }
+
+
+
+
+
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_readFromStream
+  (JNIEnv * env, jobject obj, jbyteArray array, jint length, jint offset);
+	pa_threaded_mainloop *mainloop = getJavaLongField (env, obj, "mainLoopPointer");
+  	pa_stream *stream = getJavaLongField(env, obj, "streamPointer");
+	pa_threaded_mainloop_lock(mainloop);
+	char[length] data;
+	while(length > 0) {
+		size_t l;
+		while(!read_data) {
+			int r = pa_stream_peek(_stream, &read_data, &read_length);
+			if(!read_data) {
+				pa_threaded_mainloop_wait(mainloop);
+			} else {
+				read_index = 0;
+			}			
+		}
+		
+		l = read_length < length ? read_length : length;
+		memcpy(data, read_data+read_index, l);
+		
+		data = data + l;
+		length -= l;
+		read_index +=l;
+		read_length-=l;
+		
+		if(! read_length) {
+			int r = pa_stream_drop(stream);
+			read_data = NULL;
+			read_length = 0;
+			read_index = 0;
+			
+		}
+		
+		
+	}
+	
+	pa_threaded_mainloop_unlock(mainloop);
+	SetByteArrayRegion(env, array, offset, initialLength, data);
+}
+
+
+
+
+
+    
+
+
+