/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /****************************************************************************** * * * Copyright (c) 1999-2004 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: RawWriter.java * * * * Author: Marc GIMPEL * * * * Date: 6th January 2004 * * * ******************************************************************************/ /* $Id: AudioFileWriter.java,v 1.1 2011/12/27 04:39:13 gauss Exp $ */ package my.home.common.speex; import java.io.DataOutput; import java.io.File; import java.io.IOException; import java.io.OutputStream; /** * Abstract Class that defines an Audio File Writer. * * @author Marc Gimpel, Wimba S.A. (mgimpel@horizonwimba.com) * @version $Revision: 1.1 $ */ public abstract class AudioFileWriter { /** * Closes the output file. * @exception IOException if there was an exception closing the Audio Writer. */ public abstract void close() throws IOException; /** * Open the output file. * @param file - file to open. * @exception IOException if there was an exception opening the Audio Writer. */ public abstract void open(File file) throws IOException; /** * Open the output file. * @param filename - file to open. * @exception IOException if there was an exception opening the Audio Writer. */ public abstract void open(String filename) throws IOException; /** * 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 abstract void writeHeader(String comment) throws IOException; /** * 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 abstract void writePacket(byte[] data, int offset, int len) throws IOException; /** * Writes an Ogg Page Header to the given byte array. * @param buf the buffer to write to. * @param offset the from which to start writing. * @param headerType the header type flag * (0=normal, 2=bos: beginning of stream, 4=eos: end of stream). * @param granulepos the absolute granule position. * @param streamSerialNumber * @param pageCount * @param packetCount * @param packetSizes * @return the amount of data written to the buffer. */ public static int writeOggPageHeader(byte[] buf, int offset, int headerType, long granulepos, int streamSerialNumber, int pageCount, int packetCount, byte[] packetSizes) { writeString(buf, offset, "OggS"); // 0 - 3: capture_pattern buf[offset + 4] = 0; // 4: stream_structure_version buf[offset + 5] = (byte) headerType; // 5: header_type_flag writeLong(buf, offset + 6, granulepos); // 6 - 13: absolute granule position writeInt(buf, offset + 14, streamSerialNumber); // 14 - 17: stream serial number writeInt(buf, offset + 18, pageCount); // 18 - 21: page sequence no writeInt(buf, offset + 22, 0); // 22 - 25: page checksum buf[offset + 26] = (byte) packetCount; // 26: page_segments System.arraycopy(packetSizes, 0, // 27 - x: segment_table buf, offset + 27, packetCount); return packetCount + 27; } /** * Builds and returns an Ogg Page Header. * @param headerType the header type flag * (0=normal, 2=bos: beginning of stream, 4=eos: end of stream). * @param granulepos the absolute granule position. * @param streamSerialNumber * @param pageCount * @param packetCount * @param packetSizes * @return an Ogg Page Header. */ public static byte[] buildOggPageHeader(int headerType, long granulepos, int streamSerialNumber, int pageCount, int packetCount, byte[] packetSizes) { byte[] data = new byte[packetCount + 27]; writeOggPageHeader(data, 0, headerType, granulepos, streamSerialNumber, pageCount, packetCount, packetSizes); return data; } /** * Writes a Speex Header to the given byte array. * @param buf the buffer to write to. * @param offset the from which to start writing. * @param sampleRate * @param mode * @param channels * @param vbr * @param nframes * @return the amount of data written to the buffer. */ public static int writeSpeexHeader(byte[] buf, int offset, int sampleRate, int mode, int channels, boolean vbr, int nframes) { writeString(buf, offset, "Speex "); // 0 - 7: speex_string writeString(buf, offset + 8, "speex-1.2rc"); // 8 - 27: speex_version System.arraycopy(new byte[11], 0, buf, offset + 17, 11); // : speex_version (fill in up to 20 bytes) writeInt(buf, offset + 28, 1); // 28 - 31: speex_version_id writeInt(buf, offset + 32, 80); // 32 - 35: header_size writeInt(buf, offset + 36, sampleRate); // 36 - 39: rate writeInt(buf, offset + 40, mode); // 40 - 43: mode (0=NB, 1=WB, 2=UWB) writeInt(buf, offset + 44, 4); // 44 - 47: mode_bitstream_version writeInt(buf, offset + 48, channels); // 48 - 51: nb_channels writeInt(buf, offset + 52, -1); // 52 - 55: bitrate writeInt(buf, offset + 56, 160 << mode); // 56 - 59: frame_size (NB=160, WB=320, UWB=640) writeInt(buf, offset + 60, vbr ? 1 : 0); // 60 - 63: mEnableVBR writeInt(buf, offset + 64, nframes); // 64 - 67: frames_per_packet writeInt(buf, offset + 68, 0); // 68 - 71: extra_headers writeInt(buf, offset + 72, 0); // 72 - 75: reserved1 writeInt(buf, offset + 76, 0); // 76 - 79: reserved2 return 80; } /** * Builds a Speex Header. * @param sampleRate * @param mode * @param channels * @param vbr * @param nframes * @return a Speex Header. */ public static byte[] buildSpeexHeader(int sampleRate, int mode, int channels, boolean vbr, int nframes) { byte[] data = new byte[80]; writeSpeexHeader(data, 0, sampleRate, mode, channels, vbr, nframes); return data; } /** * Writes a Speex Comment to the given byte array. * @param buf the buffer to write to. * @param offset the from which to start writing. * @param comment the comment. * @return the amount of data written to the buffer. */ public static int writeSpeexComment(byte[] buf, int offset, String comment) { int length = comment.length(); writeInt(buf, offset, length); // vendor comment size writeString(buf, offset + 4, comment); // vendor comment writeInt(buf, offset + length + 4, 0); // user comment list length return length + 8; } /** * Builds and returns a Speex Comment. * @param comment the comment. * @return a Speex Comment. */ public static byte[] buildSpeexComment(String comment) { byte[] data = new byte[comment.length() + 8]; writeSpeexComment(data, 0, comment); return data; } /** * Writes a Little-endian short. * @param out the data output to write to. * @param v value to write. * @exception IOException */ public static void writeShort(DataOutput out, short v) throws IOException { out.writeByte((0xff & v)); out.writeByte((0xff & (v >>> 8))); } /** * Writes a Little-endian int. * @param out the data output to write to. * @param v value to write. * @exception IOException */ public static void writeInt(DataOutput out, int v) throws IOException { out.writeByte(0xff & v); out.writeByte(0xff & (v >>> 8)); out.writeByte(0xff & (v >>> 16)); out.writeByte(0xff & (v >>> 24)); } /** * Writes a Little-endian short. * @param os - the output stream to write to. * @param v - the value to write. * @exception IOException */ public static void writeShort(OutputStream os, short v) throws IOException { os.write((0xff & v)); os.write((0xff & (v >>> 8))); } /** * Writes a Little-endian int. * @param os - the output stream to write to. * @param v - the value to write. * @exception IOException */ public static void writeInt(OutputStream os, int v) throws IOException { os.write(0xff & v); os.write(0xff & (v >>> 8)); os.write(0xff & (v >>> 16)); os.write(0xff & (v >>> 24)); } /** * Writes a Little-endian long. * @param os - the output stream to write to. * @param v - the value to write. * @exception IOException */ public static void writeLong(OutputStream os, long v) throws IOException { os.write((int) (0xff & v)); os.write((int) (0xff & (v >>> 8))); os.write((int) (0xff & (v >>> 16))); os.write((int) (0xff & (v >>> 24))); os.write((int) (0xff & (v >>> 32))); os.write((int) (0xff & (v >>> 40))); os.write((int) (0xff & (v >>> 48))); os.write((int) (0xff & (v >>> 56))); } /** * Writes a Little-endian short. * @param data the array into which the data should be written. * @param offset the offset from which to start writing in the array. * @param v the value to write. */ public static void writeShort(byte[] data, int offset, int v) { data[offset] = (byte) (0xff & v); data[offset + 1] = (byte) (0xff & (v >>> 8)); } /** * Writes a Little-endian int. * @param data the array into which the data should be written. * @param offset the offset from which to start writing in the array. * @param v the value to write. */ public static void writeInt(byte[] data, int offset, int v) { data[offset] = (byte) (0xff & v); data[offset + 1] = (byte) (0xff & (v >>> 8)); data[offset + 2] = (byte) (0xff & (v >>> 16)); data[offset + 3] = (byte) (0xff & (v >>> 24)); } /** * Writes a Little-endian long. * @param data the array into which the data should be written. * @param offset the offset from which to start writing in the array. * @param v the value to write. */ public static void writeLong(byte[] data, int offset, long v) { data[offset] = (byte) (0xff & v); data[offset + 1] = (byte) (0xff & (v >>> 8)); data[offset + 2] = (byte) (0xff & (v >>> 16)); data[offset + 3] = (byte) (0xff & (v >>> 24)); data[offset + 4] = (byte) (0xff & (v >>> 32)); data[offset + 5] = (byte) (0xff & (v >>> 40)); data[offset + 6] = (byte) (0xff & (v >>> 48)); data[offset + 7] = (byte) (0xff & (v >>> 56)); } /** * Writes a String. * @param data the array into which the data should be written. * @param offset the offset from which to start writing in the array. * @param v the value to write. */ public static void writeString(byte[] data, int offset, String v) { byte[] str = v.getBytes(); System.arraycopy(str, 0, data, offset, str.length); } }