/* * @(#)PcmDepacketizer.java 1.2 01/03/13 * * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved. * * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use, * modify and redistribute this software in source and binary code form, * provided that i) this copyright notice and license appear on all copies of * the software; and ii) Licensee does not utilize the software in a manner * which is disparaging to Sun. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * This software is not designed or intended for use in on-line control of * aircraft, air traffic, aircraft navigation or aircraft communications; or in * the design, construction, operation or maintenance of any nuclear * facility. Licensee represents and warrants that it will not use or * redistribute the Software for such purposes. */ import javax.media.*; import javax.media.format.*; /** * Implements an PCM depacketizer. It uses a custom payload header * to send uncompressed PCM data over RTP. This is not the same * as the standard PCMU or PCMA payloads as defined in the RTP spec. * Nor do we claim that this is an efficient way to transmit PCM * audio. The sole purpose of this sample is to illustrate the * concept to write a custom RTP depacketizer in JMF. */ public class PcmDepacketizer implements Codec { static String PLUGIN_NAME = "PCM DePacketizer"; static String CUSTOM_PCM = "mypcm/rtp"; static int HDR_SIZE = 8; static int DEFAULT_RATE = 8000; static int DEFAULT_SIZE = 8; static int DEFAULT_CHNLS = 1; private Format supportedInputFormats[]; private Format supportedOutputFormats[]; private AudioFormat inFormat; private AudioFormat outFormat; public PcmDepacketizer() { supportedInputFormats = new AudioFormat[] { new AudioFormat( CUSTOM_PCM ) }; // We have to assume some defaults for the output // format. Otherwise, the data flow graph cannot // be initialized. supportedOutputFormats = new AudioFormat[] { new AudioFormat( AudioFormat.LINEAR, DEFAULT_RATE, DEFAULT_SIZE, DEFAULT_CHNLS ) }; } public String getName() { return PLUGIN_NAME; } static public boolean matches(Format input, Format supported[]) { for (int i = 0; i < supported.length; i++) { if (input.matches(supported[i])) return true; } return false; } public Format [] getSupportedInputFormats() { return supportedInputFormats; } public Format [] getSupportedOutputFormats(Format input) { if (input == null || matches(input, supportedInputFormats)) { return supportedOutputFormats; } return new Format[0]; } public Format setInputFormat(Format format) { if (!matches(format, supportedInputFormats)) return null; inFormat = (AudioFormat)format; return format; } public Format setOutputFormat(Format format) { if (!matches(format, supportedOutputFormats)) return null; outFormat = (AudioFormat)format; return format; } protected Format getInputFormat() { return inFormat; } protected Format getOutputFormat() { return outFormat; } public void open() { } public void close() { } /** * No controls implemented for this plugin. */ public Object[] getControls() { return new Object[0]; } /** * No controls implemented for this plugin. */ public Object getControl(String type) { return null; } /** * The processing function that does all the work. */ public int process(Buffer inBuf, Buffer outBuf) { if (inBuf.isEOM()) { outBuf.setLength(0); outBuf.setEOM(true); return BUFFER_PROCESSED_OK; } // Decode the packet header which contains the format. byte hdr[] = (byte[])inBuf.getData(); int offset = inBuf.getOffset(); int rate = ((hdr[offset+1] & 0xff) << 16) | ((hdr[offset+2] & 0xff) << 8) | (hdr[offset+3] & 0xff); int sizeInBits = hdr[offset+4]; int channels = hdr[offset+5]; int endian = hdr[offset+6]; int signed = hdr[offset+7]; // Generate the output format if it's been changed from last time. if ((int)outFormat.getSampleRate() != rate || outFormat.getSampleSizeInBits() != sizeInBits || outFormat.getChannels() != channels || outFormat.getEndian() != endian || outFormat.getSigned() != signed) { // There's either a format change or the initially // assumed format has been updated to the correct one. outFormat = new AudioFormat(AudioFormat.LINEAR, rate, sizeInBits, channels, endian, signed); } Object outData = outBuf.getData(); outBuf.setData(inBuf.getData()); inBuf.setData(outData); outBuf.setLength(inBuf.getLength() - HDR_SIZE); outBuf.setOffset(inBuf.getOffset() + HDR_SIZE); outBuf.setFormat(outFormat); return BUFFER_PROCESSED_OK; } public void reset() { } }