# HG changeset patch # User Omair Majid # Date 1222184298 14400 # Node ID 381f212496ebcb486c558ae890ef1bc286ffab72 # Parent 4a1c8f3d1f627f6c9b4d50a462f510f5f9e04df1 2008-09-23 Omair Majid * src/java/org/classpath/icedtea/pulseaudio/Operation.java (waitForComplete): Handles interrupts now. Maybe not the best way of handling them, but it works. * src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java (ClipThread.run): Drain the stream by using the stream functions, not by a call to drain. (drain): Fixed to work the way reported in the bug report. * unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java (testLoopStartStopClip): Renamed to testLoop4Times. Now uses drain to wait for the loop to complete playing. (testDrainWithoutStart): Added a timeout. (testDrainBlocksWhilePlaying): New function. Tests that drain() blocks while playing. (testLoop0Clip): Renamed to testLoop0InterruptsPlayback. (testFramePosition): New function. Checks the value of getLongFrames() from clip. (testFramePositionAfterLooping): Checks that Looping the clip still returns the correct number of frames played (not just the current frame position in the audio stream). diff -r 4a1c8f3d1f62 -r 381f212496eb src/java/org/classpath/icedtea/pulseaudio/Operation.java --- a/src/java/org/classpath/icedtea/pulseaudio/Operation.java Tue Sep 23 10:29:27 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/Operation.java Tue Sep 23 11:38:18 2008 -0400 @@ -133,6 +133,8 @@ public void waitForCompletion() { assert (operationPointer != null); + + boolean interrupted = false; do { synchronized (eventLoop.threadLock) { if (getState() == Operation.State.Done) { @@ -141,10 +143,15 @@ try { eventLoop.threadLock.wait(); } catch (InterruptedException e) { - e.printStackTrace(); + // ingore the interrupt for now + interrupted = true; } } } while (getState() != State.Done); + // let the caller know about the interrupt + if (interrupted) { + Thread.currentThread().interrupt(); + } } } diff -r 4a1c8f3d1f62 -r 381f212496eb src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java --- a/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Tue Sep 23 10:29:27 2008 -0400 +++ b/src/java/org/classpath/icedtea/pulseaudio/PulseAudioClip.java Tue Sep 23 11:38:18 2008 -0400 @@ -104,7 +104,15 @@ } - PulseAudioClip.this.drain(); + Operation operation; + + synchronized (eventLoop.threadLock) { + operation = stream.drain(); + } + + operation.waitForCompletion(); + operation.releaseReference(); + } } @@ -209,19 +217,29 @@ } + /* + * + * drain() on a Clip should block until the entire clip has finished playing + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4732218 + * + * + * @see org.classpath.icedtea.pulseaudio.PulseAudioDataLine#drain() + */ @Override public void drain() { if (!isOpen) { throw new IllegalStateException("line not open"); } - if (clipThread != null) { - clipThread.interrupt(); + while (clipThread != null && clipThread.isAlive()) { try { clipThread.join(); } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } + Operation operation; synchronized (eventLoop.threadLock) { diff -r 4a1c8f3d1f62 -r 381f212496eb unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java --- a/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java Tue Sep 23 10:29:27 2008 -0400 +++ b/unittests/org/classpath/icedtea/pulseaudio/PulseAudioClipTest.java Tue Sep 23 11:38:18 2008 -0400 @@ -116,8 +116,12 @@ } @Test - public void testLoopStopStartClip() throws LineUnavailableException, - IOException, UnsupportedAudioFileException { + public void testLoop4Times() throws LineUnavailableException, IOException, + UnsupportedAudioFileException { + System.out + .println("This tests loop(4) on the Clip. " + + "You should hear a certain part of the clip play back 5 time"); + Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); File soundFile = new File("testsounds/startup.wav"); AudioInputStream audioInputStream = AudioSystem @@ -127,18 +131,11 @@ clip.setLoopPoints((int) (clip.getFrameLength() / 4), (int) (clip .getFrameLength() / 2)); clip.loop(4); - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } + + clip.drain(); + clip.stop(); - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - clip.start(); + clip.close(); } @@ -280,7 +277,7 @@ } - @Test + @Test(timeout = 1000) public void testDrainWithoutStart() throws UnsupportedAudioFileException, IOException, LineUnavailableException { @@ -300,7 +297,37 @@ } @Test - public void testLoop0Clip() throws LineUnavailableException, IOException, + public void testDrainBlocksWhilePlaying() + throws UnsupportedAudioFileException, IOException, + LineUnavailableException { + + String fileName = "testsounds/startup.wav"; + File soundFile = new File(fileName); + AudioInputStream audioInputStream = AudioSystem + .getAudioInputStream(soundFile); + AudioFormat audioFormat = audioInputStream.getFormat(); + + Clip clip; + clip = (Clip) mixer.getLine(new DataLine.Info(Clip.class, audioFormat)); + Assert.assertNotNull(clip); + + long startTime = System.currentTimeMillis(); + + clip.open(audioInputStream); + clip.start(); + clip.drain(); + clip.stop(); + clip.close(); + + long endTime = System.currentTimeMillis(); + + Assert.assertTrue(endTime - startTime > 3000); + System.out.println("Playback of " + fileName + " completed in " + + (endTime - startTime) + " milliseconds"); + } + + @Test + public void testLoop0InterruptsPlayback() throws LineUnavailableException, IOException, UnsupportedAudioFileException { Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); File soundFile = new File("testsounds/startup.wav"); @@ -383,6 +410,65 @@ } @Test + public void testFramePosition() throws LineUnavailableException, + UnsupportedAudioFileException, IOException { + System.out + .println("This tests if the Clip provides the correct frame position"); + Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); + String fileName = "testsounds/logout.wav"; + File soundFile1 = new File(fileName); + AudioInputStream audioInputStream1 = AudioSystem + .getAudioInputStream(soundFile1); + clip.open(audioInputStream1); + + clip.start(); + + clip.drain(); + + long pos = clip.getFramePosition(); + + clip.close(); + + long expected = 136703; + long granularity = 100; + System.out.println("Frames in " + fileName + ": " + expected); + System.out.println("Frame position in clip :" + pos); + Assert.assertTrue("Expected: " + expected + " got " + pos, Math + .abs(expected - pos) < granularity); + + } + + @Test + public void testFramePositionAfterLooping() + throws LineUnavailableException, UnsupportedAudioFileException, + IOException { + System.out + .println("This tests if the Clip provides the correct frame position"); + Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class)); + String fileName = "testsounds/logout.wav"; + File soundFile1 = new File(fileName); + AudioInputStream audioInputStream1 = AudioSystem + .getAudioInputStream(soundFile1); + clip.open(audioInputStream1); + + clip.loop(1); + + clip.drain(); + + long pos = clip.getFramePosition(); + + clip.close(); + + long expected = 136703 * 2; + long granularity = 100; + System.out.println("Frames in " + fileName + ": " + expected); + System.out.println("Frame position in clip :" + pos); + Assert.assertTrue("Expected: " + expected + " got " + pos, Math + .abs(expected - pos) < granularity); + + } + + @Test public void testMixerKnowsAboutOpenClips() throws LineUnavailableException, UnsupportedAudioFileException, IOException { Clip clip = (Clip) mixer.getLine(new Line.Info(Clip.class));