/* * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. * * Distributable under LGPL license. * See terms of license at gnu.org. */ package net.java.sip.communicator.impl.media.codec.audio.alaw; import javax.media.*; import javax.media.format.*; /** * The ALAW Encoder * * @author Damian Minkov */ public class JavaEncoder extends com.ibm.media.codec.audio.AudioCodec { private Format lastFormat = null; private int inputSampleSize; private boolean bigEndian = false; public JavaEncoder() { supportedInputFormats = new AudioFormat[] { new AudioFormat( AudioFormat.LINEAR, Format.NOT_SPECIFIED, 16, 1, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED ), new AudioFormat( AudioFormat.LINEAR, Format.NOT_SPECIFIED, 8, 1, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED )}; // support 1 channel and 8/16 bit samples defaultOutputFormats = new AudioFormat[] { new AudioFormat( AudioFormat.ALAW, 8000, 8, 1, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED )}; PLUGIN_NAME = "pcm to alaw converter"; } protected Format[] getMatchingOutputFormats(Format in) { AudioFormat inFormat = (AudioFormat) in; int channels = inFormat.getChannels(); int sampleRate = (int) (inFormat.getSampleRate()); supportedOutputFormats = new AudioFormat[] { new AudioFormat( AudioFormat.ALAW, sampleRate, 8, 1, Format.NOT_SPECIFIED, Format.NOT_SPECIFIED )}; return supportedOutputFormats; } public void open() throws ResourceUnavailableException {} public void close() {} private int calculateOutputSize(int inputLength) { if (inputSampleSize == 16) { inputLength /= 2; } return inputLength; } /** * Init the converter to the new format * @param inFormat AudioFormat */ private void initConverter(AudioFormat inFormat) { lastFormat = inFormat; inputSampleSize = inFormat.getSampleSizeInBits(); bigEndian = inFormat.getEndian()==AudioFormat.BIG_ENDIAN; } /** * Encodes the input buffer passing it to the output one * @param inputBuffer Buffer * @param outputBuffer Buffer * @return int */ public int process(Buffer inputBuffer, Buffer outputBuffer) { if (!checkInputBuffer(inputBuffer)) { return BUFFER_PROCESSED_FAILED; } if (isEOM(inputBuffer)) { propagateEOM(outputBuffer); return BUFFER_PROCESSED_OK; } Format newFormat = inputBuffer.getFormat(); if (lastFormat != newFormat) { initConverter( (AudioFormat) newFormat); } int inpLength = inputBuffer.getLength(); int outLength = calculateOutputSize(inputBuffer.getLength()); byte[] inpData = (byte[]) inputBuffer.getData(); byte[] outData = validateByteArraySize(outputBuffer, outLength); pcm162alaw( inpData, inputBuffer.getOffset(), outData, 0, outData.length, bigEndian); updateOutput(outputBuffer, outputFormat, outLength, 0); return BUFFER_PROCESSED_OK; } /* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use. Users may copy or modify this source code without * charge. * * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law * * linear2alaw() accepts an 16-bit integer and encodes it as A-law data. * * Linear Input Code Compressed Code * ------------------------ --------------- * 0000000wxyza 000wxyz * 0000001wxyza 001wxyz * 000001wxyzab 010wxyz * 00001wxyzabc 011wxyz * 0001wxyzabcd 100wxyz * 001wxyzabcde 101wxyz * 01wxyzabcdef 110wxyz * 1wxyzabcdefg 111wxyz * * For further information see John C. Bellamy's Digital Telephony, 1982, * John Wiley & Sons, pps 98-111 and 472-476. */ private static final byte QUANT_MASK = 0xf; /* Quantization field mask. */ private static final byte SEG_SHIFT = 4; /* Left shift for segment number. */ private static final short[] seg_end = { 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF }; private static byte linear2alaw(short pcm_val) /* 2's complement (16-bit range) */ { byte mask; byte seg = 8; byte aval; if (pcm_val >= 0) { mask = (byte) 0xD5; /* sign (7th) bit = 1 */ } else { mask = 0x55; /* sign bit = 0 */ pcm_val = (short) ( -pcm_val - 8); } /* Convert the scaled magnitude to segment number. */ for (int i = 0; i < 8; i++) { if (pcm_val <= seg_end[i]) { seg = (byte) i; break; } } /* Combine the sign, segment, and quantization bits. */ if (seg >= 8) /* out of range, return maximum value. */ { return (byte) ( (0x7F ^ mask) & 0xFF); } else { aval = (byte) (seg << SEG_SHIFT); if (seg < 2) { aval |= (pcm_val >> 4) & QUANT_MASK; } else { aval |= (pcm_val >> (seg + 3)) & QUANT_MASK; } return (byte) ( (aval ^ mask) & 0xFF); } } /** * Converts the input buffer to the output one using the alaw codec * @param inBuffer byte[] * @param inByteOffset int * @param outBuffer byte[] * @param outByteOffset int * @param sampleCount int * @param bigEndian boolean */ private static void pcm162alaw(byte[] inBuffer, int inByteOffset, byte[] outBuffer, int outByteOffset, int sampleCount, boolean bigEndian) { int shortIndex = inByteOffset; int alawIndex = outByteOffset; if (bigEndian) { while (sampleCount > 0) { outBuffer[alawIndex++] = linear2alaw (bytesToShort16(inBuffer[shortIndex], inBuffer[shortIndex + 1])); shortIndex++; shortIndex++; sampleCount--; } } else { while (sampleCount > 0) { outBuffer[alawIndex++] = linear2alaw (bytesToShort16(inBuffer[shortIndex + 1], inBuffer[shortIndex])); shortIndex++; shortIndex++; sampleCount--; } } } /** * Converts the 2 bytes to the corresponding short value * @param highByte byte * @param lowByte byte * @return short */ private static short bytesToShort16(byte highByte, byte lowByte) { return (short) ( (highByte << 8) | (lowByte & 0xFF)); } }