Mercurial > hg > pulseaudio
changeset 26:bc8045fdeaf2
start of merging java threads
committer: Omair Majid <omajid@redhat.com>
line wrap: on
line diff
--- 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 +
--- /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 { + } + +}