diff options
author | Damian Minkov <damencho@jitsi.org> | 2010-05-10 15:02:05 +0000 |
---|---|---|
committer | Damian Minkov <damencho@jitsi.org> | 2010-05-10 15:02:05 +0000 |
commit | e748384b3665d4135f99515c7ab73159207449aa (patch) | |
tree | 488b78334c8375e39e9be4891e3bb7bae5695b49 | |
parent | 238fb19f7e198844bbc3370aa6a32d83451cb8d0 (diff) | |
download | jitsi-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.jar | bin | 98722 -> 79826 bytes | |||
-rw-r--r-- | src/net/java/sip/communicator/impl/neomedia/codec/audio/speex/JavaDecoder.java | 266 |
2 files changed, 90 insertions, 176 deletions
diff --git a/lib/installer-exclude/jspeex.jar b/lib/installer-exclude/jspeex.jar Binary files differindex 0a0079b..e80d67c 100644 --- a/lib/installer-exclude/jspeex.jar +++ b/lib/installer-exclude/jspeex.jar 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; -// } } |