changeset 26:bc8045fdeaf2

start of merging java threads committer: Omair Majid <omajid@redhat.com>
author Omair Majid <omajid@redhat.com>
date Thu, 31 Jul 2008 16:39:41 -0400
parents 7fc1bc131b7e
children f1a1eaa0f610
files logout.wav makefile new.wav src/org/openjdk/sound/ContextEvent.java src/org/openjdk/sound/ContextListener.java src/org/openjdk/sound/EventLoop.java src/org/openjdk/sound/PulseAudioMixer.java src/org/openjdk/sound/PulseAudioMixerInfo.java src/org/openjdk/sound/PulseAudioMixerProvider.java src/org/openjdk/sound/PulseAudioSourceDataLine.java src/org/openjdk/sound/PulseAudioStreamVolumeControl.java src/org/openjdk/sound/PulseAudioTargetDataLine.java src/org_openjdk_sound_EventLoop.c src/org_openjdk_sound_EventLoop.h src/org_openjdk_sound_PulseAudioSourceDataLine.h src/org_openjdk_sound_PulseAudioTargetDataLine.h unittests/org/openjdk/sound/PulseAudioMixerRawTest.java unittests/org/openjdk/sound/PulseAudioMixerTest.java unittests/org/openjdk/sound/PulseSourceDataLineTest.java
diffstat 19 files changed, 1091 insertions(+), 295 deletions(-) [+]
line wrap: on
line diff
Binary file logout.wav has changed
--- a/makefile	Thu Jul 31 10:24:13 2008 -0400
+++ b/makefile	Thu Jul 31 16:39:41 2008 -0400
@@ -1,45 +1,68 @@
 
-all: lib/libPulseAudioMixer.so lib/libPulseAudioSourceDataLine.so 
+
+JAVAH=javah
+JAVAC=javac
+JAVA=java
+
+# Standard targets
 
-lib/libPulseAudioMixer.so: bin/org_openjdk_sound_PulseAudioMixer.o lib
-	gcc -g -shared -o $@ $< /usr/lib/libpulse.so
+all: lib/libpulse-java.so 
+
 
-lib/libPulseAudioSourceDataLine.so: bin/org_openjdk_sound_PulseAudioSourceDataLine.o lib
-	gcc -g -shared -o $@ $< /usr/lib/libpulse.so
+clean:
+	rm src/*.h src/org/openjdk/sound/*.class
+	rm -r bin
+	rm -r lib
 
-lib/libPulseAudioTargetDataLine.so: bin/org_openjdk_sound_PulseAudioTargetDataLine.o lib
-	gcc -g -shared -o $@ $< /usr/lib/libpulse.so
+
+# Executables
+
+
+# Shared Libraries
 
-bin/org_openjdk_sound_PulseAudioMixer.o: src/org_openjdk_sound_PulseAudioMixer.c src/org_openjdk_sound_PulseAudioMixer.h bin
-	gcc -g -c -o $@ $<
+lib/libpulse-java.so: \
+                      bin/org_openjdk_sound_EventLoop.o 
+#                      bin/org_openjdk_sound_PulseAudioSourceDataLine.o \
+#                      bin/org_openjdk_sound_PulseAudioTargetDataLine.o 
+	gcc -g -shared -o $@ $^ /usr/lib/libpulse.so
 
-bin/org_openjdk_sound_PulseAudioSourceDataLine.o: src/org_openjdk_sound_PulseAudioSourceDataLine.c src/org_openjdk_sound_PulseAudioSourceDataLine.h bin
-	gcc -g -c -o $@ $<
+# Object files
 
-bin/org_openjdk_sound_PulseAudioTargetDataLine.o: src/org_openjdk_sound_PulseAudioTargetDataLine.c src/org_openjdk_sound_PulseAudioTargetDataLine.h bin
+bin/org_openjdk_sound_EventLoop.o: src/org_openjdk_sound_EventLoop.c src/org_openjdk_sound_EventLoop.h bin
 	gcc -g -c -o $@ $<
 
-src/org_openjdk_sound_PulseAudioMixer.h: src/org/openjdk/sound/PulseAudioMixer.class
-	javah -d src -classpath src org.openjdk.sound.PulseAudioMixer
+#bin/org_openjdk_sound_PulseAudioSourceDataLine.o: src/org_openjdk_sound_PulseAudioSourceDataLine.c src/org_openjdk_sound_PulseAudioSourceDataLine.h bin
+#	gcc -g -c -o $@ $<
 
-src/org_openjdk_sound_PulseAudioSourceDataLine.h: src/org/openjdk/sound/PulseAudioSourceDataLine.class
-	javah -d src -classpath src org.openjdk.sound.PulseAudioSourceDataLine
+#bin/org_openjdk_sound_PulseAudioTargetDataLine.o: src/org_openjdk_sound_PulseAudioTargetDataLine.c src/org_openjdk_sound_PulseAudioTargetDataLine.h bin
+#	gcc -g -c -o $@ $<
+
+# Java headers
 
-src/org_openjdk_sound_PulseAudioTargetDataLine.h: src/org/openjdk/sound/PulseAudioTargetDataLine.class
-	javah -d src -classpath src org.openjdk.sound.PulseAudioTargetDataLine
+src/org_openjdk_sound_EventLoop.h: src/org/openjdk/sound/EventLoop.class
+	javah -d src -classpath src org.openjdk.sound.EventLoop
+
+#src/org_openjdk_sound_PulseAudioSourceDataLine.h: src/org/openjdk/sound/PulseAudioSourceDataLine.class
+#	javah -d src -classpath src org.openjdk.sound.PulseAudioSourceDataLine
 
+#src/org_openjdk_sound_PulseAudioTargetDataLine.h: src/org/openjdk/sound/PulseAudioTargetDataLine.class
+#	javah -d src -classpath src org.openjdk.sound.PulseAudioTargetDataLine
 
-src/org/openjdk/sound/PulseAudioMixer.class: src/org/openjdk/sound/PulseAudioMixer.java src/org/openjdk/sound/PulseAudioSourceDataLine.class src/org/openjdk/sound/PulseAudioTargetDataLine.class src/org/openjdk/sound/PulseAudioMixerInfo.class 
+# Compile Java
+
+src/org/openjdk/sound/EventLoop.class: src/org/openjdk/sound/EventLoop.java
 	javac -classpath src $<
 
-src/org/openjdk/sound/PulseAudioSourceDataLine.class: src/org/openjdk/sound/PulseAudioSourceDataLine.java 
-	javac $<
-
-src/org/openjdk/sound/PulseAudioTargetDataLine.class: src/org/openjdk/sound/PulseAudioTargetDataLine.java 
-	javac $<
-
-src/org/openjdk/sound/PulseAudioMixerInfo.class: src/org/openjdk/sound/PulseAudioMixerInfo.java 
-	javac $<
+#src/org/openjdk/sound/PulseAudioSourceDataLine.class: src/org/openjdk/sound/PulseAudioSourceDataLine.java 
+#	javac $<
+#
+#src/org/openjdk/sound/PulseAudioTargetDataLine.class: src/org/openjdk/sound/PulseAudioTargetDataLine.java 
+#	javac $<
+#
+#src/org/openjdk/sound/PulseAudioMixerInfo.class: src/org/openjdk/sound/PulseAudioMixerInfo.java 
+#	javac $<
+	
+# Build Directories	
 	
 bin/:
 	mkdir -p bin
@@ -47,9 +70,6 @@
 lib/:
 	mkdir -p lib
 
-clean:
-	rm src/*.h src/org/openjdk/sound/*.class
-	rm -r bin
-	rm -r lib
 
 
+
Binary file new.wav has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/openjdk/sound/ContextEvent.java	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,19 @@
+package org.openjdk.sound;
+
+public class ContextEvent {
+
+	public static enum Type {
+		UNCONNECTED, CONNECTING, AUTHORIZING, SETTING_NAME, READY, FAILED, TERMINATED
+	}
+
+	private Type type;
+
+	public ContextEvent(Type type) {
+		this.type = type;
+	}
+
+	public Type getType() {
+		return type;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/openjdk/sound/ContextListener.java	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,7 @@
+package org.openjdk.sound;
+
+public interface ContextListener {
+
+	public void update(ContextEvent e);
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/openjdk/sound/EventLoop.java	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,228 @@
+package org.openjdk.sound;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+
+import org.openjdk.sound.ContextEvent.Type;
+
+/*
+ * any methods that can obstruct the behaviour of pa_mainloop
+ * should run synchronized
+ * 
+ * 
+ */
+
+public class EventLoop implements Runnable {
+
+	/*
+	 * the threadLock object is the object used for synchronizing the
+	 * non-thread-safe operations of pulseaudio's c api
+	 * 
+	 */
+	public Object threadLock = new Object();
+
+	private List<ContextListener> contextListeners;
+	// private List<SourceDataLine> lines;
+	private String name;
+	private String serverString;
+
+	private int status;
+
+	public Semaphore finished = new Semaphore(0);
+
+	/*
+	 * JNI stuff
+	 * 
+	 * Do not synchronize the individual functions, synchronize
+	 * block/method/lines around the call
+	 * 
+	 */
+
+	private native void native_setup(String appName, String server);
+
+	private native int native_iterate(int mainloop, int timeout);
+
+	private native void native_shutdown();
+
+	private native void native_set_sink_volume(int contextPointer,
+			int streamPointer, int volume);
+
+	// pointers
+	@SuppressWarnings("unused")
+	private int contextPointer;
+	@SuppressWarnings("unused")
+	private int mainloopPointer;
+
+	/*
+	 * 
+	 */
+
+	static {
+		try {
+			String library = new java.io.File(".").getCanonicalPath()
+					+ java.io.File.separatorChar + "lib"
+					+ java.io.File.separatorChar
+					+ System.mapLibraryName("pulse-java");
+			System.out.println(library);
+			System.load(library);
+		} catch (IOException e) {
+			assert ("Loading failed".endsWith("library"));
+		}
+	}
+
+	public EventLoop() {
+		contextListeners = new ArrayList<ContextListener>();
+	}
+
+
+
+	public void setAppName(String name) {
+		this.name = name;
+	}
+
+	public void setServer(String serverString) {
+		this.serverString = serverString;
+	}
+
+	@Override
+	public void run() {
+		native_setup(this.name, this.serverString);
+
+		/*
+		 * Perhaps this loop should be written in C doing a Java to C call on
+		 * every iteration of the loop might be slow
+		 */
+		while (true) {
+			synchronized (threadLock) {
+				// timeout is a funky parameter (in milliseconds)
+				// timout = 0 means dont block
+				// setting it to even 1 makes the program crawl
+				// question is, why?
+				native_iterate(mainloopPointer, 0);
+
+				if (Thread.interrupted()) {
+					native_shutdown();
+					System.out.println(this.getClass().getName()
+							+ ": shutting down");
+					finished.release();
+					return;
+
+				}
+			}
+		}
+
+	}
+
+	public void addContextListener(ContextListener l) {
+		synchronized (threadLock) {
+			contextListeners.add(l);
+		}
+	}
+
+	public int getStatus() {
+		return this.status;
+	}
+
+	// public PulseAudioSourceDataLine getLine(Stream s) throws
+	// LineUnavailableException {
+	//
+	// final Semaphore semaphore = new Semaphore(0);
+	//
+	// synchronized (threadLock) {
+	// Stream stream = s;
+	//
+	// stream.addListener(new StreamListener() {
+	// @Override
+	// public void update(StreamEvent e) {
+	// System.out.println(this.getClass().getName()
+	// + " waiting to stream to become ready");
+	// if (e.getType() == StreamEvent.Type.READY) {
+	// semaphore.release();
+	// }
+	// }
+	// });
+	//
+	// System.out.println("about to open stream");
+	// stream.open(contextPointer, "java-stream");
+	// System.out.println("opened testing stream");
+	// }
+	//
+	// try {
+	// semaphore.acquire();
+	// } catch (InterruptedException e) {
+	// throw new LineUnavailableException("unable to prepare stream");
+	// }
+	//
+	// System.out.println(this.getClass().getName() + "stream is ready");
+	//
+	// }
+
+	public void update(int status) {
+		synchronized (threadLock) {
+			System.out.println(this.getClass().getName()
+					+ ".update() called! status = " + status);
+			this.status = status;
+			switch (status) {
+			case 0:
+				fireEvent(new ContextEvent(Type.UNCONNECTED));
+				break;
+			case 1:
+				fireEvent(new ContextEvent(Type.CONNECTING));
+				break;
+			case 2:
+				break;
+			case 3:
+				break;
+			case 4:
+				fireEvent(new ContextEvent(Type.READY));
+				break;
+			case 5:
+				fireEvent(new ContextEvent(Type.FAILED));
+				break;
+			case 6:
+				fireEvent(new ContextEvent(Type.TERMINATED));
+				break;
+			default:
+
+			}
+		}
+	}
+
+	private void fireEvent(final ContextEvent e) {
+
+		Thread th = new Thread(new Runnable() {
+
+			@Override
+			public void run() {
+				synchronized (contextListeners) {
+					for (ContextListener listener : contextListeners) {
+						listener.update(e);
+					}
+				}
+			}
+
+		});
+
+		th.start();
+
+	}
+
+	public void setVolume(int streamPointer, int volume) {
+
+		synchronized (threadLock) {
+			native_set_sink_volume(contextPointer, streamPointer, volume);
+		}
+
+	}
+
+	public int getContextPointer() {
+		return contextPointer;
+	}
+
+	public int getMainLoopPointer() {
+		return mainloopPointer;
+	}
+
+}
--- a/src/org/openjdk/sound/PulseAudioMixer.java	Thu Jul 31 10:24:13 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioMixer.java	Thu Jul 31 16:39:41 2008 -0400
@@ -1,14 +1,10 @@
 package org.openjdk.sound;
 
-
-
-
-
-import java.io.IOException;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Semaphore;
 
 import javax.sound.sampled.AudioSystem;
 import javax.sound.sampled.Control;
@@ -17,81 +13,65 @@
 import javax.sound.sampled.LineListener;
 import javax.sound.sampled.LineUnavailableException;
 import javax.sound.sampled.Mixer;
-import javax.sound.sampled.SourceDataLine;
-import javax.sound.sampled.TargetDataLine;
 import javax.sound.sampled.Control.Type;
 
 public class PulseAudioMixer implements javax.sound.sampled.Mixer {
 	// singleton
-	
+
+	public EventLoop eventLoop;
+	public Thread eventLoopThread;
+
 	private static PulseAudioMixer _instance = null;
-	
+
 	private final String DEFAULT_APP_NAME = "Java App";
-	
+
 	private boolean _isOpen = false;
-	
-	private List<PulseAudioSourceDataLine> _sourceLines = null;
-	private List<PulseAudioTargetDataLine> _targetLines = null;
-	
-	private Line.Info _sourceDataLineInfo = new Line.Info(PulseAudioSourceDataLine.class);
-	private Line.Info _targetDataLineInfo = new Line.Info(PulseAudioTargetDataLine.class);
-	
-	
-	List<LineListener> lineListeners = null;
-	
-	/*
-	 * JNI stuff
-	 */
-	private native void native_initialize(String appName, String server);
-	private native void native_shutdown();
-	private native int native_getStatus();
-	
-	// pointers
-	@SuppressWarnings("unused")
-	private int contextPointer;
-	@SuppressWarnings("unused")
-	private int mainloopPointer;
-	
-	/*
-	 * 
-	 */
+
+	// private List<PulseAudioSourceDataLine> _sourceLines = null;
+	// private List<PulseAudioTargetDataLine> _targetLines = null;
+
+	// private Line.Info _sourceDataLineInfo = new
+	// Line.Info(PulseAudioSourceDataLine.class);
+	// private Line.Info _targetDataLineInfo = new
+	// Line.Info(PulseAudioTargetDataLine.class);
 
-	static {
-		
-			System.load( "/home/iivan/workspace/pulse-java" + java.io.File.separatorChar + "lib" + java.io.File.separatorChar +  System.mapLibraryName("PulseAudioMixer"));	
-			}
-	
-	private PulseAudioMixer(){
-		lineListeners = new ArrayList<LineListener>();
+	List<LineListener> _lineListeners = null;
+
+	private PulseAudioMixer() {
+		_lineListeners = new ArrayList<LineListener>();
+		// _sourceLines = new ArrayList<PulseAudioSourceDataLine>();
+		// _targetLines = new ArrayList<PulseAudioTargetDataLine>();
 	}
-	
+
 	synchronized public static PulseAudioMixer getInstance() {
-		if ( _instance == null) {
+		if (_instance == null) {
 			_instance = new PulseAudioMixer();
 		}
 		return _instance;
 	}
-	
+
 	@Override
 	public Line getLine(javax.sound.sampled.Line.Info info)
 			throws LineUnavailableException {
-		
+
 		if (!_isOpen) {
 			throw new LineUnavailableException();
 		}
-		
-		if ( info.matches(_sourceDataLineInfo)) {
-			PulseAudioSourceDataLine sourceLine = new PulseAudioSourceDataLine(contextPointer, mainloopPointer);
-			_sourceLines.add(sourceLine);
-			return sourceLine;
-		}
-		
-		if (info.matches(_targetDataLineInfo)) {
-			PulseAudioTargetDataLine targetLine = new PulseAudioTargetDataLine();
-			_targetLines.add(targetLine);
-			return targetLine;
-		}
-		
+
+		// if ( info.matches(_sourceDataLineInfo)) {
+		// PulseAudioSourceDataLine sourceLine = null;
+		// // FIXME : THIS LINE HERE v
+		// // sourceLine = new PulseAudioSourceDataLine(eventLoop);
+		// _sourceLines.add(sourceLine);
+		// return sourceLine;
+		// }
+
+		// if (info.matches(_targetDataLineInfo)) {
+		// PulseAudioTargetDataLine targetLine = new PulseAudioTargetDataLine();
+		// _targetLines.add(targetLine);
+		// return targetLine;
+		// }
+
 		throw new IllegalArgumentException();
 	}
 
@@ -115,19 +95,21 @@
 	public javax.sound.sampled.Line.Info[] getSourceLineInfo(
 			javax.sound.sampled.Line.Info info) {
 		Line.Info sourceInfo = new Line.Info(PulseAudioSourceDataLine.class);
-		if (info.matches(sourceInfo)){
+		if (info.matches(sourceInfo)) {
 			Line.Info[] sourceInfos = { sourceInfo, };
 			return sourceInfos;
 		} else {
-			Line.Info[] sourceInfos = { };
+			Line.Info[] sourceInfos = {};
 			return sourceInfos;
-			
+
 		}
 	}
+
 	@Override
 	public Line[] getSourceLines() {
-		return (Line[]) _sourceLines.toArray();
-		
+		// return (Line[]) _sourceLines.toArray();
+		return null;
+
 	}
 
 	@Override
@@ -140,25 +122,26 @@
 	public javax.sound.sampled.Line.Info[] getTargetLineInfo(
 			javax.sound.sampled.Line.Info info) {
 		Line.Info sourceInfo = new Line.Info(PulseAudioTargetDataLine.class);
-		if (info.matches(sourceInfo)){
+		if (info.matches(sourceInfo)) {
 			Line.Info[] sourceInfos = { sourceInfo, };
 			return sourceInfos;
 		} else {
-			Line.Info[] sourceInfos = { };
-			return sourceInfos;	
+			Line.Info[] sourceInfos = {};
+			return sourceInfos;
 		}
 	}
 
 	@Override
 	public Line[] getTargetLines() {
-		return (Line[]) _targetLines.toArray();
+		// return (Line[]) _targetLines.toArray();
+		return null;
 	}
 
 	@Override
 	public boolean isLineSupported(javax.sound.sampled.Line.Info info) {
-		if ( _sourceDataLineInfo.matches(info)) {
-			return true;
-		}
+		// if ( _sourceDataLineInfo.matches(info)) {
+		// return true;
+		// }
 		return false;
 	}
 
@@ -170,45 +153,48 @@
 
 	@Override
 	public void synchronize(Line[] lines, boolean maintainSync) {
-		//FIXME pulse audio supports this
+		// FIXME pulse audio supports this
 		throw new IllegalArgumentException();
 	}
 
 	@Override
 	public void unsynchronize(Line[] lines) {
 		// FIXME should be able to implement this
-		throw new IllegalArgumentException();	
+		throw new IllegalArgumentException();
 	}
 
 	@Override
 	public void addLineListener(LineListener listener) {
-		lineListeners.add(listener);
+		_lineListeners.add(listener);
 	}
 
 	@Override
 	synchronized public void close() {
-		if ( !_isOpen) {
-			throw new UnsupportedOperationException("Mixer is already closed");
+
+		if (!_isOpen) {
+			return; // TODO do we throw an exception too?
 		}
-		
-		// close all source/target lines
-		for (SourceDataLine sl: _sourceLines) {
-			if(sl.isOpen()) {
-				sl.close();	
-			}
-			
+
+		eventLoopThread.interrupt();
+
+		try {
+			eventLoop.finished.acquire();
+		} catch (InterruptedException e) {
+			System.out.println(this.getClass().getName()
+					+ ": interrupted while waiting for eventloop to finish");
 		}
-		_sourceLines = null;
-		
-		for (TargetDataLine tl: _targetLines) {
-			tl.close();
-		}
-		_targetLines = null;
-		
-		native_shutdown();
+
+		System.out.println(this.getClass().getName() + ": closing");
+
 		_isOpen = false;
-		
-		//fireEvent(new LineEvent(this,LineEvent.Type.CLOSE,AudioSystem.NOT_SPECIFIED));
+		fireEvent(new LineEvent(this, LineEvent.Type.CLOSE,
+				AudioSystem.NOT_SPECIFIED));
+
+		/*
+		 * FIXME need to clean up the listeners on close without a race
+		 * condition
+		 */
+
 	}
 
 	@Override
@@ -238,112 +224,128 @@
 		return _isOpen;
 	}
 
-	@Override 
+	@Override
 	public void open() throws LineUnavailableException {
 		openLocal();
 	}
-	
-	public void open(String appName, String host ) throws UnknownHostException  {
+
+	public void open(String appName, String host) throws UnknownHostException,
+			LineUnavailableException {
 		openRemote(appName, host);
 	}
-	
-	public void openLocal() {
+
+	public void openLocal() throws LineUnavailableException {
 		openLocal(DEFAULT_APP_NAME);
 	}
-	
-	
-	public void openLocal(String appName) {
+
+	public void openLocal(String appName) throws LineUnavailableException {
 		try {
 			openRemote(appName, null);
 		} catch (UnknownHostException e) {
 			// not possible
 		}
 	}
-	
-	
-	public void openRemote(String appName, String host) throws  UnknownHostException {
+
+	public void openRemote(String appName, String host)
+			throws UnknownHostException, LineUnavailableException {
 		openRemote(appName, host, null);
 	}
-	
-	
-	synchronized public void openRemote(String appName, String host, Integer port) throws UnknownHostException {
+
+	synchronized public void openRemote(String appName, String host,
+			Integer port) throws UnknownHostException, LineUnavailableException {
 		if (_isOpen) {
-			throw new UnsupportedOperationException("PulseAudio Mixer is already open");
+			return;
 		}
 
 		InetAddress addr = InetAddress.getAllByName(host)[0];
-		_sourceLines = new ArrayList<PulseAudioSourceDataLine>();
-		_targetLines = new ArrayList<PulseAudioTargetDataLine>();
-		
+
 		if (port != null) {
 			host = addr.getHostAddress();
 			host = host + ":" + String.valueOf(port);
 		}
-		
-		// do this last
+
+		eventLoop = new EventLoop();
+		eventLoop.setAppName(appName);
+		eventLoop.setServer(host);
+
+		final Semaphore ready = new Semaphore(0);
+
+		eventLoop.addContextListener(new ContextListener() {
+
+			@Override
+			public void update(ContextEvent e) {
+				System.out.println("Event detected " + e.getType().toString());
+				if (e.getType() == ContextEvent.Type.READY
+						|| e.getType() == ContextEvent.Type.FAILED
+						|| e.getType() == ContextEvent.Type.TERMINATED) {
+					ready.release();
+				}
+			}
+
+		});
+
+		eventLoopThread = new Thread(eventLoop, "PulseAudio Eventloop Thread");
+
+		eventLoopThread.setDaemon(false);
+		eventLoopThread.start();
+
 		try {
-			native_initialize(appName, host );
-			_isOpen = true;
-			System.out.println("INITIALIZED");
-			fireEvent(new LineEvent(this, LineEvent.Type.OPEN, AudioSystem.NOT_SPECIFIED));
-			System.out.println("FIRED EVENT");
+			System.out.println("waiting...");
+			ready.acquire();
+			if (eventLoop.getStatus() != 4) {
+				throw new LineUnavailableException();
+			}
 
-		} catch (UnsupportedOperationException e) {
-			_isOpen = false;
-			System.out.println("EXCEPTION CATCHED");
-			throw e;
+			System.out.println("got signal");
+		} catch (InterruptedException e) {
+			System.out.println("got interrupted");
 		}
 
+		_isOpen = true;
+		fireEvent(new LineEvent(this, LineEvent.Type.OPEN,
+				AudioSystem.NOT_SPECIFIED));
+
 	}
-	
 
 	@Override
 	synchronized public void removeLineListener(LineListener listener) {
-		lineListeners.remove(listener);
+		_lineListeners.remove(listener);
 	}
 
-	synchronized private void fireEvent(LineEvent e) {
-		for ( LineListener lineListener: lineListeners) {
-			lineListener.update(e);
-		}
+	synchronized private void fireEvent(final LineEvent e) {
+		Thread th = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				synchronized (_lineListeners) {
+					for (LineListener lineListener : _lineListeners) {
+						lineListener.update(e);
+					}
+				}
+			}
+		});
+		th.start();
 	}
-	
-	/*
-	 * this function gets called from a different thread while the lock is held 
-	 * by java's thread. so cant use synchronized on this :(
-	 */
-	
-	 public void callback() {
-		System.out.println("JAVA Callback called!");
-		System.out.println("JAVA CALLBACK: status = " + native_getStatus());
-	}
-	 
-	public static void main(String[] args) throws Exception{
-		Mixer.Info mixerInfos [] = AudioSystem.getMixerInfo();
+
+	public static void main(String[] args) throws Exception {
+		Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo();
 		Mixer.Info selectedMixerInfo = null;
-		int i = 0;
-		for ( Mixer.Info info: mixerInfos) {
-			//System.out.println("Mixer Line " + i++ + ": " + info.getName() + " " + info.getDescription());
-			if ( info.getName().contains("PulseAudio")) {
-				selectedMixerInfo =	info; 
+//		int i = 0;
+		for (Mixer.Info info : mixerInfos) {
+			// System.out.println("Mixer Line " + i++ + ": " + info.getName() +
+			// " " + info.getDescription());
+			if (info.getName().contains("PulseAudio")) {
+				selectedMixerInfo = info;
 				System.out.println(selectedMixerInfo);
 			}
 		}
-		
-		PulseAudioMixer selectedMixer = (PulseAudioMixer) AudioSystem.getMixer(selectedMixerInfo);
-	
+
+		PulseAudioMixer selectedMixer = (PulseAudioMixer) AudioSystem
+				.getMixer(selectedMixerInfo);
+
 		selectedMixer.open();
-		Line.Info allLineInfo[] = selectedMixer.getSourceLineInfo();
-		int j = 0;
-		for ( Line.Info lineInfo : allLineInfo) {
-			System.out.println("Source Line " + j++ + ": " + lineInfo.getLineClass());
-			SourceDataLine sourceDataLine = (SourceDataLine) selectedMixer.getLine(lineInfo);
-			System.out.println(sourceDataLine);
-			
-		}
-		if (selectedMixer.isOpen())
-			selectedMixer.close();
-		
+
+		selectedMixer.close();
+
 	}
-	
+
 }
--- a/src/org/openjdk/sound/PulseAudioMixerInfo.java	Thu Jul 31 10:24:13 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioMixerInfo.java	Thu Jul 31 16:39:41 2008 -0400
@@ -14,7 +14,7 @@
 	// the "getInstance()" method
 	synchronized public static PulseAudioMixerInfo getInfo() {
 		if ( _instance == null) {
-			_instance = new PulseAudioMixerInfo("PulseAudioMixer", "openjdk", "the ear-candy mixer", "0.1");
+			_instance = new PulseAudioMixerInfo("PulseAudio Mixer", "openjdk", "the ear-candy mixer", "0.01");
 		}
 		
 		return _instance;
--- a/src/org/openjdk/sound/PulseAudioMixerProvider.java	Thu Jul 31 10:24:13 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioMixerProvider.java	Thu Jul 31 16:39:41 2008 -0400
@@ -10,6 +10,7 @@
 
 	@Override
 	public Mixer getMixer(Info info) {
+		System.out.println("DEBUG: getMixer called");
 		if (info.equals(PulseAudioMixerInfo.getInfo())) {
 			return PulseAudioMixer.getInstance();
 		} else {
--- a/src/org/openjdk/sound/PulseAudioSourceDataLine.java	Thu Jul 31 10:24:13 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioSourceDataLine.java	Thu Jul 31 16:39:41 2008 -0400
@@ -1,46 +1,42 @@
 package org.openjdk.sound;
 
-
-
-
-
+import java.io.IOException;
 import java.util.ArrayList;
 
 import javax.sound.sampled.*;
 import javax.sound.sampled.Control.Type;
 
-public class PulseAudioSourceDataLine  implements SourceDataLine {
+public class PulseAudioSourceDataLine implements SourceDataLine {
+
+	private EventLoop eventLoop = null;
+	private int streamPointer;
 
-	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 boolean isPaused = false;
+	private int defaultBufferSize;
+	private ArrayList<LineListener> listeners;
+
 	static {
-		
-			String library = "/home/iivan/workspace/pulse-java" + java.io.File.separatorChar + "lib" + java.io.File.separatorChar +  System.mapLibraryName("PulseAudioSourceDataLine");
+		try {
+			String library = new java.io.File(".").getCanonicalPath()
+					+ java.io.File.separatorChar + "lib"
+					+ java.io.File.separatorChar
+					+ System.mapLibraryName("pulse-java");
 			System.out.println(library);
-			System.load(library) ;	
-		
-	}
-	
-	PulseAudioSourceDataLine() {
-		this.contextPointer = 1;
-		this.mainLoopPointer = 1;
+			System.load(library);
+		} catch (IOException e) {
+			assert ("Loading failed".endsWith("library"));
+		}
 	}
-	
-	
-	public PulseAudioSourceDataLine(long context, long mainLoop) {
-		this.contextPointer = context;
-		this.mainLoopPointer = mainLoop;
+
+	public PulseAudioSourceDataLine(EventLoop eventLoop) {
+		this.eventLoop = eventLoop;
 	}
-	
-	public void open(AudioFormat format, int bufferSize) throws LineUnavailableException {
+
+	public void open(AudioFormat format, int bufferSize)
+			throws LineUnavailableException {
 		isOpen = true;
-		
+
 		int channels = format.getChannels();
 		float rate = format.getSampleRate();
 		int sampleSize = format.getSampleSizeInBits();
@@ -51,24 +47,25 @@
 
 	public void open(AudioFormat format) throws LineUnavailableException {
 		open(format, defaultBufferSize);
-		
+
 	}
-	
 
 	public void open() throws LineUnavailableException {
-		openStream("PCM_SIGNED", 44100, 16, 2, false, defaultBufferSize);
+		synchronized (eventLoop.threadLock) {
+			openStream("PCM_SIGNED", 44100, 16, 2, false, defaultBufferSize);
+
+		}
 	}
 
-	private native void openStream(String encoding, float rate, int size, int channels, boolean bigEndian, int bufferSize);
+	private native void openStream(String encoding, float rate, int size,
+			int channels, boolean bigEndian, int bufferSize);
 
 	public int write(byte[] b, int off, int len) {
 		writeToStream(b, len, off);
 		return len;
 	}
-	
-	private native void writeToStream(byte[]data, int bytes, int off);
 
-	
+	private native void writeToStream(byte[] data, int bytes, int off);
 
 	public void start() {
 		if (isPaused) {
@@ -77,88 +74,83 @@
 		} else {
 			startStream();
 		}
-		System.out.println(mainLoopPointer);
-		System.out.println(streamPointer);
-		/*for(LineListener l :listeners) {
-			l.update(new LineEvent(this, LineEvent.Type.START, 0));
-		}*/
+		
+		/*
+		 * 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();
 
-	public native void drain() ;
+	public native void drain();
+
 	public native void flush();
 
-
-	public void addLineListener(LineListener listener){
-		listeners.add(listener);
+	public void addLineListener(LineListener listener) {
+		this.listeners.add(listener);
 	}
-	
-	public void removeLineListener(LineListener listener){
-		listeners.remove(listener);
+
+	public void removeLineListener(LineListener listener) {
+		this.listeners.remove(listener);
 	}
-	
+
 	public boolean isOpen() {
 		return isOpen;
 	}
-	
+
 	public native int available();
-	
+
 	public void close() {
 		closeStream();
-		for (LineListener l : listeners) {
+		for (LineListener l : this.listeners) {
 			l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0));
 		}
-		
+
 	}
-	
+
 	private native void closeStream();
-	
+
 	public int getBufferSize() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-
 	public AudioFormat getFormat() {
 		// TODO Auto-generated method stub
 		return null;
 	}
 
-
 	public int getFramePosition() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-	
 	public float getLevel() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-	
 	public long getLongFramePosition() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-
 	public long getMicrosecondPosition() {
 		// TODO Auto-generated method stub
 		return 0;
 	}
 
-
 	public boolean isActive() {
 		// TODO Auto-generated method stub
 		return false;
@@ -168,34 +160,24 @@
 		// TODO Auto-generated method stub
 		return false;
 	}
-	
+
 	public Control getControl(Type control) {
 		// TODO Auto-generated method stub
 		return null;
 	}
 
-
 	public Control[] getControls() {
 		// TODO Auto-generated method stub
 		return null;
 	}
 
-
 	public javax.sound.sampled.Line.Info getLineInfo() {
 		return new Line.Info(SourceDataLine.class);
 	}
 
-
 	public boolean isControlSupported(Type control) {
 		// TODO Auto-generated method stub
 		return false;
 	}
 
-
-
-
-	
-
-	
-
 }
--- a/src/org/openjdk/sound/PulseAudioStreamVolumeControl.java	Thu Jul 31 10:24:13 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioStreamVolumeControl.java	Thu Jul 31 16:39:41 2008 -0400
@@ -1,16 +1,23 @@
 package org.openjdk.sound;
 
+import java.io.IOException;
+
 
 public class PulseAudioStreamVolumeControl extends PulseAudioVolumeControl{
 	private long streamPointer;
 	private long mainLoopPointer;
 	
 	static {
-		
-		String library = "/home/iivan/workspace/pulse-java" + java.io.File.separatorChar + "lib" + java.io.File.separatorChar +  System.mapLibraryName("PulseAudioStreamVolumeControl");
-		System.out.println(library);
-		System.load(library) ;	
-	
+		try {
+			String library = new java.io.File(".").getCanonicalPath()
+					+ java.io.File.separatorChar + "lib"
+					+ java.io.File.separatorChar
+					+ System.mapLibraryName("pulse-java");
+			System.out.println(library);
+			System.load(library);
+		} catch (IOException e) {
+			assert ("Loading failed".endsWith("library"));
+		}
 	}
 	
 	protected PulseAudioStreamVolumeControl(Type type, float minimum,
--- a/src/org/openjdk/sound/PulseAudioTargetDataLine.java	Thu Jul 31 10:24:13 2008 -0400
+++ b/src/org/openjdk/sound/PulseAudioTargetDataLine.java	Thu Jul 31 16:39:41 2008 -0400
@@ -1,4 +1,5 @@
 package org.openjdk.sound;
+import java.io.IOException;
 import java.util.ArrayList;
 
 import javax.sound.sampled.*;
@@ -16,6 +17,20 @@
 	protected int defaultBufferSize;
 	protected ArrayList<LineListener> listeners;
 	
+	
+	static {
+		try {
+			String library = new java.io.File(".").getCanonicalPath()
+					+ java.io.File.separatorChar + "lib"
+					+ java.io.File.separatorChar
+					+ System.mapLibraryName("pulse-java");
+			System.out.println(library);
+			System.load(library);
+		} catch (IOException e) {
+			assert ("Loading failed".endsWith("library"));
+		}
+	}
+	
 	public void open(AudioFormat format, int bufferSize) throws LineUnavailableException {
 		isOpen = true;
 		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org_openjdk_sound_EventLoop.c	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,242 @@
+#include <pulse/pulseaudio.h>
+
+#include "org_openjdk_sound_EventLoop.h"
+
+const int PA_ITERATE_BLOCK = 1;
+const int PA_ITERATE_NOBLOCK = 0;
+
+typedef struct java_context_t {
+	JNIEnv* env;
+	jobject obj;
+} java_context_t;
+
+java_context_t* java_context = NULL;
+
+JNIEnv* pulse_thread_env = NULL;
+
+static void context_change_callback(pa_context* context, void* userdata) {
+	assert(context);
+	assert(userdata == NULL);
+
+	//java_context_t* java_context = (java_context_t*)userdata;
+	JNIEnv* env = java_context->env;
+	jobject obj = java_context->obj;
+
+	printf("context state changed to %d\n", pa_context_get_state(context));
+
+	/* 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;
+
+	}
+	(*env)->CallVoidMethod(env, obj, mid, pa_context_get_state(context));
+	return;
+
+}
+
+/*
+ * Class:     org_openjdk_sound_EventLoop
+ * Method:    native_setup
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1setup
+(JNIEnv* env, jobject obj, jstring appName, jstring server) {
+
+	assert(appName != NULL);
+
+	jfieldID fid; /* the field id */
+	jclass cls = (*env)->GetObjectClass(env,obj);
+
+	printf("native_setup() called\n");
+	pa_mainloop *mainloop = pa_mainloop_new();
+	assert(mainloop != NULL);
+	pa_mainloop_api *mainloop_api = pa_mainloop_get_api(mainloop);
+	assert(mainloop != NULL);
+
+	pa_context *context = NULL;
+
+	const jbyte* string_appName;
+	string_appName = (*env)->GetStringUTFChars(env, appName, NULL);
+	if (string_appName == NULL) {
+		return; /* a OutOfMemoryError thrown by vm */
+	}
+	printf("using appName : %s\n", string_appName);
+	context = pa_context_new(mainloop_api, string_appName);
+	assert(mainloop != NULL);
+	(*env)->ReleaseStringUTFChars(env, appName, string_appName);
+
+	obj = (*env)->NewGlobalRef(env, obj);
+
+	java_context = malloc(sizeof(java_context_t));
+	java_context->env = env;
+	pulse_thread_env = env;
+	java_context->obj = obj;
+
+	pa_context_set_state_callback(context, context_change_callback, NULL);
+
+	if (server != NULL) {
+		/* obtain the server from the caller */
+		const jbyte* string_server = NULL;
+		string_server = (*env)->GetStringUTFChars(env, server, NULL);
+		if (string_server == NULL) {
+			return; /* OutOfMemoryError */
+		}
+		printf("About to connect to server: %s\n", string_server);
+		pa_context_connect(context, string_server, 0, NULL);
+		(*env)->ReleaseStringUTFChars(env, appName, string_server);
+	} else {
+		printf("using default server\n");
+		pa_context_connect(context, NULL, 0, NULL);
+	}
+
+	fid = (*env)->GetFieldID(env, cls, "mainloopPointer", "I");
+	(*env)->SetIntField(env, obj, fid, (jint)mainloop);
+
+	fid = (*env)->GetFieldID(env, cls, "contextPointer", "I");
+	(*env)->SetIntField(env, obj, fid, (jint) context);
+
+	printf("native_setup() returning\n");
+	return;
+
+}
+
+/*
+ * Class:     org_openjdk_sound_EventLoopThread
+ * Method:    native_iterate
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL Java_org_openjdk_sound_EventLoop_native_1iterate
+(JNIEnv* env, jobject obj, jint mainloopPointer, jint timeout) {
+
+	pa_mainloop* mainloop = (pa_mainloop*)mainloopPointer;
+	assert(mainloop);
+
+	int returnval;
+
+	returnval = pa_mainloop_prepare(mainloop, timeout);
+	if ( returnval < 0) {
+		return -1;
+	}
+	returnval = pa_mainloop_poll(mainloop);
+	if ( returnval < 0) {
+		return -1;
+	}
+	returnval = pa_mainloop_dispatch(mainloop);
+	if ( returnval < 0) {
+		return -1;
+	}
+	return returnval;
+
+}
+
+static void context_drain_complete_callback(pa_context* context, void* userdata) {
+	pa_context_disconnect(context);
+
+}
+
+/*
+ * Class:     org_openjdk_sound_EventLoop
+ * Method:    native_shutdown
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1shutdown
+(JNIEnv *env, jobject obj) {
+
+	printf("native_shutdown() starting\n");
+
+	jfieldID fid; /* the field id */
+	jclass cls = (*env)->GetObjectClass(env,obj);
+
+	fid = (*env)->GetFieldID(env, cls, "mainloopPointer", "I");
+	pa_mainloop* mainloop = (pa_mainloop*) ((*env)->GetIntField(env, obj, fid));
+	assert(mainloop != NULL);
+
+	fid = (*env)->GetFieldID(env, cls, "contextPointer", "I");
+	pa_context* context = (pa_context*) ((*env)->GetIntField(env, obj, fid));
+	assert(context != NULL);
+
+	pa_operation* o = pa_context_drain(context, context_drain_complete_callback, NULL);
+	if ( o == NULL) {
+		pa_context_disconnect(context);
+		pa_mainloop_free(mainloop);
+	} else {
+		pa_operation_unref(o);
+	}
+
+	(*env)->DeleteGlobalRef(env, java_context->obj);
+
+	free(java_context);
+
+	printf("native_shutdown() returning\n");
+
+}
+
+static void sink_input_volume_change_complete(pa_context* contest, int success,
+		void* userdata) {
+	// userdata is the pointer to the int containing the new volume 
+
+	assert(userdata);
+	free(userdata);
+	assert(success);
+	printf("volume change complete\n");
+
+}
+
+static void sink_input_change_volume(pa_context* c,
+		const pa_sink_input_info* i, int eol, void* userdata) {
+	assert(c);
+
+	// end of list ?
+	if (eol) {
+		return;
+	}
+
+	assert(i);
+	assert(userdata);
+	int volume = *((int*)userdata);
+
+	int j = 0;
+	//	printf("changing sink input volume\n");
+	pa_cvolume* new_volume = malloc(sizeof(pa_cvolume));
+
+	//	printf("allocated memory\n");
+	new_volume->channels = i->volume.channels;
+	//	printf("set the number of channels\n");
+	for (j = 0; j < new_volume->channels; j++) {
+		new_volume->values[j] = volume;
+	}
+
+	//	printf("calling set_sick_input_volume\n");
+	pa_operation* o = pa_context_set_sink_input_volume(c, i->index, new_volume,
+			sink_input_volume_change_complete, new_volume);
+	if (o != NULL) {
+		pa_operation_unref(o);
+	}
+
+	//	printf("done setup for changing volume\n");
+}
+
+/*
+ * Class:     org_openjdk_sound_EventLoop
+ * Method:    native_set_sink_volume
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1set_1sink_1volume
+(JNIEnv* env, jobject obj, jint contextPointer, jint streamPointer, jint volume) {
+
+	int* new_volume = malloc(sizeof(int));
+	*new_volume = volume;
+	int stream_id = pa_stream_get_index((pa_stream*) streamPointer);
+	pa_context_get_sink_input_info((pa_context*) contextPointer ,stream_id,sink_input_change_volume, new_volume);
+	return;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org_openjdk_sound_EventLoop.h	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,45 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_openjdk_sound_EventLoop */
+
+#ifndef _Included_org_openjdk_sound_EventLoop
+#define _Included_org_openjdk_sound_EventLoop
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     org_openjdk_sound_EventLoop
+ * Method:    native_setup
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1setup
+  (JNIEnv *, jobject, jstring, jstring);
+
+/*
+ * Class:     org_openjdk_sound_EventLoop
+ * Method:    native_iterate
+ * Signature: (II)I
+ */
+JNIEXPORT jint JNICALL Java_org_openjdk_sound_EventLoop_native_1iterate
+  (JNIEnv *, jobject, jint, jint);
+
+/*
+ * Class:     org_openjdk_sound_EventLoop
+ * Method:    native_shutdown
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1shutdown
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_EventLoop
+ * Method:    native_set_sink_volume
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_EventLoop_native_1set_1sink_1volume
+  (JNIEnv *, jobject, jint, jint, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org_openjdk_sound_PulseAudioSourceDataLine.h	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,85 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_openjdk_sound_PulseAudioSourceDataLine */
+
+#ifndef _Included_org_openjdk_sound_PulseAudioSourceDataLine
+#define _Included_org_openjdk_sound_PulseAudioSourceDataLine
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    openStream
+ * Signature: (Ljava/lang/String;FIIZI)V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_openStream
+  (JNIEnv *, jobject, jstring, jfloat, jint, jint, jboolean, jint);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    writeToStream
+ * Signature: ([BII)V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_writeToStream
+  (JNIEnv *, jobject, jbyteArray, jint, jint);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    startStream
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_startStream
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    pauseStream
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_pauseStream
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    resumeStream
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_resumeStream
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    drain
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_drain
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    flush
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_flush
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    available
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_available
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioSourceDataLine
+ * Method:    closeStream
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioSourceDataLine_closeStream
+  (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org_openjdk_sound_PulseAudioTargetDataLine.h	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,69 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class org_openjdk_sound_PulseAudioTargetDataLine */
+
+#ifndef _Included_org_openjdk_sound_PulseAudioTargetDataLine
+#define _Included_org_openjdk_sound_PulseAudioTargetDataLine
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     org_openjdk_sound_PulseAudioTargetDataLine
+ * Method:    openStream
+ * Signature: (Ljava/lang/String;FIIZI)V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_openStream
+  (JNIEnv *, jobject, jstring, jfloat, jint, jint, jboolean, jint);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioTargetDataLine
+ * Method:    readFromStream
+ * Signature: ([BII)V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_readFromStream
+  (JNIEnv *, jobject, jbyteArray, jint, jint);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioTargetDataLine
+ * Method:    startStream
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_startStream
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioTargetDataLine
+ * Method:    pauseStream
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_pauseStream
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioTargetDataLine
+ * Method:    resumeStream
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_resumeStream
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioTargetDataLine
+ * Method:    available
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_available
+  (JNIEnv *, jobject);
+
+/*
+ * Class:     org_openjdk_sound_PulseAudioTargetDataLine
+ * Method:    closeStream
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_openjdk_sound_PulseAudioTargetDataLine_closeStream
+  (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/unittests/org/openjdk/sound/PulseAudioMixerRawTest.java	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,33 @@
+package org.openjdk.sound;
+
+import javax.sound.sampled.LineUnavailableException;
+import javax.sound.sampled.Mixer;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PulseAudioMixerRawTest {
+
+	Mixer mixer = null;
+	
+	@Before
+	public void setUp() {
+		mixer = PulseAudioMixer.getInstance();
+	}
+	
+	
+	@Test
+	public void testOpen() throws LineUnavailableException {
+		mixer.open();
+		
+	}
+	
+	
+	
+	@After
+	public void tearDown() {
+		
+	}
+	
+}
--- a/unittests/org/openjdk/sound/PulseAudioMixerTest.java	Thu Jul 31 10:24:13 2008 -0400
+++ b/unittests/org/openjdk/sound/PulseAudioMixerTest.java	Thu Jul 31 16:39:41 2008 -0400
@@ -32,7 +32,7 @@
 	public void setUp() throws Exception {
 		Mixer.Info mixerInfos [] = AudioSystem.getMixerInfo();
 		Mixer.Info selectedMixerInfo = null;
-		int i = 0;
+//		int i = 0;
 		for ( Mixer.Info info: mixerInfos) {
 			//System.out.println("Mixer Line " + i++ + ": " + info.getName() + " " + info.getDescription());
 			if ( info.getName().contains("PulseAudio")) {
@@ -46,39 +46,45 @@
 	}
 	
 	@Test 
-	public void testLocalOpen() {
+	public void testLocalOpen() throws LineUnavailableException {
 		selectedMixer.openLocal();
 	}
 	
 	@Test
-	public void testLocalOpenAppName() {
+	public void testLocalOpenAppName() throws LineUnavailableException {
 		selectedMixer.openLocal("JunitTest");
 	}
 	
-	@Test 
-	public void testRemoteOpenWithPort() throws UnknownHostException {
-		selectedMixer.openRemote("JUnitTest", "127.0.0.1", 10);
+	
+	@Test (expected=LineUnavailableException.class)
+	public void testRemoteOpenWithInvalidPort() throws UnknownHostException, LineUnavailableException {
+		selectedMixer.openRemote("JUnitTest", "128.0.0.1", 10);
 	}
 	
 
+	/*
+	 * This test assumes a computer named 'town' is in the network with pulseaudio
+	 * listening on port 4173
+	 */
 	@Test 
-	public void testRemoteOpenWithPort2() throws UnknownHostException {
-		selectedMixer.openRemote("JUnitTest", "localhost", 30);
+	public void testRemoteOpenWithValidPort() throws UnknownHostException, LineUnavailableException {
+		selectedMixer.openRemote("JUnitTest", "town", 4713);
+		selectedMixer.close();
 	}
 
 	
+	/*
+	 * This test assumes a computer named 'town' is in the network with pulseaudio
+	 * listening 
+	 */
 	@Test 
-	public void testRemoteOpen() throws UnknownHostException {
-
-		selectedMixer.openRemote("JUnitTest", "localhost");
-		selectedMixer.close();
+	public void testRemoteOpen() throws UnknownHostException, LineUnavailableException {
+		selectedMixer.openRemote("JUnitTest", "town");
 	}
 
-	@Test 
-	public void testRemoteOpen2() throws UnknownHostException {
-
+	@Test (expected=LineUnavailableException.class)
+	public void testInvalidRemoteOpen() throws UnknownHostException, LineUnavailableException {
 		selectedMixer.openRemote("JUnitTest", "127.0.0.1");
-		selectedMixer.close();
 	}
 
 	
@@ -97,14 +103,13 @@
 
 	}
 
-	@Test (expected=UnsupportedOperationException.class)
+	@Test
 	public void testOpeningAgain() throws LineUnavailableException, UnsupportedOperationException {
 		selectedMixer.open();
 		selectedMixer.open();
-		System.out.println("here");
 	}
 	
-	@Test (expected=UnsupportedOperationException.class)
+	@Test
 	public void testClosingAgain() throws LineUnavailableException, UnsupportedOperationException {
 		selectedMixer.close();
 		selectedMixer.close();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/unittests/org/openjdk/sound/PulseSourceDataLineTest.java	Thu Jul 31 16:39:41 2008 -0400
@@ -0,0 +1,36 @@
+package org.openjdk.sound;
+
+
+import javax.sound.sampled.Line;
+import javax.sound.sampled.LineUnavailableException;
+
+import junit.framework.JUnit4TestAdapter;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PulseSourceDataLineTest {
+
+	
+	public static junit.framework.Test suite() { 
+	    return new JUnit4TestAdapter(PulseSourceDataLineTest.class); 
+	}
+	
+	@Before
+	public void setUp() throws Exception {
+	}
+	
+	@Test
+	public void testAcquiringSourceDataLine() throws LineUnavailableException {
+		PulseAudioMixer mixer = PulseAudioMixer.getInstance();
+		mixer.open();
+		PulseAudioSourceDataLine line = (PulseAudioSourceDataLine) mixer.getLine(new Line.Info(PulseAudioSourceDataLine.class));
+		
+	}
+
+	@After
+	public void tearDown() throws Exception {
+	}
+
+}