package org.red5.app.sip.codecs;
import org.red5.app.sip.codecs.ilbc.bitstream;
import org.red5.app.sip.codecs.ilbc.ilbc_constants;
import org.red5.app.sip.codecs.ilbc.ilbc_decoder;
import org.red5.app.sip.codecs.ilbc.ilbc_encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ILBCCodec implements Codec {
protected static Logger log = LoggerFactory.getLogger( ILBCCodec.class );
// Codec information
private static final String codecName = "ILBC";
private static String[] codecMediaAttributes = { "fmtp:111 mode=30" };
private static final int codecId = 111;
private static int sampleFrame20ms = 20;
private static int sampleFrame30ms = 30;
private static int defaultEncodedFrameSize20ms = ilbc_constants.NO_OF_BYTES_20MS;
private static int defaultEncodedFrameSize30ms = ilbc_constants.NO_OF_BYTES_30MS;
private static int defaultDecodedFrameSize20ms = ilbc_constants.BLOCKL_20MS;
private static int defaultDecodedFrameSize30ms = ilbc_constants.BLOCKL_30MS;
private static int defaultSampleRate = 8000;
// For iLBC we must init this with default "mode" packetization.
private int outgoingPacketization = 30;
// For iLBC we must init this with default "mode" packetization.
private int incomingPacketization = 30;
private ilbc_encoder ilbcEncoder;
private ilbc_decoder ilbcDecoder;
public ILBCCodec() {
}
public void encodeInit( int defaultEncodePacketization ) {
ilbcEncoder = new ilbc_encoder( outgoingPacketization );
}
public void decodeInit( int defaultDecodePacketization ) {
ilbcDecoder = new ilbc_decoder( incomingPacketization, 1 );
}
public String codecNegotiateAttribute( String attributeName, String localAttributeValue, String remoteAttributeValue ) {
Integer localMode = Codec.DEFAULT_PACKETIZATION;
Integer remoteMode = 0;
String finalAttributeValue = "";
printLog( "codecNegotiateAttribute ",
"attributeName = [" + attributeName +
"localAttributeValue = [" + localAttributeValue +
"] remoteAttributeValue = [" + remoteAttributeValue + "]." );
if ( 0 == attributeName.compareTo( Codec.ATTRIBUTE_FMTP ) ) {
if ( ( null == remoteAttributeValue ) || ( remoteAttributeValue.isEmpty() ) ) {
finalAttributeValue = "";
}
else {
remoteMode = extractModeFromFmtpValue( remoteAttributeValue );
if ( ( null != localAttributeValue ) && ( !localAttributeValue.isEmpty() ) ) {
localMode = extractModeFromFmtpValue( localAttributeValue );
}
if ( remoteMode > localMode ) {
finalAttributeValue = remoteAttributeValue;
outgoingPacketization = remoteMode;
incomingPacketization = remoteMode;
}
else if ( null == localAttributeValue ) {
finalAttributeValue = remoteAttributeValue.substring(
0, remoteAttributeValue.indexOf( " mode=" ) + 6 );
finalAttributeValue.concat( localMode.toString() );
}
}
}
printLog( "codecNegotiateAttribute ",
"finalAttributeValue = [" + finalAttributeValue + "]." );
return finalAttributeValue;
}
protected int extractModeFromFmtpValue( String fmtpValue ) {
int modePos = fmtpValue.indexOf( " mode=" ) + 6;
return Integer.parseInt( fmtpValue.substring( modePos ) );
}
public int getCodecBlankPacket( byte[] buffer, int offset ) {
// TODO Auto-generated method stub
return 0;
}
public int codecToPcm( byte[] bufferIn, float[] bufferOut ) {
short[] encodedData = CodecUtils.byteToShortArray(bufferIn, 0, bufferIn.length, false);
bitstream encodedBitStream = new bitstream( getOutgoingDecodedFrameSize() * 2 );
for (int i = 0; i < encodedData.length; i++) {
encodedBitStream.buffer[2*i+1] = (char) (encodedData[i] & 0xff);
encodedBitStream.buffer[2*i] = (char) ((encodedData[i] >> 8) & 0xff);
}
ilbcDecoder.iLBC_decode(bufferOut, encodedBitStream, 1);
return getOutgoingDecodedFrameSize();
}
public int pcmToCodec( float[] bufferIn, byte[] bufferOut ) {
short[] encodedData = new short[ getIncomingEncodedFrameSize() / 2 ];
bitstream encodedBitStream = new bitstream( getIncomingEncodedFrameSize() * 2 );
ilbcEncoder.iLBC_encode( encodedBitStream, bufferIn );
for ( int i = 0; i < encodedData.length; i++ ) {
encodedData[ i ] = (short) ( ( ( encodedBitStream.buffer[ 2 * i ] << 8 ) & 0xff00 ) | ( ( (short) encodedBitStream.buffer[ 2 * i + 1 ] ) & 0x00ff ) );
}
CodecUtils.shortArrToByteArr( encodedData, bufferOut, false );
return getIncomingEncodedFrameSize();
}
public int getIncomingEncodedFrameSize() {
if ( incomingPacketization == sampleFrame20ms ) {
return defaultEncodedFrameSize20ms;
}
else if ( incomingPacketization == sampleFrame30ms ) {
return defaultEncodedFrameSize30ms;
}
return defaultEncodedFrameSize20ms;
}
public int getIncomingDecodedFrameSize() {
if ( incomingPacketization == sampleFrame20ms ) {
return defaultDecodedFrameSize20ms;
}
else if ( incomingPacketization == sampleFrame30ms ) {
return defaultDecodedFrameSize30ms;
}
return defaultDecodedFrameSize20ms;
}
public int getOutgoingEncodedFrameSize() {
if ( outgoingPacketization == sampleFrame20ms ) {
return defaultEncodedFrameSize20ms;
}
else if ( outgoingPacketization == sampleFrame30ms ) {
return defaultEncodedFrameSize30ms;
}
return defaultEncodedFrameSize20ms;
}
public int getOutgoingDecodedFrameSize() {
if ( outgoingPacketization == sampleFrame20ms ) {
return defaultDecodedFrameSize20ms;
}
else if ( outgoingPacketization == sampleFrame30ms ) {
return defaultDecodedFrameSize30ms;
}
return defaultDecodedFrameSize20ms;
}
public int getIncomingPacketization() {
return incomingPacketization;
}
public int getOutgoingPacketization() {
return outgoingPacketization;
}
public void setLocalPtime( int localPtime ) {
// For iLBC we have a "mode" paramater setted and it
// overcomes any ptime configuration.
}
public void setRemotePtime( int remotePtime ) {
// For iLBC we have a "mode" paramater setted and it
// overcomes any ptime configuration.
}
public int getSampleRate() {
return defaultSampleRate;
}
public String getCodecName() {
return codecName;
}
public int getCodecId() {
return codecId;
}
public String[] getCodecMediaAttributes() {
return codecMediaAttributes;
}
private static void printLog( String method, String message ) {
log.debug( "SIPCodecUtils - " + method + " -> " + message );
System.out.println( "SIPCodecUtils - " + method + " -> " + message );
}
}