6459818: Audio A-law and law decoder skip() method not implemented
Reviewed-by: amenkov
--- 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);
+ }
+}