/* * Copyright 2007 Sun Microsystems, Inc. * * This file is part of jVoiceBridge. * * jVoiceBridge is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation and distributed hereunder * to you. * * jVoiceBridge is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Sun designates this particular file as subject to the "Classpath" * exception as provided by Sun in the License file that accompanied this * code. */ package com.sun.voip; import org.xiph.speex.*; public class SpeexEncoder { private org.xiph.speex.SpeexEncoder speexEncoder; private int sampleRate; private int channels; private int pcmPacketSize; private int encodes; private int bytesEncoded = 0; private long encodeTime; private boolean bigEndian = true; public SpeexEncoder(int sampleRate, int channels) throws SpeexException { this.sampleRate = sampleRate; this.channels = channels; if (sampleRate > 32000) { throw new SpeexException( "Speex cannot be used with sample rate " + sampleRate); } speexEncoder = new org.xiph.speex.SpeexEncoder(); int mode = 0; String s = "Narrow Band"; if (sampleRate > 8000) { s = "Wide Band"; mode++; // wide band } if (sampleRate > 16000) { s = "Ultra-Wide Band"; mode++; // ultra wide band } if (Logger.logLevel >= Logger.LOG_INFO) { Logger.println("Initializing Speex encoder using " + sampleRate + "/" + channels + " " + s); } if (speexEncoder.init(mode, 0, sampleRate, channels) == false) { throw new SpeexException( "Speex encoder initialization failed!"); } try { speexEncoder.setBigEndian(true); } catch (Exception e) { bigEndian = false; } speexEncoder.getEncoder().setVbr(true); pcmPacketSize = 2 * channels * speexEncoder.getFrameSize();; if (Logger.logLevel >= Logger.LOG_INFO) { Logger.println("speex frame size " + speexEncoder.getFrameSize() + " pcmPacketSize " + pcmPacketSize); } } public void setQuality(int quality) { speexEncoder.getEncoder().setQuality(quality); } public void setComplexity(int complexity) { // XXX setting complexity to 0 breaks it horribly! speexEncoder.getEncoder().setComplexity(complexity); } public int getPcmPacketSize() { return pcmPacketSize; } /* * processes data starting at offset for length bytes. * Return the length of the encoded data. */ public int encode(int[] inData, byte[] outData, int outOffset) throws SpeexException { return encode(AudioConversion.intsToBytes(inData), outData, outOffset); } public int encode(byte[] inData, byte[] outData, int outOffset) throws SpeexException { if (Logger.logLevel == -59) { Logger.logLevel = 3; Util.dump("encode input: length " + inData.length, inData, 0, 16); } long start = CurrentTime.getTime(); if (bigEndian == false) { /* * The latest version of JSpeex only understands little endian */ byte[] data = new byte[inData.length]; for (int i = 0; i < data.length; i += 2) { data[i] = inData[i + 1]; data[i + 1] = inData[i]; } inData = data; } try { speexEncoder.processData(inData, 0, inData.length); } catch (Exception e) { Logger.println("inData.length " + inData.length + " outData.length " + outData.length + " outOffset " + outOffset); e.printStackTrace(); throw new SpeexException("SpeexEncode: " + e.getMessage()); } int encSize = speexEncoder.getProcessedDataByteSize(); encodes++; encodeTime += (CurrentTime.getTime() - start); bytesEncoded += inData.length; speexEncoder.getProcessedData(outData, outOffset); if (Logger.logLevel >= Logger.LOG_MOREDETAIL) { Util.dump("encodeData output: " + encSize, outData, 0, encSize); } return encSize; } public int getEncodes() { return encodes; } public int getBytesEncoded() { return bytesEncoded; } public long getEncodeTime() { return encodeTime; } public void resetStatistics() { encodes = 0; bytesEncoded = 0; encodeTime = 0; } }