package javaforce.voip;
/*
struct rtp_header {
byte version; //usually 0x80
byte type; //0x00
short seqnum;
int timestamp;
int syncsrcid;
};
*/
import javaforce.*;
/**
* Encodes/decodes g711 packets (A-Law). (European format)
*/
public class g711a implements Coder {
private RTP rtp;
public g711a(RTP rtp) {
this.rtp = rtp;
}
private static short alaw_lut[]; //signed
private static int exp_lut[] = {
1,1,2,2,3,3,3,3,
4,4,4,4,4,4,4,4,
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,
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
};
static {
g711a.init();
}
/** init the decode lookup table (256 entries) */
private static void init() {
short i, seg, linear, alaw;
alaw_lut = new short[256];
for (short idx = 0; idx < 256; idx++) {
alaw = idx;
alaw ^= 0x55; //AMI_MASK 01010101
i = (short)(((alaw & 0x0f) << 4) + 8); /* rounding error */
seg = (short)(((int)alaw & 0x70) >> 4);
if (seg != 0) {
i = (short)((i + 0x100) << (seg - 1));
}
alaw_lut[idx] = (short)((((alaw & 0x80) == 0x80) ? i : -i));
}
}
private static final short CLIP = 32767; //not MAX short
private byte encoded[] = new byte[160 + 12];
//samples must be 160 samples
public byte[] encode(short samples[]) {
int sign, exponent, mantissa, mag;
byte alawbyte;
short sample;
RTPChannel rtpChannel = rtp.getDefaultChannel();
rtpChannel.buildHeader(encoded, 8, rtpChannel.getseqnum(), rtpChannel.gettimestamp(160), rtpChannel.getssrc(), false);
for (int i = 0; i < 160; i++) {
/* Get the sample into sign-magnitude. */
sample = samples[i];
sign = (sample >> 8) & 0x80; /* set aside the sign */
if (sign != 0) {
mag = -sample;
} else {
mag = sample;
}
if (mag > CLIP) {
mag = CLIP; /* clip the magnitude */
}
/* Convert from 16 bit linear to alaw. */
exponent = exp_lut[(mag >> 8) & 0x7f];
mantissa = ((mag >> (exponent + 3)) & 0x0f);
if (mag < 0x100) exponent = 0;
alawbyte = (byte) ((sign | (exponent << 4) | mantissa));
alawbyte ^= 0x55;
encoded[12 + i] = alawbyte;
}
return encoded;
}
private int decode_timestamp;
private short decoded[] = new short[160];
//encoded must be 160+12 bytes at least
public short[] decode(byte encoded[], int off) {
int decode_timestamp = BE.getuint32(encoded, off + 4);
if (this.decode_timestamp == 0) {
this.decode_timestamp = decode_timestamp;
} else {
if (RTP.debug) {
JFLog.log("G711a:timestamp = " + decode_timestamp + ":" + ((this.decode_timestamp + 160 == decode_timestamp) ? "ok" : "lost packet"));
}
this.decode_timestamp = decode_timestamp;
}
for (int i = 0; i < 160; i++) {
decoded[i] = alaw_lut[encoded[off + i + 12] & 0xff];
}
return decoded;
}
public int getSampleRate() {return 8000;}
}