6459818: Audio A-law and law decoder skip() method not implemented
authorserb
Tue, 12 Jan 2016 23:33:45 +0300
changeset 35685 f405bbd07cc6
parent 35684 900e28dae561
child 35686 1c21a27682a5
6459818: Audio A-law and law decoder skip() method not implemented Reviewed-by: amenkov
jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java
jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java
jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioInputStream.java
jdk/test/javax/sound/sampled/AudioInputStream/SkipOnConvertSampleSize.java
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java	Tue Jan 12 23:27:23 2016 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AlawCodec.java	Tue Jan 12 23:33:45 2016 +0300
@@ -254,7 +254,7 @@
     }
 
 
-    final class AlawCodecStream extends AudioInputStream {
+    private final class AlawCodecStream extends AudioInputStream {
 
         // tempBuffer required only for encoding (when encode is true)
         private static final int tempBufferSize = 64;
@@ -444,5 +444,12 @@
                 return (i - off);
             }
         }
+
+        @Override
+        public long skip(final long n) throws IOException {
+            // Implementation of this method assumes that we support
+            // encoding/decoding from/to 8/16 bits only
+            return encode ? super.skip(n * 2) / 2 : super.skip(n / 2) * 2;
+        }
     } // end class AlawCodecStream
 } // end class ALAW
--- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java	Tue Jan 12 23:27:23 2016 +0300
+++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/UlawCodec.java	Tue Jan 12 23:33:45 2016 +0300
@@ -242,7 +242,7 @@
     }
 
 
-    class UlawCodecStream extends AudioInputStream {
+    private final class UlawCodecStream extends AudioInputStream {
 
         private static final int tempBufferSize = 64;
         private byte tempBuffer [] = null;
@@ -414,6 +414,12 @@
                 return (i - off);
             }
         }
+
+        @Override
+        public long skip(final long n) throws IOException {
+            // Implementation of this method assumes that we support
+            // encoding/decoding from/to 8/16 bits only
+            return encode ? super.skip(n * 2) / 2 : super.skip(n / 2) * 2;
+        }
     } // end class UlawCodecStream
-
 } // end class ULAW
--- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioInputStream.java	Tue Jan 12 23:27:23 2016 +0300
+++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/AudioInputStream.java	Tue Jan 12 23:33:45 2016 +0300
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -321,31 +321,48 @@
      */
     @Override
     public long skip(long n) throws IOException {
+        if (n <= 0) {
+            return 0;
+        }
 
         // make sure not to skip fractional frames
-        if( (n%frameSize) != 0 ) {
-            n -= (n%frameSize);
+        final long reminder = n % frameSize;
+        if (reminder != 0) {
+            n -= reminder;
         }
 
-        if( frameLength != AudioSystem.NOT_SPECIFIED ) {
+        if (frameLength != AudioSystem.NOT_SPECIFIED) {
             // don't skip more than our set length in frames.
-            if( (n/frameSize) > (frameLength-framePos) ) {
-                n = (frameLength-framePos) * frameSize;
+            if ((n / frameSize) > (frameLength - framePos)) {
+                n = (frameLength - framePos) * frameSize;
             }
         }
-        long temp = stream.skip(n);
+        long remaining = n;
+        while (remaining > 0) {
+            // Some input streams like FileInputStream can return more bytes,
+            // when EOF is reached.
+            long ret = Math.min(stream.skip(remaining), remaining);
+            if (ret == 0) {
+                // EOF or not? we need to check.
+                if (stream.read() == -1) {
+                    break;
+                }
+                ret = 1;
+            } else if (ret < 0) {
+                // the skip should not return negative value, but check it also
+                break;
+            }
+            remaining -= ret;
+        }
+        final long temp =  n - remaining;
 
         // if no error, update our position.
-        if( temp%frameSize != 0 ) {
-
+        if (temp % frameSize != 0) {
             // Throw an IOException if we've skipped a fractional number of frames
             throw new IOException("Could not skip an integer number of frames.");
         }
-        if( temp >= 0 ) {
-            framePos += temp/frameSize;
-        }
+        framePos += temp/frameSize;
         return temp;
-
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/sound/sampled/AudioInputStream/SkipOnConvertSampleSize.java	Tue Jan 12 23:33:45 2016 +0300
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+
+import javax.sound.sampled.AudioFormat;
+import javax.sound.sampled.AudioFormat.Encoding;
+import javax.sound.sampled.AudioInputStream;
+import javax.sound.sampled.AudioSystem;
+
+/**
+ * @test
+ * @bug 6459818
+ * @summary Audio A-law and law decoder skip() method not implemented
+ * @author Klaus Jaensch
+ */
+public class SkipOnConvertSampleSize {
+
+    private static final int TEST_FRAME_LENGTH = 20000;
+
+    private static void testskipping(final Encoding encoding) throws Exception {
+
+        // create temporary PCM_SIGNED audio file
+        int pcmBufSize = TEST_FRAME_LENGTH * 2;
+        byte[] tempAudioBuf = new byte[pcmBufSize];
+        for (int i = 0; i < TEST_FRAME_LENGTH; i++) {
+            // fill with noise
+            tempAudioBuf[i * 2] = (byte) ((Math.random() - 1) * Byte.MAX_VALUE);
+            tempAudioBuf[i * 2 + 1] = (byte) ((Math.random() - 1)
+                    * Byte.MAX_VALUE);
+        }
+        final ByteArrayInputStream bis = new ByteArrayInputStream(tempAudioBuf);
+        AudioFormat format = new AudioFormat(8000, 16, 1, true, false);
+        final AudioInputStream testAis = new AudioInputStream(bis, format,
+                                                              TEST_FRAME_LENGTH);
+        final AudioFormat lawFormat;
+        final byte[] alawAudioBuf;
+        try (AudioInputStream lawStream = AudioSystem.getAudioInputStream(
+                encoding, testAis)) {
+
+            lawFormat = lawStream.getFormat();
+            int alawFrameSize = lawFormat.getFrameSize();
+
+            int lawBufSize = TEST_FRAME_LENGTH * alawFrameSize;
+            alawAudioBuf = new byte[lawBufSize];
+            int r1 = 0;
+            int totalRead = 0;
+            while ((r1 = lawStream.read(alawAudioBuf, totalRead,
+                                        lawBufSize - totalRead)) != -1) {
+                totalRead += r1;
+            }
+        }
+
+        // Convert back to PCM
+
+        ByteArrayInputStream alawBis = new ByteArrayInputStream(alawAudioBuf);
+        AudioInputStream lawAis = new AudioInputStream(alawBis, lawFormat,
+                                                       TEST_FRAME_LENGTH);
+        try (AudioInputStream convPcmStream = AudioSystem.getAudioInputStream(
+                Encoding.PCM_SIGNED, lawAis)) {
+            final AudioFormat convPcmAudioFormat = convPcmStream.getFormat();
+            final int convPcmFrameSize = convPcmAudioFormat.getFrameSize();
+
+            // skip half of the stream
+            final long toSkip = (TEST_FRAME_LENGTH / 2) * convPcmFrameSize;
+            long skipped = 0;
+            do {
+                skipped += convPcmStream.skip(toSkip - skipped);
+            } while (skipped < toSkip);
+            int r2 = convPcmStream.read(new byte[convPcmFrameSize]);
+            // if skip is not correctly implemented we are at the end of the
+            // stream
+            if (r2 == -1) {
+                throw new RuntimeException(
+                        "Skip method of decoder not correctly implemented!");
+            }
+            // otherwise we could read the rest ...
+            // we don't do it here
+        }
+    }
+
+    public static void main(final String[] args) throws Exception {
+        testskipping(Encoding.ALAW);
+        testskipping(Encoding.ULAW);
+    }
+}