Mercurial > hg > pulseaudio
changeset 67:856e11044f24
2008-08-11 Omair Majid <omajid@redhat.com>
* src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java: now notifies any linelisteners of OPEN event. write() now tests the arguments passed to it
* src/native/org_classpath_icedtea_pulseaudio/PulseAudioSourceDataLine.c: enabled a little debug output
* unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java: added tests to confirm write's argument checking. also added tests to check that listeners are notified of OPEN and CLOSE LineEvents
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Tue, 12 Aug 2008 15:17:14 -0400 |
parents | 8f4e01b67c92 |
children | 9a72b909f18a |
files | src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java src/native/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.c unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java |
diffstat | 3 files changed, 158 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Tue Aug 12 11:28:22 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioSourceDataLine.java Tue Aug 12 15:17:14 2008 -0400 @@ -73,7 +73,7 @@ private AudioFormat currentFormat = null; private AudioFormat defaultFormat = null; - private List<LineListener> listeners; + private List<LineListener> lineListeners; private Control[] controls = null; private PulseAudioStreamMuteControl muteControl; @@ -123,7 +123,7 @@ public PulseAudioSourceDataLine(EventLoop eventLoop) { this.eventLoop = eventLoop; - this.listeners = new ArrayList<LineListener>(); + this.lineListeners = new ArrayList<LineListener>(); this.volume = PulseAudioVolumeControl.MAX_VOLUME; /* @@ -349,6 +349,24 @@ throw new IllegalArgumentException("Invalid format"); } + StreamListener openCloseListener = new StreamListener() { + + @Override + public void update(StreamEvent e) { + if (e.getType() == StreamEvent.Type.READY) { + fireLineEvent(new LineEvent(PulseAudioSourceDataLine.this, + LineEvent.Type.OPEN, AudioSystem.NOT_SPECIFIED)); + } else if (e.getType() == StreamEvent.Type.TERMINATED + || e.getType() == StreamEvent.Type.FAILED) { + fireLineEvent((new LineEvent(PulseAudioSourceDataLine.this, + LineEvent.Type.CLOSE, AudioSystem.NOT_SPECIFIED))); + } + } + + }; + + addStreamListener(openCloseListener); + final Semaphore semaphore = new Semaphore(0); synchronized (eventLoop.threadLock) { @@ -374,6 +392,7 @@ // throw new LineUnavailableException("unable to prepare // stream"); } + System.out.println(this.getClass().getName() + "stream is ready"); controls = new Control[2]; @@ -402,7 +421,18 @@ @Override public int write(byte[] data, int offset, int length) { - // TODO add check that the data is an integral number of frames + int frameSize = currentFormat.getFrameSize(); + if (length % frameSize != 0) { + throw new IllegalArgumentException( + "amount of data to write does not represent an integral number of frames"); + } + if (length < 0) { + throw new IllegalArgumentException("length is negative"); + } + + if (length + offset > data.length) { + throw new ArrayIndexOutOfBoundsException(length + offset); + } int position = offset; int remainingLength = length; @@ -462,11 +492,11 @@ } public void addLineListener(LineListener listener) { - this.listeners.add(listener); + this.lineListeners.add(listener); } public void removeLineListener(LineListener listener) { - this.listeners.remove(listener); + this.lineListeners.remove(listener); } private void addStreamListener(StreamListener listener) { @@ -490,10 +520,6 @@ native_close(); } - for (LineListener l : this.listeners) { - l.update(new LineEvent(this, LineEvent.Type.CLOSE, 0)); - } - } public int getBufferSize() { @@ -563,7 +589,7 @@ } else { return new Control[] {}; } - + } public javax.sound.sampled.Line.Info getLineInfo() { @@ -622,16 +648,16 @@ synchronized (eventLoop.threadLock) { switch (status) { case 0: - fireEvent(new StreamEvent(StreamEvent.Type.UNCONNECTED)); + fireStreamEvent(new StreamEvent(StreamEvent.Type.UNCONNECTED)); break; case 1: - fireEvent(new StreamEvent(StreamEvent.Type.CREATING)); + fireStreamEvent(new StreamEvent(StreamEvent.Type.CREATING)); break; case 2: - fireEvent(new StreamEvent(StreamEvent.Type.READY)); + fireStreamEvent(new StreamEvent(StreamEvent.Type.READY)); break; case 3: - fireEvent(new StreamEvent(StreamEvent.Type.FAILED)); + fireStreamEvent(new StreamEvent(StreamEvent.Type.FAILED)); break; case 4: break; @@ -641,8 +667,13 @@ } } - private void fireEvent(StreamEvent e) { + private void fireLineEvent(LineEvent e) { + for (LineListener lineListener : lineListeners) { + lineListener.update(e); + } + } + private void fireStreamEvent(StreamEvent e) { for (StreamListener streamListener : streamListeners) { streamListener.update(e); }
--- a/src/native/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.c Tue Aug 12 11:28:22 2008 -0400 +++ b/src/native/org_classpath_icedtea_pulseaudio_PulseAudioSourceDataLine.c Tue Aug 12 15:17:14 2008 -0400 @@ -75,7 +75,7 @@ jobject obj = java_context->obj; - // printf("stream state changed to %d\n", pa_stream_get_state(stream)); + printf("----> Stream state changed to %d\n", pa_stream_get_state(stream)); /* Call the 'update' method in java * to handle all java-side events
--- a/unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java Tue Aug 12 11:28:22 2008 -0400 +++ b/unittests/org/classpath/icedtea/pulseaudio/PulseSourceDataLineTest.java Tue Aug 12 15:17:14 2008 -0400 @@ -48,6 +48,8 @@ import javax.sound.sampled.DataLine; import javax.sound.sampled.FloatControl; 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; @@ -63,6 +65,8 @@ public class PulseSourceDataLineTest { Mixer mixer; + private int listenerCalled = 0; + public static junit.framework.Test suite() { return new JUnit4TestAdapter(PulseSourceDataLineTest.class); } @@ -105,6 +109,51 @@ } + @Test(expected = IllegalArgumentException.class) + public void testPlayLessThanFrameSize() throws LineUnavailableException, + UnsupportedAudioFileException, IOException { + File soundFile = new File("testsounds/startup.wav"); + AudioInputStream audioInputStream = AudioSystem + .getAudioInputStream(soundFile); + AudioFormat audioFormat = audioInputStream.getFormat(); + // the audio file must have an even number of channels + Assert.assertTrue(audioFormat.getChannels() % 2 == 0); + SourceDataLine line; + line = (SourceDataLine) mixer.getLine(new DataLine.Info( + SourceDataLine.class, audioFormat)); + + byte[] data = new byte[1]; + data[0] = (byte) 'a'; + + line.open(); + line.write(data, 0, 1); + + line.close(); + + } + + @Test + public void testOpenFormat() throws LineUnavailableException, + UnsupportedAudioFileException, IOException { + /* + * This test makes sure that the default format of a line using open() + * is the same format that was passed to the mixer's getLine() function + * to get the line in the first place + */ + + File soundFile = new File("testsounds/startup.wav"); + AudioInputStream audioInputStream = AudioSystem + .getAudioInputStream(soundFile); + AudioFormat audioFormat = audioInputStream.getFormat(); + + SourceDataLine line; + line = (SourceDataLine) mixer.getLine(new DataLine.Info( + SourceDataLine.class, audioFormat)); + Assert.assertNotNull(line); + line.open(); + Assert.assertTrue(line.getFormat().matches(audioFormat)); + } + @Test public void testFindLineWithFormat() throws LineUnavailableException { System.out @@ -199,6 +248,68 @@ sourceLine.close(); } + @Test + public void testOpenEvent() throws LineUnavailableException { + + listenerCalled = 0; + LineListener openListener = new LineListener() { + public void update(LineEvent event) { + Assert.assertTrue(event.getType() == LineEvent.Type.OPEN); + PulseSourceDataLineTest.this.listenerCalled++; + } + }; + + SourceDataLine line = (SourceDataLine) mixer.getLine(new Line.Info( + SourceDataLine.class)); + line.addLineListener(openListener); + line.open(); + line.removeLineListener(openListener); + line.close(); + Assert.assertEquals(1, listenerCalled); + listenerCalled = 0; + } + + @Test + public void testCloseEvent() throws LineUnavailableException { + listenerCalled = 0; + LineListener closeListener = new LineListener() { + public void update(LineEvent event) { + Assert.assertTrue(event.getType() == LineEvent.Type.CLOSE); + PulseSourceDataLineTest.this.listenerCalled++; + } + }; + + SourceDataLine line = (SourceDataLine) mixer.getLine(new Line.Info( + SourceDataLine.class)); + line.open(); + line.addLineListener(closeListener); + line.close(); + line.removeLineListener(closeListener); + Assert.assertEquals(1, listenerCalled); + listenerCalled = 0; + } + + @Test + public void testCloseEventWrongListener() throws LineUnavailableException { + listenerCalled = 0; + LineListener closeListener = new LineListener() { + public void update(LineEvent event) { + PulseSourceDataLineTest.this.listenerCalled++; + } + }; + + SourceDataLine line = (SourceDataLine) mixer.getLine(new Line.Info( + SourceDataLine.class)); + + line.open(); + line.addLineListener(closeListener); + line.removeLineListener(closeListener); + line.close(); + Assert.assertEquals(0, listenerCalled); + listenerCalled = 0; + + } + @After public void tearDown() throws Exception {