aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamian Minkov <damencho@jitsi.org>2010-05-10 15:02:05 +0000
committerDamian Minkov <damencho@jitsi.org>2010-05-10 15:02:05 +0000
commite748384b3665d4135f99515c7ab73159207449aa (patch)
tree488b78334c8375e39e9be4891e3bb7bae5695b49
parent238fb19f7e198844bbc3370aa6a32d83451cb8d0 (diff)
downloadjitsi-e748384b3665d4135f99515c7ab73159207449aa.zip
jitsi-e748384b3665d4135f99515c7ab73159207449aa.tar.gz
jitsi-e748384b3665d4135f99515c7ab73159207449aa.tar.bz2
Fix some speex decoder issues, rtp packets can contain multiple speex frames (we were decoding only one of them).
-rw-r--r--lib/installer-exclude/jspeex.jarbin98722 -> 79826 bytes
-rw-r--r--src/net/java/sip/communicator/impl/neomedia/codec/audio/speex/JavaDecoder.java266
2 files changed, 90 insertions, 176 deletions
diff --git a/lib/installer-exclude/jspeex.jar b/lib/installer-exclude/jspeex.jar
index 0a0079b..e80d67c 100644
--- a/lib/installer-exclude/jspeex.jar
+++ b/lib/installer-exclude/jspeex.jar
Binary files differ
diff --git a/src/net/java/sip/communicator/impl/neomedia/codec/audio/speex/JavaDecoder.java b/src/net/java/sip/communicator/impl/neomedia/codec/audio/speex/JavaDecoder.java
index 9711372..bc1ed9d 100644
--- a/src/net/java/sip/communicator/impl/neomedia/codec/audio/speex/JavaDecoder.java
+++ b/src/net/java/sip/communicator/impl/neomedia/codec/audio/speex/JavaDecoder.java
@@ -12,15 +12,30 @@ import javax.media.format.*;
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 class 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 class 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 class JavaDecoder
public void close()
{}
+ /**
+ * Initialize the decoder.
+ * @param inFormat the input format.
+ */
private void initConverter(AudioFormat inFormat)
{
lastFormat = inFormat;
@@ -137,7 +176,6 @@ public class JavaDecoder
byte[] inData = (byte[]) inputBuffer.getData();
int inpLength = inputBuffer.getLength();
-
int outLength = 0;
int inOffset = inputBuffer.getOffset();
@@ -152,172 +190,48 @@ public class JavaDecoder
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;
-// }
}