Mercurial > hg > pulseaudio
changeset 50:61cf6f811619
fixed problem in acquiring a SourceDataLine given only a Line.Info (instead of a DataLine.Info)
some minor cleanup
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Fri, 08 Aug 2008 16:24:38 -0400 |
parents | bdc766c0c2ae |
children | 5c09d21c2d70 |
files | src/org/classpath/icedtea/pulseaudio/EventLoop.java src/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java src/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java |
diffstat | 4 files changed, 157 insertions(+), 99 deletions(-) [+] |
line wrap: on
line diff
--- a/src/org/classpath/icedtea/pulseaudio/EventLoop.java Fri Aug 08 14:54:18 2008 -0400 +++ b/src/org/classpath/icedtea/pulseaudio/EventLoop.java Fri Aug 08 16:24:38 2008 -0400 @@ -63,12 +63,11 @@ private static EventLoop instance = null; private List<ContextListener> contextListeners; - // private List<SourceDataLine> lines; + private String name; private String serverString; private int status; - // private boolean eventLoopIsRunning = false; public Semaphore finished = new Semaphore(0); @@ -76,7 +75,7 @@ * JNI stuff * * Do not synchronize the individual functions, synchronize - * block/method/lines around the call + * block/method/lines around the call using threadLock * */ @@ -91,7 +90,6 @@ /* * These fields hold pointers * - * */ @SuppressWarnings("unused") private long contextPointer; @@ -103,17 +101,16 @@ */ static { - //try { - /*String library = new java.io.File(".").getCanonicalPath() + try { + String library = new java.io.File(".").getCanonicalPath() + java.io.File.separatorChar + "lib" + java.io.File.separatorChar - + System.mapLibraryName("pulse-java");*/ - String library = "/home/yyz/iivan/workspace/pulseaudio/lib/libpulse-java.so"; - System.out.println(library); + + System.mapLibraryName("pulse-java"); + // System.out.println(library); System.load(library); - /*} catch (IOException e) { + } catch (IOException e) { assert ("Loading failed".endsWith("library")); - }*/ + } } private EventLoop() { @@ -156,12 +153,12 @@ native_shutdown(); // System.out.println(this.getClass().getName() // + ": shutting down"); - + // clean up the listeners synchronized (contextListeners) { contextListeners.clear(); } - + return; } @@ -218,11 +215,11 @@ } private void fireEvent(final ContextEvent e) { -// System.out.println(this.getClass().getName() + "firing event: " -// + e.getType().toString()); + // System.out.println(this.getClass().getName() + "firing event: " + // + e.getType().toString()); synchronized (contextListeners) { -// System.out.println(contextListeners.size()); + // System.out.println(contextListeners.size()); for (ContextListener listener : contextListeners) { listener.update(e); }
--- a/src/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java Fri Aug 08 14:54:18 2008 -0400 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioMixer.java Fri Aug 08 16:24:38 2008 -0400 @@ -50,7 +50,6 @@ import javax.sound.sampled.BooleanControl; import javax.sound.sampled.Control; import javax.sound.sampled.FloatControl; -import javax.sound.sampled.DataLine; import javax.sound.sampled.Line; import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineListener; @@ -74,9 +73,6 @@ private List<PulseAudioSourceDataLine> sourceLines = new ArrayList<PulseAudioSourceDataLine>(); // private List<PulseAudioTargetDataLine> targetLines = null; - // private Line.Info targetDataLineInfo = new - // Line.Info(PulseAudioTargetDataLine.class); - List<LineListener> lineListeners = null; private PulseAudioMixer() { @@ -103,22 +99,24 @@ PulseAudioSourceDataLine sourceLine = null; sourceLine = new PulseAudioSourceDataLine(eventLoop); Line.Info sourceDataLineInfo = sourceLine.getLineInfo(); - /*if (info instanceof DataLine.Info) { - if (info.matches(sourceDataLineInfo)) { - sourceLines.add(sourceLine); - return sourceLine; - } - }*/ - - return sourceLine; - // if (info.matches(_targetDataLineInfo)) { - // PulseAudioTargetDataLine targetLine = new PulseAudioTargetDataLine(); - // _targetLines.add(targetLine); + // TODO need to add special case code for + // DataLine.Info case + if (info.matches(sourceDataLineInfo)) { + sourceLines.add(sourceLine); + return sourceLine; + } + + // PulseAudioTargetDataLine targetLine = new + // PulseAudioTargetDataLine(eventLoop); + // Line.Info targetDataLineInfo = targetLine.getLineInfo(); + + // if (info.matches(targetDataLineInfo)) { + // targetLines.add(targetLine); // return targetLine; // } - //throw new IllegalArgumentException(); + throw new IllegalArgumentException(); } @Override @@ -146,28 +144,31 @@ @Override public javax.sound.sampled.Line.Info[] getSourceLineInfo( javax.sound.sampled.Line.Info info) { - Line.Info sourceInfo = new Line.Info(PulseAudioSourceDataLine.class); + SourceDataLine sourceLine = new PulseAudioSourceDataLine(eventLoop); + Line.Info sourceInfo = sourceLine.getLineInfo(); + if (info.matches(sourceInfo)) { Line.Info[] sourceInfos = { sourceInfo, }; return sourceInfos; - } else { - Line.Info[] sourceInfos = {}; - return sourceInfos; + } - } + return new Line.Info[] {}; + } @Override public Line[] getSourceLines() { - // return (Line[]) _sourceLines.toArray(); - return null; - + return (Line[]) sourceLines.toArray(); } @Override public javax.sound.sampled.Line.Info[] getTargetLineInfo() { - Line.Info[] info = { new Line.Info(PulseAudioTargetDataLine.class), }; - return info; + if (isOpen) { + PulseAudioTargetDataLine targetDataLine = new PulseAudioTargetDataLine(); + return new Line.Info[] { targetDataLine.getLineInfo() }; + } + // if not open, return an empty array + return new Line.Info[] {}; } @Override @@ -177,10 +178,10 @@ if (info.matches(sourceInfo)) { Line.Info[] sourceInfos = { sourceInfo, }; return sourceInfos; - } else { - Line.Info[] sourceInfos = {}; - return sourceInfos; } + + return new Line.Info[] {}; + } @Override @@ -191,9 +192,15 @@ @Override public boolean isLineSupported(javax.sound.sampled.Line.Info info) { - // if ( _sourceDataLineInfo.matches(info)) { - // return true; - // } + if (isOpen) { + PulseAudioSourceDataLine sourceLine = new PulseAudioSourceDataLine( + eventLoop); + Line.Info sourceLineInfo = sourceLine.getLineInfo(); + + if (info.matches(sourceLineInfo)) { + return true; + } + } return false; } @@ -242,10 +249,9 @@ fireEvent(new LineEvent(this, LineEvent.Type.CLOSE, AudioSystem.NOT_SPECIFIED)); - /* - * FIXME need to clean up the listeners on close without a race - * condition - */ + synchronized (lineListeners) { + lineListeners.clear(); + } } @@ -294,7 +300,8 @@ try { openRemote(appName, null); } catch (UnknownHostException e) { - // not possible + assert ("opening a local connection cant result in unknownhost" + .length() == 0); } } @@ -393,7 +400,9 @@ /* * Should this method be synchronized? I had a few reasons, but i forgot - * them Pros: - Thread safety? + * them :( + * + * Pros: - Thread safety? * * Cons: - eventListeners are run from other threads, if those then call * fireEvent while a method is waiting on a listener, this synchronized @@ -430,21 +439,25 @@ System.out.println("got a line"); - //File soundFile = new File(new java.io.File(".").getCanonicalPath() + "/testsounds/logout.wav"); - File soundFile = new File( "/home/iivan/workspace/pulseaudio/testsounds/logout.wav"); + // File soundFile = new File(new java.io.File(".").getCanonicalPath() + // + "/testsounds/logout.wav"); + File soundFile = new File( + "/home/iivan/workspace/pulseaudio/testsounds/logout.wav"); AudioInputStream audioInputStream = AudioSystem .getAudioInputStream(soundFile); AudioFormat audioFormat = audioInputStream.getFormat(); + System.out.println(); line.open(audioFormat); line.start(); - PulseAudioStreamVolumeControl control = (PulseAudioStreamVolumeControl) line.getControl(FloatControl.Type.VOLUME); - PulseAudioStreamMuteControl mute = (PulseAudioStreamMuteControl) line.getControl(BooleanControl.Type.MUTE); + PulseAudioStreamVolumeControl control = (PulseAudioStreamVolumeControl) line + .getControl(FloatControl.Type.VOLUME); + PulseAudioStreamMuteControl mute = (PulseAudioStreamMuteControl) line + .getControl(BooleanControl.Type.MUTE); mute.setValue(true); control.setValue(40000); mute.setValue(false); System.out.println("Volume set to " + control.getValue()); - - + byte[] abData = new byte[1000]; int bytesRead = 0;
--- a/src/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Fri Aug 08 14:54:18 2008 -0400 +++ b/src/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Fri Aug 08 16:24:38 2008 -0400 @@ -47,7 +47,6 @@ import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.BooleanControl; import javax.sound.sampled.Control; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineEvent; @@ -74,7 +73,7 @@ private AudioFormat currentFormat = null; private List<LineListener> listeners; - + private Control[] controls = new Control[2]; private PulseAudioStreamMuteControl muteControl; private PulseAudioStreamVolumeControl volumeControl; @@ -124,19 +123,11 @@ } - - - - - - public PulseAudioSourceDataLine(EventLoop eventLoop) { this.eventLoop = eventLoop; this.listeners = new ArrayList<LineListener>(); this.volume = 65536; - - /* * FIXME puselaudio supports any sample rate (it can covert between * sample rates without a problem). it calculates the frame size and the @@ -153,9 +144,9 @@ * * */ - + supportedFormats = new LinkedList<AudioFormat>(); - + Map<String, Object> properties; int[] channelSizes = new int[] { 1, 2, 5 }; @@ -168,8 +159,7 @@ // as soon as they change something // FIXME ^ int sampleSize = 8; // in bits - AudioFormat PA_SAMPLE_U8 = new AudioFormat( - Encoding.PCM_UNSIGNED, // encoding + AudioFormat PA_SAMPLE_U8 = new AudioFormat(Encoding.PCM_UNSIGNED, // encoding AudioSystem.NOT_SPECIFIED, // sample rate sampleSize, // sample size channelSize, // channels @@ -319,32 +309,31 @@ currentFormat = null; - } protected boolean isMuted() { return muted; } - + protected void setMuted(boolean value) { muted = value; } - + protected float getVolume() { return this.volume; } - + protected void setVolume(float value) { this.volume = value; - + } - + public void open(AudioFormat format, int bufferSize) throws LineUnavailableException { if (isOpen) { throw new IllegalStateException("Line is already open"); } - + // ignore suggested buffer size for (AudioFormat myFormat : supportedFormats) { @@ -358,7 +347,9 @@ } } - //throw new IllegalArgumentException("invalid format"); + if (!isOpen) { + throw new IllegalArgumentException("Unsupported format"); + } final Semaphore semaphore = new Semaphore(0); @@ -382,11 +373,9 @@ try { semaphore.acquire(); } catch (InterruptedException e) { - // throw new LineUnavailableException("unable to prepare - // stream"); + throw new LineUnavailableException("unable to prepare stream"); } - System.out.println(this.getClass().getName() + "stream is ready"); - + volumeControl = new PulseAudioStreamVolumeControl(this); controls[0] = volumeControl; muteControl = new PulseAudioStreamMuteControl(this); @@ -446,16 +435,16 @@ } public void start() { - if (isPaused) { - native_resume(); - isPaused = false; - } + if (isPaused) { + native_resume(); + isPaused = false; + } /* * for(LineListener l :listeners) { l.update(new LineEvent(this, * LineEvent.Type.START, 0)); } */ - + } public void stop() { @@ -530,7 +519,6 @@ return 0; } - public boolean isActive() { // TODO Auto-generated method stub return false; @@ -543,7 +531,7 @@ public Control getControl(Type control) { for (int i = 0; i < controls.length; i++) { - if (controls[i].getType() == control){ + if (controls[i].getType() == control) { return controls[i]; } @@ -556,7 +544,7 @@ } public javax.sound.sampled.Line.Info getLineInfo() { - return new DataLine.Info(SourceDataLine.class, + return new DataLine.Info(PulseAudioSourceDataLine.class, supportedFormats.toArray(new AudioFormat[0]), 0, 100000); } @@ -626,12 +614,10 @@ streamListener.update(e); } } - + protected EventLoop getEventLoop() { return this.eventLoop; } - - public long getStreamPointer() { return streamPointer;
--- a/unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java Fri Aug 08 14:54:18 2008 -0400 +++ b/unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java Fri Aug 08 16:24:38 2008 -0400 @@ -43,7 +43,10 @@ import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.BooleanControl; import javax.sound.sampled.DataLine; +import javax.sound.sampled.FloatControl; +import javax.sound.sampled.Line; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.Mixer; import javax.sound.sampled.SourceDataLine; @@ -77,13 +80,12 @@ AudioInputStream audioInputStream = AudioSystem .getAudioInputStream(soundFile); AudioFormat audioFormat = audioInputStream.getFormat(); - + SourceDataLine line; line = (PulseAudioSourceDataLine) mixer.getLine(new DataLine.Info( SourceDataLine.class, audioFormat)); Assert.assertNotNull(line); - line.open(audioFormat); line.start(); @@ -112,6 +114,66 @@ } + @Test (expected = IllegalArgumentException.class) + public void testFindLineWithWrongFormat() throws LineUnavailableException { + SourceDataLine line = (SourceDataLine) mixer.getLine(new DataLine.Info( + SourceDataLine.class, new AudioFormat( + AudioFormat.Encoding.PCM_UNSIGNED, 44100, 100000, 1, 1, 10, + true))); + line.open(); + + } + + @Test + public void testVolumeAndMute() throws Exception { + Mixer.Info mixerInfos[] = AudioSystem.getMixerInfo(); + Mixer.Info selectedMixerInfo = null; + for (Mixer.Info info : mixerInfos) { + if (info.getName().contains("PulseAudio")) { + selectedMixerInfo = info; + System.out.println(selectedMixerInfo); + } + } + + Mixer selectedMixer = AudioSystem.getMixer(selectedMixerInfo); + + selectedMixer.open(); + SourceDataLine line = (SourceDataLine) selectedMixer + .getLine(new Line.Info(SourceDataLine.class)); + + File soundFile = new File(new java.io.File(".").getCanonicalPath() + + "/testsounds/logout.wav"); + AudioInputStream audioInputStream = AudioSystem + .getAudioInputStream(soundFile); + AudioFormat audioFormat = audioInputStream.getFormat(); + + line.open(audioFormat); + line.start(); + PulseAudioStreamVolumeControl volume = (PulseAudioStreamVolumeControl) line + .getControl(FloatControl.Type.VOLUME); + PulseAudioStreamMuteControl mute = (PulseAudioStreamMuteControl) line + .getControl(BooleanControl.Type.MUTE); + + mute.setValue(true); + volume.setValue(40000); + + mute.setValue(false); + + byte[] abData = new byte[1000]; + int bytesRead = 0; + + while (bytesRead >= 0) { + bytesRead = audioInputStream.read(abData, 0, abData.length); + if (bytesRead > 0) { + line.write(abData, 0, bytesRead); + } + } + + line.flush(); + selectedMixer.close(); + + } + @After public void tearDown() throws Exception {