Fix some speex decoder issues, rtp packets can contain multiple speex frames (we were decoding only one of them).

cusax-fix
Damian Minkov 16 years ago
parent 238fb19f7e
commit e748384b36

Binary file not shown.

@ -12,15 +12,30 @@
import org.xiph.speex.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
import net.sf.fmj.media.*;
/**
* Speex to PCM java decoder
* @author Damian Minkov
**/
public class JavaDecoder
extends com.ibm.media.codec.audio.AudioCodec
extends AbstractCodec
{
/**
* Default output formats.
*/
protected Format[] DEFAULT_OUTPUT_FORMATS = new Format[] {
new AudioFormat(AudioFormat.LINEAR)};
/**
* The input format used to initialize the decoder.
* If null decoder must be created.
*/
private Format lastFormat = null;
/**
* The decoder.
*/
private SpeexDecoder decoder = null;
/**
@ -28,7 +43,7 @@ public class JavaDecoder
*/
public JavaDecoder()
{
supportedInputFormats = new AudioFormat[]
this.inputFormats = new AudioFormat[]
{
new AudioFormat(Constants.SPEEX_RTP,
8000,
@ -49,12 +64,35 @@ public JavaDecoder()
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED)
};
inputFormats = supportedInputFormats;
}
/**
* Returns the name of this plugin/codec.
* @return the name.
*/
public String getName()
{
return "Speex Decoder";
}
/**
* 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(AudioFormat.LINEAR)};
// mismatch input format
if (!(in instanceof AudioFormat)
|| (null == AbstractCodecExt.matches(in, inputFormats)))
return new Format[0];
PLUGIN_NAME = "Speex Decoder";
return getMatchingOutputFormats(in);
}
/**
@ -62,23 +100,20 @@ public JavaDecoder()
* @param in input format
* @return array of format 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(
AudioFormat.LINEAR,
af.getSampleRate(),
16,
af.getChannels(),
AudioFormat.LITTLE_ENDIAN, //isBigEndian(),
AudioFormat.SIGNED //isSigned());
new AudioFormat(
AudioFormat.LINEAR,
af.getSampleRate(),
16,
af.getChannels(),
AudioFormat.LITTLE_ENDIAN, //isBigEndian(),
AudioFormat.SIGNED //isSigned());
)};
return supportedOutputFormats;
}
/**
@ -93,6 +128,10 @@ public void open()
public void close()
{}
/**
* Initialize the decoder.
* @param inFormat the input format.
*/
private void initConverter(AudioFormat inFormat)
{
lastFormat = inFormat;
@ -137,7 +176,6 @@ public int process(Buffer inputBuffer, Buffer outputBuffer)
byte[] inData = (byte[]) inputBuffer.getData();
int inpLength = inputBuffer.getLength();
int outLength = 0;
int inOffset = inputBuffer.getOffset();
@ -152,172 +190,48 @@ public int process(Buffer inputBuffer, Buffer outputBuffer)
try
{
decoder.processData(inData, inOffset, inpLength);
int fullyProcessed =
decoder.processData(inData, inOffset, inpLength);
// sometimes we get more than a frame in single speex packet
// we must process it all
while(fullyProcessed != 1)
{
fullyProcessed = decoder.processData(false);
}
outLength = decoder.getProcessedDataByteSize();
byte[] outData = validateByteArraySize(outputBuffer, outLength);
/*
* 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;
decoder.getProcessedData(outData, outOffset);
if (outData instanceof byte[])
{
out = (byte[]) outData;
if (out.length < outLength)
out = null;
}
else
out = null;
if (out == null)
out = new byte[outLength];
decoder.getProcessedData(out, outOffset);
outputBuffer.setData(out);
outputBuffer.setLength(out.length);
outputBuffer.setOffset(0);
outputBuffer.setFormat(outputFormat);
}
catch (StreamCorruptedException ex)
{
ex.printStackTrace();
}
updateOutput(outputBuffer, outputFormat, outLength, 0);
return BUFFER_PROCESSED_OK;
}
// public java.lang.Object[] getControls()
// {
// if (controls == null)
// {
// controls = new Control[1];
// controls[0] = new com.sun.media.controls.SilenceSuppressionAdapter(this, false, false);
// }
// return (Object[]) controls;
// }
// TODO clean code (remove) array if really not needed
// static int SpeexSubModeSz[] =
// {
// 0, 43, 119, 160,
// 220, 300, 364, 492,
// 79, 0, 0, 0,
// 0, 0, 0, 0};
// static int SpeexInBandSz[] =
// {
// 1, 1, 4, 4,
// 4, 4, 4, 4,
// 8, 8, 16, 16,
// 32, 32, 64, 64};
/**
* Counts the samples in given data
* @param data byte[]
* @param len int
* @return int
*/
// TODO: clean code (remove) following method if really not used
// private static int speex_get_samples(byte[] data, int len)
// {
// int bit = 0;
// int cnt = 0;
// int off = 0;
//
// int c;
//
// //DEBU(G "speex_get_samples(%d)\n", len);
// while ((len * 8 - bit) >= 5) {
// /* skip wideband frames */
// off = speex_get_wb_sz_at(data, len, bit);
// if (off < 0) {
// //DEBU(G "\tERROR reading wideband frames\n");
// break;
// }
// bit += off;
//
// if ((len * 8 - bit) < 5) {
// //DEBU(G "\tERROR not enough bits left after wb\n");
// break;
// }
//
// /* get control bits */
// c = get_n_bits_at(data, 5, bit);
// //DEBU(G "\tCONTROL: %d at %d\n", c, bit);
// bit += 5;
//
// if (c == 15) {
// //DEBU(G "\tTERMINATOR\n");
// break;
// } else if (c == 14) {
// /* in-band signal; next 4 bits contain signal id */
// c = get_n_bits_at(data, 4, bit);
// bit += 4;
// //DEBUG "\tIN-BAND %d bits\n", SpeexInBandSz[c]);
// bit += SpeexInBandSz[c];
// } else if (c == 13) {
// /* user in-band; next 5 bits contain msg len */
// c = get_n_bits_at(data, 5, bit);
// bit += 5;
// //DEBUG "\tUSER-BAND %d bytes\n", c);
// bit += c * 8;
// } else if (c > 8) {
// //DEBU(G "\tUNKNOWN sub-mode %d\n", c);
// break;
// } else {
// /* skip number bits for submode (less the 5 control bits) */
// //DEBU(G "\tSUBMODE %d %d bits\n", c, SpeexSubModeSz[c]);
// bit += SpeexSubModeSz[c] - 5;
//
// cnt += 160; /* new frame */
// }
// }
// //DEBU(G "\tSAMPLES: %d\n", cnt);
// return cnt;
// }
// TODO: clean code (remove) following method if really not used - wide band?
// private static int get_n_bits_at(byte[] data, int n, int bit)
// {
// int byteInt = bit / 8; /* byte containing first bit */
// int rem = 8 - (bit % 8); /* remaining bits in first byte */
// int ret = 0;
//
// if (n <= 0 || n > 8)
// return 0;
//
// if (rem < n)
// {
// ret = (data[byteInt] << (n - rem));
// ret |= (data[byteInt +1] >> (8 - n + rem));
// }
// else
// {
// ret = (data[byteInt] >> (rem - n));
// }
//
// return (ret & (0xff >> (8 - n)));
// }
//
// TODO clean code (remove) array if really not needed
// static int SpeexWBSubModeSz[] =
// {
// 0, 36, 112, 192,
// 352, 0, 0, 0};
// TODO: clean code (remove) following method if really not used - wide band?
// private static int speex_get_wb_sz_at(byte[] data, int len, int bit)
// {
// int off = bit;
// int c;
//
// /* skip up to two wideband frames */
// if ( ( (len * 8 - off) >= 5) &&
// get_n_bits_at(data, 1, off) != 0)
// {
// c = get_n_bits_at(data, 3, off + 1);
// off += SpeexWBSubModeSz[c];
//
// if ( ( (len * 8 - off) >= 5) &&
// get_n_bits_at(data, 1, off) != 0)
// {
// c = get_n_bits_at(data, 3, off + 1);
// off += SpeexWBSubModeSz[c];
//
// if ( ( (len * 8 - off) >= 5) &&
// get_n_bits_at(data, 1, off) != 0)
// {
// /* too many in a row */
// //DEBU(G "\tCORRUPT too many wideband streams in a row\n");
// return -1;
// }
// }
//
// }
// return off - bit;
// }
}

Loading…
Cancel
Save