--- old/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java 2016-02-05 19:59:38.000000000 +0300 +++ new/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java 2016-02-05 19:59:38.000000000 +0300 @@ -59,7 +59,6 @@ super(new AudioFileFormat.Type[]{AudioFileFormat.Type.AIFF}); } - // METHODS TO IMPLEMENT AudioFileWriter @Override @@ -83,7 +82,6 @@ return new AudioFileFormat.Type[0]; } - @Override public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException { Objects.requireNonNull(stream); @@ -102,11 +100,9 @@ throw new IOException("stream length not specified"); } - int bytesWritten = writeAiffFile(stream, aiffFileFormat, out); - return bytesWritten; + return writeAiffFile(stream, aiffFileFormat, out); } - @Override public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException { Objects.requireNonNull(stream); @@ -173,12 +169,7 @@ AudioFormat streamFormat = stream.getFormat(); AudioFormat.Encoding streamEncoding = streamFormat.getEncoding(); - - float sampleRate; int sampleSizeInBits; - int channels; - int frameSize; - float frameRate; int fileSize; boolean convert8to16 = false; @@ -235,7 +226,6 @@ return fileFormat; } - private int writeAiffFile(InputStream in, AiffFileFormat aiffFileFormat, OutputStream out) throws IOException { int bytesRead = 0; @@ -275,25 +265,20 @@ AudioFormat.Encoding encoding = null; //$$fb a little bit nicer handling of constants - - //int headerSize = 54; int headerSize = aiffFileFormat.getHeaderSize(); - //int fverChunkSize = 0; int fverChunkSize = aiffFileFormat.getFverChunkSize(); - //int commChunkSize = 26; int commChunkSize = aiffFileFormat.getCommChunkSize(); int aiffLength = -1; int ssndChunkSize = -1; - //int ssndOffset = headerSize - 16; int ssndOffset = aiffFileFormat.getSsndChunkOffset(); short channels = (short) format.getChannels(); short sampleSize = (short) format.getSampleSizeInBits(); - int ssndBlockSize = (channels * sampleSize); - int numFrames = aiffFileFormat.getFrameLength(); - long dataSize = -1; + int ssndBlockSize = channels * ((sampleSize + 7) / 8); + int numFrames = aiffFileFormat.getFrameLength(); + long dataSize = -1; if( numFrames != AudioSystem.NOT_SPECIFIED) { - dataSize = (long) numFrames * ssndBlockSize / 8; + dataSize = (long) numFrames * ssndBlockSize; ssndChunkSize = (int)dataSize + 16; aiffLength = (int)dataSize+headerSize; } @@ -403,9 +388,6 @@ } - - - // HELPER METHODS private static final int DOUBLE_MANTISSA_LENGTH = 52; @@ -452,6 +434,4 @@ dos.writeShort(extendedBits79To64); dos.writeLong(extendedBits63To0); } - - } --- old/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java 2016-02-05 19:59:39.000000000 +0300 +++ new/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java 2016-02-05 19:59:38.000000000 +0300 @@ -255,16 +255,17 @@ public AudioInputStream getAudioInputStream(final InputStream stream) throws UnsupportedAudioFileException, IOException { - AudioFileFormat format = getAudioFileFormat(stream); + final AudioFileFormat format = getAudioFileFormat(stream); // we've got everything, the stream is supported and it is at the // beginning of the header, so find the data chunk again and return an // AudioInputStream - RIFFReader riffiterator = new RIFFReader(stream); + final RIFFReader riffiterator = new RIFFReader(stream); while (riffiterator.hasNextChunk()) { RIFFReader chunk = riffiterator.nextChunk(); if (chunk.getFormat().equals("data")) { - return new AudioInputStream(chunk, format.getFormat(), chunk - .getSize()); + final AudioFormat af = format.getFormat(); + final long length = chunk.getSize() / af.getFrameSize(); + return new AudioInputStream(chunk, af, length); } } throw new UnsupportedAudioFileException(); --- old/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java 2016-02-05 19:59:39.000000000 +0300 +++ new/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java 2016-02-05 19:59:39.000000000 +0300 @@ -95,16 +95,17 @@ public AudioInputStream getAudioInputStream(final InputStream stream) throws UnsupportedAudioFileException, IOException { - AudioFileFormat format = getAudioFileFormat(stream); + final AudioFileFormat format = getAudioFileFormat(stream); // we've got everything, the stream is supported and it is at the // beginning of the header, so find the data chunk again and return an // AudioInputStream - RIFFReader riffiterator = new RIFFReader(stream); + final RIFFReader riffiterator = new RIFFReader(stream); while (riffiterator.hasNextChunk()) { RIFFReader chunk = riffiterator.nextChunk(); if (chunk.getFormat().equals("data")) { - return new AudioInputStream(chunk, format.getFormat(), - chunk.getSize()); + final AudioFormat af = format.getFormat(); + final long length = chunk.getSize() / af.getFrameSize(); + return new AudioInputStream(chunk, af, length); } } throw new UnsupportedAudioFileException(); --- /dev/null 2016-02-05 19:59:40.000000000 +0300 +++ new/test/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java 2016-02-05 19:59:40.000000000 +0300 @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016, 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 java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileWriter; +import javax.sound.sampled.spi.FormatConversionProvider; + +import static java.util.ServiceLoader.load; +import static javax.sound.sampled.AudioFileFormat.Type.AIFC; +import static javax.sound.sampled.AudioFileFormat.Type.AIFF; +import static javax.sound.sampled.AudioFileFormat.Type.AU; +import static javax.sound.sampled.AudioFileFormat.Type.SND; +import static javax.sound.sampled.AudioFileFormat.Type.WAVE; +import static javax.sound.sampled.AudioSystem.NOT_SPECIFIED; + +/** + * @test + * @bug 8038139 + */ +public final class FrameLengthAfterConversion { + + /** + * We will try to use all formats, in this case all our providers will be + * covered by supported/unsupported formats. + */ + private static final List formats = new ArrayList<>(23000); + + private static final AudioFormat.Encoding[] encodings = { + AudioFormat.Encoding.ALAW, AudioFormat.Encoding.ULAW, + AudioFormat.Encoding.PCM_SIGNED, AudioFormat.Encoding.PCM_UNSIGNED, + AudioFormat.Encoding.PCM_FLOAT, new AudioFormat.Encoding("Test") + }; + + private static final int[] sampleBits = { + 1, 4, 8, 11, 16, 20, 24, 32, 48, 64, 128 + }; + + private static final int[] channels = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 + }; + + private static final AudioFileFormat.Type[] types = { + WAVE, AU, AIFF, AIFC, SND, + new AudioFileFormat.Type("TestName", "TestExt") + }; + + private static final int FRAME_LENGTH = 10; + + static { + for (final int sampleSize : sampleBits) { + for (final int channel : channels) { + for (final AudioFormat.Encoding enc : encodings) { + final int frameSize = ((sampleSize + 7) / 8) * channel; + formats.add(new AudioFormat(enc, 44100, sampleSize, channel, + frameSize, 44100, true)); + formats.add(new AudioFormat(enc, 44100, sampleSize, channel, + frameSize, 44100, false)); + } + } + } + } + + public static void main(final String[] args) { + for (final FormatConversionProvider fcp : load( + FormatConversionProvider.class)) { + System.out.println("fcp = " + fcp); + for (final AudioFormat from : formats) { + final AudioInputStream ais = getStream(from); + for (final AudioFormat to : formats) { + testAfterConversion(fcp, ais, to); + } + } + } + + for (final AudioFileWriter afw : load(AudioFileWriter.class)) { + System.out.println("afw = " + afw); + for (final AudioFileFormat.Type type : types) { + for (final AudioFormat from : formats) { + testAfterSaveToFile(afw, type, from); + } + } + } + } + + /** + * Verifies the frame length after the stream was saved/read to/from + * stream. + */ + private static void testAfterSaveToFile(AudioFileWriter afw, + AudioFileFormat.Type type, + AudioFormat from) { + final AudioInputStream ais = getStream(from); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + afw.write(ais, type, out); + InputStream input = new ByteArrayInputStream(out.toByteArray()); + validate(AudioSystem.getAudioInputStream(input).getFrameLength()); + } catch (IllegalArgumentException | UnsupportedAudioFileException + | IOException ignored) { + } + } + + /** + * Verifies the frame length after the stream was converted to other + * stream. + * + * @see FormatConversionProvider#getAudioInputStream(AudioFormat, + * AudioInputStream) + */ + private static void testAfterConversion(FormatConversionProvider fcp, + AudioInputStream ais, + AudioFormat to) { + if (fcp.isConversionSupported(to, ais.getFormat())) { + validate(fcp.getAudioInputStream(to, ais).getFrameLength()); + } + } + + /** + * Throws an exception if the frameLength is specified and is not equal to + * the gold value. + */ + private static void validate(final long frameLength) { + if (frameLength != NOT_SPECIFIED && frameLength != FRAME_LENGTH) { + System.err.println("Expected: " + FRAME_LENGTH); + System.err.println("Actual: " + frameLength); + throw new RuntimeException(); + } + } + + private static AudioInputStream getStream(final AudioFormat format) { + final InputStream in = new ByteArrayInputStream(new byte[2048]); + return new AudioInputStream(in, format, FRAME_LENGTH); + } +}