|
|
|
|
@ -11,6 +11,7 @@
|
|
|
|
|
|
|
|
|
|
import org.xiph.speex.*;
|
|
|
|
|
import net.java.sip.communicator.impl.neomedia.codec.*;
|
|
|
|
|
import net.sf.fmj.media.*;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The Speex Encoder
|
|
|
|
|
@ -18,16 +19,48 @@
|
|
|
|
|
* @author Damian Minkov
|
|
|
|
|
*/
|
|
|
|
|
public class JavaEncoder
|
|
|
|
|
extends com.ibm.media.codec.audio.AudioCodec
|
|
|
|
|
extends AbstractCodec
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* Default output formats.
|
|
|
|
|
*/
|
|
|
|
|
protected Format[] DEFAULT_OUTPUT_FORMATS = new Format[] {
|
|
|
|
|
new AudioFormat(Constants.SPEEX_RTP)};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The last input format used by this instance of the encoder.
|
|
|
|
|
* If null we must create the encoder with the current input format.
|
|
|
|
|
*/
|
|
|
|
|
private Format lastFormat = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Our custom output format which computes the rtp data duration correctly.
|
|
|
|
|
*/
|
|
|
|
|
private AudioFormat outFormat = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The frame size used for current encoder configuration.
|
|
|
|
|
*/
|
|
|
|
|
private int FRAME_SIZE = -1;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The speex encoder instance.
|
|
|
|
|
*/
|
|
|
|
|
private SpeexEncoder encoder = null;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Narrow band used for 8 kHz.
|
|
|
|
|
*/
|
|
|
|
|
final static int NARROW_BAND= 0;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Wide band used for 16 kHz.
|
|
|
|
|
*/
|
|
|
|
|
final static int WIDE_BAND= 1;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Utra wide band used for 32 kHz.
|
|
|
|
|
*/
|
|
|
|
|
final static int ULTRA_WIDE_BAND= 2;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -35,7 +68,7 @@ public class JavaEncoder
|
|
|
|
|
*/
|
|
|
|
|
public JavaEncoder()
|
|
|
|
|
{
|
|
|
|
|
supportedInputFormats = new AudioFormat[]
|
|
|
|
|
this.inputFormats = new AudioFormat[]
|
|
|
|
|
{
|
|
|
|
|
new AudioFormat(
|
|
|
|
|
AudioFormat.LINEAR,
|
|
|
|
|
@ -62,11 +95,35 @@ public JavaEncoder()
|
|
|
|
|
AudioFormat.SIGNED //isSigned());
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the name of this plugin/codec.
|
|
|
|
|
* @return the name.
|
|
|
|
|
*/
|
|
|
|
|
public String getName()
|
|
|
|
|
{
|
|
|
|
|
return "pcm to speex converter";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the list of formats supported at the output.
|
|
|
|
|
*
|
|
|
|
|
* @param in the input format.
|
|
|
|
|
* @return array of formats supported at output
|
|
|
|
|
*/
|
|
|
|
|
public Format[] getSupportedOutputFormats(Format in)
|
|
|
|
|
{
|
|
|
|
|
// null input format
|
|
|
|
|
if (in == null)
|
|
|
|
|
return DEFAULT_OUTPUT_FORMATS;
|
|
|
|
|
|
|
|
|
|
defaultOutputFormats = new AudioFormat[]
|
|
|
|
|
{new AudioFormat(Constants.SPEEX_RTP)};
|
|
|
|
|
// mismatch input format
|
|
|
|
|
if (!(in instanceof AudioFormat)
|
|
|
|
|
|| (null == AbstractCodecExt.matches(in, inputFormats)))
|
|
|
|
|
return new Format[0];
|
|
|
|
|
|
|
|
|
|
PLUGIN_NAME = "pcm to speex converter";
|
|
|
|
|
return getMatchingOutputFormats(in);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -74,11 +131,11 @@ public JavaEncoder()
|
|
|
|
|
* @param in input format
|
|
|
|
|
* @return array of formats that match input ones
|
|
|
|
|
*/
|
|
|
|
|
protected Format[] getMatchingOutputFormats(Format in)
|
|
|
|
|
private Format[] getMatchingOutputFormats(Format in)
|
|
|
|
|
{
|
|
|
|
|
AudioFormat af = (AudioFormat) in;
|
|
|
|
|
|
|
|
|
|
supportedOutputFormats = new AudioFormat[]
|
|
|
|
|
return new AudioFormat[]
|
|
|
|
|
{new AudioFormat(
|
|
|
|
|
Constants.SPEEX_RTP,
|
|
|
|
|
af.getSampleRate(),
|
|
|
|
|
@ -87,8 +144,6 @@ protected Format[] getMatchingOutputFormats(Format in)
|
|
|
|
|
af.getEndian(),
|
|
|
|
|
af.getSigned()
|
|
|
|
|
)};
|
|
|
|
|
|
|
|
|
|
return supportedOutputFormats;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -107,30 +162,54 @@ public void close()
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialize the encoder with the supplied input format.
|
|
|
|
|
* @param inFormat the input format.
|
|
|
|
|
*/
|
|
|
|
|
private void initConverter(AudioFormat inFormat)
|
|
|
|
|
{
|
|
|
|
|
lastFormat = inFormat;
|
|
|
|
|
|
|
|
|
|
AudioFormat oFormat = (AudioFormat)outputFormat;
|
|
|
|
|
outFormat = new AudioFormat(
|
|
|
|
|
oFormat.getEncoding(),
|
|
|
|
|
oFormat.getSampleRate(),
|
|
|
|
|
oFormat.getSampleSizeInBits(),
|
|
|
|
|
oFormat.getChannels(),
|
|
|
|
|
oFormat.getEndian(),
|
|
|
|
|
oFormat.getSigned(),
|
|
|
|
|
oFormat.getFrameSizeInBits(),
|
|
|
|
|
oFormat.getFrameRate(),
|
|
|
|
|
oFormat.getDataType())
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* The length in nanoseconds.
|
|
|
|
|
*/
|
|
|
|
|
public long computeDuration(long l)
|
|
|
|
|
{
|
|
|
|
|
// 20ms in nano
|
|
|
|
|
return 20 * 1000000;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
encoder = new SpeexEncoder();
|
|
|
|
|
|
|
|
|
|
int sampleRate =
|
|
|
|
|
(int)inFormat.getSampleRate();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int band = NARROW_BAND;
|
|
|
|
|
FRAME_SIZE = 320;
|
|
|
|
|
|
|
|
|
|
if(sampleRate == 16000)
|
|
|
|
|
{
|
|
|
|
|
band = WIDE_BAND;
|
|
|
|
|
FRAME_SIZE = 640;
|
|
|
|
|
}
|
|
|
|
|
else if(sampleRate == 32000)
|
|
|
|
|
{
|
|
|
|
|
band = ULTRA_WIDE_BAND;
|
|
|
|
|
FRAME_SIZE = 1280;
|
|
|
|
|
band = ULTRA_WIDE_BAND;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
encoder.init(band, 4, sampleRate, 1);
|
|
|
|
|
FRAME_SIZE = 2 * encoder.getFrameSize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -175,12 +254,31 @@ public int process(Buffer inputBuffer, Buffer outputBuffer)
|
|
|
|
|
byte[] buff = new byte[encoder.getProcessedDataByteSize()];
|
|
|
|
|
encoder.getProcessedData(buff, 0);
|
|
|
|
|
|
|
|
|
|
byte[] outData = validateByteArraySize(outputBuffer, buff.length);
|
|
|
|
|
/*
|
|
|
|
|
* Do not always allocate a new data array for outBuffer, try to reuse
|
|
|
|
|
* the existing one if it is suitable.
|
|
|
|
|
*/
|
|
|
|
|
Object outData = outputBuffer.getData();
|
|
|
|
|
byte[] out;
|
|
|
|
|
|
|
|
|
|
if (outData instanceof byte[])
|
|
|
|
|
{
|
|
|
|
|
out = (byte[]) outData;
|
|
|
|
|
if (out.length < buff.length)
|
|
|
|
|
out = null;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
out = null;
|
|
|
|
|
if (out == null)
|
|
|
|
|
out = new byte[buff.length];
|
|
|
|
|
|
|
|
|
|
System.arraycopy(buff, 0, outData, outputBuffer.getOffset(),
|
|
|
|
|
System.arraycopy(buff, 0, out, outputBuffer.getOffset(),
|
|
|
|
|
buff.length);
|
|
|
|
|
|
|
|
|
|
updateOutput(outputBuffer, outputFormat, outData.length, 0);
|
|
|
|
|
outputBuffer.setData(out);
|
|
|
|
|
outputBuffer.setLength(out.length);
|
|
|
|
|
outputBuffer.setOffset(0);
|
|
|
|
|
outputBuffer.setFormat(outFormat);
|
|
|
|
|
|
|
|
|
|
if ( (inpLength - inOffset) > FRAME_SIZE)
|
|
|
|
|
{
|
|
|
|
|
|