Attachment 'OggSpeexStreamWriter.java'

Download

   1 package au.com.foundationstone.model.audio.jspeex;
   2 
   3 
   4 import java.io.File;
   5 import java.io.IOException;
   6 import java.io.OutputStream;
   7 import java.util.Random;
   8 import org.xiph.speex.AudioFileWriter;
   9 import org.xiph.speex.OggCrc;
  10 import au.com.foundationstone.model.standalone.ModelConstants;
  11 
  12 
  13 /**
  14  * Ogg Speex Stream Writer
  15  * unfortunately cannot subclass OggSpeexWriter to get at the many private instance variables
  16  */
  17 public class OggSpeexStreamWriter extends AudioFileWriter {
  18 	private static final int FOUR = 4;
  19 	private static final int ONE_SIXTY = 160;
  20 	private static final int THREE_TWENTY = 320;
  21 	private static final int SIX_FORTY = 640;
  22 	private static final int EIGHT = 8;
  23 	private static final int TWENTY_TWO = 22;
  24 	private static final int EIGHTY = 80;
  25 	/** Number of packets in an Ogg page (must be less than 255) */
  26 	public static final int PACKETS_PER_OGG_PAGE = 250;
  27 	/** The OutputStream */
  28 	private OutputStream out;
  29 	/** Defines the encoder mode (0=NB, 1=WB and 2-UWB). */
  30 	private int mode;
  31 	/** Defines the sampling rate of the audio input. */
  32 	private int sampleRate;
  33 	/** Defines the number of channels of the audio input (1=mono, 2=stereo). */
  34 	private int channels;
  35 	/** Defines the number of frames per speex packet. */
  36 	private int nframes;
  37 	/** Defines whether or not to use VBR (Variable Bit Rate). */
  38 	private boolean vbr;
  39 	/** Ogg Stream Serial Number */
  40 	private int streamSerialNumber;
  41 	/** Data buffer */
  42 	private byte[] dataBuffer;
  43 	/** Pointer within the Data buffer */
  44 	private int dataBufferPtr;
  45 	/** Header buffer */
  46 	private byte[] headerBuffer;
  47 	/** Pointer within the Header buffer */
  48 	private int headerBufferPtr;
  49 	/** Ogg Page count */
  50 	private int pageCount;
  51 	/** Speex packet count within an Ogg Page */
  52 	private int packetCount;
  53 	/**
  54 	 * Absolute granule position
  55 	 * (the number of audio samples from beginning of file to end of Ogg Packet).
  56 	 */
  57 	private long granulepos;
  58 
  59 
  60 	/**
  61 	 * Builds an Ogg Speex Writer.
  62 	 */
  63 	public OggSpeexStreamWriter() {
  64 		if (streamSerialNumber == 0) streamSerialNumber = new Random().nextInt();
  65 		dataBuffer = new byte[ModelConstants.IO_BUFFER_SIZE];
  66 		dataBufferPtr = 0;
  67 		headerBuffer = new byte[ModelConstants.SMALL_IO_BUFFER_SIZE];
  68 		headerBufferPtr = 0;
  69 		pageCount = 0;
  70 		packetCount = 0;
  71 		granulepos = 0;
  72 	}
  73 
  74 
  75 	/**
  76 	 * Builds an Ogg Speex Writer.
  77 	 * @param mode       the mode of the encoder (0=NB, 1=WB, 2=UWB).
  78 	 * @param sampleRate the number of samples per second.
  79 	 * @param channels   the number of audio channels (1=mono, 2=stereo, ...).
  80 	 * @param nframes    the number of frames per speex packet.
  81 	 * @param vbr
  82 	 */
  83 	public OggSpeexStreamWriter(final int aMode, final int aSampleRate, final int numberOfChannels,
  84 		final int numberOfFrames, final boolean variableBitRate) {
  85 		this();
  86 		setFormat(aMode, aSampleRate, numberOfChannels, numberOfFrames, variableBitRate);
  87 	}
  88 
  89 
  90 	/**
  91 	 * Sets the output format.
  92 	 * Must be called before WriteHeader().
  93 	 * @param mode       the mode of the encoder (0=NB, 1=WB, 2=UWB).
  94 	 * @param sampleRate the number of samples per second.
  95 	 * @param channels   the number of audio channels (1=mono, 2=stereo, ...).
  96 	 * @param nframes    the number of frames per speex packet.
  97 	 * @param vbr
  98 	 */
  99 	private void setFormat(final int aMode, final int aSampleRate, final int numberOfChannels,
 100 		final int numberOfFrames, final boolean variableBitRate) {
 101 		this.mode = aMode;
 102 		this.sampleRate = aSampleRate;
 103 		this.channels = numberOfChannels;
 104 		this.nframes = numberOfFrames;
 105 		this.vbr = variableBitRate;
 106 	}
 107 
 108 
 109 	/**
 110 	 * Sets the Stream Serial Number.
 111 	 * Must not be changed mid stream.
 112 	 * @param serialNumber
 113 	 */
 114 	public void setSerialNumber(final int serialNumber) {
 115 		this.streamSerialNumber = serialNumber;
 116 	}
 117 
 118 
 119 	/**
 120 	 * Closes the output file.
 121 	 * @exception IOException if there was an exception closing the Audio Writer.
 122 	 */
 123 	public void close() throws IOException {
 124 		flush(true);
 125 		out.close();
 126 	}
 127 
 128 
 129 	public void open(final OutputStream outputStream) throws IOException {
 130 		out = outputStream;
 131 	}
 132 
 133 
 134 	/**
 135 	 * Writes the header pages that start the Ogg Speex file.
 136 	 * Prepares file for data to be written.
 137 	 * @param comment description to be included in the header.
 138 	 * @exception IOException
 139 	 */
 140 	public void writeHeader(final String comment) throws IOException {
 141 		int chksum;
 142 		byte[] header;
 143 		byte[] data;
 144 		/* writes the OGG header page */
 145 		header = buildOggPageHeader(2, 0, streamSerialNumber, pageCount++, 1, new byte[] { EIGHTY });
 146 		data = buildSpeexHeader(sampleRate, mode, channels, vbr, nframes);
 147 		chksum = OggCrc.checksum(0, header, 0, header.length);
 148 		chksum = OggCrc.checksum(chksum, data, 0, data.length);
 149 		writeInt(header, TWENTY_TWO, chksum);
 150 		out.write(header);
 151 		out.write(data);
 152 		/* writes the OGG comment page */
 153 		header = buildOggPageHeader(0, 0, streamSerialNumber, pageCount++, 1,
 154 			new byte[] { (byte) (comment.length() + EIGHT) });
 155 		data = buildSpeexComment(comment);
 156 		chksum = OggCrc.checksum(0, header, 0, header.length);
 157 		chksum = OggCrc.checksum(chksum, data, 0, data.length);
 158 		writeInt(header, TWENTY_TWO, chksum);
 159 		out.write(header);
 160 		out.write(data);
 161 	}
 162 
 163 
 164 	/**
 165 	 * Writes a packet of audio.
 166 	 * @param data - audio data.
 167 	 * @param offset - the offset from which to start reading the data.
 168 	 * @param len - the length of data to read.
 169 	 * @exception IOException
 170 	 */
 171 	public void writePacket(final byte[] data, final int offset, final int len) throws IOException {
 172 		if (len <= 0) { // nothing to write
 173 			return;
 174 		}
 175 		if (packetCount > PACKETS_PER_OGG_PAGE) {
 176 			flush(false);
 177 		}
 178 		System.arraycopy(data, offset, dataBuffer, dataBufferPtr, len);
 179 		dataBufferPtr += len;
 180 		headerBuffer[headerBufferPtr++] = (byte) len;
 181 		packetCount++;
 182 		int i1 = ONE_SIXTY;
 183 		if (mode == 2) i1 = SIX_FORTY;
 184 		if (mode == 1) i1 = THREE_TWENTY;
 185 		granulepos += nframes * i1;
 186 	}
 187 
 188 
 189 	/**
 190 	 * Flush the Ogg page out of the buffers into the file.
 191 	 * @param eos - end of stream
 192 	 * @exception IOException
 193 	 */
 194 	private void flush(final boolean eos) throws IOException {
 195 		int chksum;
 196 		byte[] header;
 197 		/* writes the OGG header page */
 198 		int headerType = 0;
 199 		if (eos) headerType = FOUR;
 200 		header = buildOggPageHeader(headerType, granulepos, streamSerialNumber, pageCount++, packetCount, headerBuffer);
 201 		chksum = OggCrc.checksum(0, header, 0, header.length);
 202 		chksum = OggCrc.checksum(chksum, dataBuffer, 0, dataBufferPtr);
 203 		writeInt(header, TWENTY_TWO, chksum);
 204 		out.write(header);
 205 		out.write(dataBuffer, 0, dataBufferPtr);
 206 		dataBufferPtr = 0;
 207 		headerBufferPtr = 0;
 208 		packetCount = 0;
 209 	}
 210 
 211 
 212 	/**
 213 	 * use OggSpeexWriter if you find yourself needing this
 214 	 */
 215 	public void open(final File file) throws IOException {
 216 		throw new UnsupportedOperationException();
 217 	}
 218 
 219 
 220 	/**
 221 	 * use OggSpeexWriter if you find yourself needing this
 222 	 */
 223 	public void open(final String filename) throws IOException {
 224 		throw new UnsupportedOperationException();
 225 	}
 226 }

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.

You are not allowed to attach a file to this page.