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 (U-Law). (North America format) */ public class g711u implements Coder { private RTP rtp; public g711u(RTP rtp) { this.rtp = rtp; } private static short ulaw_lut[]; //signed private static short etab[] = {0, 132, 396, 924, 1980, 4092, 8316, 16764}; private static int exp_lut[] = { 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 }; static { g711u.init(); } /** init the decode lookup table (256 entries) */ private static void init() { short mu, e, f, y; ulaw_lut = new short[256]; for (short i = 0; i < 256; i++) { mu = (short) (255 - i); e = (short) ((mu & 0x70) / 16); f = (short) (mu & 0x0f); y = (short) (f * (1 << (e + 3))); y += etab[e]; if ((mu & 0x80) == 0x80) { y = (short) -y; } ulaw_lut[i] = y; } } private static final short BIAS = 0x84; private static final short CLIP = 32635; //not MAX short private byte encoded[] = new byte[160 + 12]; //samples must be 160 samples public byte[] encode(short samples[]) { int sign, exponent, mantissa; byte ulawbyte; short sample; RTPChannel rtpChannel = rtp.getDefaultChannel(); rtpChannel.buildHeader(encoded, 0, 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) { sample = (short) -sample; /* get magnitude */ } if (sample > CLIP) { sample = CLIP; /* clip the magnitude */ } /* Convert from 16 bit linear to ulaw. */ sample += BIAS; exponent = exp_lut[(sample >> 7) & 0xff]; mantissa = ((sample >> (exponent + 3)) & 0x0f); ulawbyte = (byte) (~(sign | (exponent << 4) | mantissa)); if (ulawbyte == 0) { ulawbyte = 0x02; /* optional CCITT trap */ } encoded[12 + i] = ulawbyte; } 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("G711u:timestamp = " + decode_timestamp + ":" + ((this.decode_timestamp + 160 == decode_timestamp) ? "ok" : "lost packet")); } this.decode_timestamp = decode_timestamp; } //skip first 12 bytes (RTP header) for (int i = 0; i < 160; i++) { decoded[i] = ulaw_lut[encoded[off + i + 12] & 0xff]; } return decoded; } public int getSampleRate() {return 8000;} }