content: /******************************************************************************
   *                                                                            *
   * Copyright (c) 1999-2003 Wimba S.A., All Rights Reserved.                   *
   *                                                                            *
   * COPYRIGHT:                                                                 *
   *      This software is the property of Wimba S.A.                           *
   *      This software is redistributed under the Xiph.org variant of          *
   *      the BSD license.                                                      *
   *      Redistribution and use in source and binary forms, with or without    *
   *      modification, are permitted provided that the following conditions    *
   *      are met:                                                              *
   *      - Redistributions of source code must retain the above copyright      *
   *      notice, this list of conditions and the following disclaimer.         *
   *      - Redistributions in binary form must reproduce the above copyright   *
   *      notice, this list of conditions and the following disclaimer in the   *
   *      documentation and/or other materials provided with the distribution.  *
   *      - Neither the name of Wimba, the Xiph.org Foundation nor the names of *
   *      its contributors may be used to endorse or promote products derived   *
   *      from this software without specific prior written permission.         *
   *                                                                            *
   * WARRANTIES:                                                                *
   *      This software is made available by the authors in the hope            *
   *      that it will be useful, but without any warranty.                     *
   *      Wimba S.A. is not liable for any consequence related to the           *
   *      use of the provided software.                                         *
   *                                                                            *
   * Class: OggSpeexWriter.java                                                 *
   *                                                                            *
   * Author: Marc GIMPEL                                                        *
   *                                                                            *
   * Date: 9th April  2003                                                      *
   *                                                                            *
   ******************************************************************************/
  
  /* $Id: OggSpeexWriter.java,v 1.2 2011/12/28 02:45:11 gauss Exp $ */
  
  package com.mogujie.tt.audio;
  
  
  import android.util.Log;
  
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.util.Random;
  
  /**
   * Ogg Speex Writer
   * 
   * @author Marc Gimpel, Wimba S.A. (mgimpel@horizonwimba.com)
   * @version $Revision: 1.2 $
   */
  public class OggSpeexWriter extends AudioFileWriter {
      /** Number of packets in an Ogg page (must be less than 255) */
      public static final int PACKETS_PER_OGG_PAGE = 250;
  
      /** The OutputStream */
      private OutputStream out;
  
      /** Defines the encoder mode (0=NB, 1=WB and 2-UWB). */
      private int mode;
      /** Defines the sampling rate of the audio input. */
      private int sampleRate;
      /** Defines the number of channels of the audio input (1=mono, 2=stereo). */
      private int channels;
      /** Defines the number of frames per speex packet. */
      private int nframes;
      /** Defines whether or not to use VBR (Variable Bit Rate). */
      private boolean vbr;
  
      /** Ogg Stream Serial Number */
      private int streamSerialNumber;
      /** Data buffer */
      private byte[] dataBuffer;
      /** Pointer within the Data buffer */
      private int dataBufferPtr;
      /** Header buffer */
      private byte[] headerBuffer;
      /** Pointer within the Header buffer */
      private int headerBufferPtr;
      /** Ogg Page count */
      private int pageCount;
      /** Speex packet count within an Ogg Page */
      private int packetCount;
      /**
       * Absolute granule position (the number of audio samples from beginning of
       * file to end of Ogg Packet).
       */
      private long granulepos;
  
      /**
       * Builds an Ogg Speex Writer.
       */
      public OggSpeexWriter() {
          if (streamSerialNumber == 0)
              streamSerialNumber = new Random().nextInt();
          dataBuffer = new byte[65565];
          dataBufferPtr = 0;
          headerBuffer = new byte[255];
          headerBufferPtr = 0;
          pageCount = 0;
          packetCount = 0;
          granulepos = 0;
      }
  
      /**
       * Builds an Ogg Speex Writer.
       * 
       * @param mode the mode of the encoder (0=NB, 1=WB, 2=UWB).
       * @param sampleRate the number of samples per second.
       * @param channels the number of audio channels (1=mono, 2=stereo, ...).
       * @param nframes the number of frames per speex packet.
       * @param vbr
       */
      public OggSpeexWriter(final int mode, final int sampleRate, final int channels,
              final int nframes, final boolean vbr) {
          this();
          setFormat(mode, sampleRate, channels, nframes, vbr);
      }
  
      /**
       * Sets the output format. Must be called before WriteHeader().
       * 
       * @param mode the mode of the encoder (0=NB, 1=WB, 2=UWB).
       * @param sampleRate the number of samples per second.
       * @param channels the number of audio channels (1=mono, 2=stereo, ...).
       * @param nframes the number of frames per speex packet.
       * @param vbr
       */
      private void setFormat(final int mode, final int sampleRate, final int channels,
              final int nframes, boolean vbr) {
          this.mode = mode;
          this.sampleRate = sampleRate;
          this.channels = channels;
          this.nframes = nframes;
          this.vbr = vbr;
      }
  
      /**
       * Sets the Stream Serial Number. Must not be changed mid stream.
       * 
       * @param serialNumber
       */
      public void setSerialNumber(final int serialNumber) {
          this.streamSerialNumber = serialNumber;
      }
  
      /**
       * Closes the output file.
       * 
       * @exception IOException if there was an exception closing the Audio
       *                Writer.
       */
      public void close() throws IOException {
          flush(true);
          if(out==null){
              return;
          }
          out.close();
      }
  
      /**
       * Open the output file.
       * 
       * @param file - file to open.
       * @exception IOException if there was an exception opening the Audio
       *                Writer.
       */
      public void open(final File file) throws IOException {
          file.delete();
          Log.d("zzzzz","打开语音的文件路径是 "+file.getAbsolutePath());
          out = new FileOutputStream(file);
      }
  
      /**
       * Open the output file.
       * 
       * @param filename - file to open.
       * @exception IOException if there was an exception opening the Audio
       *                Writer.
       */
      public void open(final String filename) throws IOException {
          open(new File(filename));
      }
  
      /**
       * Writes the header pages that start the Ogg Speex file. Prepares file for
       * data to be written.
       * 
       * @param comment description to be included in the header.
       * @exception IOException
       */
      public void writeHeader(final String comment) throws IOException {
          int chksum;
          byte[] header;
          byte[] data;
          /* writes the OGG header page */
          header = buildOggPageHeader(2, 0, streamSerialNumber, pageCount++, 1, new byte[] {
              80
          });
          data = buildSpeexHeader(sampleRate, mode, channels, vbr, nframes);
          chksum = OggCrc.checksum(0, header, 0, header.length);
          chksum = OggCrc.checksum(chksum, data, 0, data.length);
          writeInt(header, 22, chksum);
          out.write(header);
          out.write(data);
          /* writes the OGG comment page */
          header = buildOggPageHeader(0, 0, streamSerialNumber, pageCount++, 1, new byte[] {
              (byte) (comment.length() + 8)
          });
          data = buildSpeexComment(comment);
          chksum = OggCrc.checksum(0, header, 0, header.length);
          chksum = OggCrc.checksum(chksum, data, 0, data.length);
          writeInt(header, 22, chksum);
          out.write(header);
          out.write(data);
      }
  
      /**
       * Writes a packet of audio.
       * 
       * @param data - audio data.
       * @param offset - the offset from which to start reading the data.
       * @param len - the length of data to read.
       * @exception IOException
       */
      public void writePacket(final byte[] data, final int offset, final int len) throws IOException {
  
          if (len <= 0) { // nothing to write
              return;
          }
          if (packetCount > PACKETS_PER_OGG_PAGE) {
              flush(false);
          }
          System.arraycopy(data, offset, dataBuffer, dataBufferPtr, len);
          dataBufferPtr += len;
          headerBuffer[headerBufferPtr++] = (byte) len;
          packetCount++;
          granulepos += nframes * (mode == 2 ? 640 : (mode == 1 ? 320 : 160));
      }
  
      /**
       * Flush the Ogg page out of the buffers into the file.
       * 
       * @param eos - end of stream
       * @exception IOException
       */
      private void flush(final boolean eos) throws IOException {
          int chksum;
          byte[] header;
          /* writes the OGG header page */
          header = buildOggPageHeader((eos ? 4 : 0), granulepos, streamSerialNumber, pageCount++,
                  packetCount, headerBuffer);
          chksum = OggCrc.checksum(0, header, 0, header.length);
          chksum = OggCrc.checksum(chksum, dataBuffer, 0, dataBufferPtr);
          writeInt(header, 22, chksum);
          if(out == null){
              return;
          }
          out.write(header);
          out.write(dataBuffer, 0, dataBufferPtr);
          dataBufferPtr = 0;
          headerBufferPtr = 0;
          packetCount = 0;
      }
  }
  