ALAW encoding and transmiting added.

cusax-fix
Damian Minkov 19 years ago
parent 89021696cb
commit 913f7bee58

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -26,6 +26,7 @@
*
* @author Martin Andre
* @author Emil Ivov
* @author Damian Minkov
*/
public class MediaControl
{
@ -124,6 +125,20 @@ public class MediaControl
private static final String DEBUG_DATA_SOURCE_URL_PROPERTY_NAME
= "net.java.sip.communicator.impl.media.DEBUG_DATA_SOURCE_URL";
/**
*
*/
private static String[] customCodecs = new String[]
{
"net.java.sip.communicator.impl.media.codec.audio.alaw.JavaEncoder",
"net.java.sip.communicator.impl.media.codec.audio.alaw.DePacketizer",
"net.java.sip.communicator.impl.media.codec.audio.alaw.Packetizer"
// "net.java.sip.communicator.impl.media.codec.audio.g729.JavaDecoder",
// "net.java.sip.communicator.impl.media.codec.audio.g729.JavaEncoder",
// "net.java.sip.communicator.impl.media.codec.audio.g729.DePacketizer",
// "net.java.sip.communicator.impl.media.codec.audio.g729.Packetizer"
};
/**
* The default constructor.
*/
@ -396,6 +411,9 @@ public void initDebugDataSource(String debugMediaSource)
private void initProcessor(DataSource dataSource)
throws MediaException
{
// register our custom codecs
registerCustomCodecs();
try
{
try
@ -960,4 +978,44 @@ public void stopProcessingMedia(Object reader)
if(processorReaders.contains(reader))
processorReaders.remove(reader);
}
/**
* Register in JMF the custom codecs we provide
*/
private void registerCustomCodecs()
{
for (int i = 0; i < customCodecs.length; i++)
{
String className = customCodecs[i];
try
{
Class pic = Class.forName(className);
Object instance = pic.newInstance();
boolean result =
PlugInManager.addPlugIn(
className,
( (Codec) instance).getSupportedInputFormats(),
( (Codec) instance).getSupportedOutputFormats(null),
PlugInManager.CODEC);
logger.debug("Codec : " + className +
" is succsefully registered : " + result);
}
catch (Exception ex)
{
logger.debug("Codec : " + className +
" is NOT succsefully registered");
}
}
try
{
PlugInManager.commit();
}
catch (IOException ex)
{
logger.error("Cannot commit to PlugInManager", ex);
}
}
}

@ -14,13 +14,8 @@
import net.java.sip.communicator.impl.media.device.*;
import net.java.sip.communicator.service.media.*;
import net.java.sip.communicator.service.media.event.*;
import net.java.sip.communicator.service.netaddr.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
import com.sun.media.util.Registry;
import javax.media.PlugInManager;
import javax.media.Format;
import javax.media.Codec;
/**
* The service is meant to be a wrapper of media libraries such as JMF,
@ -265,16 +260,6 @@ public static void main(String[] args)
MediaServiceImpl msimpl = new MediaServiceImpl();
msimpl.start();
String className = "classname";
Class pic = Class.forName(className);
Object instance = pic.newInstance();
PlugInManager.addPlugIn(
className,
((Codec)instance).getSupportedInputFormats(),
((Codec)instance).getSupportedOutputFormats(null),
PlugInManager.CODEC);
System.out.println("done");
}
}

@ -9,6 +9,7 @@
import javax.media.format.*;
import javax.sdp.*;
import java.util.*;
import net.java.sip.communicator.impl.media.codec.*;
/**
* Implements static utility methods used by media classes.
@ -48,7 +49,7 @@ public static String sdpToJmfEncoding(String sdpEncodingStr)
case SdpConstants.DVI4_16000:
return AudioFormat.DVI_RTP;
case SdpConstants.PCMA:
return AudioFormat.ALAW;
return Constants.ALAW_RTP;
case SdpConstants.G728:
return AudioFormat.G728_RTP;
case SdpConstants.G729:
@ -84,6 +85,10 @@ else if (jmfEncoding.equals(AudioFormat.ULAW_RTP))
{
return Integer.toString(SdpConstants.PCMU);
}
else if (jmfEncoding.equals(Constants.ALAW_RTP))
{
return Integer.toString(SdpConstants.PCMA);
}
else if (jmfEncoding.equals(AudioFormat.GSM_RTP))
{
return Integer.toString(SdpConstants.GSM);

@ -0,0 +1,16 @@
/*
* 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;
/**
* Constants needed in codecs impl.
* @author Damian Minkov
*/
public class Constants
{
public static final String ALAW_RTP = "ALAW/rtp";
}

@ -0,0 +1,113 @@
/*
* 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.*;
import com.sun.media.codec.audio.*;
import net.java.sip.communicator.impl.media.codec.*;
/**
* DePacketizer for ALAW codec
* @author Damian Minkov
*/
public class DePacketizer
extends AudioCodec
{
/**
* Creates DePacketizer
*/
public DePacketizer()
{
inputFormats = new Format[]{new AudioFormat(Constants.ALAW_RTP)};
}
/**
* Returns the name of the DePacketizer
* @return String
*/
public String getName()
{
return "ALAW DePacketizer";
}
/**
* Returns the supported output formats
* @param in Format
* @return Format[]
*/
public Format[] getSupportedOutputFormats(Format in)
{
if (in == null)
{
return new Format[]{new AudioFormat(AudioFormat.ALAW)};
}
if (matches(in, inputFormats) == null)
{
return new Format[1];
}
if (! (in instanceof AudioFormat))
{
return new Format[]{new AudioFormat(AudioFormat.ALAW)};
}
AudioFormat af = (AudioFormat) in;
return new Format[]
{
new AudioFormat(
AudioFormat.ALAW,
af.getSampleRate(),
af.getSampleSizeInBits(),
af.getChannels())
};
}
/**
* Initializes the codec.
*/
public void open()
{}
/**
* Clean up
*/
public void close()
{}
/**
* decode the buffer
* @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;
}
Object outData = outputBuffer.getData();
outputBuffer.setData(inputBuffer.getData());
inputBuffer.setData(outData);
outputBuffer.setLength(inputBuffer.getLength());
outputBuffer.setFormat(outputFormat);
outputBuffer.setOffset(inputBuffer.getOffset());
return BUFFER_PROCESSED_OK;
}
}

@ -0,0 +1,342 @@
/*
* 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 numberOfInputChannels;
private int numberOfOutputChannels = 1;
private boolean downmix = false;
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,
16,
2,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED
),
new AudioFormat(
AudioFormat.LINEAR,
Format.NOT_SPECIFIED,
8,
1,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED
),
new AudioFormat(
AudioFormat.LINEAR,
Format.NOT_SPECIFIED,
8,
2,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED
)}; // support 1/2 channels 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());
if (channels == 2)
{
supportedOutputFormats = new AudioFormat[]
{
new AudioFormat(
AudioFormat.ALAW,
sampleRate,
8,
2,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED
),
new AudioFormat(
AudioFormat.ALAW,
sampleRate,
8,
1,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED
)};
}
else
{
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;
}
if (downmix)
{
inputLength /= 2;
}
return inputLength;
}
/**
* Init the converter to the new format
* @param inFormat AudioFormat
*/
private void initConverter(AudioFormat inFormat)
{
lastFormat = inFormat;
numberOfInputChannels = inFormat.getChannels();
if (outputFormat != null)
{
numberOfOutputChannels = outputFormat.getChannels();
}
inputSampleSize = inFormat.getSampleSizeInBits();
bigEndian = inFormat.getEndian()==AudioFormat.BIG_ENDIAN;
if ( (numberOfInputChannels == 2) && (numberOfOutputChannels == 1))
{
downmix = true;
}
else
{
downmix = false;
}
}
/**
* 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 otput 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));
}
}

@ -0,0 +1,147 @@
/*
* 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.*;
import com.ibm.media.codec.audio.*;
import net.java.sip.communicator.impl.media.codec.*;
/**
* Packetizer for ALAW codec
* @author Damian Minkov
*/
public class Packetizer
extends AudioPacketizer
{
public Packetizer()
{
packetSize = 480;
supportedInputFormats = new AudioFormat[]
{
new AudioFormat(
AudioFormat.ALAW,
Format.NOT_SPECIFIED,
8,
1,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
8,
Format.NOT_SPECIFIED,
Format.byteArray
)
};
defaultOutputFormats = new AudioFormat[]
{
new AudioFormat(
AudioFormat.ALAW,
Format.NOT_SPECIFIED,
8,
1,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
8,
Format.NOT_SPECIFIED,
Format.byteArray
)
};
PLUGIN_NAME = "Mu-Law Packetizer";
}
protected Format[] getMatchingOutputFormats(Format in)
{
AudioFormat af = (AudioFormat) in;
supportedOutputFormats = new AudioFormat[]
{
new AudioFormat(
Constants.ALAW_RTP,
af.getSampleRate(),
8,
1,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
8,
Format.NOT_SPECIFIED,
Format.byteArray
)
};
return supportedOutputFormats;
}
public void open() throws ResourceUnavailableException
{
setPacketSize(packetSize);
reset();
}
public java.lang.Object[] getControls()
{
if (controls == null)
{
controls = new Control[1];
controls[0] = new PacketSizeAdapter(this, packetSize, true);
}
return (Object[]) controls;
}
public synchronized void setPacketSize(int newPacketSize)
{
packetSize = newPacketSize;
sample_count = packetSize;
if (history == null)
{
history = new byte[packetSize];
return;
}
if (packetSize > history.length)
{
byte[] newHistory = new byte[packetSize];
System.arraycopy(history, 0, newHistory, 0, historyLength);
history = newHistory;
}
}
}
class PacketSizeAdapter
extends com.sun.media.controls.PacketSizeAdapter
{
public PacketSizeAdapter(Codec newOwner, int newPacketSize,
boolean newIsSetable)
{
super(newOwner, newPacketSize, newIsSetable);
}
public int setPacketSize(int numBytes)
{
int numOfPackets = numBytes;
if (numOfPackets < 10)
{
numOfPackets = 10;
}
if (numOfPackets > 8000)
{
numOfPackets = 8000;
}
packetSize = numOfPackets;
( (Packetizer) owner).setPacketSize(packetSize);
return packetSize;
}
}
Loading…
Cancel
Save