Mercurial > hg > pulseaudio
changeset 98:220882a984dd
2008-08-25 Omair Majid <omajid@redhat.com>
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java
(getBufferSize): Return the default buffer size if not opened.
(isActive): Removed method; parent class PulseAudioDataLine has this.
(start): Call parent class' start.
(stop): Likewise.
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java
Added isStarted and isEngagedInIo. Commented out isPaused.
(open): Use the default format supplied in the constructor.
(close): Set isOpen to false.
(start): Commented out isPaused stuff, seems to work ok. Set isStarted to
true.
(stop): Commented out isPaused. Set isStarted to false.
(isActive): New function.
(isRunning): Likewise.
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java
(write): Added a check that the line has been open()ed.
(getBufferSize): Return the default buffer size if the line hasnt been
opened.
(setDefaultFormat): Removed obsolete function.
(isActive): Moved function to parent class
(isRunning): Likewise.
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java
Removed duplicate variables isOpen and isPaused.
(read): Added a check that the line has been open()ed.
(isActive): Moved functino to parent class.
(isRunning): Likewise.
* unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java
(testIsActiveAndIsOpen): New function.
* unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLineTest.java
(testIsActiveAndIsOpen): New function.
* unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java
(testOpenAndClose): New function.
(testIsActiveAndIsOpen): Likewise.
(testPlayLessThanFrameSize): Added calls to start() and stop().
(testBufferSizes): New function.
(testHasADefaultFormat): Likewise.
(testDefaultFormatWithGetLine): Likewise.
(testDefaultBufferSize): Likewise.
(messWithStreams): Likewise.
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Mon, 25 Aug 2008 17:27:52 -0400 |
parents | 2e4a2a022ffb |
children | 548fa22ff716 |
files | src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLineTest.java unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java |
diffstat | 7 files changed, 252 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Mon Aug 25 14:51:13 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Mon Aug 25 17:27:52 2008 -0400 @@ -193,6 +193,9 @@ @Override public int getBufferSize() { + if (!isOpen) { + return DEFAULT_BUFFER_SIZE; + } return bufferSize; } @@ -262,12 +265,6 @@ } @Override - public boolean isActive() { - // TODO Auto-generated method stub - return false; - } - - @Override public boolean isControlSupported(Type control) { return false; } @@ -378,6 +375,8 @@ @Override public void start() { + super.start(); + if (!clipThread.isAlive()) { synchronized (clipLock) { loopsLeft = 0; @@ -388,6 +387,7 @@ } public void stop() { + if (clipThread.isAlive()) { clipThread.interrupt(); } @@ -400,6 +400,8 @@ currentFrame = 0; loopsLeft = 0; } + + super.stop(); } }
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java Mon Aug 25 14:51:13 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioDataLine.java Mon Aug 25 17:27:52 2008 -0400 @@ -10,7 +10,6 @@ import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineListener; import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.AudioFormat.Encoding; public abstract class PulseAudioDataLine implements Line { @@ -19,14 +18,24 @@ protected String streamName = "Java Stream"; + // true between open() and close(). ie represents when a line has acquire + // resources protected boolean isOpen = false; - private boolean isPaused = false; + + // true between start() and stop() + protected boolean isStarted = false; + + protected boolean isEngagedInIo = false; + + // true if a stream has been paused + // protected boolean isPaused = false; + protected AudioFormat[] supportedFormats = null; protected AudioFormat currentFormat = null; protected AudioFormat defaultFormat = null; protected int bufferSize = 0; - + protected List<LineListener> lineListeners = new ArrayList<LineListener>();; protected EventLoop eventLoop = null; @@ -103,16 +112,13 @@ } public void open() throws LineUnavailableException { - // pick a random format - if (defaultFormat == null) { - defaultFormat = new AudioFormat(Encoding.PCM_UNSIGNED, 44100, 8, 2, - 2, AudioSystem.NOT_SPECIFIED, false); - } + assert (defaultFormat != null); open(defaultFormat, DEFAULT_BUFFER_SIZE); } public void close() { + // FIXME what should be done here assert (isOpen); synchronized (eventLoop.threadLock) { @@ -127,15 +133,19 @@ // stream"); } + isOpen = false; + } public void start() { - if (isPaused) { - synchronized (eventLoop.threadLock) { - stream.cork(false); - } - isPaused = false; - } + // if (isPaused) { + // synchronized (eventLoop.threadLock) { + // stream.cork(false); + // } + // isPaused = false; + // } + + isStarted = true; /* * for(LineListener l :listeners) { l.update(new LineEvent(this, @@ -145,11 +155,35 @@ } public void stop() { - synchronized (eventLoop.threadLock) { - stream.cork(true); - } - isPaused = true; + // synchronized (eventLoop.threadLock) { + // stream.cork(true); + // } + // isPaused = true; + + isStarted = false; + + } + /* + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4791152 : + * + * a line is active in between calls to start() and stop(). In that sense, + * active means that the line is ready to take or give data. Running is + * tightly bound to data flow in the line. I.e. when you start a + * SourceDataLine but never write data to it, the line should not be + * running. This also means that a line should become not running on buffer + * underrun/overflow. + * + * + */ + + public boolean isActive() { + return isStarted; + } + + public boolean isRunning() { + // FIXME Auto-generated method stub + return false; } public void addLineListener(LineListener listener) {
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Mon Aug 25 14:51:13 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Mon Aug 25 17:27:52 2008 -0400 @@ -111,6 +111,9 @@ @Override public int write(byte[] data, int offset, int length) { + if (!isStarted) { + throw new IllegalStateException("must call start() before write()"); + } int frameSize = currentFormat.getFrameSize(); if (length % frameSize != 0) { @@ -168,6 +171,9 @@ }; public int getBufferSize() { + if (!isOpen) { + return DEFAULT_BUFFER_SIZE; + } return bufferSize; } @@ -178,14 +184,6 @@ return currentFormat; } - public void setDefaultFormat(AudioFormat format) { - for (AudioFormat aFormat : supportedFormats) { - if (format.matches(aFormat)) { - defaultFormat = format; - } - } - } - public int getFramePosition() { return (int) currentFramePosition; } @@ -206,16 +204,6 @@ return microseconds; } - public boolean isActive() { - // TODO Auto-generated method stub - return false; - } - - public boolean isRunning() { - // TODO Auto-generated method stub - return false; - } - public Control getControl(Type control) { if (!isOpen) { throw new IllegalArgumentException( @@ -240,7 +228,8 @@ } public javax.sound.sampled.Line.Info getLineInfo() { - return new DataLine.Info(this.getClass(), supportedFormats, StreamBufferAttributes.MIN_VALUE, + return new DataLine.Info(this.getClass(), supportedFormats, + StreamBufferAttributes.MIN_VALUE, StreamBufferAttributes.MAX_VALUE); }
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Mon Aug 25 14:51:13 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLine.java Mon Aug 25 17:27:52 2008 -0400 @@ -50,9 +50,6 @@ public class PulseAudioTargetDataLine extends PulseAudioDataLine implements TargetDataLine { - protected boolean isOpen = false; - protected boolean isPaused = false; - private long currentFramePosition = 0; @SuppressWarnings("unused") @@ -78,6 +75,10 @@ @Override public int read(byte[] data, int offset, int length) { + if (!isStarted) { + throw new IllegalStateException("must call open before read()"); + } + int frameSize = currentFormat.getFrameSize(); if (length % frameSize != 0) { @@ -169,16 +170,6 @@ return (long) (currentFramePosition / currentFormat.getFrameRate()); } - public boolean isActive() { - // TODO Auto-generated method stub - return false; - } - - public boolean isRunning() { - // TODO Auto-generated method stub - return false; - } - public Control getControl(Type control) { throw new IllegalArgumentException( "PulseAudioTargetDataLine does not support any controls");
--- a/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java Mon Aug 25 14:51:13 2008 -0400 +++ b/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java Mon Aug 25 17:27:52 2008 -0400 @@ -40,12 +40,15 @@ import java.io.File; import java.io.IOException; +import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; +import javax.sound.sampled.DataLine; import javax.sound.sampled.Line; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; import junit.framework.JUnit4TestAdapter; @@ -58,6 +61,8 @@ public class PulseAudioClipTest { Mixer mixer; + AudioFormat aSupportedFormat = new AudioFormat( + AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 10, true); public static junit.framework.Test suite() { return new JUnit4TestAdapter(PulseAudioClipTest.class); @@ -84,31 +89,33 @@ Assert.assertNotNull(clip); } - - @Test (expected=IllegalArgumentException.class) + @Test(expected = IllegalArgumentException.class) public void testClipOpen() throws LineUnavailableException { Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); clip.open(); } - + @Test - public void testClipOpens() throws LineUnavailableException, UnsupportedAudioFileException, IOException { + public void testClipOpens() throws LineUnavailableException, + UnsupportedAudioFileException, IOException { Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); File soundFile = new File("testsounds/startup.wav"); AudioInputStream audioInputStream = AudioSystem .getAudioInputStream(soundFile); clip.open(audioInputStream); } - + @Test - public void testLoopStopStartClip() throws LineUnavailableException, IOException, UnsupportedAudioFileException { + public void testLoopStopStartClip() throws LineUnavailableException, + IOException, UnsupportedAudioFileException { Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); File soundFile = new File("testsounds/startup.wav"); AudioInputStream audioInputStream = AudioSystem .getAudioInputStream(soundFile); clip.open(audioInputStream); - - clip.setLoopPoints((int) (clip.getFrameLength() / 4), (int) (clip.getFrameLength() / 2)); + + clip.setLoopPoints((int) (clip.getFrameLength() / 4), (int) (clip + .getFrameLength() / 2)); clip.loop(4); try { Thread.sleep(2000); @@ -124,16 +131,44 @@ clip.start(); clip.close(); } - + @Test - public void testLoop0Clip() throws LineUnavailableException, IOException, UnsupportedAudioFileException { + public void testIsActiveAndIsOpen() throws LineUnavailableException, + UnsupportedAudioFileException, IOException { + + Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); + File soundFile = new File("testsounds/startup.wav"); + AudioInputStream audioInputStream = AudioSystem + .getAudioInputStream(soundFile); + + Assert.assertFalse(clip.isActive()); + Assert.assertFalse(clip.isOpen()); + clip.open(audioInputStream); + Assert.assertTrue(clip.isOpen()); + Assert.assertFalse(clip.isActive()); + clip.start(); + Assert.assertTrue(clip.isOpen()); + Assert.assertTrue(clip.isActive()); + clip.stop(); + Assert.assertTrue(clip.isOpen()); + Assert.assertFalse(clip.isActive()); + clip.close(); + Assert.assertFalse(clip.isOpen()); + Assert.assertFalse(clip.isActive()); + + } + + @Test + public void testLoop0Clip() throws LineUnavailableException, IOException, + UnsupportedAudioFileException { Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); File soundFile = new File("testsounds/startup.wav"); AudioInputStream audioInputStream = AudioSystem .getAudioInputStream(soundFile); clip.open(audioInputStream); - - clip.setLoopPoints((int) (clip.getFrameLength() / 4), (int) (clip.getFrameLength() / 2)); + + clip.setLoopPoints((int) (clip.getFrameLength() / 4), (int) (clip + .getFrameLength() / 2)); clip.loop(4); try { Thread.sleep(2000); @@ -143,14 +178,14 @@ clip.loop(0); clip.close(); } - - @Test (expected=IllegalArgumentException.class) + + @Test(expected = IllegalArgumentException.class) public void testOpenWrongUse() throws LineUnavailableException { Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); clip.open(); - + } - + @After public void tearDown() {
--- a/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLineTest.java Mon Aug 25 14:51:13 2008 -0400 +++ b/unittests/org/classpath/icedtea/pulseaudio/PulseAudioTargetDataLineTest.java Mon Aug 25 17:27:52 2008 -0400 @@ -1,11 +1,14 @@ package org.classpath.icedtea.pulseaudio; +import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; import javax.sound.sampled.Line; import javax.sound.sampled.LineEvent; 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 junit.framework.JUnit4TestAdapter; @@ -17,13 +20,16 @@ public class PulseAudioTargetDataLineTest { + private Mixer mixer; + private TargetDataLine targetDataLine; + + AudioFormat aSupportedFormat = new AudioFormat( + AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 10, true); + public static junit.framework.Test suite() { return new JUnit4TestAdapter(PulseAudioTargetDataLineTest.class); } - private Mixer mixer; - private TargetDataLine targetDataLine; - @Before public void setUp() throws LineUnavailableException { Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo(); @@ -50,6 +56,29 @@ } @Test + public void testIsActiveAndIsOpen() throws LineUnavailableException { + + SourceDataLine line = (SourceDataLine) mixer.getLine(new DataLine.Info( + SourceDataLine.class, aSupportedFormat, 1000)); + + Assert.assertFalse(line.isActive()); + Assert.assertFalse(line.isOpen()); + line.open(); + Assert.assertTrue(line.isOpen()); + Assert.assertFalse(line.isActive()); + line.start(); + Assert.assertTrue(line.isOpen()); + Assert.assertTrue(line.isActive()); + line.stop(); + Assert.assertTrue(line.isOpen()); + Assert.assertFalse(line.isActive()); + line.close(); + Assert.assertFalse(line.isOpen()); + Assert.assertFalse(line.isActive()); + + } + + @Test public void testOpenEvents() throws LineUnavailableException { targetDataLine = (TargetDataLine) mixer.getLine(new Line.Info( TargetDataLine.class)); @@ -71,7 +100,7 @@ targetDataLine.open(); targetDataLine.removeLineListener(openListener); targetDataLine.close(); - + } @Test @@ -92,15 +121,13 @@ }; - targetDataLine.open(); targetDataLine.addLineListener(closeListener); targetDataLine.close(); targetDataLine.removeLineListener(closeListener); - + } - - + @After public void tearDown() { mixer.close();
--- a/unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java Mon Aug 25 14:51:13 2008 -0400 +++ b/unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java Mon Aug 25 17:27:52 2008 -0400 @@ -67,6 +67,9 @@ private int listenerCalled = 0; + AudioFormat aSupportedFormat = new AudioFormat( + AudioFormat.Encoding.PCM_UNSIGNED, 44100f, 8, 1, 1, 10, true); + public static junit.framework.Test suite() { return new JUnit4TestAdapter(PulseSourceDataLineTest.class); } @@ -79,6 +82,42 @@ } @Test + public void testOpenAndClose() throws LineUnavailableException { + SourceDataLine line = (SourceDataLine) mixer.getLine(new Line.Info( + SourceDataLine.class)); + + line.open(); + Assert.assertTrue(line.isOpen()); + + line.close(); + Assert.assertFalse(line.isOpen()); + + } + + @Test + public void testIsActiveAndIsOpen() throws LineUnavailableException { + + SourceDataLine line = (SourceDataLine) mixer.getLine(new DataLine.Info( + SourceDataLine.class, aSupportedFormat, 1000)); + + Assert.assertFalse(line.isActive()); + Assert.assertFalse(line.isOpen()); + line.open(); + Assert.assertTrue(line.isOpen()); + Assert.assertFalse(line.isActive()); + line.start(); + Assert.assertTrue(line.isOpen()); + Assert.assertTrue(line.isActive()); + line.stop(); + Assert.assertTrue(line.isOpen()); + Assert.assertFalse(line.isActive()); + line.close(); + Assert.assertFalse(line.isOpen()); + Assert.assertFalse(line.isActive()); + + } + + @Test public void testPlay() throws LineUnavailableException, UnsupportedAudioFileException, IOException { System.out.println("This test plays a file"); @@ -132,8 +171,9 @@ data[0] = (byte) 'a'; line.open(); + line.start(); line.write(data, 0, 1); - + line.stop(); line.close(); } @@ -387,6 +427,59 @@ line.close(); } + @Test + public void testBufferSizes() throws LineUnavailableException { + SourceDataLine line = (SourceDataLine) mixer.getLine(new Line.Info( + SourceDataLine.class)); + line.open(aSupportedFormat, 10000); + Assert.assertEquals(10000, line.getBufferSize()); + line.close(); + } + + @Test + public void testHasADefaultFormat() throws LineUnavailableException { + SourceDataLine line = (SourceDataLine) mixer.getLine(new Line.Info( + SourceDataLine.class)); + Assert.assertNotNull(line.getFormat()); + System.out.println(line.getFormat()); + + } + + @Test + public void testDefaultFormatWithGetLine() throws LineUnavailableException { + SourceDataLine line = (SourceDataLine) mixer.getLine(new DataLine.Info( + SourceDataLine.class, aSupportedFormat, 1000)); + Assert.assertEquals(aSupportedFormat, line.getFormat()); + + } + + @Test + public void testDefaultBufferSize() throws LineUnavailableException { + SourceDataLine line = (SourceDataLine) mixer.getLine(new DataLine.Info( + SourceDataLine.class, aSupportedFormat, 1000)); + Assert.assertEquals(StreamBufferAttributes.SANE_DEFAULT, line + .getBufferSize()); + } + + @Test + public void messWithStreams() throws LineUnavailableException { + System.out + .println("This test tries to cork(false) a stream which hasnt been corked"); + + PulseAudioSourceDataLine line = (PulseAudioSourceDataLine) mixer + .getLine(new DataLine.Info(SourceDataLine.class, + aSupportedFormat, 1000)); + + line.open(); + line.start(); + Stream s = line.getStream(); + Operation o; + synchronized (EventLoop.getEventLoop().threadLock) { + o = s.unCork(); + } + o.waitForCompletion(); + } + @After public void tearDown() throws Exception {