Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]
    1   /*
    2    * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package com.sun.media.sound;
   27   
   28   import java.io.File;
   29   import java.io.InputStream;
   30   import java.io.OutputStream;
   31   import java.io.IOException;
   32   
   33   import java.io.BufferedOutputStream;
   34   import java.io.DataOutputStream;
   35   import java.io.FileOutputStream;
   36   import java.io.ByteArrayInputStream;
   37   import java.io.ByteArrayOutputStream;
   38   import java.io.RandomAccessFile;
   39   import java.io.SequenceInputStream;
   40   
   41   import javax.sound.sampled.AudioFileFormat;
   42   import javax.sound.sampled.AudioInputStream;
   43   import javax.sound.sampled.AudioFormat;
   44   import javax.sound.sampled.AudioSystem;
   45   
   46   
   47   /**
   48    * AU file writer.
   49    *
   50    * @author Jan Borgersen
   51    */
   52   public class AuFileWriter extends SunFileWriter {
   53   
   54       //$$fb value for length field if length is not known
   55       public final static int UNKNOWN_SIZE=-1;
   56   
   57       /**
   58        * AU type
   59        */
   60       private static final AudioFileFormat.Type auTypes[] = {
   61           AudioFileFormat.Type.AU
   62       };
   63   
   64   
   65       /**
   66        * Constructs a new AuFileWriter object.
   67        */
   68       public AuFileWriter() {
   69           super(auTypes);
   70       }
   71   
   72   
   73   
   74       public AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream stream) {
   75   
   76           AudioFileFormat.Type[] filetypes = new AudioFileFormat.Type[types.length];
   77           System.arraycopy(types, 0, filetypes, 0, types.length);
   78   
   79           // make sure we can write this stream
   80           AudioFormat format = stream.getFormat();
   81           AudioFormat.Encoding encoding = format.getEncoding();
   82   
   83           if( (AudioFormat.Encoding.ALAW.equals(encoding)) ||
   84               (AudioFormat.Encoding.ULAW.equals(encoding)) ||
   85               (AudioFormat.Encoding.PCM_SIGNED.equals(encoding)) ||
   86               (AudioFormat.Encoding.PCM_UNSIGNED.equals(encoding)) ) {
   87   
   88               return filetypes;
   89           }
   90   
   91           return new AudioFileFormat.Type[0];
   92       }
   93   
   94   
   95       public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException {
   96   
   97           // we must know the total data length to calculate the file length
   98           //$$fb 2001-07-13: fix for bug 4351296: do not throw an exception
   99           //if( stream.getFrameLength() == AudioSystem.NOT_SPECIFIED ) {
  100           //      throw new IOException("stream length not specified");
  101           //}
  102   
  103           // throws IllegalArgumentException if not supported
  104           AuFileFormat auFileFormat = (AuFileFormat)getAudioFileFormat(fileType, stream);
  105   
  106           int bytesWritten = writeAuFile(stream, auFileFormat, out);
  107           return bytesWritten;
  108       }
  109   
  110   
  111   
  112       public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException {
  113   
  114           // throws IllegalArgumentException if not supported
  115           AuFileFormat auFileFormat = (AuFileFormat)getAudioFileFormat(fileType, stream);
  116   
  117           // first write the file without worrying about length fields
  118           FileOutputStream fos = new FileOutputStream( out );     // throws IOException
  119           BufferedOutputStream bos = new BufferedOutputStream( fos, bisBufferSize );
  120           int bytesWritten = writeAuFile(stream, auFileFormat, bos );
  121           bos.close();
  122   
  123           // now, if length fields were not specified, calculate them,
  124           // open as a random access file, write the appropriate fields,
  125           // close again....
  126           if( auFileFormat.getByteLength()== AudioSystem.NOT_SPECIFIED ) {
  127   
  128               // $$kk: 10.22.99: jan: please either implement this or throw an exception!
  129               // $$fb: 2001-07-13: done. Fixes Bug 4479981
  130               RandomAccessFile raf=new RandomAccessFile(out, "rw");
  131               if (raf.length()<=0x7FFFFFFFl) {
  132                   // skip AU magic and data offset field
  133                   raf.skipBytes(8);
  134                   raf.writeInt(bytesWritten-AuFileFormat.AU_HEADERSIZE);
  135                   // that's all
  136               }
  137               raf.close();
  138           }
  139   
  140           return bytesWritten;
  141       }
  142   
  143   
  144       // -------------------------------------------------------------
  145   
  146       /**
  147        * Returns the AudioFileFormat describing the file that will be written from this AudioInputStream.
  148        * Throws IllegalArgumentException if not supported.
  149        */
  150       private AudioFileFormat getAudioFileFormat(AudioFileFormat.Type type, AudioInputStream stream) {
  151   
  152           AudioFormat format = null;
  153           AuFileFormat fileFormat = null;
  154           AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
  155   
  156           AudioFormat streamFormat = stream.getFormat();
  157           AudioFormat.Encoding streamEncoding = streamFormat.getEncoding();
  158   
  159   
  160           float sampleRate;
  161           int sampleSizeInBits;
  162           int channels;
  163           int frameSize;
  164           float frameRate;
  165           int fileSize;
  166   
  167           if( !types[0].equals(type) ) {
  168               throw new IllegalArgumentException("File type " + type + " not supported.");
  169           }
  170   
  171           if( (AudioFormat.Encoding.ALAW.equals(streamEncoding)) ||
  172               (AudioFormat.Encoding.ULAW.equals(streamEncoding)) ) {
  173   
  174               encoding = streamEncoding;
  175               sampleSizeInBits = streamFormat.getSampleSizeInBits();
  176   
  177           } else if ( streamFormat.getSampleSizeInBits()==8 ) {
  178   
  179               encoding = AudioFormat.Encoding.PCM_SIGNED;
  180               sampleSizeInBits=8;
  181   
  182           } else {
  183   
  184               encoding = AudioFormat.Encoding.PCM_SIGNED;
  185               sampleSizeInBits=streamFormat.getSampleSizeInBits();
  186           }
  187   
  188   
  189           format = new AudioFormat( encoding,
  190                                     streamFormat.getSampleRate(),
  191                                     sampleSizeInBits,
  192                                     streamFormat.getChannels(),
  193                                     streamFormat.getFrameSize(),
  194                                     streamFormat.getFrameRate(),
  195                                     true);        // AU is always big endian
  196   
  197   
  198           if( stream.getFrameLength()!=AudioSystem.NOT_SPECIFIED ) {
  199               fileSize = (int)stream.getFrameLength()*streamFormat.getFrameSize() + AuFileFormat.AU_HEADERSIZE;
  200           } else {
  201               fileSize = AudioSystem.NOT_SPECIFIED;
  202           }
  203   
  204           fileFormat = new AuFileFormat( AudioFileFormat.Type.AU,
  205                                          fileSize,
  206                                          format,
  207                                          (int)stream.getFrameLength() );
  208   
  209           return fileFormat;
  210       }
  211   
  212   
  213       private InputStream getFileStream(AuFileFormat auFileFormat, InputStream audioStream) throws IOException {
  214   
  215           // private method ... assumes auFileFormat is a supported file type
  216   
  217           AudioFormat format            = auFileFormat.getFormat();
  218   
  219           int magic          = AuFileFormat.AU_SUN_MAGIC;
  220           int headerSize     = AuFileFormat.AU_HEADERSIZE;
  221           long dataSize       = auFileFormat.getFrameLength();
  222           //$$fb fix for Bug 4351296
  223           //int dataSizeInBytes = dataSize * format.getFrameSize();
  224           long dataSizeInBytes = (dataSize==AudioSystem.NOT_SPECIFIED)?UNKNOWN_SIZE:dataSize * format.getFrameSize();
  225           if (dataSizeInBytes>0x7FFFFFFFl) {
  226               dataSizeInBytes=UNKNOWN_SIZE;
  227           }
  228           int encoding_local = auFileFormat.getAuType();
  229           int sampleRate     = (int)format.getSampleRate();
  230           int channels       = format.getChannels();
  231           //$$fb below is the fix for 4297100.
  232           //boolean bigendian      = format.isBigEndian();
  233           boolean bigendian      = true;                  // force bigendian
  234   
  235           byte header[] = null;
  236           ByteArrayInputStream headerStream = null;
  237           ByteArrayOutputStream baos = null;
  238           DataOutputStream dos = null;
  239           SequenceInputStream auStream = null;
  240   
  241           AudioFormat audioStreamFormat = null;
  242           AudioFormat.Encoding encoding = null;
  243           InputStream codedAudioStream = audioStream;
  244   
  245           // if we need to do any format conversion, do it here.
  246   
  247           codedAudioStream = audioStream;
  248   
  249           if( audioStream instanceof AudioInputStream ) {
  250   
  251   
  252               audioStreamFormat = ((AudioInputStream)audioStream).getFormat();
  253               encoding = audioStreamFormat.getEncoding();
  254   
  255               //$$ fb 2001-07-13: Bug 4391108
  256               if( (AudioFormat.Encoding.PCM_UNSIGNED.equals(encoding)) ||
  257                   (AudioFormat.Encoding.PCM_SIGNED.equals(encoding)
  258                    && bigendian != audioStreamFormat.isBigEndian()) ) {
  259   
  260                                   // plug in the transcoder to convert to PCM_SIGNED, bigendian
  261                                   // NOTE: little endian AU is not common, so we're always converting
  262                                   //       to big endian unless the passed in audioFileFormat is little.
  263                                   // $$fb this NOTE is superseded. We always write big endian au files, this is by far the standard.
  264                   codedAudioStream = AudioSystem.getAudioInputStream( new AudioFormat (
  265                                                                                        AudioFormat.Encoding.PCM_SIGNED,
  266                                                                                        audioStreamFormat.getSampleRate(),
  267                                                                                        audioStreamFormat.getSampleSizeInBits(),
  268                                                                                        audioStreamFormat.getChannels(),
  269                                                                                        audioStreamFormat.getFrameSize(),
  270                                                                                        audioStreamFormat.getFrameRate(),
  271                                                                                        bigendian),
  272                                                                       (AudioInputStream)audioStream );
  273   
  274   
  275               }
  276           }
  277   
  278           baos = new ByteArrayOutputStream();
  279           dos = new DataOutputStream(baos);
  280   
  281   
  282           if (bigendian) {
  283               dos.writeInt(AuFileFormat.AU_SUN_MAGIC);
  284               dos.writeInt(headerSize);
  285               dos.writeInt((int)dataSizeInBytes);
  286               dos.writeInt(encoding_local);
  287               dos.writeInt(sampleRate);
  288               dos.writeInt(channels);
  289           } else {
  290               dos.writeInt(AuFileFormat.AU_SUN_INV_MAGIC);
  291               dos.writeInt(big2little(headerSize));
  292               dos.writeInt(big2little((int)dataSizeInBytes));
  293               dos.writeInt(big2little(encoding_local));
  294               dos.writeInt(big2little(sampleRate));
  295               dos.writeInt(big2little(channels));
  296           }
  297   
  298           // Now create a new InputStream from headerStream and the InputStream
  299           // in audioStream
  300   
  301           dos.close();
  302           header = baos.toByteArray();
  303           headerStream = new ByteArrayInputStream( header );
  304           auStream = new SequenceInputStream(headerStream,
  305                           new NoCloseInputStream(codedAudioStream));
  306   
  307           return auStream;
  308       }
  309   
  310       private int writeAuFile(InputStream in, AuFileFormat auFileFormat, OutputStream out) throws IOException {
  311   
  312           int bytesRead = 0;
  313           int bytesWritten = 0;
  314           InputStream fileStream = getFileStream(auFileFormat, in);
  315           byte buffer[] = new byte[bisBufferSize];
  316           int maxLength = auFileFormat.getByteLength();
  317   
  318           while( (bytesRead = fileStream.read( buffer )) >= 0 ) {
  319               if (maxLength>0) {
  320                   if( bytesRead < maxLength ) {
  321                       out.write( buffer, 0, (int)bytesRead );
  322                       bytesWritten += bytesRead;
  323                       maxLength -= bytesRead;
  324                   } else {
  325                       out.write( buffer, 0, (int)maxLength );
  326                       bytesWritten += maxLength;
  327                       maxLength = 0;
  328                       break;
  329                   }
  330               } else {
  331                   out.write( buffer, 0, (int)bytesRead );
  332                   bytesWritten += bytesRead;
  333               }
  334           }
  335   
  336           return bytesWritten;
  337       }
  338   
  339   
  340   }

Save This Page
Home » openjdk-7 » com.sun.media » sound » [javadoc | source]