/*
* Mobicents Media Gateway
*
* The source code contained in this file is in in the public domain.
* It can be used in any project or product without prior permission,
* license or royalty payments. There is NO WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION,
* THE IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
* AND DATA ACCURACY. We do not warrant or make any representations
* regarding the use of the software or the results thereof, including
* but not limited to the correctness, accuracy, reliability or
* usefulness of the software.
*/
package org.mobicents.media.server.impl.dsp.audio.g711.ulaw;
import org.mobicents.media.Buffer;
import org.mobicents.media.Format;
import org.mobicents.media.server.spi.dsp.Codec;
/**
* Implements G.711 U-law compressor.
*
* @author Oleg Kulikov
*/
public class Encoder implements Codec {
private final static byte[] muLawCompressTable = new byte[]{
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
private final static int cBias = 0x84;
private final static int cClip = 32635;
private static short seg_end[] = new short[]{0xFF, 0x1FF, 0x3FF, 0x7FF,
0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
};
private byte[] temp = new byte[8192];
public Format getSupportedInputFormat() {
return Codec.LINEAR_AUDIO;
}
public Format getSupportedOutputFormat() {
return Codec.PCMU;
}
public Format[] getSupportedInputFormats(Format fmt) {
Format[] formats = new Format[]{
Codec.LINEAR_AUDIO
};
return formats;
}
public Format[] getSupportedOutputFormats() {
Format[] formats = new Format[]{
Codec.PCMU
};
return formats;
}
/**
* (Non Java-doc)
*
* @see org.mobicents.media.server.impl.jmf.dsp.Codec#process(Buffer).
*/
public void process(Buffer buffer) {
int len = process((byte[]) buffer.getData(), buffer.getOffset(), buffer.getLength(), temp);
System.arraycopy(temp, 0, (byte[])buffer.getData(), 0, len);
buffer.setOffset(0);
buffer.setLength(len);
buffer.setFormat(PCMU);
}
private int process(byte[] src, int offset, int len, byte[] res) {
int j = offset;
int count = len / 2;
short sample = 0;
for (int i = 0; i < count; i++) {
sample = (short) (((src[j++] & 0xff) | (src[j++]) << 8));
res[i] = this.linear2ulaw(sample);
}
return count;
}
/*
* linear2ulaw() - Convert a linear PCM value to u-law
*
* In order to simplify the encoding process, the original linear magnitude
* is biased by adding 33 which shifts the encoding range from (0 - 8158) to
* (33 - 8191). The result can be seen in the following encoding table:
*
* Biased Linear Input Code Compressed Code
* ------------------------ ---------------
* 00000001wxyza 000wxyz
* 0000001wxyzab 001wxyz
* 000001wxyzabc 010wxyz
* 00001wxyzabcd 011wxyz
* 0001wxyzabcde 100wxyz
* 001wxyzabcdef 101wxyz
* 01wxyzabcdefg 110wxyz
* 1wxyzabcdefgh 111wxyz
*
* Each biased linear code has a leading 1 which identifies the segment
* number. The value of the segment number is equal to 7 minus the number
* of leading 0's. The quantization interval is directly available as the
* four bits wxyz. * The trailing bits (a - h) are ignored.
*
* Ordinarily the complement of the resulting code word is used for
* transmission, and so the code word is complemented before it is returned.
*
* For further information see John C. Bellamy's Digital Telephony, 1982,
* John Wiley & Sons, pps 98-111 and 472-476.
*/
private byte linear2ulaw(short pcm_val) {
int mask;
int seg;
byte uval;
/* Get the sign and the magnitude of the value. */
if (pcm_val < 0) {
pcm_val = (short) (cBias - pcm_val);
mask = 0x7F;
} else {
pcm_val += cBias;
mask = 0xFF;
}
/* Convert the scaled magnitude to segment number. */
seg = search(pcm_val, seg_end, 8);
/*
* Combine the sign, segment, quantization bits;
* and complement the code word.
*/
if (seg >= 8) /* out of range, return maximum value. */ {
return (byte)(0x7F ^ mask);
} else {
uval = (byte)((seg << 4) | ((pcm_val >> (seg + 3)) & 0xF));
return (byte)(uval ^ mask);
}
}
private static int search(int val, short[] table, int size) {
int i;
for (i = 0; i < size; i++) {
if (val <= table[i]) {
return (i);
}
}
return (size);
}
}