Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/com/sun/media/sound/AuFileWriter.java
38924 views
/*1* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.media.sound;2627import java.io.File;28import java.io.InputStream;29import java.io.OutputStream;30import java.io.IOException;3132import java.io.BufferedOutputStream;33import java.io.DataOutputStream;34import java.io.FileOutputStream;35import java.io.ByteArrayInputStream;36import java.io.ByteArrayOutputStream;37import java.io.RandomAccessFile;38import java.io.SequenceInputStream;3940import javax.sound.sampled.AudioFileFormat;41import javax.sound.sampled.AudioInputStream;42import javax.sound.sampled.AudioFormat;43import javax.sound.sampled.AudioSystem;444546/**47* AU file writer.48*49* @author Jan Borgersen50*/51public final class AuFileWriter extends SunFileWriter {5253//$$fb value for length field if length is not known54public final static int UNKNOWN_SIZE=-1;5556/**57* Constructs a new AuFileWriter object.58*/59public AuFileWriter() {60super(new AudioFileFormat.Type[]{AudioFileFormat.Type.AU});61}6263public AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {6465AudioFileFormat.Type[] filetypes = new AudioFileFormat.Type[types.length];66System.arraycopy(types, 0, filetypes, 0, types.length);6768// make sure we can write this stream69AudioFormat format = stream.getFormat();70AudioFormat.Encoding encoding = format.getEncoding();7172if( (AudioFormat.Encoding.ALAW.equals(encoding)) ||73(AudioFormat.Encoding.ULAW.equals(encoding)) ||74(AudioFormat.Encoding.PCM_SIGNED.equals(encoding)) ||75(AudioFormat.Encoding.PCM_UNSIGNED.equals(encoding)) ) {7677return filetypes;78}7980return new AudioFileFormat.Type[0];81}828384public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException {8586// we must know the total data length to calculate the file length87//$$fb 2001-07-13: fix for bug 4351296: do not throw an exception88//if( stream.getFrameLength() == AudioSystem.NOT_SPECIFIED ) {89// throw new IOException("stream length not specified");90//}9192// throws IllegalArgumentException if not supported93AuFileFormat auFileFormat = (AuFileFormat)getAudioFileFormat(fileType, stream);9495int bytesWritten = writeAuFile(stream, auFileFormat, out);96return bytesWritten;97}9899100101public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException {102103// throws IllegalArgumentException if not supported104AuFileFormat auFileFormat = (AuFileFormat)getAudioFileFormat(fileType, stream);105106// first write the file without worrying about length fields107FileOutputStream fos = new FileOutputStream( out ); // throws IOException108BufferedOutputStream bos = new BufferedOutputStream( fos, bisBufferSize );109int bytesWritten = writeAuFile(stream, auFileFormat, bos );110bos.close();111112// now, if length fields were not specified, calculate them,113// open as a random access file, write the appropriate fields,114// close again....115if( auFileFormat.getByteLength()== AudioSystem.NOT_SPECIFIED ) {116117// $$kk: 10.22.99: jan: please either implement this or throw an exception!118// $$fb: 2001-07-13: done. Fixes Bug 4479981119RandomAccessFile raf=new RandomAccessFile(out, "rw");120if (raf.length()<=0x7FFFFFFFl) {121// skip AU magic and data offset field122raf.skipBytes(8);123raf.writeInt(bytesWritten-AuFileFormat.AU_HEADERSIZE);124// that's all125}126raf.close();127}128129return bytesWritten;130}131132133// -------------------------------------------------------------134135/**136* Returns the AudioFileFormat describing the file that will be written from this AudioInputStream.137* Throws IllegalArgumentException if not supported.138*/139private AudioFileFormat getAudioFileFormat(AudioFileFormat.Type type, AudioInputStream stream) {140141AudioFormat format = null;142AuFileFormat fileFormat = null;143AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;144145AudioFormat streamFormat = stream.getFormat();146AudioFormat.Encoding streamEncoding = streamFormat.getEncoding();147148149float sampleRate;150int sampleSizeInBits;151int channels;152int frameSize;153float frameRate;154int fileSize;155156if( !types[0].equals(type) ) {157throw new IllegalArgumentException("File type " + type + " not supported.");158}159160if( (AudioFormat.Encoding.ALAW.equals(streamEncoding)) ||161(AudioFormat.Encoding.ULAW.equals(streamEncoding)) ) {162163encoding = streamEncoding;164sampleSizeInBits = streamFormat.getSampleSizeInBits();165166} else if ( streamFormat.getSampleSizeInBits()==8 ) {167168encoding = AudioFormat.Encoding.PCM_SIGNED;169sampleSizeInBits=8;170171} else {172173encoding = AudioFormat.Encoding.PCM_SIGNED;174sampleSizeInBits=streamFormat.getSampleSizeInBits();175}176177178format = new AudioFormat( encoding,179streamFormat.getSampleRate(),180sampleSizeInBits,181streamFormat.getChannels(),182streamFormat.getFrameSize(),183streamFormat.getFrameRate(),184true); // AU is always big endian185186187if( stream.getFrameLength()!=AudioSystem.NOT_SPECIFIED ) {188fileSize = (int)stream.getFrameLength()*streamFormat.getFrameSize() + AuFileFormat.AU_HEADERSIZE;189} else {190fileSize = AudioSystem.NOT_SPECIFIED;191}192193fileFormat = new AuFileFormat( AudioFileFormat.Type.AU,194fileSize,195format,196(int)stream.getFrameLength() );197198return fileFormat;199}200201202private InputStream getFileStream(AuFileFormat auFileFormat, InputStream audioStream) throws IOException {203204// private method ... assumes auFileFormat is a supported file type205206AudioFormat format = auFileFormat.getFormat();207208int magic = AuFileFormat.AU_SUN_MAGIC;209int headerSize = AuFileFormat.AU_HEADERSIZE;210long dataSize = auFileFormat.getFrameLength();211//$$fb fix for Bug 4351296212//int dataSizeInBytes = dataSize * format.getFrameSize();213long dataSizeInBytes = (dataSize==AudioSystem.NOT_SPECIFIED)?UNKNOWN_SIZE:dataSize * format.getFrameSize();214if (dataSizeInBytes>0x7FFFFFFFl) {215dataSizeInBytes=UNKNOWN_SIZE;216}217int encoding_local = auFileFormat.getAuType();218int sampleRate = (int)format.getSampleRate();219int channels = format.getChannels();220//$$fb below is the fix for 4297100.221//boolean bigendian = format.isBigEndian();222boolean bigendian = true; // force bigendian223224byte header[] = null;225ByteArrayInputStream headerStream = null;226ByteArrayOutputStream baos = null;227DataOutputStream dos = null;228SequenceInputStream auStream = null;229230AudioFormat audioStreamFormat = null;231AudioFormat.Encoding encoding = null;232InputStream codedAudioStream = audioStream;233234// if we need to do any format conversion, do it here.235236codedAudioStream = audioStream;237238if( audioStream instanceof AudioInputStream ) {239240241audioStreamFormat = ((AudioInputStream)audioStream).getFormat();242encoding = audioStreamFormat.getEncoding();243244//$$ fb 2001-07-13: Bug 4391108245if( (AudioFormat.Encoding.PCM_UNSIGNED.equals(encoding)) ||246(AudioFormat.Encoding.PCM_SIGNED.equals(encoding)247&& bigendian != audioStreamFormat.isBigEndian()) ) {248249// plug in the transcoder to convert to PCM_SIGNED, bigendian250// NOTE: little endian AU is not common, so we're always converting251// to big endian unless the passed in audioFileFormat is little.252// $$fb this NOTE is superseded. We always write big endian au files, this is by far the standard.253codedAudioStream = AudioSystem.getAudioInputStream( new AudioFormat (254AudioFormat.Encoding.PCM_SIGNED,255audioStreamFormat.getSampleRate(),256audioStreamFormat.getSampleSizeInBits(),257audioStreamFormat.getChannels(),258audioStreamFormat.getFrameSize(),259audioStreamFormat.getFrameRate(),260bigendian),261(AudioInputStream)audioStream );262263264}265}266267baos = new ByteArrayOutputStream();268dos = new DataOutputStream(baos);269270271if (bigendian) {272dos.writeInt(AuFileFormat.AU_SUN_MAGIC);273dos.writeInt(headerSize);274dos.writeInt((int)dataSizeInBytes);275dos.writeInt(encoding_local);276dos.writeInt(sampleRate);277dos.writeInt(channels);278} else {279dos.writeInt(AuFileFormat.AU_SUN_INV_MAGIC);280dos.writeInt(big2little(headerSize));281dos.writeInt(big2little((int)dataSizeInBytes));282dos.writeInt(big2little(encoding_local));283dos.writeInt(big2little(sampleRate));284dos.writeInt(big2little(channels));285}286287// Now create a new InputStream from headerStream and the InputStream288// in audioStream289290dos.close();291header = baos.toByteArray();292headerStream = new ByteArrayInputStream( header );293auStream = new SequenceInputStream(headerStream,294new NoCloseInputStream(codedAudioStream));295296return auStream;297}298299private int writeAuFile(InputStream in, AuFileFormat auFileFormat, OutputStream out) throws IOException {300301int bytesRead = 0;302int bytesWritten = 0;303InputStream fileStream = getFileStream(auFileFormat, in);304byte buffer[] = new byte[bisBufferSize];305int maxLength = auFileFormat.getByteLength();306307while( (bytesRead = fileStream.read( buffer )) >= 0 ) {308if (maxLength>0) {309if( bytesRead < maxLength ) {310out.write( buffer, 0, (int)bytesRead );311bytesWritten += bytesRead;312maxLength -= bytesRead;313} else {314out.write( buffer, 0, (int)maxLength );315bytesWritten += maxLength;316maxLength = 0;317break;318}319} else {320out.write( buffer, 0, (int)bytesRead );321bytesWritten += bytesRead;322}323}324325return bytesWritten;326}327328329}330331332