merge
authorNikita Kozlov <nikita@beem-project.com>
Sat, 23 Jan 2010 00:51:15 +0100
changeset 829 f703b3e14f9a
parent 828 6089f3255c5f (diff)
parent 649 e29937c5670c (current diff)
child 830 c8b4ace735ea
merge
.classpath
AndroidManifest.xml
libs/jingle-namespace.patch
libs/jstun-android.patch
libs/new-android-r1.diff
libs/patch-smack-android-sasl.diff
libs/smack-android-r1.diff
libs/smack-android.diff
libs/smack.jar
libs/smackx-debug.jar
libs/smackx-jingle.jar
libs/smackx.jar
--- a/.classpath	Sat Jan 23 00:46:38 2010 +0100
+++ b/.classpath	Sat Jan 23 00:51:15 2010 +0100
@@ -1,10 +1,7 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
-	<classpathentry exported="true" kind="lib" path="libs/security.jar"/>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="src" path="gen"/>
-	<classpathentry kind="lib" path="libs/jlibrtp.jar"/>
-	<classpathentry kind="lib" path="libs/asmack-jse.jar"/>
-	<classpathentry kind="output" path="bin"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="lib" path="/home/nikita/android/platforms/android-2.0.1/android.jar">
+	<classpathentry kind="lib" path="libs/jlibrtp.jar"/>
+	<classpathentry kind="lib" path="libs/asmack-jse.jar"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
--- a/AndroidManifest.xml	Sat Jan 23 00:46:38 2010 +0100
+++ b/AndroidManifest.xml	Sat Jan 23 00:51:15 2010 +0100
@@ -14,6 +14,7 @@
 		</activity>
 		<activity android:name=".ui.LoginAnim" android:label="@string/login_login_progress"
 			android:launchMode="singleTop" />
+		<activity android:name=".ui.CallScreen" android:label="@string/call_screen" />
 		<activity android:name=".ui.Settings" android:label="@string/edit_settings_name">
 			<intent-filter android:label="Beem Connection">
 				<action
@@ -65,12 +66,19 @@
 					android:name="com.beem.project.beem.service.XmppConnectionAdapter.CONNECTION_CLOSED" />
 			</intent-filter>
 		</activity>
-		<!-- Could be interesting if we would launch beem at startup
-		<receiver android:name=".tool.BeemBroadcastReceiver" android:enabled="true">
-			<intent-filter>
-				<action android:name="android.intent.action.BOOT_COMPLETED" />
+		<activity android:name=".ui.Call" android:label="Call String en dur">
+			<intent-filter android:label="Beem Connection">
+				<action
+					android:name="com.beem.project.beem.service.XmppConnectionAdapter.CONNECTION_CLOSED" />
 			</intent-filter>
-		</receiver>  -->
+		</activity>
+		<!--
+			Could be interesting if we would launch beem at startup <receiver
+			android:name=".tool.BeemBroadcastReceiver" android:enabled="true">
+			<intent-filter> <action
+			android:name="android.intent.action.BOOT_COMPLETED" />
+			</intent-filter> </receiver>
+		-->
 		<service android:name="BeemService" android:enabled="true"
 			android:label="Beem Service" android:permission="com.beem.project.beem.BEEM_SERVICE">
 			<intent-filter>
@@ -83,8 +91,12 @@
 		android:name="com.beem.project.beem.BEEM_SERVICE"></permission>
 	<uses-permission android:name="android.permission.INTERNET"></uses-permission>
 	<uses-permission android:name="android.permission.VIBRATE"></uses-permission>
+	<uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>
+	<uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission>
+	<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
+	<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
 	<uses-permission android:name="com.beem.project.beem.BEEM_SERVICE"></uses-permission>
 	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
-	<uses-sdk android:minSdkVersion="3"/>
+	<uses-sdk android:minSdkVersion="3" />
 
 </manifest> 
--- a/build.xml	Sat Jan 23 00:46:38 2010 +0100
+++ b/build.xml	Sat Jan 23 00:51:15 2010 +0100
@@ -66,7 +66,7 @@
 
     <property name="javadoc.output" value="doc/javadoc" />
     <property name="external.libs.dir" value="libs" />
-
+	<property name="encoding" value="UTF-8" />
     <target name="clean"
 	description="Delete old build and dist directories">
 	<delete verbose="false" dir="${out.dir}"/>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/Android.mk	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,50 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := gsm
+
+SRC_FILES := 	gsm/add.c\
+		gsm/code.c\
+		gsm/debug.c\
+		gsm/decode.c\
+		gsm/gsm_create.c\
+		gsm/gsm_decode.c\
+		gsm/gsm_destroy.c\
+		gsm/gsm_encode.c\
+		gsm/gsm_explode.c\
+		gsm/gsm_implode.c\
+		gsm/gsm_option.c\
+		gsm/gsm_print.c\
+		gsm/long_term.c\
+		gsm/lpc.c\
+		gsm/preprocess.c\
+		gsm/rpe.c\
+		gsm/short_term.c\
+		gsm/table.c\
+		gsm/gsm_jni.c
+LOCAL_SRC_FILES := $(SRC_FILES)	
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := g722
+
+SRC_FILES := 	g722/g722_encode.c\
+		g722/g722_decode.c\
+		g722/g722_jni.c
+LOCAL_SRC_FILES := $(SRC_FILES)	
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := OSNetworkSystem
+
+SRC_FILES := 	OSNetworkSystem.cpp
+
+#LOCAL_LDLIBS := -llog
+LOCAL_SRC_FILES := $(SRC_FILES)	
+
+include $(BUILD_SHARED_LIBRARY)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/Application.mk	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,3 @@
+APP_PROJECT_PATH := /home/nikita/devel/beem/beem-audio/
+APP_BUILD_SCRIPT := ${APP_PROJECT_PATH}/jni/Android.mk
+APP_MODULES      := gsm g722 OSNetworkSystem
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/OSNetworkSystem.cpp	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,3688 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ * Copyright (C) 2007 The Android Open Source Project
+ * 
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ * 
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define LOG_TAG "OSNetworkSystem"
+
+#include <android/log.h>
+#include "jni.h"
+#include "errno.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+
+//#include <cutils/properties.h>
+//#include <cutils/adb_networking.h>
+//#include <utils/LogSocket.h>
+//#include "AndroidSystemNatives.h"
+
+/**
+ * @name Socket Errors
+ * Error codes for socket operations
+ *
+ * @internal SOCKERR* range from -200 to -299 avoid overlap
+ */
+#define SOCKERR_BADSOCKET          -200 /* generic error */
+#define SOCKERR_NOTINITIALIZED     -201 /* socket library uninitialized */
+#define SOCKERR_BADAF              -202 /* bad address family */
+#define SOCKERR_BADPROTO           -203 /* bad protocol */
+#define SOCKERR_BADTYPE            -204 /* bad type */
+#define SOCKERR_SYSTEMBUSY         -205 /* system busy handling requests */
+#define SOCKERR_SYSTEMFULL         -206 /* too many sockets */
+#define SOCKERR_NOTCONNECTED       -207 /* socket is not connected */
+#define SOCKERR_INTERRUPTED        -208 /* the call was cancelled */
+#define SOCKERR_TIMEOUT            -209 /* the operation timed out */
+#define SOCKERR_CONNRESET          -210 /* the connection was reset */
+#define SOCKERR_WOULDBLOCK         -211 /* the socket is marked as nonblocking operation would block */
+#define SOCKERR_ADDRNOTAVAIL       -212 /* address not available */
+#define SOCKERR_ADDRINUSE          -213 /* address already in use */
+#define SOCKERR_NOTBOUND           -214 /* the socket is not bound */
+#define SOCKERR_UNKNOWNSOCKET      -215 /* resolution of fileDescriptor to socket failed */
+#define SOCKERR_INVALIDTIMEOUT     -216 /* the specified timeout is invalid */
+#define SOCKERR_FDSETFULL          -217 /* Unable to create an FDSET */
+#define SOCKERR_TIMEVALFULL        -218 /* Unable to create a TIMEVAL */
+#define SOCKERR_REMSOCKSHUTDOWN    -219 /* The remote socket has shutdown gracefully */
+#define SOCKERR_NOTLISTENING       -220 /* listen() was not invoked prior to accept() */
+#define SOCKERR_NOTSTREAMSOCK      -221 /* The socket does not support connection-oriented service */
+#define SOCKERR_ALREADYBOUND       -222 /* The socket is already bound to an address */
+#define SOCKERR_NBWITHLINGER       -223 /* The socket is marked non-blocking & SO_LINGER is non-zero */
+#define SOCKERR_ISCONNECTED        -224 /* The socket is already connected */
+#define SOCKERR_NOBUFFERS          -225 /* No buffer space is available */
+#define SOCKERR_HOSTNOTFOUND       -226 /* Authoritative Answer Host not found */
+#define SOCKERR_NODATA             -227 /* Valid name, no data record of requested type */
+#define SOCKERR_BOUNDORCONN        -228 /* The socket has not been bound or is already connected */
+#define SOCKERR_OPNOTSUPP          -229 /* The socket does not support the operation */
+#define SOCKERR_OPTUNSUPP          -230 /* The socket option is not supported */
+#define SOCKERR_OPTARGSINVALID     -231 /* The socket option arguments are invalid */
+#define SOCKERR_SOCKLEVELINVALID   -232 /* The socket level is invalid */
+#define SOCKERR_TIMEOUTFAILURE     -233
+#define SOCKERR_SOCKADDRALLOCFAIL  -234 /* Unable to allocate the sockaddr structure */
+#define SOCKERR_FDSET_SIZEBAD      -235 /* The calculated maximum size of the file descriptor set is bad */
+#define SOCKERR_UNKNOWNFLAG        -236 /* The flag is unknown */
+#define SOCKERR_MSGSIZE            -237 /* The datagram was too big to fit the specified buffer & was truncated. */
+#define SOCKERR_NORECOVERY         -238 /* The operation failed with no recovery possible */
+#define SOCKERR_ARGSINVALID        -239 /* The arguments are invalid */
+#define SOCKERR_BADDESC            -240 /* The socket argument is not a valid file descriptor */
+#define SOCKERR_NOTSOCK            -241 /* The socket argument is not a socket */
+#define SOCKERR_HOSTENTALLOCFAIL   -242 /* Unable to allocate the hostent structure */
+#define SOCKERR_TIMEVALALLOCFAIL   -243 /* Unable to allocate the timeval structure */
+#define SOCKERR_LINGERALLOCFAIL    -244 /* Unable to allocate the linger structure */
+#define SOCKERR_IPMREQALLOCFAIL    -245 /* Unable to allocate the ipmreq structure */
+#define SOCKERR_FDSETALLOCFAIL     -246 /* Unable to allocate the fdset structure */
+#define SOCKERR_OPFAILED           -247 /* Operation failed */
+#define SOCKERR_VALUE_NULL         -248 /* The value indexed was NULL */
+#define SOCKERR_CONNECTION_REFUSED -249 /* connection was refused */
+#define SOCKERR_ENETUNREACH        -250 /* network is not reachable */
+#define SOCKERR_EACCES             -251 /* permissions do not allow action on socket */
+#define SOCKERR_EHOSTUNREACH       -252 /* no route to host */
+#define SOCKERR_EPIPE              -253 /* broken pipe */
+
+#define JAVASOCKOPT_TCP_NODELAY 1
+#define JAVASOCKOPT_IP_TOS 3
+#define JAVASOCKOPT_SO_REUSEADDR 4
+#define JAVASOCKOPT_SO_KEEPALIVE 8
+#define JAVASOCKOPT_MCAST_TIME_TO_LIVE 10 /* Currently unused */
+#define JAVASOCKOPT_SO_BINDADDR 15
+#define JAVASOCKOPT_MCAST_INTERFACE 16
+#define JAVASOCKOPT_MCAST_TTL 17
+#define JAVASOCKOPT_IP_MULTICAST_LOOP 18
+#define JAVASOCKOPT_MCAST_ADD_MEMBERSHIP 19
+#define JAVASOCKOPT_MCAST_DROP_MEMBERSHIP 20
+#define JAVASOCKOPT_IP_MULTICAST_IF2 31
+#define JAVASOCKOPT_SO_BROADCAST 32
+#define JAVASOCKOPT_SO_LINGER 128
+#define JAVASOCKOPT_REUSEADDR_AND_REUSEPORT  10001
+#define JAVASOCKOPT_SO_SNDBUF 4097
+#define JAVASOCKOPT_SO_RCVBUF 4098
+#define JAVASOCKOPT_SO_RCVTIMEOUT  4102
+#define JAVASOCKOPT_SO_OOBINLINE  4099
+
+/* constants for calling multi-call functions */
+#define SOCKET_STEP_START 10
+#define SOCKET_STEP_CHECK 20
+#define SOCKET_STEP_DONE 30
+
+#define BROKEN_MULTICAST_IF 1
+#define BROKEN_MULTICAST_TTL 2
+#define BROKEN_TCP_NODELAY 4
+
+#define SOCKET_CONNECT_STEP_START 0
+#define SOCKET_CONNECT_STEP_CHECK 1
+
+#define SOCKET_OP_NONE 0
+#define SOCKET_OP_READ 1
+#define SOCKET_OP_WRITE 2
+#define SOCKET_READ_WRITE 3
+
+#define SOCKET_MSG_PEEK 1
+#define SOCKET_MSG_OOB 2
+
+#define SOCKET_NOFLAGS 0
+
+#undef BUFFERSIZE
+#define BUFFERSIZE 2048
+
+// wait for 500000 usec = 0.5 second
+#define SEND_RETRY_TIME 500000
+
+
+struct CachedFields {
+    jfieldID fd_descriptor;
+    jclass iaddr_class;
+    jmethodID iaddr_class_init;
+    jmethodID iaddr_getbyaddress;
+    jfieldID iaddr_ipaddress;
+    jclass genericipmreq_class;
+    jclass integer_class;
+    jmethodID integer_class_init;
+    jfieldID integer_class_value;
+    jclass boolean_class;
+    jmethodID boolean_class_init;
+    jfieldID boolean_class_value;
+    jclass byte_class;
+    jmethodID byte_class_init;
+    jfieldID byte_class_value;
+    jclass string_class;
+    jmethodID string_class_init;
+    jfieldID socketimpl_address;
+    jfieldID socketimpl_port;
+    jclass dpack_class;
+    jfieldID dpack_address;
+    jfieldID dpack_port;
+    jfieldID dpack_length;
+    jclass fd_class;
+    jfieldID descriptor;
+} gCachedFields;
+
+static int useAdbNetworking = 0;
+
+/* needed for connecting with timeout */
+typedef struct selectFDSet {
+  int nfds;
+  int sock;
+  fd_set writeSet;
+  fd_set readSet;
+  fd_set exceptionSet;
+} selectFDSet;
+
+static const char * netLookupErrorString(int anErrorNum);
+
+#define log_socket_close(a,b)
+#define log_socket_connect(a,b,c)
+#define add_send_stats(a,b)
+#define add_recv_stats(a,b)
+#define adb_networking_connect_fd(a,b) 0
+#define adb_networking_gethostbyname(a,b) 0
+#define PROPERTY_VALUE_MAX 1
+#define property_get(a,b,c)
+#define assert(a)
+/*
+ * Throw an exception with the specified class and an optional message.
+ */
+int jniThrowException(JNIEnv* env, const char* className, const char* msg)
+{
+    jclass exceptionClass;
+
+    exceptionClass = env->FindClass(className);
+    if (exceptionClass == NULL) {
+//        LOGE("Unable to find exception class %s\n", className);
+        assert(0);      /* fatal during dev; should always be fatal? */
+        return -1;
+    }
+
+    if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {
+//        LOGE("Failed throwing '%s' '%s'\n", className, msg);
+        assert(!"failed to throw");
+    }
+    return 0;
+}
+
+/*
+ * Internal helper function.
+ *
+ * Get the file descriptor.
+ */
+static inline int getFd(JNIEnv* env, jobject obj)
+{
+    return env->GetIntField(obj, gCachedFields.descriptor);
+}
+
+/*
+ * Internal helper function.
+ *
+ * Set the file descriptor.
+ */
+static inline void setFd(JNIEnv* env, jobject obj, jint value)
+{
+    env->SetIntField(obj, gCachedFields.descriptor, value);
+}
+
+/* 
+ * For JNIHelp.c
+ * Get an int file descriptor from a java.io.FileDescriptor
+ */
+
+static int jniGetFDFromFileDescriptor (JNIEnv* env, jobject fileDescriptor) {
+
+    return getFd(env, fileDescriptor);
+}
+
+/*
+ * For JNIHelp.c
+ * Set the descriptor of a java.io.FileDescriptor
+ */
+
+static void jniSetFileDescriptorOfFD (JNIEnv* env, jobject fileDescriptor, int value) {
+
+    setFd(env, fileDescriptor, value);
+}
+
+/**
+ * Throws an SocketException with the message affiliated with the errorCode.
+ */
+static void throwSocketException(JNIEnv *env, int errorCode) {
+    jniThrowException(env, "java/net/SocketException",
+        netLookupErrorString(errorCode));
+}
+
+/**
+ * Throws an IOException with the given message.
+ */
+static void throwIOExceptionStr(JNIEnv *env, const char *message) {
+    jniThrowException(env, "java/io/IOException", message);
+}
+
+/**
+ * Throws a NullPointerException.
+ */
+static void throwNullPointerException(JNIEnv *env) {
+    jniThrowException(env, "java/lang/NullPointerException", NULL);
+}
+
+/**
+ * Converts a 4-byte array to a native address structure. Throws a
+ * NullPointerException or an IOException in case of error. This is
+ * signaled by a return value of -1. The normal return value is 0.
+ */
+static int javaAddressToStructIn(
+        JNIEnv *env, jbyteArray java_address, struct in_addr *address) {
+
+    memset(address, 0, sizeof(address));
+
+    if (java_address == NULL) {
+        return -1;
+    }
+
+    if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
+        return -1;
+    }
+
+    jbyte * java_address_bytes
+        =  env->GetByteArrayElements(java_address, NULL);
+
+    memcpy(&(address->s_addr),
+        java_address_bytes,
+        sizeof(address->s_addr));
+
+    env->ReleaseByteArrayElements(java_address, java_address_bytes, JNI_ABORT);
+
+    return 0;
+}
+
+/**
+ * Converts a native address structure to a 4-byte array. Throws a
+ * NullPointerException or an IOException in case of error. This is
+ * signaled by a return value of -1. The normal return value is 0.
+ */
+static int structInToJavaAddress(
+        JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
+
+    if (java_address == NULL) {
+        return -1;
+    }
+
+    if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
+        return -1;
+    }
+
+    jbyte *java_address_bytes;
+
+    java_address_bytes = env->GetByteArrayElements(java_address, NULL);
+
+    memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
+
+    env->ReleaseByteArrayElements(java_address, java_address_bytes, 0);
+
+    return 0;
+}
+
+/**
+ * Converts a native address structure to an InetAddress object.
+ * Throws a NullPointerException or an IOException in case of
+ * error. This is signaled by a return value of -1. The normal
+ * return value is 0.
+ */
+static int socketAddressToInetAddress(JNIEnv *env,
+        struct sockaddr_in *sockaddress, jobject inetaddress, int *port) {
+
+    jbyteArray ipaddress;
+    int result;
+
+    ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
+            gCachedFields.iaddr_ipaddress);
+
+    if (structInToJavaAddress(env, &sockaddress->sin_addr, ipaddress) < 0) {
+        return -1;
+    }
+
+    *port = ntohs(sockaddress->sin_port);
+
+    return 0;
+}
+
+/**
+ * Converts an InetAddress object to a native address structure.
+ * Throws a NullPointerException or an IOException in case of
+ * error. This is signaled by a return value of -1. The normal
+ * return value is 0.
+ */
+static int inetAddressToSocketAddress(JNIEnv *env,
+        jobject inetaddress, int port, struct sockaddr_in *sockaddress) {
+
+    jbyteArray ipaddress;
+    int result;
+
+    ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
+            gCachedFields.iaddr_ipaddress);
+
+    memset(sockaddress, 0, sizeof(sockaddress));
+
+    sockaddress->sin_family = AF_INET;
+    sockaddress->sin_port = htons(port);
+
+    if (javaAddressToStructIn(env, ipaddress, &(sockaddress->sin_addr)) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
+    jbyteArray bytes;
+    int success;
+
+    bytes = env->NewByteArray(4);
+
+    if (bytes == NULL) {
+        return NULL;
+    }
+
+    if (structInToJavaAddress(env, address, bytes) < 0) {
+        return NULL;
+    }
+
+    return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
+            gCachedFields.iaddr_getbyaddress, bytes);
+}
+
+/**
+ * Answer a new java.lang.Boolean object.
+ *
+ * @param env   pointer to the JNI library
+ * @param anInt the Boolean constructor argument
+ *
+ * @return  the new Boolean
+ */
+
+static jobject newJavaLangBoolean(JNIEnv * env, jint anInt) {
+    jclass tempClass;
+    jmethodID tempMethod;
+
+    tempClass = gCachedFields.boolean_class;
+    tempMethod = gCachedFields.boolean_class_init;
+    return env->NewObject(tempClass, tempMethod, (jboolean) (anInt != 0));
+}
+
+/**
+ * Answer a new java.lang.Byte object.
+ *
+ * @param env   pointer to the JNI library
+ * @param anInt the Byte constructor argument
+ *
+ * @return  the new Byte
+ */
+
+static jobject newJavaLangByte(JNIEnv * env, jbyte val) {
+    jclass tempClass;
+    jmethodID tempMethod;
+
+    tempClass = gCachedFields.byte_class;
+    tempMethod = gCachedFields.byte_class_init;
+    return env->NewObject(tempClass, tempMethod, val);
+}
+
+/**
+ * Answer a new java.lang.Integer object.
+ *
+ * @param env   pointer to the JNI library
+ * @param anInt the Integer constructor argument
+ *
+ * @return  the new Integer
+ */
+
+static jobject newJavaLangInteger(JNIEnv * env, jint anInt) {
+    jclass tempClass;
+    jmethodID tempMethod;
+
+    tempClass = gCachedFields.integer_class;
+    tempMethod = gCachedFields.integer_class_init;
+    return env->NewObject(tempClass, tempMethod, anInt);
+}
+
+/**
+ * Answer a new java.lang.String object.
+ *
+ * @param env   pointer to the JNI library
+ * @param anInt the byte[] constructor argument
+ *
+ * @return  the new String
+ */
+
+static jobject newJavaLangString(JNIEnv * env, jbyteArray bytes) {
+    jclass tempClass;
+    jmethodID tempMethod;
+
+    tempClass = gCachedFields.string_class;
+    tempMethod = gCachedFields.string_class_init;
+    return env->NewObject(tempClass, tempMethod, (jbyteArray) bytes);
+}
+
+/**
+ * Query OS for timestamp.
+ * Retrieve the current value of system clock and convert to milliseconds.
+ *
+ * @param[in] portLibrary The port library.
+ *
+ * @return 0 on failure, time value in milliseconds on success.
+ * @deprecated Use @ref time_hires_clock and @ref time_hires_delta
+ *
+ * technically, this should return I_64 since both timeval.tv_sec and
+ * timeval.tv_usec are long
+ */
+
+static int time_msec_clock() {
+    struct timeval tp;
+    struct timezone tzp;
+
+    gettimeofday(&tp, &tzp);
+    return (tp.tv_sec * 1000) + (tp.tv_usec / 1000);
+}
+
+/**
+ * check if the passed sockaddr_in struct contains a localhost address
+ *
+ * @param[in] address pointer to the address to check
+ *
+ * @return 0 if the passed address isn't a localhost address
+ */
+static int isLocalhost(struct sockaddr_in *address) {
+    // return address == 127.0.0.1
+    return (unsigned int) address->sin_addr.s_addr == 16777343;
+}
+
+/**
+ * Answer the errorString corresponding to the errorNumber, if available.
+ * This function will answer a default error string, if the errorNumber is not
+ * recognized.
+ *
+ * This function will have to be reworked to handle internationalization
+ * properly, removing the explicit strings.
+ *
+ * @param anErrorNum    the error code to resolve to a human readable string
+ *
+ * @return  a human readable error string
+ */
+
+static const char * netLookupErrorString(int anErrorNum) {
+    switch (anErrorNum) {
+        case SOCKERR_BADSOCKET:
+            return "Bad socket";
+        case SOCKERR_NOTINITIALIZED:
+            return "Socket library uninitialized";
+        case SOCKERR_BADAF:
+            return "Bad address family";
+        case SOCKERR_BADPROTO:
+            return "Bad protocol";
+        case SOCKERR_BADTYPE:
+            return "Bad type";
+        case SOCKERR_SYSTEMBUSY:
+            return "System busy handling requests";
+        case SOCKERR_SYSTEMFULL:
+            return "Too many sockets allocated";
+        case SOCKERR_NOTCONNECTED:
+            return "Socket is not connected";
+        case SOCKERR_INTERRUPTED:
+            return "The system call was cancelled";
+        case SOCKERR_TIMEOUT:
+            return "The operation timed out";
+        case SOCKERR_CONNRESET:
+            return "The connection was reset";
+        case SOCKERR_WOULDBLOCK:
+            return "The nonblocking operation would block";
+        case SOCKERR_ADDRNOTAVAIL:
+            return "The address is not available";
+        case SOCKERR_ADDRINUSE:
+            return "The address is already in use";
+        case SOCKERR_NOTBOUND:
+            return "The socket is not bound";
+        case SOCKERR_UNKNOWNSOCKET:
+            return "Resolution of the FileDescriptor to socket failed";
+        case SOCKERR_INVALIDTIMEOUT:
+            return "The specified timeout is invalid";
+        case SOCKERR_FDSETFULL:
+            return "Unable to create an FDSET";
+        case SOCKERR_TIMEVALFULL:
+            return "Unable to create a TIMEVAL";
+        case SOCKERR_REMSOCKSHUTDOWN:
+            return "The remote socket has shutdown gracefully";
+        case SOCKERR_NOTLISTENING:
+            return "Listen() was not invoked prior to accept()";
+        case SOCKERR_NOTSTREAMSOCK:
+            return "The socket does not support connection-oriented service";
+        case SOCKERR_ALREADYBOUND:
+            return "The socket is already bound to an address";
+        case SOCKERR_NBWITHLINGER:
+            return "The socket is marked non-blocking & SO_LINGER is non-zero";
+        case SOCKERR_ISCONNECTED:
+            return "The socket is already connected";
+        case SOCKERR_NOBUFFERS:
+            return "No buffer space is available";
+        case SOCKERR_HOSTNOTFOUND:
+            return "Authoritative Answer Host not found";
+        case SOCKERR_NODATA:
+            return "Valid name, no data record of requested type";
+        case SOCKERR_BOUNDORCONN:
+            return "The socket has not been bound or is already connected";
+        case SOCKERR_OPNOTSUPP:
+            return "The socket does not support the operation";
+        case SOCKERR_OPTUNSUPP:
+            return "The socket option is not supported";
+        case SOCKERR_OPTARGSINVALID:
+            return "The socket option arguments are invalid";
+        case SOCKERR_SOCKLEVELINVALID:
+            return "The socket level is invalid";
+        case SOCKERR_TIMEOUTFAILURE:
+            return "The timeout operation failed";
+        case SOCKERR_SOCKADDRALLOCFAIL:
+            return "Failed to allocate address structure";
+        case SOCKERR_FDSET_SIZEBAD:
+            return "The calculated maximum size of the file descriptor set is bad";
+        case SOCKERR_UNKNOWNFLAG:
+            return "The flag is unknown";
+        case SOCKERR_MSGSIZE:
+            return "The datagram was too big to fit the specified buffer, so truncated";
+        case SOCKERR_NORECOVERY:
+            return "The operation failed with no recovery possible";
+        case SOCKERR_ARGSINVALID:
+            return "The arguments are invalid";
+        case SOCKERR_BADDESC:
+            return "The socket argument is not a valid file descriptor";
+        case SOCKERR_NOTSOCK:
+            return "The socket argument is not a socket";
+        case SOCKERR_HOSTENTALLOCFAIL:
+            return "Unable to allocate the hostent structure";
+        case SOCKERR_TIMEVALALLOCFAIL:
+            return "Unable to allocate the timeval structure";
+        case SOCKERR_LINGERALLOCFAIL:
+            return "Unable to allocate the linger structure";
+        case SOCKERR_IPMREQALLOCFAIL:
+            return "Unable to allocate the ipmreq structure";
+        case SOCKERR_FDSETALLOCFAIL:
+            return "Unable to allocate the fdset structure";
+        case SOCKERR_OPFAILED:
+            return "Operation failed";
+        case SOCKERR_CONNECTION_REFUSED:
+            return "Connection refused";
+        case SOCKERR_ENETUNREACH:
+            return "Network unreachable";
+        case SOCKERR_EHOSTUNREACH:
+            return "No route to host";
+        case SOCKERR_EPIPE:
+            return "Broken pipe";
+        case SOCKERR_EACCES:
+            return "Permission denied (maybe missing INTERNET permission)";
+
+        default:
+//            LOGE("unknown socket error %d", anErrorNum);
+            return "unknown error";
+    }
+}
+
+static int convertError(int errorCode) {
+    switch (errorCode) {
+        case EBADF:
+            return SOCKERR_BADDESC;
+        case ENOBUFS:
+            return SOCKERR_NOBUFFERS;
+        case EOPNOTSUPP:
+            return SOCKERR_OPNOTSUPP;
+        case ENOPROTOOPT:
+            return SOCKERR_OPTUNSUPP;
+        case EINVAL:
+            return SOCKERR_SOCKLEVELINVALID;
+        case ENOTSOCK:
+            return SOCKERR_NOTSOCK;
+        case EINTR:
+            return SOCKERR_INTERRUPTED;
+        case ENOTCONN:
+            return SOCKERR_NOTCONNECTED;
+        case EAFNOSUPPORT:
+            return SOCKERR_BADAF;
+            /* note: CONNRESET not included because it has the same
+             * value as ECONNRESET and they both map to SOCKERR_CONNRESET */
+        case ECONNRESET:
+            return SOCKERR_CONNRESET;
+        case EAGAIN:
+            return SOCKERR_WOULDBLOCK;
+        case EPROTONOSUPPORT:
+            return SOCKERR_BADPROTO;
+        case EFAULT:
+            return SOCKERR_ARGSINVALID;
+        case ETIMEDOUT:
+            return SOCKERR_TIMEOUT;
+        case ECONNREFUSED:
+            return SOCKERR_CONNECTION_REFUSED;
+        case ENETUNREACH:
+            return SOCKERR_ENETUNREACH;
+        case EACCES:
+            return SOCKERR_EACCES;
+        case EPIPE:
+            return SOCKERR_EPIPE;
+        case EHOSTUNREACH:
+            return SOCKERR_EHOSTUNREACH;
+        case EADDRINUSE:
+            return SOCKERR_ADDRINUSE;
+        case EADDRNOTAVAIL:
+            return SOCKERR_ADDRNOTAVAIL;
+        case EMSGSIZE:
+            return SOCKERR_MSGSIZE;
+        default:
+//            LOGE("unclassified errno %d (%s)", errorCode, strerror(errorCode));
+            return SOCKERR_OPFAILED;
+    }
+}
+
+static int sockSelect(int nfds, fd_set *readfds, fd_set *writefds,
+        fd_set *exceptfds, struct timeval *timeout) {
+
+    int result = select(nfds, readfds, writefds, exceptfds, timeout);
+
+    if (result < 0) {
+        if (errno == EINTR) {
+            result = SOCKERR_INTERRUPTED;
+        } else {
+            result = SOCKERR_OPFAILED;
+        }
+    } else if (result == 0) {
+        result = SOCKERR_TIMEOUT;
+    }
+    return result;
+}
+
+#define SELECT_READ_TYPE 0
+#define SELECT_WRITE_TYPE 1
+
+static int selectWait(int handle, int uSecTime, int type) {
+    fd_set fdset;
+    struct timeval time, *timePtr;
+    int result = 0;
+    int size = handle + 1;
+
+    FD_ZERO(&fdset);
+    FD_SET(handle, &fdset);
+
+    if (0 <= uSecTime) {
+        /* Use a timeout if uSecTime >= 0 */
+        memset(&time, 0, sizeof(time));
+        time.tv_usec = uSecTime;
+        timePtr = &time;
+    } else {
+        /* Infinite timeout if uSecTime < 0 */
+        timePtr = NULL;
+    }
+
+    if (type == SELECT_READ_TYPE) {
+        result = sockSelect(size, &fdset, NULL, NULL, timePtr);
+    } else {
+        result = sockSelect(size, NULL, &fdset, NULL, timePtr);
+    }
+    return result;
+}
+
+static int pollSelectWait(JNIEnv *env, jobject fileDescriptor, int timeout, int type) {
+    /* now try reading the socket for the timespan timeout.
+     * if timeout is 0 try forever until the soclets gets ready or until an
+     * exception occurs.
+     */
+    int pollTimeoutUSec = 100000, pollMsec = 100;
+    int finishTime = 0;
+    int timeLeft = timeout;
+    int hasTimeout = timeout > 0 ? 1 : 0;
+    int result = 0;
+    int handle;
+
+    if (hasTimeout) {
+        finishTime = time_msec_clock() + timeout;
+    }
+
+    int poll = 1;
+
+    while (poll) { /* begin polling loop */
+
+        /*
+         * Fetch the handle every time in case the socket is closed.
+         */
+        handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+        if (handle == 0 || handle == -1) {
+            throwSocketException(env, SOCKERR_INTERRUPTED);
+            return -1;
+        }
+
+        if (hasTimeout) {
+
+            if (timeLeft - 10 < pollMsec) {
+                pollTimeoutUSec = timeLeft <= 0 ? 0 : (timeLeft * 1000);
+            }
+
+            result = selectWait(handle, pollTimeoutUSec, type);
+
+            /*
+             * because we are polling at a time smaller than timeout
+             * (presumably) lets treat an interrupt and timeout the same - go
+             * see if we're done timewise, and then just try again if not.
+             */
+            if (SOCKERR_TIMEOUT == result ||
+                SOCKERR_INTERRUPTED == result) {
+
+                timeLeft = finishTime - time_msec_clock();
+
+                if (timeLeft <= 0) {
+                    /*
+                     * Always throw the "timeout" message because that is
+                     * effectively what has happened, even if we happen to
+                     * have been interrupted.
+                     */
+                    jniThrowException(env, "java/net/SocketTimeoutException",
+                            netLookupErrorString(SOCKERR_TIMEOUT));
+                } else {
+                    continue; // try again
+                }
+
+            } else if (0 > result) {
+                log_socket_close(handle, result);
+                throwSocketException(env, result);
+            }
+            poll = 0;
+
+        } else { /* polling with no timeout (why would you do this?)*/
+
+            result = selectWait(handle, pollTimeoutUSec, type);
+
+            /*
+             *  if interrupted (or a timeout) just retry
+             */
+            if (SOCKERR_TIMEOUT == result ||
+               SOCKERR_INTERRUPTED == result) {
+
+                continue; // try again
+            } else if (0 > result) {
+                log_socket_close(handle, result);
+                throwSocketException(env, result);
+            }
+            poll = 0;
+        }
+    } /* end polling loop */
+
+    return result;
+}
+
+/**
+ * A helper method, to set the connect context to a Long object.
+ *
+ * @param env  pointer to the JNI library
+ * @param longclass Java Long Object
+ */
+void setConnectContext(JNIEnv *env,jobject longclass,jbyte * context) {
+    jclass descriptorCLS;
+    jfieldID descriptorFID;
+    descriptorCLS = env->FindClass("java/lang/Long");
+    descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+    env->SetLongField(longclass, descriptorFID, (jlong)((jint)context));
+};
+
+/**
+ * A helper method, to get the connect context.
+ *
+ * @param env  pointer to the JNI library
+ * @param longclass Java Long Object
+ */
+jbyte *getConnectContext(JNIEnv *env, jobject longclass) {
+    jclass descriptorCLS;
+    jfieldID descriptorFID;
+    descriptorCLS = env->FindClass("java/lang/Long");
+    descriptorFID = env->GetFieldID(descriptorCLS, "value", "J");
+    return (jbyte*) ((jint)env->GetLongField(longclass, descriptorFID));
+};
+
+// typical ip checksum
+unsigned short ip_checksum(unsigned short* buffer, int size) {
+    register unsigned short * buf = buffer;
+    register int bufleft = size;
+    register unsigned long sum = 0;
+
+    while (bufleft > 1) {
+        sum = sum + (*buf++);
+        bufleft = bufleft - sizeof(unsigned short );
+    }
+    if (bufleft) {
+        sum = sum + (*(unsigned char*)buf);
+    }
+    sum = (sum >> 16) + (sum & 0xffff);
+    sum += (sum >> 16);
+
+    return (unsigned short )(~sum);
+}
+
+/**
+ * Establish a connection to a peer with a timeout.  This function is called
+ * repeatedly in order to carry out the connect and to allow other tasks to
+ * proceed on certain platforms. The caller must first call with
+ * step = SOCKET_STEP_START, if the result is SOCKERR_NOTCONNECTED it will then
+ * call it with step = CHECK until either another error or 0 is returned to
+ * indicate the connect is complete.  Each time the function should sleep for no
+ * more than timeout milliseconds.  If the connect succeeds or an error occurs,
+ * the caller must always end the process by calling the function with
+ * step = SOCKET_STEP_DONE
+ *
+ * @param[in] portLibrary The port library.
+ * @param[in] sock pointer to the unconnected local socket.
+ * @param[in] addr pointer to the sockaddr, specifying remote host/port.
+ * @param[in] timeout the timeout in milliseconds. If timeout is negative,
+ *         perform a block operation.
+ * @param[in,out] pointer to context pointer. Filled in on first call and then
+ *         to be passed into each subsequent call.
+ *
+ * @return 0, if no errors occurred, otherwise the (negative) error code.
+ */
+static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
+        unsigned int timeout, unsigned int step, jbyte *ctxt) {
+    int rc = 0;
+    struct timeval passedTimeout;
+    int errorVal;
+    socklen_t errorValLen = sizeof(int);
+    struct selectFDSet *context = NULL;
+
+    if (SOCKET_STEP_START == step) {
+
+        context = (struct selectFDSet *) ctxt;
+
+        context->sock = handle;
+        context->nfds = handle + 1;
+
+        if (useAdbNetworking && !isLocalhost(&addr)) {
+
+            // LOGD("+connect to address 0x%08x (via adb)",
+            //         addr.sin_addr.s_addr);
+            rc = adb_networking_connect_fd(handle, &addr);
+            // LOGD("-connect ret %d errno %d (via adb)", rc, errno);
+
+        } else {
+            log_socket_connect(handle, ntohl(addr.sin_addr.s_addr),
+                    ntohs(addr.sin_port));
+            /* set the socket to non-blocking */
+            int block = JNI_TRUE;
+            rc = ioctl(handle, FIONBIO, &block);
+            if (0 != rc) {
+                return convertError(rc);
+            }
+
+            // LOGD("+connect to address 0x%08x (via normal) on handle %d",
+            //         addr.sin_addr.s_addr, handle);
+            do {
+                rc = connect(handle, (struct sockaddr *) &addr,
+                        sizeof(struct sockaddr));
+            } while (rc < 0 && errno == EINTR);
+            // LOGD("-connect to address 0x%08x (via normal) returned %d",
+            //         addr.sin_addr.s_addr, (int) rc);
+
+        }
+
+        if (rc == -1) {
+            rc = errno;
+            switch (rc) {
+                case EINTR:
+                    return SOCKERR_ALREADYBOUND;
+                case EAGAIN:
+                case EINPROGRESS:
+                    return SOCKERR_NOTCONNECTED;
+                default:
+                    return convertError(rc);
+            }
+        }
+
+        /* we connected right off the bat so just return */
+        return rc;
+
+    } else if (SOCKET_STEP_CHECK == step) {
+        /* now check if we have connected yet */
+
+        context = (struct selectFDSet *) ctxt;
+
+        /*
+         * set the timeout value to be used. Because on some unix platforms we
+         * don't get notified when a socket is closed we only sleep for 100ms
+         * at a time
+         */
+        passedTimeout.tv_sec = 0;
+        if (timeout > 100) {
+            passedTimeout.tv_usec = 100 * 1000;
+        } else if ((int)timeout >= 0) {
+          passedTimeout.tv_usec = timeout * 1000;
+        }
+
+        /* initialize the FD sets for the select */
+        FD_ZERO(&(context->exceptionSet));
+        FD_ZERO(&(context->writeSet));
+        FD_ZERO(&(context->readSet));
+        FD_SET(context->sock, &(context->writeSet));
+        FD_SET(context->sock, &(context->readSet));
+        FD_SET(context->sock, &(context->exceptionSet));
+
+        rc = select(context->nfds,
+                   &(context->readSet),
+                   &(context->writeSet),
+                   &(context->exceptionSet),
+                   (int)timeout >= 0 ? &passedTimeout : NULL);
+
+        /* if there is at least one descriptor ready to be checked */
+        if (0 < rc) {
+            /* if the descriptor is in the write set we connected or failed */
+            if (FD_ISSET(context->sock, &(context->writeSet))) {
+
+                if (!FD_ISSET(context->sock, &(context->readSet))) {
+                    /* ok we have connected ok */
+                    return 0;
+                } else {
+                    /* ok we have more work to do to figure it out */
+                    if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR,
+                            &errorVal, &errorValLen) >= 0) {
+                        return errorVal ? convertError(errorVal) : 0;
+                    } else {
+                        return convertError(errno);
+                    }
+                }
+            }
+
+            /* if the descriptor is in the exception set the connect failed */
+            if (FD_ISSET(context->sock, &(context->exceptionSet))) {
+                if (getsockopt(context->sock, SOL_SOCKET, SO_ERROR, &errorVal,
+                        &errorValLen) >= 0) {
+                    return errorVal ? convertError(errorVal) : 0;
+                }
+                rc = errno;
+                return convertError(rc);
+            }
+
+        } else if (rc < 0) {
+            /* something went wrong with the select call */
+            rc = errno;
+
+            /* if it was EINTR we can just try again. Return not connected */
+            if (EINTR == rc) {
+                return SOCKERR_NOTCONNECTED;
+            }
+
+            /* some other error occured so look it up and return */
+            return convertError(rc);
+        }
+
+        /*
+         * if we get here the timeout expired or the connect had not yet
+         * completed just indicate that the connect is not yet complete
+         */
+        return SOCKERR_NOTCONNECTED;
+    } else if (SOCKET_STEP_DONE == step) {
+        /* we are done the connect or an error occured so clean up  */
+        if (handle != -1) {
+            int block = JNI_FALSE;
+            ioctl(handle, FIONBIO, &block);
+        }
+        return 0;
+    }
+    return SOCKERR_ARGSINVALID;
+}
+
+/**
+ * Join/Leave the nominated multicast group on the specified socket.
+ * Implemented by setting the multicast 'add membership'/'drop membership'
+ * option at the HY_IPPROTO_IP level on the socket.
+ *
+ * Implementation note for multicast sockets in general:
+ *
+ * - This code is untested, because at the time of this writing multicast can't
+ * be properly tested on Android due to GSM routing restrictions. So it might
+ * or might not work.
+ *
+ * - The REUSEPORT socket option that Harmony employs is not supported on Linux
+ * and thus also not supported on Android. It's is not needed for multicast
+ * to work anyway (REUSEADDR should suffice).
+ *
+ * @param env pointer to the JNI library.
+ * @param socketP pointer to the hysocket to join/leave on.
+ * @param optVal pointer to the InetAddress, the multicast group to join/drop.
+ *
+ * @exception SocketException if an error occurs during the call
+ */
+static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
+        int ignoreIF, int setSockOptVal) {
+    int result;
+    struct ip_mreq ipmreqP;
+    struct sockaddr_in sockaddrP;
+    int length = sizeof(struct ip_mreq);
+    socklen_t lengthIF = sizeof(struct sockaddr_in);
+
+    /*
+     * JNI objects needed to access the information in the optVal oject
+     * passed in. The object passed in is a GenericIPMreq object
+     */
+    jclass cls;
+    jfieldID multiaddrID;
+    jfieldID interfaceAddrID;
+    jobject multiaddr;
+    jobject interfaceAddr;
+
+    /*
+     * check whether we are getting an InetAddress or an Generic IPMreq, for now
+     * we support both so that we will not break the tests
+     */
+    if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
+
+        ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
+        if (!ignoreIF) {
+
+            result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockaddrP,
+                    &lengthIF);
+
+            if (0 != result) {
+                throwSocketException (env, convertError(errno));
+                return;
+            }
+
+            memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
+        }
+
+        result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
+
+        if (result < 0) {
+            throwSocketException(env, SOCKERR_BADSOCKET);
+            return;
+        }
+
+        memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
+
+        result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+        if (0 != result) {
+            throwSocketException (env, convertError(errno));
+            return;
+        }
+
+    } else {
+
+        /* we need the multicast address regardless of the type of address */
+        cls = env->GetObjectClass(optVal);
+        multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
+        multiaddr = env->GetObjectField(optVal, multiaddrID);
+
+        result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
+
+        if (result < 0) {
+            throwSocketException(env, SOCKERR_BADSOCKET);
+            return;
+        }
+
+        memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
+
+        /* we need to use an IP_MREQ as it is an IPV4 address */
+        interfaceAddrID = env->GetFieldID(cls, "interfaceAddr",
+                "Ljava/net/InetAddress;");
+        interfaceAddr = env->GetObjectField(optVal, interfaceAddrID);
+
+        ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
+
+        /*
+         * if an interfaceAddr was passed then use that value, otherwise set the
+         * interface to all 0 to indicate the system should select the interface
+         * used
+         */
+        if (!ignoreIF) {
+            if (NULL != interfaceAddr) {
+
+                result = inetAddressToSocketAddress(env, interfaceAddr, 0,
+                        &sockaddrP);
+
+                if (result < 0) {
+                    throwSocketException(env, SOCKERR_BADSOCKET);
+                    return;
+                }
+
+                memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
+
+            }
+        }
+
+        /* join/drop the multicast address */
+        result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+        if (0 != result) {
+            throwSocketException (env, convertError(errno));
+            return;
+        }
+    }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj,
+        jboolean jcl_supports_ipv6) {
+    // LOGD("ENTER oneTimeInitializationImpl of OSNetworkSystem");
+
+    char useAdbNetworkingProperty[PROPERTY_VALUE_MAX];
+    char adbConnectedProperty[PROPERTY_VALUE_MAX];
+
+    property_get("android.net.use-adb-networking", useAdbNetworkingProperty, "");
+    property_get("adb.connected", adbConnectedProperty, "");
+
+    if (strlen((char *)useAdbNetworkingProperty) > 0
+            && strlen((char *)adbConnectedProperty) > 0) {
+        useAdbNetworking = 1;
+    }
+
+    memset(&gCachedFields, 0, sizeof(gCachedFields));
+
+    // initializing InetAddress
+
+    jclass iaddrclass = env->FindClass("java/net/InetAddress");
+
+    if (iaddrclass == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "java.net.InetAddress");
+        return;
+    }
+
+    gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass);
+
+    jmethodID iaddrclassinit = env->GetMethodID(iaddrclass, "<init>", "()V");
+
+    if (iaddrclassinit == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.<init>()");
+        return;
+    }
+
+    gCachedFields.iaddr_class_init = iaddrclassinit;
+
+    jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass,
+            "getByAddress", "([B)Ljava/net/InetAddress;");
+
+    if (iaddrgetbyaddress == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError",
+                "InetAddress.getByAddress(byte[] val)");
+        return;
+    }
+
+    gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress;
+    
+    jmethodID iaddrgetaddress = env->GetStaticMethodID(iaddrclass,
+            "getByAddress", "([B)Ljava/net/InetAddress;");
+
+
+
+
+    jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B");
+
+    if (iaddripaddress == NULL) {
+        jniThrowException(env, "java/lang/NoSuchFieldError",
+                "Can't find field InetAddress.ipaddress");
+        return;
+    }
+
+    gCachedFields.iaddr_ipaddress = iaddripaddress;
+
+    // get the GenericIPMreq class
+
+    jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq");
+
+    if (genericipmreqclass == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "org.apache.harmony.luni.net.GenericIPMreq");
+        return;
+    }
+
+    gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass);
+
+    // initializing Integer
+
+    jclass integerclass = env->FindClass("java/lang/Integer");
+
+    if (integerclass == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "java.lang.Integer");
+        return;
+    }
+
+    jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V");
+
+    if (integerclassinit == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError",
+                "Integer.<init>(int val)");
+        return;
+    }
+
+    jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I");
+
+    if (integerclassvalue == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value");
+        return;
+    }
+
+    gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass);
+    gCachedFields.integer_class_init = integerclassinit;
+    gCachedFields.integer_class_value = integerclassvalue;
+
+    // initializing Boolean
+
+    jclass booleanclass = env->FindClass("java/lang/Boolean");
+
+    if (booleanclass == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "java.lang.Boolean");
+        return;
+    }
+
+    jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V");
+
+    if (booleanclassinit == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError",
+                "Boolean.<init>(boolean val)");
+        return;
+    }
+
+    jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z");
+
+    if (booleanclassvalue == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value");
+        return;
+    }
+
+    gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass);
+    gCachedFields.boolean_class_init = booleanclassinit;
+    gCachedFields.boolean_class_value = booleanclassvalue;
+
+    // initializing Byte
+
+    jclass byteclass = env->FindClass("java/lang/Byte");
+
+    if (byteclass == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "java.lang.Byte");
+        return;
+    }
+
+    jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V");
+
+    if (byteclassinit == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError",
+                "Byte.<init>(byte val)");
+        return;
+    }
+
+    jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B");
+
+    if (byteclassvalue == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value");
+        return;
+    }
+
+    gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass);
+    gCachedFields.byte_class_init = byteclassinit;
+    gCachedFields.byte_class_value = byteclassvalue;
+
+    // initializing String
+
+    jclass stringclass = env->FindClass("java/lang/String");
+
+    if (stringclass == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "java.lang.String");
+        return;
+    }
+
+    jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V");
+
+    if (stringclassinit == NULL) {
+        jniThrowException(env, "java/lang/NoSuchMethodError",
+                "String.<init>(byte[] val)");
+        return;
+    }
+
+    gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass);
+    gCachedFields.string_class_init = stringclassinit;
+
+    // initializing ScoketImpl
+
+    jclass socketimplclass = env->FindClass("java/net/SocketImpl");
+
+    if (socketimplclass == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "java.net.SocketImpl");
+        return;
+    }
+
+    jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I");
+
+    if (socketimplport == NULL) {
+        jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port");
+        return;
+    }
+
+    jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address",
+            "Ljava/net/InetAddress;");
+
+    if (socketimpladdress == NULL) {
+        jniThrowException(env, "java/lang/NoSuchFieldError",
+                "SocketImpl.address");
+        return;
+    }
+
+    gCachedFields.socketimpl_address = socketimpladdress;
+    gCachedFields.socketimpl_port = socketimplport;
+
+    gCachedFields.dpack_class = env->FindClass("java/net/DatagramPacket");
+    if (gCachedFields.dpack_class == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "java.net.DatagramPacket");
+        return;
+    }
+
+    gCachedFields.dpack_address = env->GetFieldID(gCachedFields.dpack_class,
+            "address", "Ljava/net/InetAddress;");
+    if (gCachedFields.dpack_address == NULL) {
+        jniThrowException(env, "java/lang/NoSuchFieldError",
+                "DatagramPacket.address");
+        return;
+    }
+
+    gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class,
+            "port", "I");
+    if (gCachedFields.dpack_port == NULL) {
+        jniThrowException(env, "java/lang/NoSuchFieldError",
+                "DatagramPacket.port");
+        return;
+    }
+
+    gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class,
+            "length", "I");
+    if (gCachedFields.dpack_length == NULL) {
+        jniThrowException(env, "java/lang/NoSuchFieldError",
+                "DatagramPacket.length");
+        return;
+    }
+
+        gCachedFields.fd_class = env->FindClass("java/io/FileDescriptor");
+    if (gCachedFields.fd_class == NULL) {
+        jniThrowException(env, "java/lang/ClassNotFoundException",
+                "java.io.FileDescriptor");
+        return;
+    }
+        gCachedFields.descriptor = env->GetFieldID(gCachedFields.fd_class, "descriptor", "I");
+    if (gCachedFields.descriptor == NULL) {
+        jniThrowException(env, "java/lang/NoSuchFieldError",
+                "FileDescriptor.descriptor");
+        return;
+    }
+
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jboolean preferIPv4Stack) {
+    // LOGD("ENTER createSocketImpl");
+
+    int ret = socket(PF_INET, SOCK_STREAM, 0);
+
+    if (ret < 0) {
+        int err = convertError(errno);
+        throwSocketException(env, err);
+        return;
+    }
+
+    jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
+
+    return;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jboolean preferIPv4Stack) {
+    // LOGD("ENTER createDatagramSocketImpl");
+
+    int ret = socket(PF_INET, SOCK_DGRAM, 0);
+
+    if (ret < 0) {
+        int err = convertError(errno);
+        throwSocketException(env, err);
+        return;
+    }
+
+    jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
+
+    return;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint address, jint offset, jint count,
+        jint timeout) {
+    // LOGD("ENTER readSocketDirectImpl");
+
+    int handle;
+    jbyte *message = (jbyte *)address;
+    int result, ret, localCount;
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    result = selectWait(handle, timeout, SELECT_READ_TYPE);
+
+    if (0 > result) {
+        return 0;
+    }
+
+    localCount = (count < 65536) ? count : 65536;
+
+    do {
+        ret = recv(handle, (jbyte *) message, localCount, SOCKET_NOFLAGS);
+    } while (ret < 0 && errno == EINTR);
+
+    if (0 == ret) {
+        return -1;
+    } else if (ret == -1) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+        return 0;
+    }
+    add_recv_stats(handle, ret);
+    return ret;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jbyteArray data, jint offset, jint count,
+        jint timeout) {
+    // LOGD("ENTER readSocketImpl");
+
+    jbyte *message;
+    int result, localCount;
+
+    jbyte internalBuffer[BUFFERSIZE];
+
+    localCount = (count < 65536) ? count : 65536;
+
+    if (localCount > BUFFERSIZE) {
+        message = (jbyte*)malloc(localCount * sizeof(jbyte));
+        if (message == NULL) {
+            jniThrowException(env, "java/lang/OutOfMemoryError",
+                    "couldn't allocate enough memory for readSocket");
+            return 0;
+        }
+    } else {
+        message = (jbyte *)internalBuffer;
+    }
+
+    result = Java_org_sipdroid_net_impl_OSNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
+            (jint) message, offset, count, timeout);
+
+    if (result > 0) {
+        env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
+    }
+
+    if (((jbyte *)message) != internalBuffer) {
+        free(( jbyte *)message);
+    }
+
+    return result;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketDirectImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint address, jint offset, jint count) {
+    // LOGD("ENTER writeSocketDirectImpl");
+
+    int handle;
+    jbyte *message = (jbyte *)address;
+    int result = 0, sent = 0;
+
+    if (count <= 0) {
+        return 0;
+    }
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
+    if (result < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+
+        if (SOCKERR_WOULDBLOCK == err){
+            jclass socketExClass,errorCodeExClass;
+            jmethodID errorCodeExConstructor, socketExConstructor,socketExCauseMethod;
+            jobject errorCodeEx, socketEx;
+            const char* errorMessage = netLookupErrorString(err);
+            jstring errorMessageString = env->NewStringUTF(errorMessage);
+
+            errorCodeExClass = env->FindClass("org/apache/harmony/luni/util/ErrorCodeException");
+            if (!errorCodeExClass){
+                return 0;
+            }
+            errorCodeExConstructor = env->GetMethodID(errorCodeExClass,"<init>","(I)V");
+            if (!errorCodeExConstructor){
+                return 0;
+            }
+            errorCodeEx = env->NewObject(errorCodeExClass,errorCodeExConstructor,err);
+
+            socketExClass = env->FindClass("java/net/SocketException");
+            if (!socketExClass) {
+                return 0;
+            }
+            socketExConstructor = env->GetMethodID(socketExClass,"<init>","(Ljava/lang/String;)V");
+            if (!socketExConstructor) {
+                return 0;
+            }
+            socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString); 
+            socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
+            env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
+            env->Throw((jthrowable)socketEx);
+            return 0;
+        }
+        throwSocketException(env, err);
+        return 0;
+    }
+
+    add_send_stats(handle, result);
+    return result;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
+    // LOGD("ENTER writeSocketImpl");
+
+    jbyte *message;
+    int sent = 0;
+    jint result = 0;
+
+/* TODO: ARRAY PINNING */
+#define INTERNAL_SEND_BUFFER_MAX 512
+    jbyte internalBuffer[INTERNAL_SEND_BUFFER_MAX];
+
+    if (count > INTERNAL_SEND_BUFFER_MAX) {
+        message = (jbyte*)malloc(count * sizeof( jbyte));
+        if (message == NULL) {
+            jniThrowException(env, "java/lang/OutOfMemoryError",
+                    "couldn't allocate enough memory for writeSocket");
+            return 0;
+        }
+    } else {
+        message = (jbyte *)internalBuffer;
+    }
+
+    env->GetByteArrayRegion(data, offset, count, message);
+
+    result = Java_org_sipdroid_net_impl_OSNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
+            (jint) message, offset, count);
+
+    if (( jbyte *)message != internalBuffer) {
+      free(( jbyte *)message);
+    }
+#undef INTERNAL_SEND_BUFFER_MAX
+   return result;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jboolean nonblocking) {
+    // LOGD("ENTER setNonBlockingImpl");
+
+    int handle;
+    int result;
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    int block = nonblocking;
+
+    result = ioctl(handle, FIONBIO, &block);
+
+    if (result == -1) {
+        throwSocketException(env, convertError(errno));
+    }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port);
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectWithTimeoutSocketImpl(JNIEnv* env,
+        jclass clazz, jobject fileDescriptor, jint timeout, jint trafficClass,
+        jobject inetAddr, jint port, jint step, jbyteArray passContext) {
+    // LOGD("ENTER connectWithTimeoutSocketImpl");
+
+    int handle;
+    int result = 0;
+    struct sockaddr_in address;
+    jbyte *context = NULL;
+
+    memset(&address, 0, sizeof(address));
+
+    address.sin_family = AF_INET;
+
+    result = inetAddressToSocketAddress(env, inetAddr, port,
+            (struct sockaddr_in *) &address);
+
+    if (result < 0) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return result;
+    }
+
+    // Check if we're using adb networking and redirect in case it is used.
+    if (useAdbNetworking && !isLocalhost(&address)) {
+        return Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(env, clazz, fileDescriptor,
+                trafficClass, inetAddr, port);
+    }
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return -1;
+    }
+
+    address.sin_port = htons(port);
+
+    context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
+
+    switch (step) {
+        case SOCKET_CONNECT_STEP_START:
+            result = sockConnectWithTimeout(handle, address, 0,
+                    SOCKET_STEP_START, context);
+            break;
+        case SOCKET_CONNECT_STEP_CHECK:
+            result = sockConnectWithTimeout(handle, address, timeout,
+                    SOCKET_STEP_CHECK, context);
+            break;
+    }
+
+    env->ReleasePrimitiveArrayCritical(passContext, context, JNI_ABORT);
+
+    if (0 == result) {
+        /* connected , so stop here */
+        sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
+    } else if (result != SOCKERR_NOTCONNECTED) {
+        /* can not connect... */
+        sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, NULL);
+        if (result == SOCKERR_EACCES) {
+            jniThrowException(env, "java/lang/SecurityException",
+                              netLookupErrorString(result));
+        } else {
+            jniThrowException(env, "java/net/ConnectException",
+                              netLookupErrorString(result));
+        }
+    }
+
+    return result;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_connectStreamWithTimeoutSocketImpl(JNIEnv* env,
+        jclass clazz, jobject fileDescriptor, jint remotePort, jint timeout,
+        jint trafficClass, jobject inetAddr) {
+    // LOGD("ENTER connectStreamWithTimeoutSocketImpl");
+
+    int result = 0;
+    int handle;
+    struct sockaddr_in address;
+    jbyte *context = NULL;
+    int remainingTimeout = timeout;
+    int passedTimeout = 0;
+    int finishTime = 0;
+    int blocking = 0;
+    char hasTimeout = timeout > 0;
+
+    /* if a timeout was specified calculate the finish time value */
+    if (hasTimeout)  {
+        finishTime = time_msec_clock() + (int) timeout;
+    }
+
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    } else {
+        result = inetAddressToSocketAddress(env, inetAddr, remotePort,
+                (struct sockaddr_in *) &address);
+
+        if (result < 0) {
+            throwSocketException(env, SOCKERR_BADSOCKET);
+            return;
+        }
+
+        // Check if we're using adb networking and redirect in case it is used.
+        if (useAdbNetworking && !isLocalhost(&address)) {
+            int retVal = Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(env, clazz,
+                    fileDescriptor, trafficClass, inetAddr, remotePort);
+            if (retVal != 0) {
+                throwSocketException(env, SOCKERR_BADSOCKET);
+            }
+            return;
+        }
+
+        /*
+         * we will be looping checking for when we are connected so allocate
+         * the descriptor sets that we will use
+         */
+        context =(jbyte *) malloc(sizeof(struct selectFDSet));
+
+        if (NULL == context) {
+            throwSocketException(env, SOCKERR_NOBUFFERS);
+            return;
+        }
+
+        result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
+        if (0 == result) {
+            /* ok we connected right away so we are done */
+            sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
+            goto bail;
+        } else if (result != SOCKERR_NOTCONNECTED) {
+            log_socket_close(handle, result);
+            sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
+                                   context);
+            /* we got an error other than NOTCONNECTED so we cannot continue */
+            if (SOCKERR_EACCES == result) {
+                jniThrowException(env, "java/lang/SecurityException",
+                                  netLookupErrorString(result));
+            } else {
+                throwSocketException(env, result);
+            }
+            goto bail;
+        }
+
+        while (SOCKERR_NOTCONNECTED == result) {
+            passedTimeout = remainingTimeout;
+
+            /*
+             * ok now try and connect. Depending on the platform this may sleep
+             * for up to passedTimeout milliseconds
+             */
+            result = sockConnectWithTimeout(handle, address, passedTimeout,
+                    SOCKET_STEP_CHECK, context);
+
+            /*
+             * now check if the socket is still connected.
+             * Do it here as some platforms seem to think they
+             * are connected if the socket is closed on them.
+             */
+            handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+            if (handle == 0 || handle == -1) {
+                sockConnectWithTimeout(handle, address, 0,
+                        SOCKET_STEP_DONE, context);
+                throwSocketException(env, SOCKERR_BADSOCKET);
+                goto bail;
+            }
+
+            /*
+             * check if we are now connected,
+             * if so we can finish the process and return
+             */
+            if (0 == result) {
+                sockConnectWithTimeout(handle, address, 0,
+                        SOCKET_STEP_DONE, context);
+                goto bail;
+            }
+
+            /*
+             * if the error is SOCKERR_NOTCONNECTED then we have not yet
+             * connected and we may not be done yet
+             */
+            if (SOCKERR_NOTCONNECTED == result) {
+                /* check if the timeout has expired */
+                if (hasTimeout) {
+                    remainingTimeout = finishTime - time_msec_clock();
+                    if (remainingTimeout <= 0) {
+                        log_socket_close(handle, result);
+                        sockConnectWithTimeout(handle, address, 0,
+                                SOCKET_STEP_DONE, context);
+                        jniThrowException(env,
+                                "java/net/SocketTimeoutException",
+                                netLookupErrorString(result));
+                        goto bail;
+                     }
+                } else {
+                    remainingTimeout = 100;
+                }
+            } else {
+                log_socket_close(handle, result);
+                sockConnectWithTimeout(handle, address, remainingTimeout,
+                                       SOCKET_STEP_DONE, context);
+                if ((SOCKERR_CONNRESET == result) ||
+                    (SOCKERR_CONNECTION_REFUSED == result) ||
+                    (SOCKERR_ADDRNOTAVAIL == result) ||
+                    (SOCKERR_ADDRINUSE == result) ||
+                    (SOCKERR_ENETUNREACH == result)) {
+                    jniThrowException(env, "java/net/ConnectException",
+                                      netLookupErrorString(result));
+                } else if (SOCKERR_EACCES == result) {
+                    jniThrowException(env, "java/lang/SecurityException",
+                                      netLookupErrorString(result));
+                } else {
+                    throwSocketException(env, result);
+                }
+                goto bail;
+            }
+        }
+    }
+
+bail:
+
+    /* free the memory for the FD set */
+    if (context != NULL)  {
+        free(context);
+    }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_connectSocketImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port) {
+    //LOGD("ENTER direct-call connectSocketImpl\n");
+
+    struct sockaddr_in address;
+    int ret;
+    int handle;
+    jbyteArray java_in_addr;
+
+    memset(&address, 0, sizeof(address));
+
+    address.sin_family = AF_INET;
+
+    ret = inetAddressToSocketAddress(env, inetAddr, port,
+            (struct sockaddr_in *) &address);
+
+    if (ret < 0) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return ret;
+    }
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return -1;
+    }
+
+    address.sin_port = htons(port);
+
+    if (useAdbNetworking && !isLocalhost(&address)) {
+
+        // LOGD("+connect to address 0x%08x port %d (via adb)",
+        //         address.sin_addr.s_addr, (int) port);
+        ret = adb_networking_connect_fd(handle, &address);
+        // LOGD("-connect ret %d errno %d (via adb)", ret, errno);
+
+    } else {
+
+        // call this method with a timeout of zero
+        Java_org_sipdroid_net_impl_OSNetworkSystem_connectStreamWithTimeoutSocketImpl(env, clazz,
+                fileDescriptor, port, 0, trafficClass, inetAddr);
+        if (env->ExceptionOccurred() != 0) {
+            return -1;
+        } else {
+            return 0;
+        }
+
+    }
+
+    if (ret < 0) {
+        jniThrowException(env, "java/net/ConnectException",
+                netLookupErrorString(convertError(errno)));
+        return ret;
+    }
+
+    return ret;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_socketBindImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint port, jobject inetAddress) {
+    // LOGD("ENTER socketBindImpl");
+
+    struct sockaddr_in sockaddress;
+    int ret;
+    int handle;
+
+    ret = inetAddressToSocketAddress(env, inetAddress, port,
+            (struct sockaddr_in *) &sockaddress);
+
+    if (ret < 0) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
+
+    if (ret < 0) {
+        jniThrowException(env, "java/net/BindException",
+                netLookupErrorString(convertError(errno)));
+        return;
+    }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_listenStreamSocketImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint backlog) {
+    // LOGD("ENTER listenStreamSocketImpl");
+
+    int ret;
+    int handle;
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    ret = listen(handle, backlog);
+
+    if (ret < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+        return;
+    }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_availableStreamImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor) {
+    // LOGD("ENTER availableStreamImpl");
+
+    int handle;
+    char message[BUFFERSIZE];
+
+    int result;
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    do {
+        result = selectWait(handle, 1, SELECT_READ_TYPE);
+
+        if (SOCKERR_TIMEOUT == result) {
+            // The read operation timed out, so answer 0 bytes available
+            return 0;
+        } else if (SOCKERR_INTERRUPTED == result) {
+            continue;
+        } else if (0 > result) {
+            log_socket_close(handle, result);
+            throwSocketException(env, result);
+            return 0;
+        }
+    } while (SOCKERR_INTERRUPTED == result);
+
+    result = recv(handle, (jbyte *) message, BUFFERSIZE, MSG_PEEK);
+
+    if (0 > result) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+        return 0;
+    }
+    add_recv_stats(handle, result);
+    return result;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_acceptSocketImpl(JNIEnv* env, jclass clazz,
+        jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
+    // LOGD("ENTER acceptSocketImpl");
+
+    union {
+        struct sockaddr address;
+        struct sockaddr_in in_address;
+    } sa;
+
+    int ret;
+    int retFD;
+    int result;
+    int handle;
+    socklen_t addrlen;
+
+    if (newSocket == NULL) {
+        throwNullPointerException(env);
+        return;
+    }
+
+    result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
+
+    if (0 > result) {
+        return;
+    }
+
+    handle = jniGetFDFromFileDescriptor(env, fdServer);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    do {
+        addrlen = sizeof(sa);
+        ret = accept(handle, &(sa.address), &addrlen);
+    } while (ret < 0 && errno == EINTR);
+
+    if (ret < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+        return;
+    }
+
+    retFD = ret;
+
+    /* For AF_INET / inetOrLocal == true only: put
+     * peer address and port in instance variables
+     * We don't bother for UNIX domain sockets, since most peers are
+     * anonymous anyway
+     */
+    if (sa.address.sa_family == AF_INET) {
+        // inetOrLocal should also be true
+
+        jobject inetAddress;
+
+        inetAddress = structInToInetAddress(env, &(sa.in_address.sin_addr));
+
+        if (inetAddress == NULL) {
+            close(retFD);
+            newSocket = NULL;
+            return;
+        }
+
+        env->SetObjectField(newSocket,
+                gCachedFields.socketimpl_address, inetAddress);
+
+        env->SetIntField(newSocket, gCachedFields.socketimpl_port,
+                ntohs(sa.in_address.sin_port));
+    }
+
+    jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
+}
+
+extern "C" jboolean Java_org_sipdroid_net_impl_OSNetworkSystem_supportsUrgentDataImpl(JNIEnv* env,
+        jclass clazz, jobject fileDescriptor) {
+    // LOGD("ENTER supportsUrgentDataImpl");
+
+    int handle;
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (handle == 0 || handle == -1) {
+        return JNI_FALSE;
+    }
+
+    return JNI_TRUE;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_sendUrgentDataImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jbyte value) {
+    // LOGD("ENTER sendUrgentDataImpl");
+
+    int handle;
+    int result;
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    result = send(handle, (jbyte *) &value, 1, MSG_OOB);
+    if (result < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+    }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_connectDatagramImpl2(JNIEnv* env, jclass clazz,
+        jobject fd, jint port, jint trafficClass, jobject inetAddress) {
+    // LOGD("ENTER connectDatagramImpl2");
+
+    int handle = jniGetFDFromFileDescriptor(env, fd);
+
+    struct sockaddr_in sockAddr;
+    int ret;
+
+    ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
+
+    if (ret < 0) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+    log_socket_connect(handle, ntohl(sockAddr.sin_addr.s_addr), port);
+    int result = connect(handle, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
+    if (result < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+    }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_disconnectDatagramImpl(JNIEnv* env, jclass clazz,
+        jobject fd) {
+    // LOGD("ENTER disconnectDatagramImpl");
+
+    int handle = jniGetFDFromFileDescriptor(env, fd);
+
+    struct sockaddr_in *sockAddr;
+    socklen_t sockAddrLen = sizeof(struct sockaddr_in);
+    sockAddr = (struct sockaddr_in *) malloc(sockAddrLen);
+    memset(sockAddr, 0, sockAddrLen);
+
+    sockAddr->sin_family = AF_UNSPEC;
+    int result = connect(handle, (struct sockaddr *)sockAddr, sockAddrLen);
+    free(sockAddr);
+
+    if (result < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+    }
+}
+
+extern "C" jboolean Java_org_sipdroid_net_impl_OSNetworkSystem_socketBindImpl2(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint port, jboolean bindToDevice,
+        jobject inetAddress) {
+    // LOGD("ENTER socketBindImpl2");
+
+    struct sockaddr_in sockaddress;
+    int ret;
+    int handle;
+
+    ret = inetAddressToSocketAddress(env, inetAddress, port,
+            (struct sockaddr_in *) &sockaddress);
+
+    if (ret < 0) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
+
+    if (ret < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        jniThrowException(env, "java/net/BindException", netLookupErrorString(err));
+        return 0;
+    }
+
+    return 0;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_peekDatagramImpl(JNIEnv* env, jclass clazz,
+        jobject fd, jobject sender, jint receiveTimeout) {
+    // LOGD("ENTER peekDatagramImpl");
+
+    int port = -1;
+
+    int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+    if (0> result) {
+        return (jint) 0;
+    }
+
+    int handle = jniGetFDFromFileDescriptor(env, fd);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    struct sockaddr_in sockAddr;
+    socklen_t sockAddrLen = sizeof(sockAddr);
+
+    int length = recvfrom(handle, NULL, 0, MSG_PEEK,
+            (struct sockaddr *)&sockAddr, &sockAddrLen);
+
+    if (length < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+        return 0;
+    }
+
+    if (socketAddressToInetAddress(env, &sockAddr, sender, &port) < 0) {
+        throwIOExceptionStr(env, "Address conversion failed");
+        return -1;
+    }
+    add_recv_stats(handle, length);
+    return port;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramDirectImpl(JNIEnv* env, jclass clazz,
+        jobject fd, jobject packet, jint address, jint offset, jint length,
+        jint receiveTimeout, jboolean peek) {
+    // LOGD("ENTER receiveDatagramDirectImpl");
+
+    int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+    if (0 > result) {
+        return (jint) 0;
+    }
+
+    int handle = jniGetFDFromFileDescriptor(env, fd);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    struct sockaddr_in sockAddr;
+    socklen_t sockAddrLen = sizeof(sockAddr);
+
+    int mode = peek ? MSG_PEEK : 0;
+
+    int actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
+            (struct sockaddr *)&sockAddr, &sockAddrLen);
+
+    if (actualLength < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+        return 0;
+    }
+
+    if (packet != NULL) {
+        int port = ntohs(sockAddr.sin_port);
+        jobject sender = env->GetObjectField(packet, gCachedFields.dpack_address);
+       	//__android_log_print(ANDROID_LOG_INFO,"OSNetwork","Sender address  %x ", sender); 
+	if (sender != 0) {
+		jbyteArray addr = (jbyteArray)env->GetObjectField(sender, gCachedFields.iaddr_ipaddress);
+		//__android_log_print(ANDROID_LOG_INFO,"OSNetwork","Sender Recup"); 
+		if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
+			jniThrowException(env, "java/net/SocketException",
+					"Could not set address of packet.");
+			return 0;
+		}
+	}
+	else {
+		jbyteArray addr = env->NewByteArray(sizeof(struct in_addr));
+		if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
+			jniThrowException(env, "java/net/SocketException",
+					"Could not set address of packet.");
+			return 0;
+		}
+		sender = env->CallStaticObjectMethod(
+		  gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
+		  addr);
+
+	}
+        env->SetObjectField(packet, gCachedFields.dpack_address, sender);
+        env->SetIntField(packet, gCachedFields.dpack_port, port);
+        env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
+    }
+    add_recv_stats(handle, actualLength);
+    return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
+        jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
+        jint receiveTimeout, jboolean peek) {
+    // LOGD("ENTER receiveDatagramImpl");
+
+    int localLength = (length < 65536) ? length : 65536;
+    jbyte *bytes = (jbyte*) malloc(localLength);
+    if (bytes == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError",
+                "couldn't allocate enough memory for receiveDatagram");
+        return 0;
+    }
+
+    int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
+            packet, (jint)bytes, offset, localLength, receiveTimeout, peek);
+
+    if (actualLength > 0) {
+        env->SetByteArrayRegion(data, offset, actualLength, bytes);
+    }
+    free(bytes);
+
+    return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramDirectImpl(JNIEnv* env,
+        jclass clazz, jobject fd, jobject packet, jint address, jint offset,
+        jint length, jint receiveTimeout, jboolean peek) {
+    // LOGD("ENTER receiveConnectedDatagramDirectImpl");
+
+    int result = pollSelectWait (env, fd, receiveTimeout, SELECT_READ_TYPE);
+
+    if (0 > result) {
+        return 0;
+    }
+
+    int handle = jniGetFDFromFileDescriptor(env, fd);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    int mode = peek ? MSG_PEEK : 0;
+
+    int actualLength = recvfrom(handle,
+            (char*)(address + offset), length, mode, NULL, NULL);
+
+    if (actualLength < 0) {
+        jniThrowException(env, "java/net/PortUnreachableException", "");
+        return 0;
+    }
+
+    if ( packet != NULL) {
+        env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
+    }
+    add_recv_stats(handle, actualLength);
+    return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramImpl(JNIEnv* env, jclass clazz,
+        jobject fd, jobject packet, jbyteArray data, jint offset, jint length,
+        jint receiveTimeout, jboolean peek) {
+    // LOGD("ENTER receiveConnectedDatagramImpl");
+
+    int localLength = (length < 65536) ? length : 65536;
+    jbyte *bytes = (jbyte*) malloc(localLength);
+    if (bytes == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError",
+                "couldn't allocate enough memory for recvConnectedDatagram");
+        return 0;
+    }
+
+    int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_recvConnectedDatagramDirectImpl(env,
+            clazz, fd, packet, (jint)bytes, offset, localLength,
+            receiveTimeout, peek);
+
+    if (actualLength > 0) {
+        env->SetByteArrayRegion(data, offset, actualLength, bytes);
+    }
+    free(bytes);
+
+    return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramDirectImpl(JNIEnv* env, jclass clazz,
+        jobject fd, jint address, jint offset, jint length, jint port,
+        jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
+    // LOGD("ENTER sendDatagramDirectImpl");
+
+    int result = 0;
+
+    int handle = jniGetFDFromFileDescriptor(env, fd);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    struct sockaddr_in receiver;
+
+    if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    result = sendto(handle, (char*)(address + offset), length, SOCKET_NOFLAGS,
+            (struct sockaddr*)&receiver, sizeof(receiver));
+
+    if (result < 0) {
+        int err = convertError(errno);
+        if ((SOCKERR_CONNRESET == err)
+                || (SOCKERR_CONNECTION_REFUSED == err)) {
+            return 0;
+        } else {
+            log_socket_close(handle, err);
+            throwSocketException(env, err);
+            return 0;
+        }
+    }
+    add_send_stats(handle, result);
+    return result;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
+        jobject fd, jbyteArray data, jint offset, jint length, jint port,
+        jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
+    // LOGD("ENTER sendDatagramImpl");
+
+    jbyte *bytes = env->GetByteArrayElements(data, NULL);
+    int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramDirectImpl(env, clazz, fd,
+            (jint)bytes, offset, length, port, bindToDevice, trafficClass,
+            inetAddress);
+    env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
+
+    return actualLength;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramDirectImpl(JNIEnv* env,
+        jclass clazz, jobject fd, jint address, jint offset, jint length,
+        jboolean bindToDevice) {
+    // LOGD("ENTER sendConnectedDatagramDirectImpl");
+
+    int handle = jniGetFDFromFileDescriptor(env, fd);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    int result = send(handle, (char*)(address + offset), length, 0);
+
+    if (result < 0) {
+        int err = convertError(errno);
+        if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
+            return 0;
+        } else {
+            log_socket_close(handle, err);
+            throwSocketException(env, err);
+            return 0;
+        }
+    }
+    add_send_stats(handle, length);
+    return result;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramImpl(JNIEnv* env, jclass clazz,
+        jobject fd, jbyteArray data, jint offset, jint length,
+        jboolean bindToDevice) {
+    // LOGD("ENTER sendConnectedDatagramImpl");
+
+    jbyte *bytes = env->GetByteArrayElements(data, NULL);
+    int actualLength = Java_org_sipdroid_net_impl_OSNetworkSystem_sendConnectedDatagramDirectImpl(env,
+            clazz, fd, (jint)bytes, offset, length, bindToDevice);
+    env->ReleaseByteArrayElements(data, bytes, JNI_ABORT);
+
+    return actualLength;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createServerStreamSocketImpl(JNIEnv* env,
+        jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
+    // LOGD("ENTER createServerStreamSocketImpl");
+
+    if (fileDescriptor == NULL) {
+        throwNullPointerException(env);
+        return;
+    }
+
+    int handle = socket(PF_INET, SOCK_STREAM, 0);
+
+    if (handle < 0) {
+        int err = convertError(errno);
+        throwSocketException(env, err);
+        return;
+    }
+
+    jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
+
+    int value = 1;
+
+    setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_createMulticastSocketImpl(JNIEnv* env,
+        jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
+    // LOGD("ENTER createMulticastSocketImpl");
+
+    int handle = socket(PF_INET, SOCK_DGRAM, 0);
+
+    if (handle < 0) {
+        int err = convertError(errno);
+        throwSocketException(env, err);
+        return;
+    }
+
+    jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
+
+    int value = 1;
+
+    // setsockopt(handle, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(jbyte));
+    setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
+}
+
+/*
+ * @param timeout in milliseconds.  If zero, block until data received
+ */
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_receiveStreamImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jbyteArray data, jint offset, jint count,
+        jint timeout) {
+    // LOGD("ENTER receiveStreamImpl");
+
+    int result;
+    int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return 0;
+    }
+
+    // Cap read length to available buf size
+    int spaceAvailable = env->GetArrayLength(data) - offset;
+    int localCount = count < spaceAvailable? count : spaceAvailable;
+
+    jboolean isCopy;
+    jbyte *body = env->GetByteArrayElements(data, &isCopy);
+
+    // set timeout
+    struct timeval tv;
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+    setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)&tv,
+               sizeof(struct timeval));
+
+    do {
+        result = recv(handle, body + offset, localCount, SOCKET_NOFLAGS);
+    } while (result < 0 && errno == EINTR);
+
+    env->ReleaseByteArrayElements(data, body, 0);
+
+    /*
+     * If no bytes are read, return -1 to signal 'endOfFile'
+     * to the Java input stream
+     */
+    if (0 < result) {
+        add_recv_stats(handle, result);
+        return result;
+    } else if (0 == result) {
+        return -1;
+    } else {
+        // If EAGAIN or EWOULDBLOCK, read timed out
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+            jniThrowException(env, "java/net/SocketTimeoutException",
+                              netLookupErrorString(SOCKERR_TIMEOUT));
+        } else {
+            int err = convertError(errno);
+            log_socket_close(handle, err);
+            throwSocketException(env, err);
+        }
+        return 0;
+    }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendStreamImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jbyteArray data, jint offset, jint count) {
+    // LOGD("ENTER sendStreamImpl");
+
+    int handle = 0;
+    int result = 0, sent = 0;
+
+    jboolean isCopy;
+    jbyte *message = env->GetByteArrayElements(data, &isCopy);
+
+    // Cap write length to available buf size
+    int spaceAvailable = env->GetArrayLength(data) - offset;
+    if (count > spaceAvailable) count = spaceAvailable;
+
+    while (sent < count) {
+
+        handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+        if (handle == 0 || handle == -1) {
+            throwSocketException(env,
+                    sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
+            env->ReleaseByteArrayElements(data, message, 0);
+            return 0;
+        }
+
+        // LOGD("before select %d", count);
+        selectWait(handle, SEND_RETRY_TIME, SELECT_WRITE_TYPE);
+        result = send(handle, (jbyte *)message + offset + sent,
+                (int) count - sent, SOCKET_NOFLAGS);
+
+        if (result < 0) {
+            result = errno;
+            if (result == EAGAIN ||result == EWOULDBLOCK) {
+                // LOGD("write blocked %d", sent);
+                continue;
+            }
+            env->ReleaseByteArrayElements(data, message, 0);
+            int err = convertError(result);
+            log_socket_close(handle, err);
+            throwSocketException(env, err);
+            return 0;
+        }
+        sent += result;
+    }
+
+    env->ReleaseByteArrayElements(data, message, 0);
+    add_send_stats(handle, sent);
+    return sent;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_shutdownInputImpl(JNIEnv* env, jobject obj,
+        jobject fileDescriptor) {
+    // LOGD("ENTER shutdownInputImpl");
+
+    int ret;
+    int handle;
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    ret = shutdown(handle, SHUT_RD);
+
+    if (ret < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+        return;
+    }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_shutdownOutputImpl(JNIEnv* env, jobject obj,
+        jobject fileDescriptor) {
+    // LOGD("ENTER shutdownOutputImpl");
+
+    int ret;
+    int handle;
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        return;
+    }
+
+    ret = shutdown(handle, SHUT_WR);
+
+    if (ret < 0) {
+        int err = convertError(errno);
+        log_socket_close(handle, err);
+        throwSocketException(env, err);
+        return;
+    }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_sendDatagramImpl2(JNIEnv* env, jclass clazz,
+        jobject fd, jbyteArray data, jint offset, jint length, jint port,
+        jobject inetAddress) {
+    // LOGD("ENTER sendDatagramImpl2");
+
+    jbyte *message;
+    jbyte nhostAddrBytes[4];
+    unsigned short nPort;
+    int result = 0, sent = 0;
+    int handle = 0;
+    struct sockaddr_in sockaddrP;
+
+    if (inetAddress != NULL) {
+
+        result = inetAddressToSocketAddress(env, inetAddress, port,
+                (struct sockaddr_in *) &sockaddrP);
+
+        if (result < 0) {
+            throwSocketException(env, SOCKERR_BADSOCKET);
+            return 0;
+        }
+
+        handle = jniGetFDFromFileDescriptor(env, fd);
+
+        if (handle == 0 || handle == -1) {
+            throwSocketException(env, SOCKERR_BADSOCKET);
+            return 0;
+        }
+    }
+
+    message = (jbyte*) malloc(length * sizeof(jbyte));
+    if (message == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError",
+                "couldn't allocate enough memory for readSocket");
+        return 0;
+    }
+
+    env->GetByteArrayRegion(data, offset, length, message);
+
+    while (sent < length) {
+        handle = jniGetFDFromFileDescriptor(env, fd);
+
+        if (handle == 0 || handle == -1) {
+            throwSocketException(env,
+                    sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
+            free(message);
+            return 0;
+        }
+
+        result = sendto(handle, (char *) (message + sent),
+                (int) (length - sent), SOCKET_NOFLAGS,
+                (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
+
+        if (result < 0) {
+            int err = convertError(errno);
+            log_socket_close(handle, err);
+            throwSocketException(env, err);
+            free(message);
+            return 0;
+        }
+
+        sent += result;
+    }
+
+    free(message);
+    add_send_stats(handle, sent);
+    return sent;
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_selectImpl(JNIEnv* env, jclass clazz,
+        jobjectArray readFDArray, jobjectArray writeFDArray, jint countReadC,
+        jint countWriteC, jintArray outFlags, jlong timeout) {
+    // LOGD("ENTER selectImpl");
+
+    struct timeval timeP;
+    int result = 0;
+    int size = 0;
+    jobject gotFD;
+    fd_set *fdset_read,*fdset_write;
+    int handle;
+    jboolean isCopy ;
+    jint *flagArray;
+    int val;
+    unsigned int time_sec = (unsigned int)timeout/1000;
+    unsigned int time_msec = (unsigned int)(timeout%1000);
+
+    fdset_read = (fd_set *)malloc(sizeof(fd_set));
+    fdset_write = (fd_set *)malloc(sizeof(fd_set));
+
+    FD_ZERO(fdset_read);
+    FD_ZERO(fdset_write);
+
+    for (val = 0; val<countReadC; val++) {
+
+        gotFD = env->GetObjectArrayElement(readFDArray,val);
+
+        handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+        FD_SET(handle, fdset_read);
+
+        if (0 > (size - handle)) {
+            size = handle;
+        }
+    }
+
+    for (val = 0; val<countWriteC; val++) {
+
+        gotFD = env->GetObjectArrayElement(writeFDArray,val);
+
+        handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+        FD_SET(handle, fdset_write);
+
+        if (0 > (size - handle)) {
+            size = handle;
+        }
+    }
+
+    /* the size is the max_fd + 1 */
+    size =size + 1;
+
+    if (0 > size) {
+        result = SOCKERR_FDSET_SIZEBAD;
+    } else {
+      /* only set when timeout >= 0 (non-block)*/
+        if (0 <= timeout) {
+
+            timeP.tv_sec = time_sec;
+            timeP.tv_usec = time_msec*1000;
+
+            result = sockSelect(size, fdset_read, fdset_write, NULL, &timeP);
+
+        } else {
+            result = sockSelect(size, fdset_read, fdset_write, NULL, NULL);
+        }
+    }
+
+    if (0 < result) {
+       /*output the result to a int array*/
+       flagArray = env->GetIntArrayElements(outFlags, &isCopy);
+
+       for (val=0; val<countReadC; val++) {
+            gotFD = env->GetObjectArrayElement(readFDArray,val);
+
+            handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+            if (FD_ISSET(handle,fdset_read)) {
+                flagArray[val] = SOCKET_OP_READ;
+            } else {
+                flagArray[val] = SOCKET_OP_NONE;
+            }
+        }
+
+        for (val=0; val<countWriteC; val++) {
+
+            gotFD = env->GetObjectArrayElement(writeFDArray,val);
+
+            handle = jniGetFDFromFileDescriptor(env, gotFD);
+
+            if (FD_ISSET(handle,fdset_write)) {
+                flagArray[val+countReadC] = SOCKET_OP_WRITE;
+            } else {
+                flagArray[val+countReadC] = SOCKET_OP_NONE;
+            }
+        }
+
+        env->ReleaseIntArrayElements(outFlags, flagArray, 0);
+    }
+
+    free(fdset_write);
+    free(fdset_read);
+
+    /* return both correct and error result, let java handle the exception*/
+    return result;
+}
+
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketLocalAddressImpl(JNIEnv* env,
+        jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
+    // LOGD("ENTER getSocketLocalAddressImpl");
+
+    struct sockaddr_in addr;
+    socklen_t addrLen = sizeof(addr);
+
+    memset(&addr, 0, addrLen);
+
+    int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    int result;
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
+        return NULL;
+    }
+
+    result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
+
+    // Spec says ignore all errors
+
+    return structInToInetAddress(env, &(addr.sin_addr));
+
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jboolean preferIPv6Addresses) {
+    // LOGD("ENTER getSocketLocalPortImpl");
+
+    struct sockaddr_in addr;
+    socklen_t addrLen = sizeof(addr);
+
+    int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    int result;
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
+        return 0;
+    }
+
+    result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
+
+    if (0 != result) {
+        // The java spec does not indicate any exceptions on this call
+        return 0;
+    } else {
+        return ntohs(addr.sin_port);
+    }
+}
+
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketOptionImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint anOption) {
+    // LOGD("ENTER getSocketOptionImpl");
+
+    int handle;
+    int intValue = 0;
+    socklen_t intSize = sizeof(int);
+    unsigned char byteValue = 0;
+    socklen_t byteSize = sizeof(unsigned char);
+    int result;
+    struct sockaddr_in sockVal;
+    socklen_t sockSize = sizeof(sockVal);
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return NULL;
+    }
+
+    switch ((int) anOption & 0xffff) {
+        case JAVASOCKOPT_SO_LINGER: {
+            struct linger lingr;
+            socklen_t size = sizeof(struct linger);
+            result = getsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr, &size);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            if (!lingr.l_onoff) {
+                intValue = -1;
+            } else {
+                intValue = lingr.l_linger;
+            }
+            return newJavaLangInteger(env, intValue);
+        }
+        case JAVASOCKOPT_TCP_NODELAY: {
+            if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
+                return NULL;
+            }
+            result = getsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangBoolean(env, intValue);
+        }
+        case JAVASOCKOPT_MCAST_TTL: {
+            if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
+                return newJavaLangByte(env, 0);
+            }
+            result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteValue, &byteSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangByte(env, (jbyte)(byteValue & 0xFF));
+        }
+        case JAVASOCKOPT_MCAST_INTERFACE: {
+            if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+                return NULL;
+            }
+            result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, &sockSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return structInToInetAddress(env, &(sockVal.sin_addr));
+        }
+        case JAVASOCKOPT_SO_SNDBUF: {
+            result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangInteger(env, intValue);
+        }
+        case JAVASOCKOPT_SO_RCVBUF: {
+            result = getsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangInteger(env, intValue);
+        }
+        case JAVASOCKOPT_SO_BROADCAST: {
+            result = getsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangBoolean(env, intValue);
+        }
+        case JAVASOCKOPT_SO_REUSEADDR: {
+            result = getsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangBoolean(env, intValue);
+        }
+        case JAVASOCKOPT_SO_KEEPALIVE: {
+            result = getsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangBoolean(env, intValue);
+        }
+        case JAVASOCKOPT_SO_OOBINLINE: {
+            result = getsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangBoolean(env, intValue);
+        }
+        case JAVASOCKOPT_IP_MULTICAST_LOOP: {
+            result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangBoolean(env, intValue);
+        }
+        case JAVASOCKOPT_IP_TOS: {
+            result = getsockopt(handle, IPPROTO_IP, IP_TOS, &intValue, &intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangInteger(env, intValue);
+        }
+        case JAVASOCKOPT_SO_RCVTIMEOUT: {
+            struct timeval timeout;
+            socklen_t size = sizeof(timeout);
+            result = getsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout, &size);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return NULL;
+            }
+            return newJavaLangInteger(env, timeout.tv_sec * 1000 + timeout.tv_usec/1000);
+        }
+        default: {
+            throwSocketException(env, SOCKERR_OPTUNSUPP);
+            return NULL;
+        }
+    }
+
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setSocketOptionImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor, jint anOption, jobject optVal) {
+    // LOGD("ENTER setSocketOptionImpl");
+
+    int handle, result;
+    int intVal, intSize = sizeof(int);
+    unsigned char byteVal, byteSize = sizeof(unsigned char);
+    struct sockaddr_in sockVal;
+    int sockSize = sizeof(sockVal);
+
+    if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
+        intVal = (int) env->GetIntField(optVal, gCachedFields.integer_class_value);
+    } else if (env->IsInstanceOf(optVal, gCachedFields.boolean_class)) {
+        intVal = (int) env->GetBooleanField(optVal, gCachedFields.boolean_class_value);
+    } else if (env->IsInstanceOf(optVal, gCachedFields.byte_class)) {
+        byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
+    } else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
+        if (inetAddressToSocketAddress(env, optVal, 0, &sockVal) < 0) {
+            throwSocketException(env, SOCKERR_BADSOCKET);
+            return;
+        }
+    } else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
+        // we'll use optVal directly
+    } else {
+        throwSocketException(env, SOCKERR_OPTUNSUPP);
+        return;
+    }
+
+    handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    switch ((int) anOption & 0xffff) {
+        case JAVASOCKOPT_SO_LINGER: {
+            struct linger lingr;
+            lingr.l_onoff = intVal > 0 ? 1 : 0;
+            lingr.l_linger = intVal;
+            result = setsockopt(handle, SOL_SOCKET, SO_LINGER, &lingr,
+                    sizeof(struct linger));
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_TCP_NODELAY: {
+            if ((anOption >> 16) & BROKEN_TCP_NODELAY) {
+                return;
+            }
+            result = setsockopt(handle, IPPROTO_TCP, TCP_NODELAY, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+      case JAVASOCKOPT_MCAST_TTL: {
+            if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
+                return;
+            }
+            result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteVal, byteSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
+            mcastAddDropMembership(env, handle, optVal,
+                    (anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
+            return;
+        }
+
+        case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
+            mcastAddDropMembership(env, handle, optVal,
+                    (anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
+            return;
+        }
+
+        case JAVASOCKOPT_MCAST_INTERFACE: {
+            if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+                return;
+            }
+            result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockVal, sockSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_SO_SNDBUF: {
+            result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_SO_RCVBUF: {
+            result = setsockopt(handle, SOL_SOCKET, SO_RCVBUF, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_SO_BROADCAST: {
+            result = setsockopt(handle, SOL_SOCKET, SO_BROADCAST, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_SO_REUSEADDR: {
+            result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+        case JAVASOCKOPT_SO_KEEPALIVE: {
+            result = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_SO_OOBINLINE: {
+            result = setsockopt(handle, SOL_SOCKET, SO_OOBINLINE, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_IP_MULTICAST_LOOP: {
+            result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_IP_TOS: {
+            result = setsockopt(handle, IPPROTO_IP, IP_TOS, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_REUSEADDR_AND_REUSEPORT: {
+            // SO_REUSEPORT doesn't need to get set on this System
+            result = setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &intVal, intSize);
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        case JAVASOCKOPT_SO_RCVTIMEOUT: {
+            struct timeval timeout;
+            timeout.tv_sec = intVal / 1000;
+            timeout.tv_usec = (intVal % 1000) * 1000;
+            result = setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, &timeout,
+                    sizeof(struct timeval));
+            if (0 != result) {
+                throwSocketException(env, convertError(errno));
+                return;
+            }
+            break;
+        }
+
+        default: {
+            throwSocketException(env, SOCKERR_OPTUNSUPP);
+        }
+    }
+}
+
+extern "C" jint Java_org_sipdroid_net_impl_OSNetworkSystem_getSocketFlagsImpl(JNIEnv* env, jclass clazz) {
+    // LOGD("ENTER getSocketFlagsImpl");
+
+    // Not implemented by harmony
+    return 0;
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz,
+        jobject fileDescriptor) {
+    // LOGD("ENTER socketCloseImpl");
+
+    int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+    if (handle == 0 || handle == -1) {
+        throwSocketException(env, SOCKERR_BADSOCKET);
+        return;
+    }
+
+    log_socket_close(handle, SOCKET_CLOSE_LOCAL);
+
+    jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
+
+    close(handle);
+}
+
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz,
+        jbyteArray addrStr) {
+    // LOGD("ENTER getHostByAddrImpl");
+
+    if (addrStr == NULL) {
+        throwNullPointerException(env);
+        return JNI_FALSE;
+    }
+
+    jstring address = (jstring)newJavaLangString(env, addrStr);
+    jstring result;
+    const char* addr = env->GetStringUTFChars(address, NULL);
+
+    struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET);
+
+    if (ent != NULL  && ent->h_name != NULL) {
+        result = env->NewStringUTF(ent->h_name);
+    } else {
+        result = NULL;
+    }
+
+    env->ReleaseStringUTFChars(address, addr);
+
+    return result;
+}
+
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz,
+        jstring nameStr, jboolean preferIPv6Addresses) {
+    // LOGD("ENTER getHostByNameImpl");
+
+    if (nameStr == NULL) {
+        throwNullPointerException(env);
+        return NULL;
+    }
+
+    const char* name = env->GetStringUTFChars(nameStr, NULL);
+
+    if (useAdbNetworking) {
+
+        union {
+            struct in_addr a;
+            jbyte j[4];
+        } outaddr;
+
+        // LOGD("ADB networking: +gethostbyname '%s'", name);
+        int err;
+        err = adb_networking_gethostbyname(name, &(outaddr.a));
+
+        env->ReleaseStringUTFChars(nameStr, name);
+#if 0
+        LOGD("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u",
+                err, (unsigned int)outaddr.a.s_addr,
+                outaddr.j[0],outaddr.j[1],
+                outaddr.j[2],outaddr.j[3]);
+#endif
+
+        if (err < 0) {
+            return NULL;
+        } else {
+            jbyteArray addr = env->NewByteArray(4);
+            env->SetByteArrayRegion(addr, 0, 4, outaddr.j);
+            return addr;
+        }
+    } else {
+
+        // normal case...no adb networking
+        struct hostent* ent = gethostbyname(name);
+
+        env->ReleaseStringUTFChars(nameStr, name);
+
+        if (ent != NULL  && ent->h_length > 0) {
+            jbyteArray addr = env->NewByteArray(4);
+            jbyte v[4];
+            memcpy(v, ent->h_addr, 4);
+            env->SetByteArrayRegion(addr, 0, 4, v);
+            return addr;
+        } else {
+            return NULL;
+        }
+    }
+}
+
+extern "C" void Java_org_sipdroid_net_impl_OSNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj,
+        jobject sender, jbyteArray address) {
+    // LOGD("ENTER setInetAddressImpl");
+
+    env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
+}
+
+/*
+extern "C" jobject Java_org_sipdroid_net_impl_OSNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
+    // LOGD("ENTER inheritedChannelImpl");
+
+    int socket = 0;
+    int opt;
+    socklen_t length = sizeof(opt);
+    int socket_type;
+    struct sockaddr_in local_addr;
+    struct sockaddr_in remote_addr;
+    jclass channel_class, socketaddr_class, serverSocket_class, socketImpl_class;
+    jobject channel_object = NULL, socketaddr_object, serverSocket_object;
+    jobject fd_object, addr_object, localAddr_object, socketImpl_object;
+    jfieldID port_field, socketaddr_field, bound_field, fd_field;
+    jfieldID serverSocket_field, socketImpl_field, addr_field, localAddr_field;
+    jmethodID channel_new;
+    jbyteArray addr_array;
+    struct sockaddr_in *sock;
+    jbyte * address;
+    jbyte * localAddr;
+    jboolean jtrue = JNI_TRUE;
+
+    if (0 != getsockopt(socket, SOL_SOCKET, SO_TYPE, &opt, &length)) {
+        return NULL;
+    }
+    if (SOCK_STREAM !=opt && SOCK_DGRAM !=opt) {
+        return NULL;
+    }
+    socket_type = opt;
+
+    length  = sizeof(struct sockaddr);
+    if (0 != getsockname(socket, (struct sockaddr *)&local_addr, &length)) {
+        return NULL;
+    } else {
+        if (AF_INET != local_addr.sin_family || length != sizeof(struct sockaddr)) {
+            return NULL;
+        }
+        localAddr = (jbyte*) malloc(sizeof(jbyte)*4);
+        if (NULL == localAddr) {
+            return NULL;
+        }
+        memcpy (localAddr, &(local_addr.sin_addr.s_addr), 4);
+    }
+    if (0 != getpeername(socket, (struct sockaddr *)&remote_addr, &length)) {
+        remote_addr.sin_port = 0;
+        remote_addr.sin_addr.s_addr = 0;
+        address = (jbyte*) malloc(sizeof(jbyte)*4);
+        bzero(address, sizeof(jbyte)*4);
+    } else {
+        if (AF_INET != remote_addr.sin_family
+                || length != sizeof(struct sockaddr)) {
+            return NULL;
+        }
+        address = (jbyte*) malloc(sizeof(jbyte)*4);
+        memcpy (address, &(remote_addr.sin_addr.s_addr), 4);
+    }
+
+    // analysis end, begin pack to java
+    if (SOCK_STREAM == opt) {
+        if (remote_addr.sin_port!=0) {
+            //socket
+            channel_class = env->FindClass(
+                    "org/apache/harmony/nio/internal/SocketChannelImpl");
+            if (NULL == channel_class) {
+                goto clean;
+            }
+
+            channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+            if (NULL == channel_new) {
+                goto clean;
+            }
+            channel_object = env->NewObject(channel_class, channel_new);
+            if (NULL == channel_object) {
+                goto clean;
+            }
+            // new and set FileDescript
+
+            fd_field = env->GetFieldID(channel_class, "fd",
+                    "java/io/FielDescriptor");
+            fd_object = env->GetObjectField(channel_object, fd_field);
+            if (NULL == fd_object) {
+                goto clean;
+            }
+
+            jniSetFileDescriptorOfFD(env, fd_object, socket);
+
+            // local port
+            port_field = env->GetFieldID(channel_class, "localPort", "I");
+            env->SetIntField(channel_object, port_field,
+                    ntohs(local_addr.sin_port));
+
+            // new and set remote addr
+            addr_object = env->NewObject(gCachedFields.iaddr_class,
+                    gCachedFields.iaddr_class_init);
+            if (NULL == addr_object) {
+                goto clean;
+            }
+            socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+            socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+                    "Ljava/net/InetSocketAddress;");
+            socketaddr_object = env->GetObjectField(channel_object,
+                    socketaddr_field);
+            if (NULL == socketaddr_object) {
+                goto clean;
+            }
+            addr_field = env->GetFieldID(socketaddr_class, "addr",
+                    "Ljava/net/InetAddress;");
+            env->SetObjectField(socketaddr_object, addr_field, addr_object);
+            addr_array = env->NewByteArray((jsize)4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+            env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress,
+                     addr_array);
+
+            // localAddr
+            socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+            socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+                     "Ljava/net/InetSocketAddress;");
+            socketaddr_object = env->GetObjectField(channel_object,
+                     socketaddr_field);
+
+            localAddr_field = env->GetFieldID(channel_class, "localAddress",
+                     "Ljava/net/InetAddress;");
+            localAddr_object = env->NewObject(gCachedFields.iaddr_class,
+                     gCachedFields.iaddr_class_init);
+            jfieldID socketaddr_field = env->GetFieldID(channel_class,
+                     "connectAddress", "Ljava/net/InetSocketAddress;");
+            jobject socketaddr_object = env->GetObjectField(channel_object,
+                     socketaddr_field);
+            env->SetObjectField(socketaddr_object, localAddr_field,
+                     localAddr_object);
+            if (NULL == localAddr_object) {
+                goto clean;
+            }
+            addr_array = env->NewByteArray((jsize)4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
+            env->SetObjectField(localAddr_object, gCachedFields.iaddr_ipaddress,
+                    addr_array);
+
+
+            // set port
+            port_field = env->GetFieldID(socketaddr_class, "port", "I");
+            env->SetIntField(socketaddr_object, port_field,
+                    ntohs(remote_addr.sin_port));
+
+            // set bound
+            if (0 != local_addr.sin_port) {
+                bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+                env->SetBooleanField(channel_object, bound_field, jtrue);
+            }
+
+        } else {
+            //serverSocket
+            channel_class = env->FindClass(
+                    "org/apache/harmony/nio/internal/ServerSocketChannelImpl");
+            if (NULL == channel_class) {
+                goto clean;
+            }
+
+            channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+            if (NULL == channel_new) {
+                goto clean;
+            }
+            channel_object = env->NewObject(channel_class, channel_new);
+            if (NULL == channel_object) {
+                goto clean;
+            }
+
+            serverSocket_field = env->GetFieldID(channel_class, "socket",
+                    "Ljava/net/ServerSocket;");
+            serverSocket_class = env->FindClass("Ljava/net/ServerSocket;");
+            serverSocket_object = env->GetObjectField(channel_object,
+                    serverSocket_field);
+            // set bound
+            if (0 != local_addr.sin_port) {
+                bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+                env->SetBooleanField(channel_object, bound_field, jtrue);
+                bound_field = env->GetFieldID(serverSocket_class, "isBound", "Z");
+                env->SetBooleanField(serverSocket_object, bound_field, jtrue);
+            }
+            // localAddr
+            socketImpl_class = env->FindClass("java/net/SocketImpl");
+            socketImpl_field = env->GetFieldID(channel_class, "impl",
+                    "Ljava/net/SocketImpl;");
+            socketImpl_object =  env->GetObjectField(channel_object,
+                    socketImpl_field);
+            if (NULL == socketImpl_object) {
+                 goto clean;
+            }
+
+            localAddr_field = env->GetFieldID(channel_class, "localAddress",
+                    "Ljava/net/InetAddress;");
+            localAddr_object = env->NewObject(gCachedFields.iaddr_class,
+                    gCachedFields.iaddr_class_init);
+            if (NULL == localAddr_object) {
+                 goto clean;
+            }
+            env->SetObjectField(socketImpl_object, localAddr_field,
+                    localAddr_object);
+            addr_array = env->NewByteArray((jsize)4);
+            env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr);
+            env->SetObjectField(localAddr_object,
+                    gCachedFields.iaddr_ipaddress, addr_array);
+
+            // set port
+            port_field = env->GetFieldID(socketImpl_class, "localport", "I");
+            env->SetIntField(socketImpl_object, port_field,
+                    ntohs(local_addr.sin_port));
+        }
+    } else {
+        //Datagram Socket
+        // new DatagramChannel
+        channel_class = env->FindClass(
+                "org/apache/harmony/nio/internal/DatagramChannelImpl");
+        if (NULL == channel_class) {
+            goto clean;
+        }
+
+        channel_new = env->GetMethodID(channel_class, "<init>", "()V");
+        if (NULL == channel_new) {
+            goto clean;
+        }
+        channel_object = env->NewObject(channel_class, channel_new);
+        if (NULL == channel_object) {
+            goto clean;
+        }
+
+        // new and set FileDescript
+        fd_field = env->GetFieldID(channel_class, "fd", "java/io/FileDescriptor");
+        fd_object = env->GetObjectField(channel_object, fd_field);
+        if (NULL == fd_object) {
+            goto clean;
+        }
+
+        jniSetFileDescriptorOfFD(env, fd_object, socket);
+
+        port_field = env->GetFieldID(channel_class, "localPort", "I");
+        env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port));
+
+        // new and set remote addr
+        addr_object = env->NewObject(gCachedFields.iaddr_class,
+                gCachedFields.iaddr_class_init);
+        if (NULL == addr_object) {
+            goto clean;
+        }
+        socketaddr_class = env->FindClass("java/net/InetSocketAddress");
+        socketaddr_field = env->GetFieldID(channel_class, "connectAddress",
+                "Ljava/net/InetSocketAddress;");
+        socketaddr_object = env->GetObjectField(channel_object, socketaddr_field);
+        if (NULL == socketaddr_object) {
+            goto clean;
+        }
+        addr_field = env->GetFieldID(socketaddr_class, "addr",
+                "Ljava/net/InetAddress;");
+        env->SetObjectField(socketaddr_object, addr_field, addr_object);
+        addr_array = env->NewByteArray((jsize)4);
+        env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address);
+        env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress, addr_array);
+
+        // set bound
+        if (0 != local_addr.sin_port) {
+            bound_field = env->GetFieldID(channel_class, "isBound", "Z");
+            env->SetBooleanField(channel_object, bound_field, jtrue);
+        }
+    }
+clean:
+    free(address);
+    free(localAddr);
+    return channel_object;
+}
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/g722/g722.h	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,159 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g722.h - The ITU G.722 codec.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2005 Steve Underwood
+ *
+ *  Despite my general liking of the GPL, I place my own contributions 
+ *  to this code in the public domain for the benefit of all mankind -
+ *  even the slimy ones who might try to proprietize my work and use it
+ *  to my detriment.
+ *
+ * Based on a single channel G.722 codec which is:
+ *
+ *****    Copyright (c) CMU    1993      *****
+ * Computer Science, Speech Group
+ * Chengxiang Lu and Alex Hauptmann
+ *
+ * $Id: g722.h 48959 2006-12-25 06:42:15Z rizzo $
+ */
+
+
+/*! \file */
+
+#if !defined(_G722_H_)
+#define _G722_H_
+
+/*! \page g722_page G.722 encoding and decoding
+\section g722_page_sec_1 What does it do?
+The G.722 module is a bit exact implementation of the ITU G.722 specification for all three
+specified bit rates - 64000bps, 56000bps and 48000bps. It passes the ITU tests.
+
+To allow fast and flexible interworking with narrow band telephony, the encoder and decoder
+support an option for the linear audio to be an 8k samples/second stream. In this mode the
+codec is considerably faster, and still fully compatible with wideband terminals using G.722.
+
+\section g722_page_sec_2 How does it work?
+???.
+*/
+
+#if !defined(__STDINT_MACROS)
+typedef signed char int8_t;
+typedef unsigned char   uint8_t;
+typedef short  int16_t;
+typedef unsigned short  uint16_t;
+typedef int  int32_t;
+typedef unsigned   uint32_t;
+typedef long long  int64_t;
+typedef unsigned long long   uint64_t;
+#endif
+
+enum
+{
+    G722_SAMPLE_RATE_8000 = 0x0001,
+    G722_PACKED = 0x0002
+};
+
+#ifndef INT16_MAX
+#define INT16_MAX       32767
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN       (-32768)
+#endif
+
+typedef struct
+{
+    /*! TRUE if the operating in the special ITU test mode, with the band split filters
+             disabled. */
+    int itu_test_mode;
+    /*! TRUE if the G.722 data is packed */
+    int packed;
+    /*! TRUE if encode from 8k samples/second */
+    int eight_k;
+    /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
+    int bits_per_sample;
+
+    /*! Signal history for the QMF */
+    int x[24];
+
+    struct
+    {
+        int s;
+        int sp;
+        int sz;
+        int r[3];
+        int a[3];
+        int ap[3];
+        int p[3];
+        int d[7];
+        int b[7];
+        int bp[7];
+        int sg[7];
+        int nb;
+        int det;
+    } band[2];
+
+    unsigned int in_buffer;
+    int in_bits;
+    unsigned int out_buffer;
+    int out_bits;
+} g722_encode_state_t;
+
+typedef struct
+{
+    /*! TRUE if the operating in the special ITU test mode, with the band split filters
+             disabled. */
+    int itu_test_mode;
+    /*! TRUE if the G.722 data is packed */
+    int packed;
+    /*! TRUE if decode to 8k samples/second */
+    int eight_k;
+    /*! 6 for 48000kbps, 7 for 56000kbps, or 8 for 64000kbps. */
+    int bits_per_sample;
+
+    /*! Signal history for the QMF */
+    int x[24];
+
+    struct
+    {
+        int s;
+        int sp;
+        int sz;
+        int r[3];
+        int a[3];
+        int ap[3];
+        int p[3];
+        int d[7];
+        int b[7];
+        int bp[7];
+        int sg[7];
+        int nb;
+        int det;
+    } band[2];
+    
+    unsigned int in_buffer;
+    int in_bits;
+    unsigned int out_buffer;
+    int out_bits;
+} g722_decode_state_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options);
+int g722_encode_release(g722_encode_state_t *s);
+int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len);
+
+g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options);
+int g722_decode_release(g722_decode_state_t *s);
+int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/g722/g722_decode.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,398 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g722_decode.c - The ITU G.722 codec, decode part.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2005 Steve Underwood
+ *
+ *  Despite my general liking of the GPL, I place my own contributions 
+ *  to this code in the public domain for the benefit of all mankind -
+ *  even the slimy ones who might try to proprietize my work and use it
+ *  to my detriment.
+ *
+ * Based in part on a single channel G.722 codec which is:
+ *
+ * Copyright (c) CMU 1993
+ * Computer Science, Speech Group
+ * Chengxiang Lu and Alex Hauptmann
+ *
+ * $Id: g722_decode.c 48661 2006-12-21 00:08:21Z mattf $
+ */
+
+/*! \file */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+//#include <inttypes.h>
+#include <memory.h>
+#include <stdlib.h>
+#if 0
+#include <tgmath.h>
+#endif
+
+#include "g722.h"
+
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+#if !defined(TRUE)
+#define TRUE (!FALSE)
+#endif
+
+static  int16_t saturate(int32_t amp)
+{
+    int16_t amp16;
+
+    /* Hopefully this is optimised for the common case - not clipping */
+    amp16 = (int16_t) amp;
+    if (amp == amp16)
+        return amp16;
+    if (amp > INT16_MAX)
+        return  INT16_MAX;
+    return  INT16_MIN;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void block4(g722_decode_state_t *s, int band, int d);
+
+static void block4(g722_decode_state_t *s, int band, int d)
+{
+    int wd1;
+    int wd2;
+    int wd3;
+    int i;
+
+    /* Block 4, RECONS */
+    s->band[band].d[0] = d;
+    s->band[band].r[0] = saturate(s->band[band].s + d);
+
+    /* Block 4, PARREC */
+    s->band[band].p[0] = saturate(s->band[band].sz + d);
+
+    /* Block 4, UPPOL2 */
+    for (i = 0;  i < 3;  i++)
+        s->band[band].sg[i] = s->band[band].p[i] >> 15;
+    wd1 = saturate(s->band[band].a[1] << 2);
+
+    wd2 = (s->band[band].sg[0] == s->band[band].sg[1])  ?  -wd1  :  wd1;
+    if (wd2 > 32767)
+        wd2 = 32767;
+    wd3 = (s->band[band].sg[0] == s->band[band].sg[2])  ?  128  :  -128;
+    wd3 += (wd2 >> 7);
+    wd3 += (s->band[band].a[2]*32512) >> 15;
+    if (wd3 > 12288)
+        wd3 = 12288;
+    else if (wd3 < -12288)
+        wd3 = -12288;
+    s->band[band].ap[2] = wd3;
+
+    /* Block 4, UPPOL1 */
+    s->band[band].sg[0] = s->band[band].p[0] >> 15;
+    s->band[band].sg[1] = s->band[band].p[1] >> 15;
+    wd1 = (s->band[band].sg[0] == s->band[band].sg[1])  ?  192  :  -192;
+    wd2 = (s->band[band].a[1]*32640) >> 15;
+
+    s->band[band].ap[1] = saturate(wd1 + wd2);
+    wd3 = saturate(15360 - s->band[band].ap[2]);
+    if (s->band[band].ap[1] > wd3)
+        s->band[band].ap[1] = wd3;
+    else if (s->band[band].ap[1] < -wd3)
+        s->band[band].ap[1] = -wd3;
+
+    /* Block 4, UPZERO */
+    wd1 = (d == 0)  ?  0  :  128;
+    s->band[band].sg[0] = d >> 15;
+    for (i = 1;  i < 7;  i++)
+    {
+        s->band[band].sg[i] = s->band[band].d[i] >> 15;
+        wd2 = (s->band[band].sg[i] == s->band[band].sg[0])  ?  wd1  :  -wd1;
+        wd3 = (s->band[band].b[i]*32640) >> 15;
+        s->band[band].bp[i] = saturate(wd2 + wd3);
+    }
+
+    /* Block 4, DELAYA */
+    for (i = 6;  i > 0;  i--)
+    {
+        s->band[band].d[i] = s->band[band].d[i - 1];
+        s->band[band].b[i] = s->band[band].bp[i];
+    }
+    
+    for (i = 2;  i > 0;  i--)
+    {
+        s->band[band].r[i] = s->band[band].r[i - 1];
+        s->band[band].p[i] = s->band[band].p[i - 1];
+        s->band[band].a[i] = s->band[band].ap[i];
+    }
+
+    /* Block 4, FILTEP */
+    wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]);
+    wd1 = (s->band[band].a[1]*wd1) >> 15;
+    wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]);
+    wd2 = (s->band[band].a[2]*wd2) >> 15;
+    s->band[band].sp = saturate(wd1 + wd2);
+
+    /* Block 4, FILTEZ */
+    s->band[band].sz = 0;
+    for (i = 6;  i > 0;  i--)
+    {
+        wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]);
+        s->band[band].sz += (s->band[band].b[i]*wd1) >> 15;
+    }
+    s->band[band].sz = saturate(s->band[band].sz);
+
+    /* Block 4, PREDIC */
+    s->band[band].s = saturate(s->band[band].sp + s->band[band].sz);
+}
+/*- End of function --------------------------------------------------------*/
+
+g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options)
+{
+    if (s == NULL)
+    {
+        if ((s = (g722_decode_state_t *) malloc(sizeof(*s))) == NULL)
+            return NULL;
+    }
+    memset(s, 0, sizeof(*s));
+    if (rate == 48000)
+        s->bits_per_sample = 6;
+    else if (rate == 56000)
+        s->bits_per_sample = 7;
+    else
+        s->bits_per_sample = 8;
+    if ((options & G722_SAMPLE_RATE_8000))
+        s->eight_k = TRUE;
+    if ((options & G722_PACKED)  &&  s->bits_per_sample != 8)
+        s->packed = TRUE;
+    else
+        s->packed = FALSE;
+    s->band[0].det = 32;
+    s->band[1].det = 8;
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+
+int g722_decode_release(g722_decode_state_t *s)
+{
+    free(s);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len)
+{
+    static const int wl[8] = {-60, -30, 58, 172, 334, 538, 1198, 3042 };
+    static const int rl42[16] = {0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3,  2, 1, 0 };
+    static const int ilb[32] =
+    {
+        2048, 2093, 2139, 2186, 2233, 2282, 2332,
+        2383, 2435, 2489, 2543, 2599, 2656, 2714,
+        2774, 2834, 2896, 2960, 3025, 3091, 3158,
+        3228, 3298, 3371, 3444, 3520, 3597, 3676,
+        3756, 3838, 3922, 4008
+    };
+    static const int wh[3] = {0, -214, 798};
+    static const int rh2[4] = {2, 1, 2, 1};
+    static const int qm2[4] = {-7408, -1616,  7408,   1616};
+    static const int qm4[16] = 
+    {
+              0, -20456, -12896,  -8968, 
+          -6288,  -4240,  -2584,  -1200,
+          20456,  12896,   8968,   6288,
+           4240,   2584,   1200,      0
+    };
+    static const int qm5[32] =
+    {
+           -280,   -280, -23352, -17560,
+         -14120, -11664,  -9752,  -8184,
+          -6864,  -5712,  -4696,  -3784,
+          -2960,  -2208,  -1520,   -880,
+          23352,  17560,  14120,  11664,
+           9752,   8184,   6864,   5712,
+           4696,   3784,   2960,   2208,
+           1520,    880,    280,   -280
+    };
+    static const int qm6[64] =
+    {
+           -136,   -136,   -136,   -136,
+         -24808, -21904, -19008, -16704,
+         -14984, -13512, -12280, -11192,
+         -10232,  -9360,  -8576,  -7856,
+          -7192,  -6576,  -6000,  -5456,
+          -4944,  -4464,  -4008,  -3576,
+          -3168,  -2776,  -2400,  -2032,
+          -1688,  -1360,  -1040,   -728,
+          24808,  21904,  19008,  16704,
+          14984,  13512,  12280,  11192,
+          10232,   9360,   8576,   7856,
+           7192,   6576,   6000,   5456,
+           4944,   4464,   4008,   3576,
+           3168,   2776,   2400,   2032,
+           1688,   1360,   1040,    728,
+            432,    136,   -432,   -136
+    };
+    static const int qmf_coeffs[12] =
+    {
+           3,  -11,   12,   32, -210,  951, 3876, -805,  362, -156,   53,  -11,
+    };
+
+    int dlowt;
+    int rlow;
+    int ihigh;
+    int dhigh;
+    int rhigh;
+    int xout1;
+    int xout2;
+    int wd1;
+    int wd2;
+    int wd3;
+    int code;
+    int outlen;
+    int i;
+    int j;
+
+    outlen = 0;
+    rhigh = 0;
+    for (j = 0;  j < len;  )
+    {
+        if (s->packed)
+        {
+            /* Unpack the code bits */
+            if (s->in_bits < s->bits_per_sample)
+            {
+                s->in_buffer |= (g722_data[j++] << s->in_bits);
+                s->in_bits += 8;
+            }
+            code = s->in_buffer & ((1 << s->bits_per_sample) - 1);
+            s->in_buffer >>= s->bits_per_sample;
+            s->in_bits -= s->bits_per_sample;
+        }
+        else
+        {
+            code = g722_data[j++];
+        }
+
+        switch (s->bits_per_sample)
+        {
+        default:
+        case 8:
+            wd1 = code & 0x3F;
+            ihigh = (code >> 6) & 0x03;
+            wd2 = qm6[wd1];
+            wd1 >>= 2;
+            break;
+        case 7:
+            wd1 = code & 0x1F;
+            ihigh = (code >> 5) & 0x03;
+            wd2 = qm5[wd1];
+            wd1 >>= 1;
+            break;
+        case 6:
+            wd1 = code & 0x0F;
+            ihigh = (code >> 4) & 0x03;
+            wd2 = qm4[wd1];
+            break;
+        }
+        /* Block 5L, LOW BAND INVQBL */
+        wd2 = (s->band[0].det*wd2) >> 15;
+        /* Block 5L, RECONS */
+        rlow = s->band[0].s + wd2;
+        /* Block 6L, LIMIT */
+        if (rlow > 16383)
+            rlow = 16383;
+        else if (rlow < -16384)
+            rlow = -16384;
+
+        /* Block 2L, INVQAL */
+        wd2 = qm4[wd1];
+        dlowt = (s->band[0].det*wd2) >> 15;
+
+        /* Block 3L, LOGSCL */
+        wd2 = rl42[wd1];
+        wd1 = (s->band[0].nb*127) >> 7;
+        wd1 += wl[wd2];
+        if (wd1 < 0)
+            wd1 = 0;
+        else if (wd1 > 18432)
+            wd1 = 18432;
+        s->band[0].nb = wd1;
+            
+        /* Block 3L, SCALEL */
+        wd1 = (s->band[0].nb >> 6) & 31;
+        wd2 = 8 - (s->band[0].nb >> 11);
+        wd3 = (wd2 < 0)  ?  (ilb[wd1] << -wd2)  :  (ilb[wd1] >> wd2);
+        s->band[0].det = wd3 << 2;
+
+        block4(s, 0, dlowt);
+        
+        if (!s->eight_k)
+        {
+            /* Block 2H, INVQAH */
+            wd2 = qm2[ihigh];
+            dhigh = (s->band[1].det*wd2) >> 15;
+            /* Block 5H, RECONS */
+            rhigh = dhigh + s->band[1].s;
+            /* Block 6H, LIMIT */
+            if (rhigh > 16383)
+                rhigh = 16383;
+            else if (rhigh < -16384)
+                rhigh = -16384;
+
+            /* Block 2H, INVQAH */
+            wd2 = rh2[ihigh];
+            wd1 = (s->band[1].nb*127) >> 7;
+            wd1 += wh[wd2];
+            if (wd1 < 0)
+                wd1 = 0;
+            else if (wd1 > 22528)
+                wd1 = 22528;
+            s->band[1].nb = wd1;
+            
+            /* Block 3H, SCALEH */
+            wd1 = (s->band[1].nb >> 6) & 31;
+            wd2 = 10 - (s->band[1].nb >> 11);
+            wd3 = (wd2 < 0)  ?  (ilb[wd1] << -wd2)  :  (ilb[wd1] >> wd2);
+            s->band[1].det = wd3 << 2;
+
+            block4(s, 1, dhigh);
+        }
+
+        if (s->itu_test_mode)
+        {
+            amp[outlen++] = (int16_t) (rlow << 1);
+            amp[outlen++] = (int16_t) (rhigh << 1);
+        }
+        else
+        {
+            if (s->eight_k)
+            {
+                amp[outlen++] = (int16_t) rlow;
+            }
+            else
+            {
+                /* Apply the receive QMF */
+                for (i = 0;  i < 22;  i++)
+                    s->x[i] = s->x[i + 2];
+                s->x[22] = rlow + rhigh;
+                s->x[23] = rlow - rhigh;
+
+                xout1 = 0;
+                xout2 = 0;
+                for (i = 0;  i < 12;  i++)
+                {
+                    xout2 += s->x[2*i]*qmf_coeffs[i];
+                    xout1 += s->x[2*i + 1]*qmf_coeffs[11 - i];
+                }
+                amp[outlen++] = (int16_t) (xout1 >> 12);
+                amp[outlen++] = (int16_t) (xout2 >> 12);
+            }
+        }
+    }
+    return outlen;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/g722/g722_encode.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,400 @@
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * g722_encode.c - The ITU G.722 codec, encode part.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2005 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ *  Despite my general liking of the GPL, I place my own contributions 
+ *  to this code in the public domain for the benefit of all mankind -
+ *  even the slimy ones who might try to proprietize my work and use it
+ *  to my detriment.
+ *
+ * Based on a single channel 64kbps only G.722 codec which is:
+ *
+ *****    Copyright (c) CMU    1993      *****
+ * Computer Science, Speech Group
+ * Chengxiang Lu and Alex Hauptmann
+ *
+ * $Id: g722_encode.c 48661 2006-12-21 00:08:21Z mattf $
+ */
+
+/*! \file */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+//#include <inttypes.h>
+#include <memory.h>
+#include <stdlib.h>
+#if 0
+#include <tgmath.h>
+#endif
+
+#include "g722.h"
+
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+#if !defined(TRUE)
+#define TRUE (!FALSE)
+#endif
+
+static int16_t saturate(int32_t amp)
+{
+    int16_t amp16;
+
+    /* Hopefully this is optimised for the common case - not clipping */
+    amp16 = (int16_t) amp;
+    if (amp == amp16)
+        return amp16;
+    if (amp > INT16_MAX)
+        return  INT16_MAX;
+    return  INT16_MIN;
+}
+/*- End of function --------------------------------------------------------*/
+
+static void block4(g722_encode_state_t *s, int band, int d)
+{
+    int wd1;
+    int wd2;
+    int wd3;
+    int i;
+
+    /* Block 4, RECONS */
+    s->band[band].d[0] = d;
+    s->band[band].r[0] = saturate(s->band[band].s + d);
+
+    /* Block 4, PARREC */
+    s->band[band].p[0] = saturate(s->band[band].sz + d);
+
+    /* Block 4, UPPOL2 */
+    for (i = 0;  i < 3;  i++)
+        s->band[band].sg[i] = s->band[band].p[i] >> 15;
+    wd1 = saturate(s->band[band].a[1] << 2);
+
+    wd2 = (s->band[band].sg[0] == s->band[band].sg[1])  ?  -wd1  :  wd1;
+    if (wd2 > 32767)
+        wd2 = 32767;
+    wd3 = (wd2 >> 7) + ((s->band[band].sg[0] == s->band[band].sg[2])  ?  128  :  -128);
+    wd3 += (s->band[band].a[2]*32512) >> 15;
+    if (wd3 > 12288)
+        wd3 = 12288;
+    else if (wd3 < -12288)
+        wd3 = -12288;
+    s->band[band].ap[2] = wd3;
+
+    /* Block 4, UPPOL1 */
+    s->band[band].sg[0] = s->band[band].p[0] >> 15;
+    s->band[band].sg[1] = s->band[band].p[1] >> 15;
+    wd1 = (s->band[band].sg[0] == s->band[band].sg[1])  ?  192  :  -192;
+    wd2 = (s->band[band].a[1]*32640) >> 15;
+
+    s->band[band].ap[1] = saturate(wd1 + wd2);
+    wd3 = saturate(15360 - s->band[band].ap[2]);
+    if (s->band[band].ap[1] > wd3)
+        s->band[band].ap[1] = wd3;
+    else if (s->band[band].ap[1] < -wd3)
+        s->band[band].ap[1] = -wd3;
+
+    /* Block 4, UPZERO */
+    wd1 = (d == 0)  ?  0  :  128;
+    s->band[band].sg[0] = d >> 15;
+    for (i = 1;  i < 7;  i++)
+    {
+        s->band[band].sg[i] = s->band[band].d[i] >> 15;
+        wd2 = (s->band[band].sg[i] == s->band[band].sg[0])  ?  wd1  :  -wd1;
+        wd3 = (s->band[band].b[i]*32640) >> 15;
+        s->band[band].bp[i] = saturate(wd2 + wd3);
+    }
+
+    /* Block 4, DELAYA */
+    for (i = 6;  i > 0;  i--)
+    {
+        s->band[band].d[i] = s->band[band].d[i - 1];
+        s->band[band].b[i] = s->band[band].bp[i];
+    }
+    
+    for (i = 2;  i > 0;  i--)
+    {
+        s->band[band].r[i] = s->band[band].r[i - 1];
+        s->band[band].p[i] = s->band[band].p[i - 1];
+        s->band[band].a[i] = s->band[band].ap[i];
+    }
+
+    /* Block 4, FILTEP */
+    wd1 = saturate(s->band[band].r[1] + s->band[band].r[1]);
+    wd1 = (s->band[band].a[1]*wd1) >> 15;
+    wd2 = saturate(s->band[band].r[2] + s->band[band].r[2]);
+    wd2 = (s->band[band].a[2]*wd2) >> 15;
+    s->band[band].sp = saturate(wd1 + wd2);
+
+    /* Block 4, FILTEZ */
+    s->band[band].sz = 0;
+    for (i = 6;  i > 0;  i--)
+    {
+        wd1 = saturate(s->band[band].d[i] + s->band[band].d[i]);
+        s->band[band].sz += (s->band[band].b[i]*wd1) >> 15;
+    }
+    s->band[band].sz = saturate(s->band[band].sz);
+
+    /* Block 4, PREDIC */
+    s->band[band].s = saturate(s->band[band].sp + s->band[band].sz);
+}
+/*- End of function --------------------------------------------------------*/
+
+g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options)
+{
+    if (s == NULL)
+    {
+        if ((s = (g722_encode_state_t *) malloc(sizeof(*s))) == NULL)
+            return NULL;
+    }
+    memset(s, 0, sizeof(*s));
+    if (rate == 48000)
+        s->bits_per_sample = 6;
+    else if (rate == 56000)
+        s->bits_per_sample = 7;
+    else
+        s->bits_per_sample = 8;
+    if ((options & G722_SAMPLE_RATE_8000))
+        s->eight_k = TRUE;
+    if ((options & G722_PACKED)  &&  s->bits_per_sample != 8)
+        s->packed = TRUE;
+    else
+        s->packed = FALSE;
+    s->band[0].det = 32;
+    s->band[1].det = 8;
+    return s;
+}
+/*- End of function --------------------------------------------------------*/
+
+int g722_encode_release(g722_encode_state_t *s)
+{
+    free(s);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
+int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len)
+{
+    static const int q6[32] =
+    {
+           0,   35,   72,  110,  150,  190,  233,  276,
+         323,  370,  422,  473,  530,  587,  650,  714,
+         786,  858,  940, 1023, 1121, 1219, 1339, 1458,
+        1612, 1765, 1980, 2195, 2557, 2919,    0,    0
+    };
+    static const int iln[32] =
+    {
+         0, 63, 62, 31, 30, 29, 28, 27,
+        26, 25, 24, 23, 22, 21, 20, 19,
+        18, 17, 16, 15, 14, 13, 12, 11,
+        10,  9,  8,  7,  6,  5,  4,  0
+    };
+    static const int ilp[32] =
+    {
+         0, 61, 60, 59, 58, 57, 56, 55,
+        54, 53, 52, 51, 50, 49, 48, 47,
+        46, 45, 44, 43, 42, 41, 40, 39,
+        38, 37, 36, 35, 34, 33, 32,  0
+    };
+    static const int wl[8] =
+    {
+        -60, -30, 58, 172, 334, 538, 1198, 3042
+    };
+    static const int rl42[16] =
+    {
+        0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0
+    };
+    static const int ilb[32] =
+    {
+        2048, 2093, 2139, 2186, 2233, 2282, 2332,
+        2383, 2435, 2489, 2543, 2599, 2656, 2714,
+        2774, 2834, 2896, 2960, 3025, 3091, 3158,
+        3228, 3298, 3371, 3444, 3520, 3597, 3676,
+        3756, 3838, 3922, 4008
+    };
+    static const int qm4[16] =
+    {
+             0, -20456, -12896, -8968,
+         -6288,  -4240,  -2584, -1200,
+         20456,  12896,   8968,  6288,
+          4240,   2584,   1200,     0
+    };
+    static const int qm2[4] =
+    {
+        -7408,  -1616,   7408,   1616
+    };
+    static const int qmf_coeffs[12] =
+    {
+           3,  -11,   12,   32, -210,  951, 3876, -805,  362, -156,   53,  -11,
+    };
+    static const int ihn[3] = {0, 1, 0};
+    static const int ihp[3] = {0, 3, 2};
+    static const int wh[3] = {0, -214, 798};
+    static const int rh2[4] = {2, 1, 2, 1};
+
+    int dlow;
+    int dhigh;
+    int el;
+    int wd;
+    int wd1;
+    int ril;
+    int wd2;
+    int il4;
+    int ih2;
+    int wd3;
+    int eh;
+    int mih;
+    int i;
+    int j;
+    /* Low and high band PCM from the QMF */
+    int xlow;
+    int xhigh;
+    int g722_bytes;
+    /* Even and odd tap accumulators */
+    int sumeven;
+    int sumodd;
+    int ihigh;
+    int ilow;
+    int code;
+
+    g722_bytes = 0;
+    xhigh = 0;
+    for (j = 0;  j < len;  )
+    {
+        if (s->itu_test_mode)
+        {
+            xlow =
+            xhigh = amp[j++] >> 1;
+        }
+        else
+        {
+            if (s->eight_k)
+            {
+                xlow = amp[j++];
+            }
+            else
+            {
+                /* Apply the transmit QMF */
+                /* Shuffle the buffer down */
+                for (i = 0;  i < 22;  i++)
+                    s->x[i] = s->x[i + 2];
+                s->x[22] = amp[j++];
+                s->x[23] = amp[j++];
+    
+                /* Discard every other QMF output */
+                sumeven = 0;
+                sumodd = 0;
+                for (i = 0;  i < 12;  i++)
+                {
+                    sumodd += s->x[2*i]*qmf_coeffs[i];
+                    sumeven += s->x[2*i + 1]*qmf_coeffs[11 - i];
+                }
+                xlow = (sumeven + sumodd) >> 13;
+                xhigh = (sumeven - sumodd) >> 13;
+            }
+        }
+        /* Block 1L, SUBTRA */
+        el = saturate(xlow - s->band[0].s);
+
+        /* Block 1L, QUANTL */
+        wd = (el >= 0)  ?  el  :  -(el + 1);
+
+        for (i = 1;  i < 30;  i++)
+        {
+            wd1 = (q6[i]*s->band[0].det) >> 12;
+            if (wd < wd1)
+                break;
+        }
+        ilow = (el < 0)  ?  iln[i]  :  ilp[i];
+
+        /* Block 2L, INVQAL */
+        ril = ilow >> 2;
+        wd2 = qm4[ril];
+        dlow = (s->band[0].det*wd2) >> 15;
+
+        /* Block 3L, LOGSCL */
+        il4 = rl42[ril];
+        wd = (s->band[0].nb*127) >> 7;
+        s->band[0].nb = wd + wl[il4];
+        if (s->band[0].nb < 0)
+            s->band[0].nb = 0;
+        else if (s->band[0].nb > 18432)
+            s->band[0].nb = 18432;
+
+        /* Block 3L, SCALEL */
+        wd1 = (s->band[0].nb >> 6) & 31;
+        wd2 = 8 - (s->band[0].nb >> 11);
+        wd3 = (wd2 < 0)  ?  (ilb[wd1] << -wd2)  :  (ilb[wd1] >> wd2);
+        s->band[0].det = wd3 << 2;
+
+        block4(s, 0, dlow);
+        
+        if (s->eight_k)
+        {
+            /* Just leave the high bits as zero */
+            code = (0xC0 | ilow) >> (8 - s->bits_per_sample);
+        }
+        else
+        {
+            /* Block 1H, SUBTRA */
+            eh = saturate(xhigh - s->band[1].s);
+
+            /* Block 1H, QUANTH */
+            wd = (eh >= 0)  ?  eh  :  -(eh + 1);
+            wd1 = (564*s->band[1].det) >> 12;
+            mih = (wd >= wd1)  ?  2  :  1;
+            ihigh = (eh < 0)  ?  ihn[mih]  :  ihp[mih];
+
+            /* Block 2H, INVQAH */
+            wd2 = qm2[ihigh];
+            dhigh = (s->band[1].det*wd2) >> 15;
+
+            /* Block 3H, LOGSCH */
+            ih2 = rh2[ihigh];
+            wd = (s->band[1].nb*127) >> 7;
+            s->band[1].nb = wd + wh[ih2];
+            if (s->band[1].nb < 0)
+                s->band[1].nb = 0;
+            else if (s->band[1].nb > 22528)
+                s->band[1].nb = 22528;
+
+            /* Block 3H, SCALEH */
+            wd1 = (s->band[1].nb >> 6) & 31;
+            wd2 = 10 - (s->band[1].nb >> 11);
+            wd3 = (wd2 < 0)  ?  (ilb[wd1] << -wd2)  :  (ilb[wd1] >> wd2);
+            s->band[1].det = wd3 << 2;
+
+            block4(s, 1, dhigh);
+            code = ((ihigh << 6) | ilow) >> (8 - s->bits_per_sample);
+        }
+
+        if (s->packed)
+        {
+            /* Pack the code bits */
+            s->out_buffer |= (code << s->out_bits);
+            s->out_bits += s->bits_per_sample;
+            if (s->out_bits >= 8)
+            {
+                g722_data[g722_bytes++] = (uint8_t) (s->out_buffer & 0xFF);
+                s->out_bits -= 8;
+                s->out_buffer >>= 8;
+            }
+        }
+        else
+        {
+            g722_data[g722_bytes++] = (uint8_t) code;
+        }
+    }
+    return g722_bytes;
+}
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/g722/g722_jni.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,80 @@
+/**
+
+g722_encode_state_t *g722_encode_init(g722_encode_state_t *s, int rate, int options);
+int g722_encode_release(g722_encode_state_t *s);
+int g722_encode(g722_encode_state_t *s, uint8_t g722_data[], const int16_t amp[], int len);
+
+g722_decode_state_t *g722_decode_init(g722_decode_state_t *s, int rate, int options);
+int g722_decode_release(g722_decode_state_t *s);
+int g722_decode(g722_decode_state_t *s, int16_t amp[], const uint8_t g722_data[], int len);
+
+*/
+
+#include <jni.h>
+#include "g722.h"
+
+jlong
+Java_org_sipdroid_media_codecs_G722JNI_encodeInit(JNIEnv *env, jlong jg722State, jint rate, jint options)
+{
+	return g722_encode_init((void *) jg722State, rate, options);
+}
+
+jint
+Java_org_sipdroid_media_codecs_G722JNI_encodeRelease(JNIEnv *env, jlong jg722State)
+{
+	return g722_encode_release((void *) jg722State);
+}
+
+jint
+Java_org_sipdroid_media_codecs_G722JNI_encode(JNIEnv *env, jlong  jg722State, jshortArray jsignal, jlong jsrcPos, jbyteArray jg722Byte, jlong jdestPos, jint len)
+{
+	jshort *signal;
+	jbyte *g722Byte;
+	jboolean isCopyByte;
+	jboolean isCopySignal;
+	void *ctx = (void *) jg722State;
+	jint res;
+
+	g722Byte = (*env)->GetByteArrayElements(env, jg722Byte, &isCopyByte);
+	signal = (*env)->GetShortArrayElements(env, jsignal, &isCopySignal);
+
+	res = g722_encode(ctx, g722Byte + jdestPos, signal + jsrcPos, len);
+	if (isCopyByte == JNI_TRUE)
+		(*env)->ReleaseByteArrayElements(env, jg722Byte, g722Byte, 0);
+	if (isCopySignal == JNI_TRUE)
+		(*env)->ReleaseShortArrayElements(env, jsignal, signal, 0);
+	return res;
+}
+
+jlong
+Java_org_sipdroid_media_codecs_G722JNI_decodeInit(JNIEnv *env, jlong jg722State, jint rate, jint options)
+{
+	return g722_decode_init((void *) jg722State, rate, options);
+}
+
+jint
+Java_org_sipdroid_media_codecs_G722JNI_decodeRelease(JNIEnv *env, jlong jg722State)
+{
+	return g722_decode_release((void *) jg722State);
+}
+
+jint
+Java_org_sipdroid_media_codecs_G722JNI_decode(JNIEnv *env, jlong  jg722State, jbyteArray jg722Byte, jlong jsrcPos, jshortArray jsignal, jlong jdestPos, jint len)
+{
+	jshort *signal;
+	jbyte *g722Byte;
+	jboolean isCopyByte;
+	jboolean isCopySignal;
+	void *ctx = (void *) jg722State;
+	jint res;
+
+	g722Byte = (*env)->GetByteArrayElements(env, jg722Byte, &isCopyByte);
+	signal = (*env)->GetShortArrayElements(env, jsignal, &isCopySignal);
+
+	res = g722_decode(ctx, signal + jdestPos, g722Byte + jsrcPos, len);
+	if (isCopyByte == JNI_TRUE)
+		(*env)->ReleaseByteArrayElements(env, jg722Byte, g722Byte, 0);
+	if (isCopySignal == JNI_TRUE)
+		(*env)->ReleaseShortArrayElements(env, jsignal, signal, 0);
+	return res;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/Android.mk	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,19 @@
+SRC_FILES := 	add.c\
+		code.c\
+		debug.c\
+		decode.c\
+		gsm_create.c\
+		gsm_decode.c\
+		gsm_destroy.c\
+		gsm_encode.c\
+		gsm_explode.c\
+		gsm_implode.c\
+		gsm_option.c\
+		gsm_print.c\
+		long_term.c\
+		lpc.c\
+		preprocess.c\
+		rpe.c\
+		short_term.c\
+		table.c\
+		gsm_jni.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/add.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,235 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/add.c,v 1.6 1996/07/02 09:57:33 jutta Exp $ */
+
+/*
+ *  See private.h for the more commonly used macro versions.
+ */
+
+#include	<stdio.h>
+#include	<assert.h>
+
+#include	"private.h"
+#include	"gsm.h"
+#include	"proto.h"
+
+#define	saturate(x) 	\
+	((x) < MIN_WORD ? MIN_WORD : (x) > MAX_WORD ? MAX_WORD: (x))
+
+word gsm_add P2((a,b), word a, word b)
+{
+	longword sum = (longword)a + (longword)b;
+	return saturate(sum);
+}
+
+word gsm_sub P2((a,b), word a, word b)
+{
+	longword diff = (longword)a - (longword)b;
+	return saturate(diff);
+}
+
+word gsm_mult P2((a,b), word a, word b)
+{
+	if (a == MIN_WORD && b == MIN_WORD) return MAX_WORD;
+	else return SASR( (longword)a * (longword)b, 15 );
+}
+
+word gsm_mult_r P2((a,b), word a, word b)
+{
+	if (b == MIN_WORD && a == MIN_WORD) return MAX_WORD;
+	else {
+		longword prod = (longword)a * (longword)b + 16384;
+		prod >>= 15;
+		return prod & 0xFFFF;
+	}
+}
+
+word gsm_abs P1((a), word a)
+{
+	return a < 0 ? (a == MIN_WORD ? MAX_WORD : -a) : a;
+}
+
+longword gsm_L_mult P2((a,b),word a, word b)
+{
+	assert( a != MIN_WORD || b != MIN_WORD );
+	return ((longword)a * (longword)b) << 1;
+}
+
+longword gsm_L_add P2((a,b), longword a, longword b)
+{
+	if (a < 0) {
+		if (b >= 0) return a + b;
+		else {
+			ulongword A = (ulongword)-(a + 1) + (ulongword)-(b + 1);
+			return A >= MAX_LONGWORD ? MIN_LONGWORD :-(longword)A-2;
+		}
+	}
+	else if (b <= 0) return a + b;
+	else {
+		ulongword A = (ulongword)a + (ulongword)b;
+		return A > MAX_LONGWORD ? MAX_LONGWORD : A;
+	}
+}
+
+longword gsm_L_sub P2((a,b), longword a, longword b)
+{
+	if (a >= 0) {
+		if (b >= 0) return a - b;
+		else {
+			/* a>=0, b<0 */
+
+			ulongword A = (ulongword)a + -(b + 1);
+			return A >= MAX_LONGWORD ? MAX_LONGWORD : (A + 1);
+		}
+	}
+	else if (b <= 0) return a - b;
+	else {
+		/* a<0, b>0 */  
+
+		ulongword A = (ulongword)-(a + 1) + b;
+		return A >= MAX_LONGWORD ? MIN_LONGWORD : -(longword)A - 1;
+	}
+}
+
+static unsigned char const bitoff[ 256 ] = {
+	 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+	 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+word gsm_norm P1((a), longword a )
+/*
+ * the number of left shifts needed to normalize the 32 bit
+ * variable L_var1 for positive values on the interval
+ *
+ * with minimum of
+ * minimum of 1073741824  (01000000000000000000000000000000) and 
+ * maximum of 2147483647  (01111111111111111111111111111111)
+ *
+ *
+ * and for negative values on the interval with
+ * minimum of -2147483648 (-10000000000000000000000000000000) and
+ * maximum of -1073741824 ( -1000000000000000000000000000000).
+ *
+ * in order to normalize the result, the following
+ * operation must be done: L_norm_var1 = L_var1 << norm( L_var1 );
+ *
+ * (That's 'ffs', only from the left, not the right..)
+ */
+{
+	assert(a != 0);
+
+	if (a < 0) {
+		if (a <= -1073741824) return 0;
+		a = ~a;
+	}
+
+	return    a & 0xffff0000 
+		? ( a & 0xff000000
+		  ?  -1 + bitoff[ 0xFF & (a >> 24) ]
+		  :   7 + bitoff[ 0xFF & (a >> 16) ] )
+		: ( a & 0xff00
+		  ?  15 + bitoff[ 0xFF & (a >> 8) ]
+		  :  23 + bitoff[ 0xFF & a ] );
+}
+
+longword gsm_L_asl P2((a,n), longword a, int n)
+{
+	if (n >= 32) return 0;
+	if (n <= -32) return -(a < 0);
+	if (n < 0) return gsm_L_asr(a, -n);
+	return a << n;
+}
+
+word gsm_asl P2((a,n), word a, int n)
+{
+	if (n >= 16) return 0;
+	if (n <= -16) return -(a < 0);
+	if (n < 0) return gsm_asr(a, -n);
+	return a << n;
+}
+
+longword gsm_L_asr P2((a,n), longword a, int n)
+{
+	if (n >= 32) return -(a < 0);
+	if (n <= -32) return 0;
+	if (n < 0) return a << -n;
+
+#	ifdef	SASR
+		return a >> n;
+#	else
+		if (a >= 0) return a >> n;
+		else return -(longword)( -(ulongword)a >> n );
+#	endif
+}
+
+word gsm_asr P2((a,n), word a, int n)
+{
+	if (n >= 16) return -(a < 0);
+	if (n <= -16) return 0;
+	if (n < 0) return a << -n;
+
+#	ifdef	SASR
+		return a >> n;
+#	else
+		if (a >= 0) return a >> n;
+		else return -(word)( -(uword)a >> n );
+#	endif
+}
+
+/* 
+ *  (From p. 46, end of section 4.2.5)
+ *
+ *  NOTE: The following lines gives [sic] one correct implementation
+ *  	  of the div(num, denum) arithmetic operation.  Compute div
+ *        which is the integer division of num by denum: with denum
+ *	  >= num > 0
+ */
+
+word gsm_div P2((num,denum), word num, word denum)
+{
+	longword	L_num   = num;
+	longword	L_denum = denum;
+	word		div 	= 0;
+	int		k 	= 15;
+
+	/* The parameter num sometimes becomes zero.
+	 * Although this is explicitly guarded against in 4.2.5,
+	 * we assume that the result should then be zero as well.
+	 */
+
+	/* assert(num != 0); */
+
+	assert(num >= 0 && denum >= num);
+	if (num == 0)
+	    return 0;
+
+	while (k--) {
+		div   <<= 1;
+		L_num <<= 1;
+
+		if (L_num >= L_denum) {
+			L_num -= L_denum;
+			div++;
+		}
+	}
+
+	return div;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/code.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,104 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/code.c,v 1.3 1996/07/02 09:59:05 jutta Exp $ */
+
+#include	"config.h"
+
+#include	<string.h>
+
+#ifdef	HAS_STDLIB_H
+#include	<stdlib.h>
+#else
+#	include "proto.h"
+	extern char	* memcpy P((char *, char *, int));
+#endif
+
+#include	"private.h"
+#include	"gsm.h"
+#include	"proto.h"
+
+
+/* 
+ *  4.2 FIXED POINT IMPLEMENTATION OF THE RPE-LTP CODER 
+ */
+
+void Gsm_Coder P8((S,s,LARc,Nc,bc,Mc,xmaxc,xMc),
+
+	struct gsm_state	* S,
+
+	word	* s,	/* [0..159] samples		  	IN	*/
+
+/*
+ * The RPE-LTD coder works on a frame by frame basis.  The length of
+ * the frame is equal to 160 samples.  Some computations are done
+ * once per frame to produce at the output of the coder the
+ * LARc[1..8] parameters which are the coded LAR coefficients and 
+ * also to realize the inverse filtering operation for the entire
+ * frame (160 samples of signal d[0..159]).  These parts produce at
+ * the output of the coder:
+ */
+
+	word	* LARc,	/* [0..7] LAR coefficients		OUT	*/
+
+/*
+ * Procedure 4.2.11 to 4.2.18 are to be executed four times per
+ * frame.  That means once for each sub-segment RPE-LTP analysis of
+ * 40 samples.  These parts produce at the output of the coder:
+ */
+
+	word	* Nc,	/* [0..3] LTP lag			OUT 	*/
+	word	* bc,	/* [0..3] coded LTP gain		OUT 	*/
+	word	* Mc,	/* [0..3] RPE grid selection		OUT     */
+	word	* xmaxc,/* [0..3] Coded maximum amplitude	OUT	*/
+	word	* xMc	/* [13*4] normalized RPE samples	OUT	*/
+)
+{
+	int	k;
+	word	* dp  = S->dp0 + 120;	/* [ -120...-1 ] */
+	word	* dpp = dp;		/* [ 0...39 ]	 */
+
+	static word e[50];
+
+	word	so[160];
+
+	Gsm_Preprocess			(S, s, so);
+	Gsm_LPC_Analysis		(S, so, LARc);
+	Gsm_Short_Term_Analysis_Filter	(S, LARc, so);
+
+	for (k = 0; k <= 3; k++, xMc += 13) {
+
+		Gsm_Long_Term_Predictor	( S,
+					 so+k*40, /* d      [0..39] IN	*/
+					 dp,	  /* dp  [-120..-1] IN	*/
+					e + 5,	  /* e      [0..39] OUT	*/
+					dpp,	  /* dpp    [0..39] OUT */
+					 Nc++,
+					 bc++);
+
+		Gsm_RPE_Encoding	( S,
+					e + 5,	/* e	  ][0..39][ IN/OUT */
+					  xmaxc++, Mc++, xMc );
+		/*
+		 * Gsm_Update_of_reconstructed_short_time_residual_signal
+		 *			( dpp, e + 5, dp );
+		 */
+
+		{ register int i;
+		  register longword ltmp;
+		  for (i = 0; i <= 39; i++)
+			dp[ i ] = GSM_ADD( e[5 + i], dpp[i] );
+		}
+		dp  += 40;
+		dpp += 40;
+
+	}
+
+	(void)memcpy( (char *)S->dp0, (char *)(S->dp0 + 160),
+		120 * sizeof(*S->dp0) );
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/config.h	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,37 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/*$Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/config.h,v 1.5 1996/07/02 11:26:20 jutta Exp $*/
+
+#ifndef	CONFIG_H
+#define	CONFIG_H
+
+//efine	SIGHANDLER_T	int 		/* signal handlers are void	*/
+//efine HAS_SYSV_SIGNAL	1		/* sigs not blocked/reset?	*/
+
+#define	HAS_STDLIB_H	1		/* /usr/include/stdlib.h	*/
+//efine	HAS_LIMITS_H	1		/* /usr/include/limits.h	*/
+#define	HAS_FCNTL_H	1		/* /usr/include/fcntl.h		*/
+//efine	HAS_ERRNO_DECL	1		/* errno.h declares errno	*/
+
+#define	HAS_FSTAT 	1		/* fstat syscall		*/
+#define	HAS_FCHMOD 	1		/* fchmod syscall		*/
+#define	HAS_CHMOD 	1		/* chmod syscall		*/
+#define	HAS_FCHOWN 	1		/* fchown syscall		*/
+#define	HAS_CHOWN 	1		/* chown syscall		*/
+//efine	HAS__FSETMODE 	1		/* _fsetmode -- set file mode	*/
+
+#define	HAS_STRING_H 	1		/* /usr/include/string.h 	*/
+//efine	HAS_STRINGS_H	1		/* /usr/include/strings.h 	*/
+
+#define	HAS_UNISTD_H	1		/* /usr/include/unistd.h	*/
+#define	HAS_UTIME	1		/* POSIX utime(path, times)	*/
+//efine	HAS_UTIMES	1		/* use utimes()	syscall instead	*/
+#define	HAS_UTIME_H	1		/* UTIME header file		*/
+//efine	HAS_UTIMBUF	1		/* struct utimbuf		*/
+//efine	HAS_UTIMEUSEC   1		/* microseconds in utimbuf?	*/
+
+#endif	/* CONFIG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/debug.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,76 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/debug.c,v 1.2 1993/01/29 18:22:20 jutta Exp $ */
+
+#include "private.h"
+
+#ifndef	NDEBUG
+
+/* If NDEBUG _is_ defined and no debugging should be performed,
+ * calls to functions in this module are #defined to nothing
+ * in private.h.
+ */
+
+#include <stdio.h>
+#include "proto.h"
+
+void gsm_debug_words P4( (name, from, to, ptr), 
+	char 	      * name,
+	int		from,
+	int		to,
+	word		* ptr)
+{
+	int 	nprinted = 0;
+
+	fprintf( stderr, "%s [%d .. %d]: ", name, from, to );
+	while (from <= to) {
+		fprintf(stderr, "%d ", ptr[ from ] );
+		from++;
+		if (nprinted++ >= 7) {
+			nprinted = 0;
+			if (from < to) putc('\n', stderr);
+		}
+	}
+	putc('\n', stderr);
+}
+
+void gsm_debug_longwords P4( (name, from, to, ptr),
+	char 	      * name,
+	int		from,
+	int		to,
+	longword      * ptr)
+{
+	int 	nprinted = 0;
+
+	fprintf( stderr, "%s [%d .. %d]: ", name, from, to );
+	while (from <= to) {
+
+		fprintf(stderr, "%ld ", ptr[ from ] );
+		from++;
+		if (nprinted++ >= 7) {
+			nprinted = 0;
+			if (from < to) putc('\n', stderr);
+		}
+	}
+	putc('\n', stderr);
+}
+
+void gsm_debug_longword P2(  (name, value),
+	char		* name,
+	longword	  value	)
+{
+	fprintf(stderr, "%s: %ld\n", name, (long)value );
+}
+
+void gsm_debug_word P2(  (name, value),
+	char	* name,
+	word	  value	)
+{
+	fprintf(stderr, "%s: %ld\n", name, (long)value);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/decode.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/decode.c,v 1.1 1992/10/28 00:15:50 jutta Exp $ */
+
+#include <stdio.h>
+
+#include	"private.h"
+#include	"gsm.h"
+#include	"proto.h"
+
+/*
+ *  4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER
+ */
+
+static void Postprocessing P2((S,s),
+	struct gsm_state	* S,
+	register word 		* s)
+{
+	register int		k;
+	register word		msr = S->msr;
+	register longword	ltmp;	/* for GSM_ADD */
+	register word		tmp;
+
+	for (k = 160; k--; s++) {
+		tmp = GSM_MULT_R( msr, 28180 );
+		msr = GSM_ADD(*s, tmp);  	   /* Deemphasis 	     */
+		*s  = GSM_ADD(msr, msr) & 0xFFF8;  /* Truncation & Upscaling */
+	}
+	S->msr = msr;
+}
+
+void Gsm_Decoder P8((S,LARcr, Ncr,bcr,Mcr,xmaxcr,xMcr,s),
+	struct gsm_state	* S,
+
+	word		* LARcr,	/* [0..7]		IN	*/
+
+	word		* Ncr,		/* [0..3] 		IN 	*/
+	word		* bcr,		/* [0..3]		IN	*/
+	word		* Mcr,		/* [0..3] 		IN 	*/
+	word		* xmaxcr,	/* [0..3]		IN 	*/
+	word		* xMcr,		/* [0..13*4]		IN	*/
+
+	word		* s)		/* [0..159]		OUT 	*/
+{
+	int		j, k;
+	word		erp[40], wt[160];
+	word		* drp = S->dp0 + 120;
+
+	for (j=0; j <= 3; j++, xmaxcr++, bcr++, Ncr++, Mcr++, xMcr += 13) {
+
+		Gsm_RPE_Decoding( S, *xmaxcr, *Mcr, xMcr, erp );
+		Gsm_Long_Term_Synthesis_Filtering( S, *Ncr, *bcr, erp, drp );
+
+		for (k = 0; k <= 39; k++) wt[ j * 40 + k ] =  drp[ k ];
+	}
+
+	Gsm_Short_Term_Synthesis_Filter( S, LARcr, wt, s );
+	Postprocessing(S, s);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm.h	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/*$Header: /home/kbs/jutta/src/gsm/gsm-1.0/inc/RCS/gsm.h,v 1.11 1996/07/05 18:02:56 jutta Exp $*/
+
+#ifndef	GSM_H
+#define	GSM_H
+
+#ifdef __cplusplus
+#	define	NeedFunctionPrototypes	1
+#endif
+
+#if __STDC__
+#	define	NeedFunctionPrototypes	1
+#endif
+
+#ifdef _NO_PROTO
+#	undef	NeedFunctionPrototypes
+#endif
+
+#ifdef NeedFunctionPrototypes
+#   include	<stdio.h>		/* for FILE * 	*/
+#endif
+
+#undef GSM_P
+#if NeedFunctionPrototypes
+#	define	GSM_P( protos )	protos
+#else
+#	define  GSM_P( protos )	( /* protos */ )
+#endif
+
+/*
+ *	Interface
+ */
+
+typedef struct gsm_state * 	gsm;
+typedef short		   	gsm_signal;		/* signed 16 bit */
+typedef unsigned char		gsm_byte;
+typedef gsm_byte 		gsm_frame[33];		/* 33 * 8 bits	 */
+
+#define	GSM_MAGIC		0xD		  	/* 13 kbit/s RPE-LTP */
+
+#define	GSM_PATCHLEVEL		10
+#define	GSM_MINOR		0
+#define	GSM_MAJOR		1
+
+#define	GSM_OPT_VERBOSE		1
+#define	GSM_OPT_FAST		2
+#define	GSM_OPT_LTP_CUT		3
+#define	GSM_OPT_WAV49		4
+#define	GSM_OPT_FRAME_INDEX	5
+#define	GSM_OPT_FRAME_CHAIN	6
+
+extern gsm  gsm_create 	GSM_P((void));
+extern void gsm_destroy GSM_P((gsm));	
+
+extern int  gsm_print   GSM_P((FILE *, gsm, gsm_byte  *));
+extern int  gsm_option  GSM_P((gsm, int, int *));
+
+extern void gsm_encode  GSM_P((gsm, gsm_signal *, gsm_byte  *));
+extern int  gsm_decode  GSM_P((gsm, gsm_byte   *, gsm_signal *));
+
+extern int  gsm_explode GSM_P((gsm, gsm_byte   *, gsm_signal *));
+extern void gsm_implode GSM_P((gsm, gsm_signal *, gsm_byte   *));
+
+#undef	GSM_P
+
+#endif	/* GSM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_create.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,45 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+static char const	ident[] = "$Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_create.c,v 1.4 1996/07/02 09:59:05 jutta Exp $";
+
+#include	"config.h"
+
+#ifdef	HAS_STRING_H
+#include	<string.h>
+#else
+#	include "proto.h"
+	extern char	* memset P((char *, int, int));
+#endif
+
+#ifdef	HAS_STDLIB_H
+#	include	<stdlib.h>
+#else
+#	ifdef	HAS_MALLOC_H
+#		include 	<malloc.h>
+#	else
+		extern char * malloc();
+#	endif
+#endif
+
+#include <stdio.h>
+
+#include "gsm.h"
+#include "private.h"
+#include "proto.h"
+
+gsm gsm_create P0()
+{
+	gsm  r;
+
+	r = (gsm)malloc(sizeof(struct gsm_state));
+	if (!r) return r;
+
+	memset((char *)r, 0, sizeof(*r));
+	r->nrp = 40;
+
+	return r;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_decode.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,361 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_decode.c,v 1.2 1996/07/02 09:59:05 jutta Exp $ */
+
+#include "private.h"
+
+#include "gsm.h"
+#include "proto.h"
+
+int gsm_decode P3((s, c, target), gsm s, gsm_byte * c, gsm_signal * target)
+{
+	word  	LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
+
+#ifdef WAV49
+	if (s->wav_fmt) {
+
+		uword sr = 0;
+
+		s->frame_index = !s->frame_index;
+		if (s->frame_index) {
+
+			sr = *c++;
+			LARc[0] = sr & 0x3f;  sr >>= 6;
+			sr |= (uword)*c++ << 2;
+			LARc[1] = sr & 0x3f;  sr >>= 6;
+			sr |= (uword)*c++ << 4;
+			LARc[2] = sr & 0x1f;  sr >>= 5;
+			LARc[3] = sr & 0x1f;  sr >>= 5;
+			sr |= (uword)*c++ << 2;
+			LARc[4] = sr & 0xf;  sr >>= 4;
+			LARc[5] = sr & 0xf;  sr >>= 4;
+			sr |= (uword)*c++ << 2;			/* 5 */
+			LARc[6] = sr & 0x7;  sr >>= 3;
+			LARc[7] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[0] = sr & 0x7f;  sr >>= 7;
+			bc[0] = sr & 0x3;  sr >>= 2;
+			Mc[0] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[0] = sr & 0x3f;  sr >>= 6;
+			xmc[0] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[1] = sr & 0x7;  sr >>= 3;
+			xmc[2] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[3] = sr & 0x7;  sr >>= 3;
+			xmc[4] = sr & 0x7;  sr >>= 3;
+			xmc[5] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 10 */
+			xmc[6] = sr & 0x7;  sr >>= 3;
+			xmc[7] = sr & 0x7;  sr >>= 3;
+			xmc[8] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[9] = sr & 0x7;  sr >>= 3;
+			xmc[10] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[11] = sr & 0x7;  sr >>= 3;
+			xmc[12] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[1] = sr & 0x7f;  sr >>= 7;
+			bc[1] = sr & 0x3;  sr >>= 2;
+			Mc[1] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[1] = sr & 0x3f;  sr >>= 6;
+			xmc[13] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 15 */
+			xmc[14] = sr & 0x7;  sr >>= 3;
+			xmc[15] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[16] = sr & 0x7;  sr >>= 3;
+			xmc[17] = sr & 0x7;  sr >>= 3;
+			xmc[18] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[19] = sr & 0x7;  sr >>= 3;
+			xmc[20] = sr & 0x7;  sr >>= 3;
+			xmc[21] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[22] = sr & 0x7;  sr >>= 3;
+			xmc[23] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[24] = sr & 0x7;  sr >>= 3;
+			xmc[25] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;			/* 20 */
+			Nc[2] = sr & 0x7f;  sr >>= 7;
+			bc[2] = sr & 0x3;  sr >>= 2;
+			Mc[2] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[2] = sr & 0x3f;  sr >>= 6;
+			xmc[26] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[27] = sr & 0x7;  sr >>= 3;
+			xmc[28] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[29] = sr & 0x7;  sr >>= 3;
+			xmc[30] = sr & 0x7;  sr >>= 3;
+			xmc[31] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[32] = sr & 0x7;  sr >>= 3;
+			xmc[33] = sr & 0x7;  sr >>= 3;
+			xmc[34] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 25 */
+			xmc[35] = sr & 0x7;  sr >>= 3;
+			xmc[36] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[37] = sr & 0x7;  sr >>= 3;
+			xmc[38] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[3] = sr & 0x7f;  sr >>= 7;
+			bc[3] = sr & 0x3;  sr >>= 2;
+			Mc[3] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[3] = sr & 0x3f;  sr >>= 6;
+			xmc[39] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[40] = sr & 0x7;  sr >>= 3;
+			xmc[41] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;			/* 30 */
+			xmc[42] = sr & 0x7;  sr >>= 3;
+			xmc[43] = sr & 0x7;  sr >>= 3;
+			xmc[44] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[45] = sr & 0x7;  sr >>= 3;
+			xmc[46] = sr & 0x7;  sr >>= 3;
+			xmc[47] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[48] = sr & 0x7;  sr >>= 3;
+			xmc[49] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[50] = sr & 0x7;  sr >>= 3;
+			xmc[51] = sr & 0x7;  sr >>= 3;
+
+			s->frame_chain = sr & 0xf;
+		}
+		else {
+			sr = s->frame_chain;
+			sr |= (uword)*c++ << 4;			/* 1 */
+			LARc[0] = sr & 0x3f;  sr >>= 6;
+			LARc[1] = sr & 0x3f;  sr >>= 6;
+			sr = *c++;
+			LARc[2] = sr & 0x1f;  sr >>= 5;
+			sr |= (uword)*c++ << 3;
+			LARc[3] = sr & 0x1f;  sr >>= 5;
+			LARc[4] = sr & 0xf;  sr >>= 4;
+			sr |= (uword)*c++ << 2;
+			LARc[5] = sr & 0xf;  sr >>= 4;
+			LARc[6] = sr & 0x7;  sr >>= 3;
+			LARc[7] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 5 */
+			Nc[0] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;
+			bc[0] = sr & 0x3;  sr >>= 2;
+			Mc[0] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[0] = sr & 0x3f;  sr >>= 6;
+			xmc[0] = sr & 0x7;  sr >>= 3;
+			xmc[1] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[2] = sr & 0x7;  sr >>= 3;
+			xmc[3] = sr & 0x7;  sr >>= 3;
+			xmc[4] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[5] = sr & 0x7;  sr >>= 3;
+			xmc[6] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;			/* 10 */
+			xmc[7] = sr & 0x7;  sr >>= 3;
+			xmc[8] = sr & 0x7;  sr >>= 3;
+			xmc[9] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[10] = sr & 0x7;  sr >>= 3;
+			xmc[11] = sr & 0x7;  sr >>= 3;
+			xmc[12] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[1] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;
+			bc[1] = sr & 0x3;  sr >>= 2;
+			Mc[1] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[1] = sr & 0x3f;  sr >>= 6;
+			xmc[13] = sr & 0x7;  sr >>= 3;
+			xmc[14] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 15 */
+			xmc[15] = sr & 0x7;  sr >>= 3;
+			xmc[16] = sr & 0x7;  sr >>= 3;
+			xmc[17] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[18] = sr & 0x7;  sr >>= 3;
+			xmc[19] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[20] = sr & 0x7;  sr >>= 3;
+			xmc[21] = sr & 0x7;  sr >>= 3;
+			xmc[22] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[23] = sr & 0x7;  sr >>= 3;
+			xmc[24] = sr & 0x7;  sr >>= 3;
+			xmc[25] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[2] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;			/* 20 */
+			bc[2] = sr & 0x3;  sr >>= 2;
+			Mc[2] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[2] = sr & 0x3f;  sr >>= 6;
+			xmc[26] = sr & 0x7;  sr >>= 3;
+			xmc[27] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;	
+			xmc[28] = sr & 0x7;  sr >>= 3;
+			xmc[29] = sr & 0x7;  sr >>= 3;
+			xmc[30] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[31] = sr & 0x7;  sr >>= 3;
+			xmc[32] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[33] = sr & 0x7;  sr >>= 3;
+			xmc[34] = sr & 0x7;  sr >>= 3;
+			xmc[35] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 25 */
+			xmc[36] = sr & 0x7;  sr >>= 3;
+			xmc[37] = sr & 0x7;  sr >>= 3;
+			xmc[38] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[3] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;		
+			bc[3] = sr & 0x3;  sr >>= 2;
+			Mc[3] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[3] = sr & 0x3f;  sr >>= 6;
+			xmc[39] = sr & 0x7;  sr >>= 3;
+			xmc[40] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[41] = sr & 0x7;  sr >>= 3;
+			xmc[42] = sr & 0x7;  sr >>= 3;
+			xmc[43] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 30 */
+			xmc[44] = sr & 0x7;  sr >>= 3;
+			xmc[45] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[46] = sr & 0x7;  sr >>= 3;
+			xmc[47] = sr & 0x7;  sr >>= 3;
+			xmc[48] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[49] = sr & 0x7;  sr >>= 3;
+			xmc[50] = sr & 0x7;  sr >>= 3;
+			xmc[51] = sr & 0x7;  sr >>= 3;
+		}
+	}
+	else
+#endif
+	{
+		/* GSM_MAGIC  = (*c >> 4) & 0xF; */
+
+		if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1;
+
+		LARc[0]  = (*c++ & 0xF) << 2;		/* 1 */
+		LARc[0] |= (*c >> 6) & 0x3;
+		LARc[1]  = *c++ & 0x3F;
+		LARc[2]  = (*c >> 3) & 0x1F;
+		LARc[3]  = (*c++ & 0x7) << 2;
+		LARc[3] |= (*c >> 6) & 0x3;
+		LARc[4]  = (*c >> 2) & 0xF;
+		LARc[5]  = (*c++ & 0x3) << 2;
+		LARc[5] |= (*c >> 6) & 0x3;
+		LARc[6]  = (*c >> 3) & 0x7;
+		LARc[7]  = *c++ & 0x7;
+		Nc[0]  = (*c >> 1) & 0x7F;
+		bc[0]  = (*c++ & 0x1) << 1;
+		bc[0] |= (*c >> 7) & 0x1;
+		Mc[0]  = (*c >> 5) & 0x3;
+		xmaxc[0]  = (*c++ & 0x1F) << 1;
+		xmaxc[0] |= (*c >> 7) & 0x1;
+		xmc[0]  = (*c >> 4) & 0x7;
+		xmc[1]  = (*c >> 1) & 0x7;
+		xmc[2]  = (*c++ & 0x1) << 2;
+		xmc[2] |= (*c >> 6) & 0x3;
+		xmc[3]  = (*c >> 3) & 0x7;
+		xmc[4]  = *c++ & 0x7;
+		xmc[5]  = (*c >> 5) & 0x7;
+		xmc[6]  = (*c >> 2) & 0x7;
+		xmc[7]  = (*c++ & 0x3) << 1;		/* 10 */
+		xmc[7] |= (*c >> 7) & 0x1;
+		xmc[8]  = (*c >> 4) & 0x7;
+		xmc[9]  = (*c >> 1) & 0x7;
+		xmc[10]  = (*c++ & 0x1) << 2;
+		xmc[10] |= (*c >> 6) & 0x3;
+		xmc[11]  = (*c >> 3) & 0x7;
+		xmc[12]  = *c++ & 0x7;
+		Nc[1]  = (*c >> 1) & 0x7F;
+		bc[1]  = (*c++ & 0x1) << 1;
+		bc[1] |= (*c >> 7) & 0x1;
+		Mc[1]  = (*c >> 5) & 0x3;
+		xmaxc[1]  = (*c++ & 0x1F) << 1;
+		xmaxc[1] |= (*c >> 7) & 0x1;
+		xmc[13]  = (*c >> 4) & 0x7;
+		xmc[14]  = (*c >> 1) & 0x7;
+		xmc[15]  = (*c++ & 0x1) << 2;
+		xmc[15] |= (*c >> 6) & 0x3;
+		xmc[16]  = (*c >> 3) & 0x7;
+		xmc[17]  = *c++ & 0x7;
+		xmc[18]  = (*c >> 5) & 0x7;
+		xmc[19]  = (*c >> 2) & 0x7;
+		xmc[20]  = (*c++ & 0x3) << 1;
+		xmc[20] |= (*c >> 7) & 0x1;
+		xmc[21]  = (*c >> 4) & 0x7;
+		xmc[22]  = (*c >> 1) & 0x7;
+		xmc[23]  = (*c++ & 0x1) << 2;
+		xmc[23] |= (*c >> 6) & 0x3;
+		xmc[24]  = (*c >> 3) & 0x7;
+		xmc[25]  = *c++ & 0x7;
+		Nc[2]  = (*c >> 1) & 0x7F;
+		bc[2]  = (*c++ & 0x1) << 1;		/* 20 */
+		bc[2] |= (*c >> 7) & 0x1;
+		Mc[2]  = (*c >> 5) & 0x3;
+		xmaxc[2]  = (*c++ & 0x1F) << 1;
+		xmaxc[2] |= (*c >> 7) & 0x1;
+		xmc[26]  = (*c >> 4) & 0x7;
+		xmc[27]  = (*c >> 1) & 0x7;
+		xmc[28]  = (*c++ & 0x1) << 2;
+		xmc[28] |= (*c >> 6) & 0x3;
+		xmc[29]  = (*c >> 3) & 0x7;
+		xmc[30]  = *c++ & 0x7;
+		xmc[31]  = (*c >> 5) & 0x7;
+		xmc[32]  = (*c >> 2) & 0x7;
+		xmc[33]  = (*c++ & 0x3) << 1;
+		xmc[33] |= (*c >> 7) & 0x1;
+		xmc[34]  = (*c >> 4) & 0x7;
+		xmc[35]  = (*c >> 1) & 0x7;
+		xmc[36]  = (*c++ & 0x1) << 2;
+		xmc[36] |= (*c >> 6) & 0x3;
+		xmc[37]  = (*c >> 3) & 0x7;
+		xmc[38]  = *c++ & 0x7;
+		Nc[3]  = (*c >> 1) & 0x7F;
+		bc[3]  = (*c++ & 0x1) << 1;
+		bc[3] |= (*c >> 7) & 0x1;
+		Mc[3]  = (*c >> 5) & 0x3;
+		xmaxc[3]  = (*c++ & 0x1F) << 1;
+		xmaxc[3] |= (*c >> 7) & 0x1;
+		xmc[39]  = (*c >> 4) & 0x7;
+		xmc[40]  = (*c >> 1) & 0x7;
+		xmc[41]  = (*c++ & 0x1) << 2;
+		xmc[41] |= (*c >> 6) & 0x3;
+		xmc[42]  = (*c >> 3) & 0x7;
+		xmc[43]  = *c++ & 0x7;			/* 30  */
+		xmc[44]  = (*c >> 5) & 0x7;
+		xmc[45]  = (*c >> 2) & 0x7;
+		xmc[46]  = (*c++ & 0x3) << 1;
+		xmc[46] |= (*c >> 7) & 0x1;
+		xmc[47]  = (*c >> 4) & 0x7;
+		xmc[48]  = (*c >> 1) & 0x7;
+		xmc[49]  = (*c++ & 0x1) << 2;
+		xmc[49] |= (*c >> 6) & 0x3;
+		xmc[50]  = (*c >> 3) & 0x7;
+		xmc[51]  = *c & 0x7;			/* 33 */
+	}
+
+	Gsm_Decoder(s, LARc, Nc, bc, Mc, xmaxc, xmc, target);
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_destroy.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,26 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_destroy.c,v 1.3 1994/11/28 19:52:25 jutta Exp $ */
+
+#include "gsm.h"
+#include "config.h"
+#include "proto.h"
+
+#ifdef	HAS_STDLIB_H
+#	include	<stdlib.h>
+#else
+#	ifdef	HAS_MALLOC_H
+#		include 	<malloc.h>
+#	else
+		extern void free();
+#	endif
+#endif
+
+void gsm_destroy P1((S), gsm S)
+{
+	if (S) free((char *)S);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_encode.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,451 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_encode.c,v 1.2 1996/07/02 09:59:05 jutta Exp $ */
+
+#include "private.h"
+#include "gsm.h"
+#include "proto.h"
+
+void gsm_encode P3((s, source, c), gsm s, gsm_signal * source, gsm_byte * c)
+{
+	word	 	LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
+
+	Gsm_Coder(s, source, LARc, Nc, bc, Mc, xmaxc, xmc);
+
+
+	/*	variable	size
+
+		GSM_MAGIC	4
+
+		LARc[0]		6
+		LARc[1]		6
+		LARc[2]		5
+		LARc[3]		5
+		LARc[4]		4
+		LARc[5]		4
+		LARc[6]		3
+		LARc[7]		3
+
+		Nc[0]		7
+		bc[0]		2
+		Mc[0]		2
+		xmaxc[0]	6
+		xmc[0]		3
+		xmc[1]		3
+		xmc[2]		3
+		xmc[3]		3
+		xmc[4]		3
+		xmc[5]		3
+		xmc[6]		3
+		xmc[7]		3
+		xmc[8]		3
+		xmc[9]		3
+		xmc[10]		3
+		xmc[11]		3
+		xmc[12]		3
+
+		Nc[1]		7
+		bc[1]		2
+		Mc[1]		2
+		xmaxc[1]	6
+		xmc[13]		3
+		xmc[14]		3
+		xmc[15]		3
+		xmc[16]		3
+		xmc[17]		3
+		xmc[18]		3
+		xmc[19]		3
+		xmc[20]		3
+		xmc[21]		3
+		xmc[22]		3
+		xmc[23]		3
+		xmc[24]		3
+		xmc[25]		3
+
+		Nc[2]		7
+		bc[2]		2
+		Mc[2]		2
+		xmaxc[2]	6
+		xmc[26]		3
+		xmc[27]		3
+		xmc[28]		3
+		xmc[29]		3
+		xmc[30]		3
+		xmc[31]		3
+		xmc[32]		3
+		xmc[33]		3
+		xmc[34]		3
+		xmc[35]		3
+		xmc[36]		3
+		xmc[37]		3
+		xmc[38]		3
+
+		Nc[3]		7
+		bc[3]		2
+		Mc[3]		2
+		xmaxc[3]	6
+		xmc[39]		3
+		xmc[40]		3
+		xmc[41]		3
+		xmc[42]		3
+		xmc[43]		3
+		xmc[44]		3
+		xmc[45]		3
+		xmc[46]		3
+		xmc[47]		3
+		xmc[48]		3
+		xmc[49]		3
+		xmc[50]		3
+		xmc[51]		3
+	*/
+
+#ifdef WAV49
+
+	if (s->wav_fmt) {
+		s->frame_index = !s->frame_index;
+		if (s->frame_index) {
+
+			uword sr;
+
+			sr = 0;
+			sr = sr >> 6 | LARc[0] << 10;
+			sr = sr >> 6 | LARc[1] << 10;
+			*c++ = sr >> 4;
+			sr = sr >> 5 | LARc[2] << 11;
+			*c++ = sr >> 7;
+			sr = sr >> 5 | LARc[3] << 11;
+			sr = sr >> 4 | LARc[4] << 12;
+			*c++ = sr >> 6;
+			sr = sr >> 4 | LARc[5] << 12;
+			sr = sr >> 3 | LARc[6] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | LARc[7] << 13;
+			sr = sr >> 7 | Nc[0] << 9;
+			*c++ = sr >> 5;
+			sr = sr >> 2 | bc[0] << 14;
+			sr = sr >> 2 | Mc[0] << 14;
+			sr = sr >> 6 | xmaxc[0] << 10;
+			*c++ = sr >> 3;
+			sr = sr >> 3 | xmc[0] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[1] << 13;
+			sr = sr >> 3 | xmc[2] << 13;
+			sr = sr >> 3 | xmc[3] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[4] << 13;
+			sr = sr >> 3 | xmc[5] << 13;
+			sr = sr >> 3 | xmc[6] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[7] << 13;
+			sr = sr >> 3 | xmc[8] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[9] << 13;
+			sr = sr >> 3 | xmc[10] << 13;
+			sr = sr >> 3 | xmc[11] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[12] << 13;
+			sr = sr >> 7 | Nc[1] << 9;
+			*c++ = sr >> 5;
+			sr = sr >> 2 | bc[1] << 14;
+			sr = sr >> 2 | Mc[1] << 14;
+			sr = sr >> 6 | xmaxc[1] << 10;
+			*c++ = sr >> 3;
+			sr = sr >> 3 | xmc[13] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[14] << 13;
+			sr = sr >> 3 | xmc[15] << 13;
+			sr = sr >> 3 | xmc[16] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[17] << 13;
+			sr = sr >> 3 | xmc[18] << 13;
+			sr = sr >> 3 | xmc[19] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[20] << 13;
+			sr = sr >> 3 | xmc[21] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[22] << 13;
+			sr = sr >> 3 | xmc[23] << 13;
+			sr = sr >> 3 | xmc[24] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[25] << 13;
+			sr = sr >> 7 | Nc[2] << 9;
+			*c++ = sr >> 5;
+			sr = sr >> 2 | bc[2] << 14;
+			sr = sr >> 2 | Mc[2] << 14;
+			sr = sr >> 6 | xmaxc[2] << 10;
+			*c++ = sr >> 3;
+			sr = sr >> 3 | xmc[26] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[27] << 13;
+			sr = sr >> 3 | xmc[28] << 13;
+			sr = sr >> 3 | xmc[29] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[30] << 13;
+			sr = sr >> 3 | xmc[31] << 13;
+			sr = sr >> 3 | xmc[32] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[33] << 13;
+			sr = sr >> 3 | xmc[34] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[35] << 13;
+			sr = sr >> 3 | xmc[36] << 13;
+			sr = sr >> 3 | xmc[37] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[38] << 13;
+			sr = sr >> 7 | Nc[3] << 9;
+			*c++ = sr >> 5;
+			sr = sr >> 2 | bc[3] << 14;
+			sr = sr >> 2 | Mc[3] << 14;
+			sr = sr >> 6 | xmaxc[3] << 10;
+			*c++ = sr >> 3;
+			sr = sr >> 3 | xmc[39] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[40] << 13;
+			sr = sr >> 3 | xmc[41] << 13;
+			sr = sr >> 3 | xmc[42] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[43] << 13;
+			sr = sr >> 3 | xmc[44] << 13;
+			sr = sr >> 3 | xmc[45] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[46] << 13;
+			sr = sr >> 3 | xmc[47] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[48] << 13;
+			sr = sr >> 3 | xmc[49] << 13;
+			sr = sr >> 3 | xmc[50] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[51] << 13;
+			sr = sr >> 4;
+			*c = sr >> 8;
+			s->frame_chain = *c;
+		}
+		else {
+			uword sr;
+
+			sr = 0;
+			sr = sr >> 4 | s->frame_chain << 12;
+			sr = sr >> 6 | LARc[0] << 10;
+			*c++ = sr >> 6;
+			sr = sr >> 6 | LARc[1] << 10;
+			*c++ = sr >> 8;
+			sr = sr >> 5 | LARc[2] << 11;
+			sr = sr >> 5 | LARc[3] << 11;
+			*c++ = sr >> 6;
+			sr = sr >> 4 | LARc[4] << 12;
+			sr = sr >> 4 | LARc[5] << 12;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | LARc[6] << 13;
+			sr = sr >> 3 | LARc[7] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 7 | Nc[0] << 9;
+			sr = sr >> 2 | bc[0] << 14;
+			*c++ = sr >> 7;
+			sr = sr >> 2 | Mc[0] << 14;
+			sr = sr >> 6 | xmaxc[0] << 10;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[0] << 13;
+			sr = sr >> 3 | xmc[1] << 13;
+			sr = sr >> 3 | xmc[2] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[3] << 13;
+			sr = sr >> 3 | xmc[4] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[5] << 13;
+			sr = sr >> 3 | xmc[6] << 13;
+			sr = sr >> 3 | xmc[7] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[8] << 13;
+			sr = sr >> 3 | xmc[9] << 13;
+			sr = sr >> 3 | xmc[10] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[11] << 13;
+			sr = sr >> 3 | xmc[12] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 7 | Nc[1] << 9;
+			sr = sr >> 2 | bc[1] << 14;
+			*c++ = sr >> 7;
+			sr = sr >> 2 | Mc[1] << 14;
+			sr = sr >> 6 | xmaxc[1] << 10;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[13] << 13;
+			sr = sr >> 3 | xmc[14] << 13;
+			sr = sr >> 3 | xmc[15] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[16] << 13;
+			sr = sr >> 3 | xmc[17] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[18] << 13;
+			sr = sr >> 3 | xmc[19] << 13;
+			sr = sr >> 3 | xmc[20] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[21] << 13;
+			sr = sr >> 3 | xmc[22] << 13;
+			sr = sr >> 3 | xmc[23] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[24] << 13;
+			sr = sr >> 3 | xmc[25] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 7 | Nc[2] << 9;
+			sr = sr >> 2 | bc[2] << 14;
+			*c++ = sr >> 7;
+			sr = sr >> 2 | Mc[2] << 14;
+			sr = sr >> 6 | xmaxc[2] << 10;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[26] << 13;
+			sr = sr >> 3 | xmc[27] << 13;
+			sr = sr >> 3 | xmc[28] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[29] << 13;
+			sr = sr >> 3 | xmc[30] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[31] << 13;
+			sr = sr >> 3 | xmc[32] << 13;
+			sr = sr >> 3 | xmc[33] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[34] << 13;
+			sr = sr >> 3 | xmc[35] << 13;
+			sr = sr >> 3 | xmc[36] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[37] << 13;
+			sr = sr >> 3 | xmc[38] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 7 | Nc[3] << 9;
+			sr = sr >> 2 | bc[3] << 14;
+			*c++ = sr >> 7;
+			sr = sr >> 2 | Mc[3] << 14;
+			sr = sr >> 6 | xmaxc[3] << 10;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[39] << 13;
+			sr = sr >> 3 | xmc[40] << 13;
+			sr = sr >> 3 | xmc[41] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[42] << 13;
+			sr = sr >> 3 | xmc[43] << 13;
+			*c++ = sr >> 8;
+			sr = sr >> 3 | xmc[44] << 13;
+			sr = sr >> 3 | xmc[45] << 13;
+			sr = sr >> 3 | xmc[46] << 13;
+			*c++ = sr >> 7;
+			sr = sr >> 3 | xmc[47] << 13;
+			sr = sr >> 3 | xmc[48] << 13;
+			sr = sr >> 3 | xmc[49] << 13;
+			*c++ = sr >> 6;
+			sr = sr >> 3 | xmc[50] << 13;
+			sr = sr >> 3 | xmc[51] << 13;
+			*c++ = sr >> 8;
+		}
+	}
+
+	else
+
+#endif	/* WAV49 */
+	{
+
+		*c++ =   ((GSM_MAGIC & 0xF) << 4)		/* 1 */
+		       | ((LARc[0] >> 2) & 0xF);
+		*c++ =   ((LARc[0] & 0x3) << 6)
+		       | (LARc[1] & 0x3F);
+		*c++ =   ((LARc[2] & 0x1F) << 3)
+		       | ((LARc[3] >> 2) & 0x7);
+		*c++ =   ((LARc[3] & 0x3) << 6)
+		       | ((LARc[4] & 0xF) << 2)
+		       | ((LARc[5] >> 2) & 0x3);
+		*c++ =   ((LARc[5] & 0x3) << 6)
+		       | ((LARc[6] & 0x7) << 3)
+		       | (LARc[7] & 0x7);
+		*c++ =   ((Nc[0] & 0x7F) << 1)
+		       | ((bc[0] >> 1) & 0x1);
+		*c++ =   ((bc[0] & 0x1) << 7)
+		       | ((Mc[0] & 0x3) << 5)
+		       | ((xmaxc[0] >> 1) & 0x1F);
+		*c++ =   ((xmaxc[0] & 0x1) << 7)
+		       | ((xmc[0] & 0x7) << 4)
+		       | ((xmc[1] & 0x7) << 1)
+		       | ((xmc[2] >> 2) & 0x1);
+		*c++ =   ((xmc[2] & 0x3) << 6)
+		       | ((xmc[3] & 0x7) << 3)
+		       | (xmc[4] & 0x7);
+		*c++ =   ((xmc[5] & 0x7) << 5)			/* 10 */
+		       | ((xmc[6] & 0x7) << 2)
+		       | ((xmc[7] >> 1) & 0x3);
+		*c++ =   ((xmc[7] & 0x1) << 7)
+		       | ((xmc[8] & 0x7) << 4)
+		       | ((xmc[9] & 0x7) << 1)
+		       | ((xmc[10] >> 2) & 0x1);
+		*c++ =   ((xmc[10] & 0x3) << 6)
+		       | ((xmc[11] & 0x7) << 3)
+		       | (xmc[12] & 0x7);
+		*c++ =   ((Nc[1] & 0x7F) << 1)
+		       | ((bc[1] >> 1) & 0x1);
+		*c++ =   ((bc[1] & 0x1) << 7)
+		       | ((Mc[1] & 0x3) << 5)
+		       | ((xmaxc[1] >> 1) & 0x1F);
+		*c++ =   ((xmaxc[1] & 0x1) << 7)
+		       | ((xmc[13] & 0x7) << 4)
+		       | ((xmc[14] & 0x7) << 1)
+		       | ((xmc[15] >> 2) & 0x1);
+		*c++ =   ((xmc[15] & 0x3) << 6)
+		       | ((xmc[16] & 0x7) << 3)
+		       | (xmc[17] & 0x7);
+		*c++ =   ((xmc[18] & 0x7) << 5)
+		       | ((xmc[19] & 0x7) << 2)
+		       | ((xmc[20] >> 1) & 0x3);
+		*c++ =   ((xmc[20] & 0x1) << 7)
+		       | ((xmc[21] & 0x7) << 4)
+		       | ((xmc[22] & 0x7) << 1)
+		       | ((xmc[23] >> 2) & 0x1);
+		*c++ =   ((xmc[23] & 0x3) << 6)
+		       | ((xmc[24] & 0x7) << 3)
+		       | (xmc[25] & 0x7);
+		*c++ =   ((Nc[2] & 0x7F) << 1)			/* 20 */
+		       | ((bc[2] >> 1) & 0x1);
+		*c++ =   ((bc[2] & 0x1) << 7)
+		       | ((Mc[2] & 0x3) << 5)
+		       | ((xmaxc[2] >> 1) & 0x1F);
+		*c++ =   ((xmaxc[2] & 0x1) << 7)
+		       | ((xmc[26] & 0x7) << 4)
+		       | ((xmc[27] & 0x7) << 1)
+		       | ((xmc[28] >> 2) & 0x1);
+		*c++ =   ((xmc[28] & 0x3) << 6)
+		       | ((xmc[29] & 0x7) << 3)
+		       | (xmc[30] & 0x7);
+		*c++ =   ((xmc[31] & 0x7) << 5)
+		       | ((xmc[32] & 0x7) << 2)
+		       | ((xmc[33] >> 1) & 0x3);
+		*c++ =   ((xmc[33] & 0x1) << 7)
+		       | ((xmc[34] & 0x7) << 4)
+		       | ((xmc[35] & 0x7) << 1)
+		       | ((xmc[36] >> 2) & 0x1);
+		*c++ =   ((xmc[36] & 0x3) << 6)
+		       | ((xmc[37] & 0x7) << 3)
+		       | (xmc[38] & 0x7);
+		*c++ =   ((Nc[3] & 0x7F) << 1)
+		       | ((bc[3] >> 1) & 0x1);
+		*c++ =   ((bc[3] & 0x1) << 7)
+		       | ((Mc[3] & 0x3) << 5)
+		       | ((xmaxc[3] >> 1) & 0x1F);
+		*c++ =   ((xmaxc[3] & 0x1) << 7)
+		       | ((xmc[39] & 0x7) << 4)
+		       | ((xmc[40] & 0x7) << 1)
+		       | ((xmc[41] >> 2) & 0x1);
+		*c++ =   ((xmc[41] & 0x3) << 6)			/* 30 */
+		       | ((xmc[42] & 0x7) << 3)
+		       | (xmc[43] & 0x7);
+		*c++ =   ((xmc[44] & 0x7) << 5)
+		       | ((xmc[45] & 0x7) << 2)
+		       | ((xmc[46] >> 1) & 0x3);
+		*c++ =   ((xmc[46] & 0x1) << 7)
+		       | ((xmc[47] & 0x7) << 4)
+		       | ((xmc[48] & 0x7) << 1)
+		       | ((xmc[49] >> 2) & 0x1);
+		*c++ =   ((xmc[49] & 0x3) << 6)
+		       | ((xmc[50] & 0x7) << 3)
+		       | (xmc[51] & 0x7);
+
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_explode.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,419 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_explode.c,v 1.2 1996/07/02 14:32:42 jutta Exp jutta $ */
+
+#include "private.h"
+#include "gsm.h"
+#include "proto.h"
+
+int gsm_explode P3((s, c, target), gsm s, gsm_byte * c, gsm_signal * target)
+{
+#	define	LARc	target
+#	define	Nc	*((gsm_signal (*) [17])(target + 8))
+#	define	bc	*((gsm_signal (*) [17])(target + 9))
+#	define	Mc	*((gsm_signal (*) [17])(target + 10))
+#	define	xmaxc	*((gsm_signal (*) [17])(target + 11))
+
+// Wirlab
+	(void)s;
+
+#ifdef WAV49
+	if (s->wav_fmt) {
+
+		uword sr = 0;
+
+		if (s->frame_index == 1) {
+
+			sr = *c++;
+			LARc[0] = sr & 0x3f;  sr >>= 6;
+			sr |= (uword)*c++ << 2;
+			LARc[1] = sr & 0x3f;  sr >>= 6;
+			sr |= (uword)*c++ << 4;
+			LARc[2] = sr & 0x1f;  sr >>= 5;
+			LARc[3] = sr & 0x1f;  sr >>= 5;
+			sr |= (uword)*c++ << 2;
+			LARc[4] = sr & 0xf;  sr >>= 4;
+			LARc[5] = sr & 0xf;  sr >>= 4;
+			sr |= (uword)*c++ << 2;			/* 5 */
+			LARc[6] = sr & 0x7;  sr >>= 3;
+			LARc[7] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[0] = sr & 0x7f;  sr >>= 7;
+			bc[0] = sr & 0x3;  sr >>= 2;
+			Mc[0] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[0] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(target + 12)
+			xmc[0] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[1] = sr & 0x7;  sr >>= 3;
+			xmc[2] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[3] = sr & 0x7;  sr >>= 3;
+			xmc[4] = sr & 0x7;  sr >>= 3;
+			xmc[5] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 10 */
+			xmc[6] = sr & 0x7;  sr >>= 3;
+			xmc[7] = sr & 0x7;  sr >>= 3;
+			xmc[8] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[9] = sr & 0x7;  sr >>= 3;
+			xmc[10] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[11] = sr & 0x7;  sr >>= 3;
+			xmc[12] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[1] = sr & 0x7f;  sr >>= 7;
+			bc[1] = sr & 0x3;  sr >>= 2;
+			Mc[1] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[1] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(target + 29 - 13)
+
+			xmc[13] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 15 */
+			xmc[14] = sr & 0x7;  sr >>= 3;
+			xmc[15] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[16] = sr & 0x7;  sr >>= 3;
+			xmc[17] = sr & 0x7;  sr >>= 3;
+			xmc[18] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[19] = sr & 0x7;  sr >>= 3;
+			xmc[20] = sr & 0x7;  sr >>= 3;
+			xmc[21] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[22] = sr & 0x7;  sr >>= 3;
+			xmc[23] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[24] = sr & 0x7;  sr >>= 3;
+			xmc[25] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;			/* 20 */
+			Nc[2] = sr & 0x7f;  sr >>= 7;
+			bc[2] = sr & 0x3;  sr >>= 2;
+			Mc[2] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[2] = sr & 0x3f;  sr >>= 6;
+
+#undef	xmc
+#define	xmc	(target + 46 - 26)
+
+			xmc[26] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[27] = sr & 0x7;  sr >>= 3;
+			xmc[28] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[29] = sr & 0x7;  sr >>= 3;
+			xmc[30] = sr & 0x7;  sr >>= 3;
+			xmc[31] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[32] = sr & 0x7;  sr >>= 3;
+			xmc[33] = sr & 0x7;  sr >>= 3;
+			xmc[34] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 25 */
+			xmc[35] = sr & 0x7;  sr >>= 3;
+			xmc[36] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[37] = sr & 0x7;  sr >>= 3;
+			xmc[38] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[3] = sr & 0x7f;  sr >>= 7;
+			bc[3] = sr & 0x3;  sr >>= 2;
+			Mc[3] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[3] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(target + 63 - 39)
+
+			xmc[39] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[40] = sr & 0x7;  sr >>= 3;
+			xmc[41] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;			/* 30 */
+			xmc[42] = sr & 0x7;  sr >>= 3;
+			xmc[43] = sr & 0x7;  sr >>= 3;
+			xmc[44] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[45] = sr & 0x7;  sr >>= 3;
+			xmc[46] = sr & 0x7;  sr >>= 3;
+			xmc[47] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[48] = sr & 0x7;  sr >>= 3;
+			xmc[49] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[50] = sr & 0x7;  sr >>= 3;
+			xmc[51] = sr & 0x7;  sr >>= 3;
+
+			s->frame_chain = sr & 0xf;
+		}
+		else {
+			sr = s->frame_chain;
+			sr |= (uword)*c++ << 4;			/* 1 */
+			LARc[0] = sr & 0x3f;  sr >>= 6;
+			LARc[1] = sr & 0x3f;  sr >>= 6;
+			sr = *c++;
+			LARc[2] = sr & 0x1f;  sr >>= 5;
+			sr |= (uword)*c++ << 3;
+			LARc[3] = sr & 0x1f;  sr >>= 5;
+			LARc[4] = sr & 0xf;  sr >>= 4;
+			sr |= (uword)*c++ << 2;
+			LARc[5] = sr & 0xf;  sr >>= 4;
+			LARc[6] = sr & 0x7;  sr >>= 3;
+			LARc[7] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 5 */
+			Nc[0] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;
+			bc[0] = sr & 0x3;  sr >>= 2;
+			Mc[0] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[0] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(target + 12)
+			xmc[0] = sr & 0x7;  sr >>= 3;
+			xmc[1] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[2] = sr & 0x7;  sr >>= 3;
+			xmc[3] = sr & 0x7;  sr >>= 3;
+			xmc[4] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[5] = sr & 0x7;  sr >>= 3;
+			xmc[6] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;			/* 10 */
+			xmc[7] = sr & 0x7;  sr >>= 3;
+			xmc[8] = sr & 0x7;  sr >>= 3;
+			xmc[9] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[10] = sr & 0x7;  sr >>= 3;
+			xmc[11] = sr & 0x7;  sr >>= 3;
+			xmc[12] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[1] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;
+			bc[1] = sr & 0x3;  sr >>= 2;
+			Mc[1] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[1] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(target + 29 - 13)
+
+			xmc[13] = sr & 0x7;  sr >>= 3;
+			xmc[14] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 15 */
+			xmc[15] = sr & 0x7;  sr >>= 3;
+			xmc[16] = sr & 0x7;  sr >>= 3;
+			xmc[17] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[18] = sr & 0x7;  sr >>= 3;
+			xmc[19] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[20] = sr & 0x7;  sr >>= 3;
+			xmc[21] = sr & 0x7;  sr >>= 3;
+			xmc[22] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[23] = sr & 0x7;  sr >>= 3;
+			xmc[24] = sr & 0x7;  sr >>= 3;
+			xmc[25] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[2] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;			/* 20 */
+			bc[2] = sr & 0x3;  sr >>= 2;
+			Mc[2] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[2] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(target + 46 - 26)
+			xmc[26] = sr & 0x7;  sr >>= 3;
+			xmc[27] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;	
+			xmc[28] = sr & 0x7;  sr >>= 3;
+			xmc[29] = sr & 0x7;  sr >>= 3;
+			xmc[30] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[31] = sr & 0x7;  sr >>= 3;
+			xmc[32] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[33] = sr & 0x7;  sr >>= 3;
+			xmc[34] = sr & 0x7;  sr >>= 3;
+			xmc[35] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 25 */
+			xmc[36] = sr & 0x7;  sr >>= 3;
+			xmc[37] = sr & 0x7;  sr >>= 3;
+			xmc[38] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[3] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;		
+			bc[3] = sr & 0x3;  sr >>= 2;
+			Mc[3] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[3] = sr & 0x3f;  sr >>= 6;
+
+#undef	xmc
+#define	xmc	(target + 63 - 39)
+
+			xmc[39] = sr & 0x7;  sr >>= 3;
+			xmc[40] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[41] = sr & 0x7;  sr >>= 3;
+			xmc[42] = sr & 0x7;  sr >>= 3;
+			xmc[43] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 30 */
+			xmc[44] = sr & 0x7;  sr >>= 3;
+			xmc[45] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[46] = sr & 0x7;  sr >>= 3;
+			xmc[47] = sr & 0x7;  sr >>= 3;
+			xmc[48] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[49] = sr & 0x7;  sr >>= 3;
+			xmc[50] = sr & 0x7;  sr >>= 3;
+			xmc[51] = sr & 0x7;  sr >>= 3;
+		}
+	}
+	else 
+#endif
+	{
+	/* GSM_MAGIC  = (*c >> 4) & 0xF; */
+
+	if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1;
+
+	LARc[0]  = (*c++ & 0xF) << 2;		/* 1 */
+	LARc[0] |= (*c >> 6) & 0x3;
+	LARc[1]  = *c++ & 0x3F;
+	LARc[2]  = (*c >> 3) & 0x1F;
+	LARc[3]  = (*c++ & 0x7) << 2;
+	LARc[3] |= (*c >> 6) & 0x3;
+	LARc[4]  = (*c >> 2) & 0xF;
+	LARc[5]  = (*c++ & 0x3) << 2;
+	LARc[5] |= (*c >> 6) & 0x3;
+	LARc[6]  = (*c >> 3) & 0x7;
+	LARc[7]  = *c++ & 0x7;
+
+	Nc[0]  = (*c >> 1) & 0x7F;
+
+	bc[0]  = (*c++ & 0x1) << 1;
+	bc[0] |= (*c >> 7) & 0x1;
+
+	Mc[0]  = (*c >> 5) & 0x3;
+
+	xmaxc[0]  = (*c++ & 0x1F) << 1;
+	xmaxc[0] |= (*c >> 7) & 0x1;
+
+#undef	xmc
+#define	xmc	(target + 12)
+
+	xmc[0]  = (*c >> 4) & 0x7;
+	xmc[1]  = (*c >> 1) & 0x7;
+	xmc[2]  = (*c++ & 0x1) << 2;
+	xmc[2] |= (*c >> 6) & 0x3;
+	xmc[3]  = (*c >> 3) & 0x7;
+	xmc[4]  = *c++ & 0x7;
+	xmc[5]  = (*c >> 5) & 0x7;
+	xmc[6]  = (*c >> 2) & 0x7;
+	xmc[7]  = (*c++ & 0x3) << 1;		/* 10 */
+	xmc[7] |= (*c >> 7) & 0x1;
+	xmc[8]  = (*c >> 4) & 0x7;
+	xmc[9]  = (*c >> 1) & 0x7;
+	xmc[10]  = (*c++ & 0x1) << 2;
+	xmc[10] |= (*c >> 6) & 0x3;
+	xmc[11]  = (*c >> 3) & 0x7;
+	xmc[12]  = *c++ & 0x7;
+
+	Nc[1]  = (*c >> 1) & 0x7F;
+
+	bc[1]  = (*c++ & 0x1) << 1;
+	bc[1] |= (*c >> 7) & 0x1;
+
+	Mc[1]  = (*c >> 5) & 0x3;
+
+	xmaxc[1]  = (*c++ & 0x1F) << 1;
+	xmaxc[1] |= (*c >> 7) & 0x1;
+
+#undef	xmc
+#define	xmc	(target + 29 - 13)
+
+	xmc[13]  = (*c >> 4) & 0x7;
+	xmc[14]  = (*c >> 1) & 0x7;
+	xmc[15]  = (*c++ & 0x1) << 2;
+	xmc[15] |= (*c >> 6) & 0x3;
+	xmc[16]  = (*c >> 3) & 0x7;
+	xmc[17]  = *c++ & 0x7;
+	xmc[18]  = (*c >> 5) & 0x7;
+	xmc[19]  = (*c >> 2) & 0x7;
+	xmc[20]  = (*c++ & 0x3) << 1;
+	xmc[20] |= (*c >> 7) & 0x1;
+	xmc[21]  = (*c >> 4) & 0x7;
+	xmc[22]  = (*c >> 1) & 0x7;
+	xmc[23]  = (*c++ & 0x1) << 2;
+	xmc[23] |= (*c >> 6) & 0x3;
+	xmc[24]  = (*c >> 3) & 0x7;
+	xmc[25]  = *c++ & 0x7;
+
+	Nc[2]  = (*c >> 1) & 0x7F;
+
+	bc[2]  = (*c++ & 0x1) << 1;		/* 20 */
+	bc[2] |= (*c >> 7) & 0x1;
+
+	Mc[2]  = (*c >> 5) & 0x3;
+
+	xmaxc[2]  = (*c++ & 0x1F) << 1;
+	xmaxc[2] |= (*c >> 7) & 0x1;
+
+#undef	xmc
+#define	xmc	(target + 46 - 26)
+
+	xmc[26]  = (*c >> 4) & 0x7;
+	xmc[27]  = (*c >> 1) & 0x7;
+	xmc[28]  = (*c++ & 0x1) << 2;
+	xmc[28] |= (*c >> 6) & 0x3;
+	xmc[29]  = (*c >> 3) & 0x7;
+	xmc[30]  = *c++ & 0x7;
+	xmc[31]  = (*c >> 5) & 0x7;
+	xmc[32]  = (*c >> 2) & 0x7;
+	xmc[33]  = (*c++ & 0x3) << 1;
+	xmc[33] |= (*c >> 7) & 0x1;
+	xmc[34]  = (*c >> 4) & 0x7;
+	xmc[35]  = (*c >> 1) & 0x7;
+	xmc[36]  = (*c++ & 0x1) << 2;
+	xmc[36] |= (*c >> 6) & 0x3;
+	xmc[37]  = (*c >> 3) & 0x7;
+	xmc[38]  = *c++ & 0x7;
+
+	Nc[3]  = (*c >> 1) & 0x7F;
+
+	bc[3]  = (*c++ & 0x1) << 1;
+	bc[3] |= (*c >> 7) & 0x1;
+
+	Mc[3]  = (*c >> 5) & 0x3;
+
+	xmaxc[3]  = (*c++ & 0x1F) << 1;
+	xmaxc[3] |= (*c >> 7) & 0x1;
+
+#undef	xmc
+#define	xmc	(target + 63 - 39)
+
+	xmc[39]  = (*c >> 4) & 0x7;
+	xmc[40]  = (*c >> 1) & 0x7;
+	xmc[41]  = (*c++ & 0x1) << 2;
+	xmc[41] |= (*c >> 6) & 0x3;
+	xmc[42]  = (*c >> 3) & 0x7;
+	xmc[43]  = *c++ & 0x7;			/* 30  */
+	xmc[44]  = (*c >> 5) & 0x7;
+	xmc[45]  = (*c >> 2) & 0x7;
+	xmc[46]  = (*c++ & 0x3) << 1;
+	xmc[46] |= (*c >> 7) & 0x1;
+	xmc[47]  = (*c >> 4) & 0x7;
+	xmc[48]  = (*c >> 1) & 0x7;
+	xmc[49]  = (*c++ & 0x1) << 2;
+	xmc[49] |= (*c >> 6) & 0x3;
+	xmc[50]  = (*c >> 3) & 0x7;
+	xmc[51]  = *c & 0x7;			/* 33 */
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_implode.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,518 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_implode.c,v 1.2 1996/07/02 14:32:43 jutta Exp jutta $ */
+
+#include "private.h"
+
+#include "gsm.h"
+#include "proto.h"
+
+void gsm_implode P3((s, source, c), gsm s, gsm_signal * source, gsm_byte * c)
+{
+	/*	variable	size	index
+
+		GSM_MAGIC	4	-
+
+		LARc[0]		6	0
+		LARc[1]		6	1
+		LARc[2]		5	2
+		LARc[3]		5	3
+		LARc[4]		4	4
+		LARc[5]		4	5
+		LARc[6]		3	6
+		LARc[7]		3	7
+
+		Nc[0]		7	8
+		bc[0]		2	9
+		Mc[0]		2	10
+		xmaxc[0]	6	11
+		xmc[0]		3	12
+		xmc[1]		3	13
+		xmc[2]		3	14
+		xmc[3]		3	15
+		xmc[4]		3	16
+		xmc[5]		3	17
+		xmc[6]		3	18
+		xmc[7]		3	19
+		xmc[8]		3	20
+		xmc[9]		3	21
+		xmc[10]		3	22
+		xmc[11]		3	23
+		xmc[12]		3	24
+
+		Nc[1]		7	25
+		bc[1]		2	26
+		Mc[1]		2	27
+		xmaxc[1]	6	28
+		xmc[13]		3	29
+		xmc[14]		3	30
+		xmc[15]		3	31
+		xmc[16]		3	32
+		xmc[17]		3	33
+		xmc[18]		3	34
+		xmc[19]		3	35
+		xmc[20]		3	36
+		xmc[21]		3	37
+		xmc[22]		3	38
+		xmc[23]		3	39
+		xmc[24]		3	40
+		xmc[25]		3	41
+
+		Nc[2]		7	42
+		bc[2]		2	43
+		Mc[2]		2	44
+		xmaxc[2]	6	45
+		xmc[26]		3	46
+		xmc[27]		3	47
+		xmc[28]		3	48
+		xmc[29]		3	49
+		xmc[30]		3	50
+		xmc[31]		3	51
+		xmc[32]		3	52
+		xmc[33]		3	53
+		xmc[34]		3	54
+		xmc[35]		3	55
+		xmc[36]		3	56
+		xmc[37]		3	57
+		xmc[38]		3	58
+
+		Nc[3]		7	59
+		bc[3]		2	60
+		Mc[3]		2	61
+		xmaxc[3]	6	62
+		xmc[39]		3	63
+		xmc[40]		3	64
+		xmc[41]		3	65
+		xmc[42]		3	66
+		xmc[43]		3	67
+		xmc[44]		3	68
+		xmc[45]		3	69
+		xmc[46]		3	70
+		xmc[47]		3	71
+		xmc[48]		3	72
+		xmc[49]		3	73
+		xmc[50]		3	74
+		xmc[51]		3	75
+	*/
+
+	/*	There are 76 parameters per frame.  The first eight are
+	 * 	unique.  The remaining 68 are four identical subframes of
+	 * 	17 parameters each.  gsm_implode converts from a representation
+	 * 	of these parameters as values in one array of signed words
+	 * 	to the "packed" version of a GSM frame.
+	 */
+
+#	define	LARc	source
+#	define	Nc	*((gsm_signal (*) [17])(source + 8))
+#	define	bc	*((gsm_signal (*) [17])(source + 9))
+#	define	Mc	*((gsm_signal (*) [17])(source + 10))
+#	define	xmaxc	*((gsm_signal (*) [17])(source + 11))
+
+// Wirlab
+	(void)s;
+
+#ifdef WAV49
+	if (s->wav_fmt) {
+
+		uword sr = 0;
+		if (s->frame_index == 0) {
+
+			sr = *c++;
+			LARc[0] = sr & 0x3f;  sr >>= 6;
+			sr |= (uword)*c++ << 2;
+			LARc[1] = sr & 0x3f;  sr >>= 6;
+			sr |= (uword)*c++ << 4;
+			LARc[2] = sr & 0x1f;  sr >>= 5;
+			LARc[3] = sr & 0x1f;  sr >>= 5;
+			sr |= (uword)*c++ << 2;
+			LARc[4] = sr & 0xf;  sr >>= 4;
+			LARc[5] = sr & 0xf;  sr >>= 4;
+			sr |= (uword)*c++ << 2;			/* 5 */
+			LARc[6] = sr & 0x7;  sr >>= 3;
+			LARc[7] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[0] = sr & 0x7f;  sr >>= 7;
+			bc[0] = sr & 0x3;  sr >>= 2;
+			Mc[0] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[0] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(source + 12)
+			xmc[0] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[1] = sr & 0x7;  sr >>= 3;
+			xmc[2] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[3] = sr & 0x7;  sr >>= 3;
+			xmc[4] = sr & 0x7;  sr >>= 3;
+			xmc[5] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 10 */
+			xmc[6] = sr & 0x7;  sr >>= 3;
+			xmc[7] = sr & 0x7;  sr >>= 3;
+			xmc[8] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[9] = sr & 0x7;  sr >>= 3;
+			xmc[10] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[11] = sr & 0x7;  sr >>= 3;
+			xmc[12] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[1] = sr & 0x7f;  sr >>= 7;
+			bc[1] = sr & 0x3;  sr >>= 2;
+			Mc[1] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[1] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(source + 29 - 13)
+			xmc[13] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 15 */
+			xmc[14] = sr & 0x7;  sr >>= 3;
+			xmc[15] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[16] = sr & 0x7;  sr >>= 3;
+			xmc[17] = sr & 0x7;  sr >>= 3;
+			xmc[18] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[19] = sr & 0x7;  sr >>= 3;
+			xmc[20] = sr & 0x7;  sr >>= 3;
+			xmc[21] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[22] = sr & 0x7;  sr >>= 3;
+			xmc[23] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[24] = sr & 0x7;  sr >>= 3;
+			xmc[25] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;			/* 20 */
+			Nc[2] = sr & 0x7f;  sr >>= 7;
+			bc[2] = sr & 0x3;  sr >>= 2;
+			Mc[2] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[2] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(source + 46 - 26)
+			xmc[26] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[27] = sr & 0x7;  sr >>= 3;
+			xmc[28] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[29] = sr & 0x7;  sr >>= 3;
+			xmc[30] = sr & 0x7;  sr >>= 3;
+			xmc[31] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[32] = sr & 0x7;  sr >>= 3;
+			xmc[33] = sr & 0x7;  sr >>= 3;
+			xmc[34] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 25 */
+			xmc[35] = sr & 0x7;  sr >>= 3;
+			xmc[36] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[37] = sr & 0x7;  sr >>= 3;
+			xmc[38] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 4;
+			Nc[3] = sr & 0x7f;  sr >>= 7;
+			bc[3] = sr & 0x3;  sr >>= 2;
+			Mc[3] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 1;
+			xmaxc[3] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(source + 63 - 39)
+
+			xmc[39] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[40] = sr & 0x7;  sr >>= 3;
+			xmc[41] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;			/* 30 */
+			xmc[42] = sr & 0x7;  sr >>= 3;
+			xmc[43] = sr & 0x7;  sr >>= 3;
+			xmc[44] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[45] = sr & 0x7;  sr >>= 3;
+			xmc[46] = sr & 0x7;  sr >>= 3;
+			xmc[47] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[48] = sr & 0x7;  sr >>= 3;
+			xmc[49] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[50] = sr & 0x7;  sr >>= 3;
+			xmc[51] = sr & 0x7;  sr >>= 3;
+
+			s->frame_chain = sr & 0xf;
+		}
+		else {
+			sr = s->frame_chain;
+			sr |= (uword)*c++ << 4;			/* 1 */
+			LARc[0] = sr & 0x3f;  sr >>= 6;
+			LARc[1] = sr & 0x3f;  sr >>= 6;
+			sr = *c++;
+			LARc[2] = sr & 0x1f;  sr >>= 5;
+			sr |= (uword)*c++ << 3;
+			LARc[3] = sr & 0x1f;  sr >>= 5;
+			LARc[4] = sr & 0xf;  sr >>= 4;
+			sr |= (uword)*c++ << 2;
+			LARc[5] = sr & 0xf;  sr >>= 4;
+			LARc[6] = sr & 0x7;  sr >>= 3;
+			LARc[7] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 5 */
+			Nc[0] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;
+			bc[0] = sr & 0x3;  sr >>= 2;
+			Mc[0] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[0] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(source + 12)
+			xmc[0] = sr & 0x7;  sr >>= 3;
+			xmc[1] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[2] = sr & 0x7;  sr >>= 3;
+			xmc[3] = sr & 0x7;  sr >>= 3;
+			xmc[4] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[5] = sr & 0x7;  sr >>= 3;
+			xmc[6] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;			/* 10 */
+			xmc[7] = sr & 0x7;  sr >>= 3;
+			xmc[8] = sr & 0x7;  sr >>= 3;
+			xmc[9] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[10] = sr & 0x7;  sr >>= 3;
+			xmc[11] = sr & 0x7;  sr >>= 3;
+			xmc[12] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[1] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;
+			bc[1] = sr & 0x3;  sr >>= 2;
+			Mc[1] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[1] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(source + 29 - 13)
+			xmc[13] = sr & 0x7;  sr >>= 3;
+			xmc[14] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 15 */
+			xmc[15] = sr & 0x7;  sr >>= 3;
+			xmc[16] = sr & 0x7;  sr >>= 3;
+			xmc[17] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[18] = sr & 0x7;  sr >>= 3;
+			xmc[19] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[20] = sr & 0x7;  sr >>= 3;
+			xmc[21] = sr & 0x7;  sr >>= 3;
+			xmc[22] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[23] = sr & 0x7;  sr >>= 3;
+			xmc[24] = sr & 0x7;  sr >>= 3;
+			xmc[25] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[2] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;			/* 20 */
+			bc[2] = sr & 0x3;  sr >>= 2;
+			Mc[2] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[2] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(source + 46 - 26)
+			xmc[26] = sr & 0x7;  sr >>= 3;
+			xmc[27] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;	
+			xmc[28] = sr & 0x7;  sr >>= 3;
+			xmc[29] = sr & 0x7;  sr >>= 3;
+			xmc[30] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			xmc[31] = sr & 0x7;  sr >>= 3;
+			xmc[32] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[33] = sr & 0x7;  sr >>= 3;
+			xmc[34] = sr & 0x7;  sr >>= 3;
+			xmc[35] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;			/* 25 */
+			xmc[36] = sr & 0x7;  sr >>= 3;
+			xmc[37] = sr & 0x7;  sr >>= 3;
+			xmc[38] = sr & 0x7;  sr >>= 3;
+			sr = *c++;
+			Nc[3] = sr & 0x7f;  sr >>= 7;
+			sr |= (uword)*c++ << 1;		
+			bc[3] = sr & 0x3;  sr >>= 2;
+			Mc[3] = sr & 0x3;  sr >>= 2;
+			sr |= (uword)*c++ << 5;
+			xmaxc[3] = sr & 0x3f;  sr >>= 6;
+#undef	xmc
+#define	xmc	(source + 63 - 39)
+
+			xmc[39] = sr & 0x7;  sr >>= 3;
+			xmc[40] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[41] = sr & 0x7;  sr >>= 3;
+			xmc[42] = sr & 0x7;  sr >>= 3;
+			xmc[43] = sr & 0x7;  sr >>= 3;
+			sr = *c++;				/* 30 */
+			xmc[44] = sr & 0x7;  sr >>= 3;
+			xmc[45] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 2;
+			xmc[46] = sr & 0x7;  sr >>= 3;
+			xmc[47] = sr & 0x7;  sr >>= 3;
+			xmc[48] = sr & 0x7;  sr >>= 3;
+			sr |= (uword)*c++ << 1;
+			xmc[49] = sr & 0x7;  sr >>= 3;
+			xmc[50] = sr & 0x7;  sr >>= 3;
+			xmc[51] = sr & 0x7;  sr >>= 3;
+		}
+	}
+	else
+#endif 
+	{
+
+	*c++ =   ((GSM_MAGIC & 0xF) << 4)		/* 1 */
+	       | ((LARc[0] >> 2) & 0xF);
+	*c++ =   ((LARc[0] & 0x3) << 6)
+	       | (LARc[1] & 0x3F);
+	*c++ =   ((LARc[2] & 0x1F) << 3)
+	       | ((LARc[3] >> 2) & 0x7);
+	*c++ =   ((LARc[3] & 0x3) << 6)
+	       | ((LARc[4] & 0xF) << 2)
+	       | ((LARc[5] >> 2) & 0x3);
+	*c++ =   ((LARc[5] & 0x3) << 6)
+	       | ((LARc[6] & 0x7) << 3)
+	       | (LARc[7] & 0x7);
+
+
+	*c++ =   ((Nc[0] & 0x7F) << 1)
+
+
+	       | ((bc[0] >> 1) & 0x1);
+	*c++ =   ((bc[0] & 0x1) << 7)
+
+
+	       | ((Mc[0] & 0x3) << 5)
+
+	       | ((xmaxc[0] >> 1) & 0x1F);
+	*c++ =   ((xmaxc[0] & 0x1) << 7)
+
+#undef xmc
+#define	xmc	(source + 12)
+
+	       | ((xmc[0] & 0x7) << 4)
+	       | ((xmc[1] & 0x7) << 1)
+	       | ((xmc[2] >> 2) & 0x1);
+	*c++ =   ((xmc[2] & 0x3) << 6)
+	       | ((xmc[3] & 0x7) << 3)
+	       | (xmc[4] & 0x7);
+	*c++ =   ((xmc[5] & 0x7) << 5)			/* 10 */
+	       | ((xmc[6] & 0x7) << 2)
+	       | ((xmc[7] >> 1) & 0x3);
+	*c++ =   ((xmc[7] & 0x1) << 7)
+	       | ((xmc[8] & 0x7) << 4)
+	       | ((xmc[9] & 0x7) << 1)
+	       | ((xmc[10] >> 2) & 0x1);
+	*c++ =   ((xmc[10] & 0x3) << 6)
+	       | ((xmc[11] & 0x7) << 3)
+	       | (xmc[12] & 0x7);
+
+
+	*c++ =   ((Nc[1] & 0x7F) << 1)
+
+
+	       | ((bc[1] >> 1) & 0x1);
+	*c++ =   ((bc[1] & 0x1) << 7)
+
+
+	       | ((Mc[1] & 0x3) << 5)
+
+
+	       | ((xmaxc[1] >> 1) & 0x1F);
+	*c++ =   ((xmaxc[1] & 0x1) << 7)
+
+#undef	xmc
+#define	xmc	(source + 29 - 13)
+
+	       | ((xmc[13] & 0x7) << 4)
+	       | ((xmc[14] & 0x7) << 1)
+	       | ((xmc[15] >> 2) & 0x1);
+	*c++ =   ((xmc[15] & 0x3) << 6)
+	       | ((xmc[16] & 0x7) << 3)
+	       | (xmc[17] & 0x7);
+	*c++ =   ((xmc[18] & 0x7) << 5)
+	       | ((xmc[19] & 0x7) << 2)
+	       | ((xmc[20] >> 1) & 0x3);
+	*c++ =   ((xmc[20] & 0x1) << 7)
+	       | ((xmc[21] & 0x7) << 4)
+	       | ((xmc[22] & 0x7) << 1)
+	       | ((xmc[23] >> 2) & 0x1);
+	*c++ =   ((xmc[23] & 0x3) << 6)
+	       | ((xmc[24] & 0x7) << 3)
+	       | (xmc[25] & 0x7);
+
+
+	*c++ =   ((Nc[2] & 0x7F) << 1)			/* 20 */
+
+
+	       | ((bc[2] >> 1) & 0x1);
+	*c++ =   ((bc[2] & 0x1) << 7)
+
+
+	       | ((Mc[2] & 0x3) << 5)
+
+
+	       | ((xmaxc[2] >> 1) & 0x1F);
+	*c++ =   ((xmaxc[2] & 0x1) << 7)
+
+#undef	xmc
+#define	xmc	(source + 46 - 26)
+
+	       | ((xmc[26] & 0x7) << 4)
+	       | ((xmc[27] & 0x7) << 1)
+	       | ((xmc[28] >> 2) & 0x1);
+	*c++ =   ((xmc[28] & 0x3) << 6)
+	       | ((xmc[29] & 0x7) << 3)
+	       | (xmc[30] & 0x7);
+	*c++ =   ((xmc[31] & 0x7) << 5)
+	       | ((xmc[32] & 0x7) << 2)
+	       | ((xmc[33] >> 1) & 0x3);
+	*c++ =   ((xmc[33] & 0x1) << 7)
+	       | ((xmc[34] & 0x7) << 4)
+	       | ((xmc[35] & 0x7) << 1)
+	       | ((xmc[36] >> 2) & 0x1);
+	*c++ =   ((xmc[36] & 0x3) << 6)
+	       | ((xmc[37] & 0x7) << 3)
+	       | (xmc[38] & 0x7);
+
+
+	*c++ =   ((Nc[3] & 0x7F) << 1)
+
+
+	       | ((bc[3] >> 1) & 0x1);
+	*c++ =   ((bc[3] & 0x1) << 7)
+
+
+	       | ((Mc[3] & 0x3) << 5)
+
+
+	       | ((xmaxc[3] >> 1) & 0x1F);
+	*c++ =   ((xmaxc[3] & 0x1) << 7)
+
+#undef	xmc
+#define	xmc	(source + 63 - 39)
+
+	       | ((xmc[39] & 0x7) << 4)
+	       | ((xmc[40] & 0x7) << 1)
+	       | ((xmc[41] >> 2) & 0x1);
+	*c++ =   ((xmc[41] & 0x3) << 6)			/* 30 */
+	       | ((xmc[42] & 0x7) << 3)
+	       | (xmc[43] & 0x7);
+	*c++ =   ((xmc[44] & 0x7) << 5)
+	       | ((xmc[45] & 0x7) << 2)
+	       | ((xmc[46] >> 1) & 0x3);
+	*c++ =   ((xmc[46] & 0x1) << 7)
+	       | ((xmc[47] & 0x7) << 4)
+	       | ((xmc[48] & 0x7) << 1)
+	       | ((xmc[49] >> 2) & 0x1);
+	*c++ =   ((xmc[49] & 0x3) << 6)
+	       | ((xmc[50] & 0x7) << 3)
+	       | (xmc[51] & 0x7);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_jni.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,87 @@
+
+
+/**
+extern gsm  gsm_create 	GSMJNI_P((void));
+extern void gsm_destroy GSMJNI_P((gsm));	
+
+extern int  gsm_print   GSMJNI_P((FILE *, gsm, gsm_byte  *));
+extern int  gsm_option  GSMJNI_P((gsm, int, int *));
+
+extern void gsm_encode  GSMJNI_P((gsm, gsm_signal *, gsm_byte  *));
+extern int  gsm_decode  GSMJNI_P((gsm, gsm_byte   *, gsm_signal *));
+
+extern int  gsm_explode GSMJNI_P((gsm, gsm_byte   *, gsm_signal *));
+extern void gsm_implode GSMJNI_P((gsm, gsm_signal *, gsm_byte   *));
+*/
+
+
+#include <jni.h>
+
+
+#include "gsm.h"
+#include "private.h"
+#include "proto.h"
+
+jlong
+Java_org_sipdroid_media_codecs_GSMJNI_create(JNIEnv *env)
+{
+	return gsm_create();
+}
+
+void
+Java_org_sipdroid_media_codecs_GSMJNI_destroy(JNIEnv *env, jlong jgsm)
+{
+	gsm_destroy((void *)jgsm);
+}
+
+void
+Java_org_sipdroid_media_codecs_GSMJNI_encode(JNIEnv *env, jlong jgsm, jshortArray jgsmSignal, jlong jsrcPos, jbyteArray jgsmByte, jlong jdestPos)
+{
+	jshort *gsmSignal;
+	jbyte *gsmByte;
+	jboolean isCopyByte;
+	jboolean isCopySignal;
+	void *ctx = (void *) jgsm;
+
+	gsmByte = (*env)->GetByteArrayElements( env, jgsmByte, &isCopyByte);
+	gsmSignal = (*env)->GetShortArrayElements( env, jgsmSignal, &isCopySignal);
+	
+	gsm_encode(ctx, gsmSignal + jsrcPos, gsmByte + jdestPos);
+	if (isCopyByte == JNI_TRUE)
+		(*env)->ReleaseByteArrayElements(env, jgsmByte, gsmByte,0);
+	if (isCopySignal == JNI_TRUE)
+		(*env)->ReleaseShortArrayElements(env, jgsmSignal, gsmSignal,0);
+}
+
+jint
+Java_org_sipdroid_media_codecs_GSMJNI_decode(JNIEnv *env, jlong jgsm, jbyteArray jgsmByte, jlong jdestPos, jshortArray jgsmSignal, jlong jsrcPos)
+{
+	jshort *gsmSignal;
+	jbyte *gsmByte;
+	jboolean isCopyByte;
+	jboolean isCopySignal;
+	jint res;
+
+	gsmSignal = (*env)->GetShortArrayElements( env, jgsmSignal, &isCopySignal);
+	gsmByte = (*env)->GetByteArrayElements( env, jgsmByte, &isCopyByte);
+	res = gsm_decode((void *)jgsm, gsmByte + jdestPos, gsmSignal + jsrcPos);
+	if (isCopyByte == JNI_TRUE)
+		(*env)->ReleaseByteArrayElements(env, jgsmByte, gsmByte,0);
+	if (isCopySignal == JNI_TRUE)
+		(*env)->ReleaseShortArrayElements(env, jgsmSignal, gsmSignal,0);
+	return res;
+}
+
+jint
+Java_org_sipdroid_media_codecs_GSMJNI_option(JNIEnv *env, jlong jgsm, jint jopt, jintArray jval)
+{
+	jint *val;
+	jboolean isCopyVal;
+	jint res;
+
+	val = (*env)->GetIntArrayElements( env, jval, &isCopyVal);
+	res = gsm_option((void *)jgsm, jopt, val);
+	if (isCopyVal == JNI_TRUE)
+		(*env)->ReleaseIntArrayElements(env, jval, val,0);
+	return res;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_option.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_option.c,v 1.3 1996/07/02 09:59:05 jutta Exp $ */
+
+#include "private.h"
+
+#include "gsm.h"
+#include "proto.h"
+
+int gsm_option P3((r, opt, val), gsm r, int opt, int * val)
+{
+	int 	result = -1;
+
+	switch (opt) {
+	case GSM_OPT_LTP_CUT:
+#ifdef 	LTP_CUT
+		result = r->ltp_cut;
+		if (val) r->ltp_cut = *val;
+#endif
+		break;
+
+	case GSM_OPT_VERBOSE:
+#ifndef	NDEBUG
+		result = r->verbose;
+		if (val) r->verbose = *val;
+#endif
+		break;
+
+	case GSM_OPT_FAST:
+
+#if	defined(FAST) && defined(USE_FLOAT_MUL)
+		result = r->fast;
+		if (val) r->fast = !!*val;
+#endif
+		break;
+
+	case GSM_OPT_FRAME_CHAIN:
+
+#ifdef WAV49
+		result = r->frame_chain;
+		if (val) r->frame_chain = *val;
+#endif
+		break;
+
+	case GSM_OPT_FRAME_INDEX:
+
+#ifdef WAV49
+		result = r->frame_index;
+		if (val) r->frame_index = *val;
+#endif
+		break;
+
+	case GSM_OPT_WAV49:
+
+#ifdef WAV49 
+		result = r->wav_fmt;
+		if (val) r->wav_fmt = !!*val;
+#endif
+		break;
+
+	default:
+		break;
+	}
+	return result;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/gsm_print.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,170 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/gsm_print.c,v 1.1 1992/10/28 00:15:50 jutta Exp $ */
+
+#include	<stdio.h>
+
+#include "private.h"
+
+#include "gsm.h"
+#include "proto.h"
+
+int gsm_print P3((f, s, c), FILE * f, gsm s, gsm_byte * c)
+{
+	word  	LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
+// Wirlab
+	(void)s;
+
+
+	/* GSM_MAGIC  = (*c >> 4) & 0xF; */
+
+	if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1;
+
+	LARc[0]  = (*c++ & 0xF) << 2;		/* 1 */
+	LARc[0] |= (*c >> 6) & 0x3;
+	LARc[1]  = *c++ & 0x3F;
+	LARc[2]  = (*c >> 3) & 0x1F;
+	LARc[3]  = (*c++ & 0x7) << 2;
+	LARc[3] |= (*c >> 6) & 0x3;
+	LARc[4]  = (*c >> 2) & 0xF;
+	LARc[5]  = (*c++ & 0x3) << 2;
+	LARc[5] |= (*c >> 6) & 0x3;
+	LARc[6]  = (*c >> 3) & 0x7;
+	LARc[7]  = *c++ & 0x7;
+
+
+	Nc[0]  = (*c >> 1) & 0x7F;
+	bc[0]  = (*c++ & 0x1) << 1;
+	bc[0] |= (*c >> 7) & 0x1;
+	Mc[0]  = (*c >> 5) & 0x3;
+	xmaxc[0]  = (*c++ & 0x1F) << 1;
+	xmaxc[0] |= (*c >> 7) & 0x1;
+	xmc[0]  = (*c >> 4) & 0x7;
+	xmc[1]  = (*c >> 1) & 0x7;
+	xmc[2]  = (*c++ & 0x1) << 2;
+	xmc[2] |= (*c >> 6) & 0x3;
+	xmc[3]  = (*c >> 3) & 0x7;
+	xmc[4]  = *c++ & 0x7;
+	xmc[5]  = (*c >> 5) & 0x7;
+	xmc[6]  = (*c >> 2) & 0x7;
+	xmc[7]  = (*c++ & 0x3) << 1;		/* 10 */
+	xmc[7] |= (*c >> 7) & 0x1;
+	xmc[8]  = (*c >> 4) & 0x7;
+	xmc[9]  = (*c >> 1) & 0x7;
+	xmc[10]  = (*c++ & 0x1) << 2;
+	xmc[10] |= (*c >> 6) & 0x3;
+	xmc[11]  = (*c >> 3) & 0x7;
+	xmc[12]  = *c++ & 0x7;
+
+	Nc[1]  = (*c >> 1) & 0x7F;
+	bc[1]  = (*c++ & 0x1) << 1;
+	bc[1] |= (*c >> 7) & 0x1;
+	Mc[1]  = (*c >> 5) & 0x3;
+	xmaxc[1]  = (*c++ & 0x1F) << 1;
+	xmaxc[1] |= (*c >> 7) & 0x1;
+	xmc[13]  = (*c >> 4) & 0x7;
+	xmc[14]  = (*c >> 1) & 0x7;
+	xmc[15]  = (*c++ & 0x1) << 2;
+	xmc[15] |= (*c >> 6) & 0x3;
+	xmc[16]  = (*c >> 3) & 0x7;
+	xmc[17]  = *c++ & 0x7;
+	xmc[18]  = (*c >> 5) & 0x7;
+	xmc[19]  = (*c >> 2) & 0x7;
+	xmc[20]  = (*c++ & 0x3) << 1;
+	xmc[20] |= (*c >> 7) & 0x1;
+	xmc[21]  = (*c >> 4) & 0x7;
+	xmc[22]  = (*c >> 1) & 0x7;
+	xmc[23]  = (*c++ & 0x1) << 2;
+	xmc[23] |= (*c >> 6) & 0x3;
+	xmc[24]  = (*c >> 3) & 0x7;
+	xmc[25]  = *c++ & 0x7;
+
+
+	Nc[2]  = (*c >> 1) & 0x7F;
+	bc[2]  = (*c++ & 0x1) << 1;		/* 20 */
+	bc[2] |= (*c >> 7) & 0x1;
+	Mc[2]  = (*c >> 5) & 0x3;
+	xmaxc[2]  = (*c++ & 0x1F) << 1;
+	xmaxc[2] |= (*c >> 7) & 0x1;
+	xmc[26]  = (*c >> 4) & 0x7;
+	xmc[27]  = (*c >> 1) & 0x7;
+	xmc[28]  = (*c++ & 0x1) << 2;
+	xmc[28] |= (*c >> 6) & 0x3;
+	xmc[29]  = (*c >> 3) & 0x7;
+	xmc[30]  = *c++ & 0x7;
+	xmc[31]  = (*c >> 5) & 0x7;
+	xmc[32]  = (*c >> 2) & 0x7;
+	xmc[33]  = (*c++ & 0x3) << 1;
+	xmc[33] |= (*c >> 7) & 0x1;
+	xmc[34]  = (*c >> 4) & 0x7;
+	xmc[35]  = (*c >> 1) & 0x7;
+	xmc[36]  = (*c++ & 0x1) << 2;
+	xmc[36] |= (*c >> 6) & 0x3;
+	xmc[37]  = (*c >> 3) & 0x7;
+	xmc[38]  = *c++ & 0x7;
+
+	Nc[3]  = (*c >> 1) & 0x7F;
+	bc[3]  = (*c++ & 0x1) << 1;
+	bc[3] |= (*c >> 7) & 0x1;
+	Mc[3]  = (*c >> 5) & 0x3;
+	xmaxc[3]  = (*c++ & 0x1F) << 1;
+	xmaxc[3] |= (*c >> 7) & 0x1;
+
+	xmc[39]  = (*c >> 4) & 0x7;
+	xmc[40]  = (*c >> 1) & 0x7;
+	xmc[41]  = (*c++ & 0x1) << 2;
+	xmc[41] |= (*c >> 6) & 0x3;
+	xmc[42]  = (*c >> 3) & 0x7;
+	xmc[43]  = *c++ & 0x7;			/* 30  */
+	xmc[44]  = (*c >> 5) & 0x7;
+	xmc[45]  = (*c >> 2) & 0x7;
+	xmc[46]  = (*c++ & 0x3) << 1;
+	xmc[46] |= (*c >> 7) & 0x1;
+	xmc[47]  = (*c >> 4) & 0x7;
+	xmc[48]  = (*c >> 1) & 0x7;
+	xmc[49]  = (*c++ & 0x1) << 2;
+	xmc[49] |= (*c >> 6) & 0x3;
+	xmc[50]  = (*c >> 3) & 0x7;
+	xmc[51]  = *c & 0x7;			/* 33 */
+
+	fprintf(f,
+	      "LARc:\t%2.2d  %2.2d  %2.2d  %2.2d  %2.2d  %2.2d  %2.2d  %2.2d\n",
+	       LARc[0],LARc[1],LARc[2],LARc[3],LARc[4],LARc[5],LARc[6],LARc[7]);
+
+	fprintf(f, "#1: 	Nc %4.4d    bc %d    Mc %d    xmaxc %d\n",
+		Nc[0], bc[0], Mc[0], xmaxc[0]);
+	fprintf(f,
+"\t%.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d\n",
+		xmc[0],xmc[1],xmc[2],xmc[3],xmc[4],xmc[5],xmc[6],
+		xmc[7],xmc[8],xmc[9],xmc[10],xmc[11],xmc[12] );
+
+	fprintf(f, "#2: 	Nc %4.4d    bc %d    Mc %d    xmaxc %d\n",
+		Nc[1], bc[1], Mc[1], xmaxc[1]);
+	fprintf(f,
+"\t%.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d\n",
+		xmc[13+0],xmc[13+1],xmc[13+2],xmc[13+3],xmc[13+4],xmc[13+5],
+		xmc[13+6], xmc[13+7],xmc[13+8],xmc[13+9],xmc[13+10],xmc[13+11],
+		xmc[13+12] );
+
+	fprintf(f, "#3: 	Nc %4.4d    bc %d    Mc %d    xmaxc %d\n",
+		Nc[2], bc[2], Mc[2], xmaxc[2]);
+	fprintf(f,
+"\t%.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d\n",
+		xmc[26+0],xmc[26+1],xmc[26+2],xmc[26+3],xmc[26+4],xmc[26+5],
+		xmc[26+6], xmc[26+7],xmc[26+8],xmc[26+9],xmc[26+10],xmc[26+11],
+		xmc[26+12] );
+
+	fprintf(f, "#4: 	Nc %4.4d    bc %d    Mc %d    xmaxc %d\n",
+		Nc[3], bc[3], Mc[3], xmaxc[3]);
+	fprintf(f,
+"\t%.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d %.2d\n",
+		xmc[39+0],xmc[39+1],xmc[39+2],xmc[39+3],xmc[39+4],xmc[39+5],
+		xmc[39+6], xmc[39+7],xmc[39+8],xmc[39+9],xmc[39+10],xmc[39+11],
+		xmc[39+12] );
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/long_term.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,954 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/long_term.c,v 1.6 1996/07/02 12:33:19 jutta Exp $ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "private.h"
+
+#include "gsm.h"
+#include "proto.h"
+
+/*
+ *  4.2.11 .. 4.2.12 LONG TERM PREDICTOR (LTP) SECTION
+ */
+
+
+/*
+ * This module computes the LTP gain (bc) and the LTP lag (Nc)
+ * for the long term analysis filter.   This is done by calculating a
+ * maximum of the cross-correlation function between the current
+ * sub-segment short term residual signal d[0..39] (output of
+ * the short term analysis filter; for simplification the index
+ * of this array begins at 0 and ends at 39 for each sub-segment of the
+ * RPE-LTP analysis) and the previous reconstructed short term
+ * residual signal dp[ -120 .. -1 ].  A dynamic scaling must be
+ * performed to avoid overflow.
+ */
+
+ /* The next procedure exists in six versions.  First two integer
+  * version (if USE_FLOAT_MUL is not defined); then four floating
+  * point versions, twice with proper scaling (USE_FLOAT_MUL defined),
+  * once without (USE_FLOAT_MUL and FAST defined, and fast run-time
+  * option used).  Every pair has first a Cut version (see the -C
+  * option to toast or the LTP_CUT option to gsm_option()), then the
+  * uncut one.  (For a detailed explanation of why this is altogether
+  * a bad idea, see Henry Spencer and Geoff Collyer, ``#ifdef Considered
+  * Harmful''.)
+  */
+
+#ifndef  USE_FLOAT_MUL
+
+#ifdef	LTP_CUT
+
+static void Cut_Calculation_of_the_LTP_parameters P5((st, d,dp,bc_out,Nc_out),
+
+	struct gsm_state * st,
+
+	register word	* d,		/* [0..39]	IN	*/
+	register word	* dp,		/* [-120..-1]	IN	*/
+	word		* bc_out,	/* 		OUT	*/
+	word		* Nc_out	/* 		OUT	*/
+)
+{
+	register int  	k, lambda;
+	word		Nc, bc;
+	word		wt[40];
+
+	longword	L_result;
+	longword	L_max, L_power;
+	word		R, S, dmax, scal, best_k;
+	word		ltp_cut;
+
+	register word	temp, wt_k;
+
+	/*  Search of the optimum scaling of d[0..39].
+	 */
+	dmax = 0;
+	for (k = 0; k <= 39; k++) {
+		temp = d[k];
+		temp = GSM_ABS( temp );
+		if (temp > dmax) {
+			dmax = temp;
+			best_k = k;
+		}
+	}
+	temp = 0;
+	if (dmax == 0) scal = 0;
+	else {
+		assert(dmax > 0);
+		temp = gsm_norm( (longword)dmax << 16 );
+	}
+	if (temp > 6) scal = 0;
+	else scal = 6 - temp;
+	assert(scal >= 0);
+
+	/* Search for the maximum cross-correlation and coding of the LTP lag
+	 */
+	L_max = 0;
+	Nc    = 40;	/* index for the maximum cross-correlation */
+	wt_k  = SASR(d[best_k], scal);
+
+	for (lambda = 40; lambda <= 120; lambda++) {
+		L_result = (longword)wt_k * dp[best_k - lambda];
+		if (L_result > L_max) {
+			Nc    = lambda;
+			L_max = L_result;
+		}
+	}
+	*Nc_out = Nc;
+	L_max <<= 1;
+
+	/*  Rescaling of L_max
+	 */
+	assert(scal <= 100 && scal >= -100);
+	L_max = L_max >> (6 - scal);	/* sub(6, scal) */
+
+	assert( Nc <= 120 && Nc >= 40);
+
+	/*   Compute the power of the reconstructed short term residual
+	 *   signal dp[..]
+	 */
+	L_power = 0;
+	for (k = 0; k <= 39; k++) {
+
+		register longword L_temp;
+
+		L_temp   = SASR( dp[k - Nc], 3 );
+		L_power += L_temp * L_temp;
+	}
+	L_power <<= 1;	/* from L_MULT */
+
+	/*  Normalization of L_max and L_power
+	 */
+
+	if (L_max <= 0)  {
+		*bc_out = 0;
+		return;
+	}
+	if (L_max >= L_power) {
+		*bc_out = 3;
+		return;
+	}
+
+	temp = gsm_norm( L_power );
+
+	R = SASR( L_max   << temp, 16 );
+	S = SASR( L_power << temp, 16 );
+
+	/*  Coding of the LTP gain
+	 */
+
+	/*  Table 4.3a must be used to obtain the level DLB[i] for the
+	 *  quantization of the LTP gain b to get the coded version bc.
+	 */
+	for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break;
+	*bc_out = bc;
+}
+
+#endif 	/* LTP_CUT */
+
+static void Calculation_of_the_LTP_parameters P4((d,dp,bc_out,Nc_out),
+	register word	* d,		/* [0..39]	IN	*/
+	register word	* dp,		/* [-120..-1]	IN	*/
+	word		* bc_out,	/* 		OUT	*/
+	word		* Nc_out	/* 		OUT	*/
+)
+{
+	register int  	k, lambda;
+	word		Nc, bc;
+	word		wt[40];
+
+	longword	L_max, L_power;
+	word		R, S, dmax, scal;
+	register word	temp;
+
+	/*  Search of the optimum scaling of d[0..39].
+	 */
+	dmax = 0;
+
+	for (k = 0; k <= 39; k++) {
+		temp = d[k];
+		temp = GSM_ABS( temp );
+		if (temp > dmax) dmax = temp;
+	}
+
+	temp = 0;
+	if (dmax == 0) scal = 0;
+	else {
+		assert(dmax > 0);
+		temp = gsm_norm( (longword)dmax << 16 );
+	}
+
+	if (temp > 6) scal = 0;
+	else scal = 6 - temp;
+
+	assert(scal >= 0);
+
+	/*  Initialization of a working array wt
+	 */
+
+	for (k = 0; k <= 39; k++) wt[k] = SASR( d[k], scal );
+
+	/* Search for the maximum cross-correlation and coding of the LTP lag
+	 */
+	L_max = 0;
+	Nc    = 40;	/* index for the maximum cross-correlation */
+
+	for (lambda = 40; lambda <= 120; lambda++) {
+
+# undef STEP
+#		define STEP(k) 	(longword)wt[k] * dp[k - lambda]
+
+		register longword L_result;
+
+		L_result  = STEP(0)  ; L_result += STEP(1) ;
+		L_result += STEP(2)  ; L_result += STEP(3) ;
+		L_result += STEP(4)  ; L_result += STEP(5)  ;
+		L_result += STEP(6)  ; L_result += STEP(7)  ;
+		L_result += STEP(8)  ; L_result += STEP(9)  ;
+		L_result += STEP(10) ; L_result += STEP(11) ;
+		L_result += STEP(12) ; L_result += STEP(13) ;
+		L_result += STEP(14) ; L_result += STEP(15) ;
+		L_result += STEP(16) ; L_result += STEP(17) ;
+		L_result += STEP(18) ; L_result += STEP(19) ;
+		L_result += STEP(20) ; L_result += STEP(21) ;
+		L_result += STEP(22) ; L_result += STEP(23) ;
+		L_result += STEP(24) ; L_result += STEP(25) ;
+		L_result += STEP(26) ; L_result += STEP(27) ;
+		L_result += STEP(28) ; L_result += STEP(29) ;
+		L_result += STEP(30) ; L_result += STEP(31) ;
+		L_result += STEP(32) ; L_result += STEP(33) ;
+		L_result += STEP(34) ; L_result += STEP(35) ;
+		L_result += STEP(36) ; L_result += STEP(37) ;
+		L_result += STEP(38) ; L_result += STEP(39) ;
+
+		if (L_result > L_max) {
+
+			Nc    = lambda;
+			L_max = L_result;
+		}
+	}
+
+	*Nc_out = Nc;
+
+	L_max <<= 1;
+
+	/*  Rescaling of L_max
+	 */
+	assert(scal <= 100 && scal >=  -100);
+	L_max = L_max >> (6 - scal);	/* sub(6, scal) */
+
+	assert( Nc <= 120 && Nc >= 40);
+
+	/*   Compute the power of the reconstructed short term residual
+	 *   signal dp[..]
+	 */
+	L_power = 0;
+	for (k = 0; k <= 39; k++) {
+
+		register longword L_temp;
+
+		L_temp   = SASR( dp[k - Nc], 3 );
+		L_power += L_temp * L_temp;
+	}
+	L_power <<= 1;	/* from L_MULT */
+
+	/*  Normalization of L_max and L_power
+	 */
+
+	if (L_max <= 0)  {
+		*bc_out = 0;
+		return;
+	}
+	if (L_max >= L_power) {
+		*bc_out = 3;
+		return;
+	}
+
+	temp = gsm_norm( L_power );
+
+	R = SASR( L_max   << temp, 16 );
+	S = SASR( L_power << temp, 16 );
+
+	/*  Coding of the LTP gain
+	 */
+
+	/*  Table 4.3a must be used to obtain the level DLB[i] for the
+	 *  quantization of the LTP gain b to get the coded version bc.
+	 */
+	for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break;
+	*bc_out = bc;
+}
+
+#else	/* USE_FLOAT_MUL */
+
+#ifdef	LTP_CUT
+
+static void Cut_Calculation_of_the_LTP_parameters P5((st, d,dp,bc_out,Nc_out),
+	struct gsm_state * st,		/*              IN 	*/
+	register word	* d,		/* [0..39]	IN	*/
+	register word	* dp,		/* [-120..-1]	IN	*/
+	word		* bc_out,	/* 		OUT	*/
+	word		* Nc_out	/* 		OUT	*/
+)
+{
+	register int  	k, lambda;
+	word		Nc, bc;
+	word		ltp_cut;
+
+	float		wt_float[40];
+	float		dp_float_base[120], * dp_float = dp_float_base + 120;
+
+	longword	L_max, L_power;
+	word		R, S, dmax, scal;
+	register word	temp;
+
+	/*  Search of the optimum scaling of d[0..39].
+	 */
+	dmax = 0;
+
+	for (k = 0; k <= 39; k++) {
+		temp = d[k];
+		temp = GSM_ABS( temp );
+		if (temp > dmax) dmax = temp;
+	}
+
+	temp = 0;
+	if (dmax == 0) scal = 0;
+	else {
+		assert(dmax > 0);
+		temp = gsm_norm( (longword)dmax << 16 );
+	}
+
+	if (temp > 6) scal = 0;
+	else scal = 6 - temp;
+
+	assert(scal >= 0);
+	ltp_cut = (longword)SASR(dmax, scal) * st->ltp_cut / 100; 
+
+
+	/*  Initialization of a working array wt
+	 */
+
+	for (k = 0; k < 40; k++) {
+		register word w = SASR( d[k], scal );
+		if (w < 0 ? w > -ltp_cut : w < ltp_cut) {
+			wt_float[k] = 0.0;
+		}
+		else {
+			wt_float[k] =  w;
+		}
+	}
+	for (k = -120; k <  0; k++) dp_float[k] =  dp[k];
+
+	/* Search for the maximum cross-correlation and coding of the LTP lag
+	 */
+	L_max = 0;
+	Nc    = 40;	/* index for the maximum cross-correlation */
+
+	for (lambda = 40; lambda <= 120; lambda += 9) {
+
+		/*  Calculate L_result for l = lambda .. lambda + 9.
+		 */
+		register float *lp = dp_float - lambda;
+
+		register float	W;
+		register float	a = lp[-8], b = lp[-7], c = lp[-6],
+				d = lp[-5], e = lp[-4], f = lp[-3],
+				g = lp[-2], h = lp[-1];
+		register float  E; 
+		register float  S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
+				S5 = 0, S6 = 0, S7 = 0, S8 = 0;
+
+#		undef STEP
+#		define	STEP(K, a, b, c, d, e, f, g, h) \
+			if ((W = wt_float[K]) != 0.0) {	\
+			E = W * a; S8 += E;		\
+			E = W * b; S7 += E;		\
+			E = W * c; S6 += E;		\
+			E = W * d; S5 += E;		\
+			E = W * e; S4 += E;		\
+			E = W * f; S3 += E;		\
+			E = W * g; S2 += E;		\
+			E = W * h; S1 += E;		\
+			a  = lp[K];			\
+			E = W * a; S0 += E; } else (a = lp[K])
+
+#		define	STEP_A(K)	STEP(K, a, b, c, d, e, f, g, h)
+#		define	STEP_B(K)	STEP(K, b, c, d, e, f, g, h, a)
+#		define	STEP_C(K)	STEP(K, c, d, e, f, g, h, a, b)
+#		define	STEP_D(K)	STEP(K, d, e, f, g, h, a, b, c)
+#		define	STEP_E(K)	STEP(K, e, f, g, h, a, b, c, d)
+#		define	STEP_F(K)	STEP(K, f, g, h, a, b, c, d, e)
+#		define	STEP_G(K)	STEP(K, g, h, a, b, c, d, e, f)
+#		define	STEP_H(K)	STEP(K, h, a, b, c, d, e, f, g)
+
+		STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3);
+		STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7);
+
+		STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11);
+		STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15);
+
+		STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19);
+		STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23);
+
+		STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27);
+		STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31);
+
+		STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35);
+		STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39);
+
+		if (S0 > L_max) { L_max = S0; Nc = lambda;     }
+		if (S1 > L_max) { L_max = S1; Nc = lambda + 1; }
+		if (S2 > L_max) { L_max = S2; Nc = lambda + 2; }
+		if (S3 > L_max) { L_max = S3; Nc = lambda + 3; }
+		if (S4 > L_max) { L_max = S4; Nc = lambda + 4; }
+		if (S5 > L_max) { L_max = S5; Nc = lambda + 5; }
+		if (S6 > L_max) { L_max = S6; Nc = lambda + 6; }
+		if (S7 > L_max) { L_max = S7; Nc = lambda + 7; }
+		if (S8 > L_max) { L_max = S8; Nc = lambda + 8; }
+
+	}
+	*Nc_out = Nc;
+
+	L_max <<= 1;
+
+	/*  Rescaling of L_max
+	 */
+	assert(scal <= 100 && scal >=  -100);
+	L_max = L_max >> (6 - scal);	/* sub(6, scal) */
+
+	assert( Nc <= 120 && Nc >= 40);
+
+	/*   Compute the power of the reconstructed short term residual
+	 *   signal dp[..]
+	 */
+	L_power = 0;
+	for (k = 0; k <= 39; k++) {
+
+		register longword L_temp;
+
+		L_temp   = SASR( dp[k - Nc], 3 );
+		L_power += L_temp * L_temp;
+	}
+	L_power <<= 1;	/* from L_MULT */
+
+	/*  Normalization of L_max and L_power
+	 */
+
+	if (L_max <= 0)  {
+		*bc_out = 0;
+		return;
+	}
+	if (L_max >= L_power) {
+		*bc_out = 3;
+		return;
+	}
+
+	temp = gsm_norm( L_power );
+
+	R = SASR( L_max   << temp, 16 );
+	S = SASR( L_power << temp, 16 );
+
+	/*  Coding of the LTP gain
+	 */
+
+	/*  Table 4.3a must be used to obtain the level DLB[i] for the
+	 *  quantization of the LTP gain b to get the coded version bc.
+	 */
+	for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break;
+	*bc_out = bc;
+}
+
+#endif /* LTP_CUT */
+
+static void Calculation_of_the_LTP_parameters P4((d,dp,bc_out,Nc_out),
+	register word	* d,		/* [0..39]	IN	*/
+	register word	* dp,		/* [-120..-1]	IN	*/
+	word		* bc_out,	/* 		OUT	*/
+	word		* Nc_out	/* 		OUT	*/
+)
+{
+	register int  	k, lambda;
+	word		Nc, bc;
+
+	float		wt_float[40];
+	float		dp_float_base[120], * dp_float = dp_float_base + 120;
+
+	longword	L_max, L_power;
+	word		R, S, dmax, scal;
+	register word	temp;
+
+	/*  Search of the optimum scaling of d[0..39].
+	 */
+	dmax = 0;
+
+	for (k = 0; k <= 39; k++) {
+		temp = d[k];
+		temp = GSM_ABS( temp );
+		if (temp > dmax) dmax = temp;
+	}
+
+	temp = 0;
+	if (dmax == 0) scal = 0;
+	else {
+		assert(dmax > 0);
+		temp = gsm_norm( (longword)dmax << 16 );
+	}
+
+	if (temp > 6) scal = 0;
+	else scal = 6 - temp;
+
+	assert(scal >= 0);
+
+	/*  Initialization of a working array wt
+	 */
+
+	for (k =    0; k < 40; k++) wt_float[k] =  SASR( d[k], scal );
+	for (k = -120; k <  0; k++) dp_float[k] =  dp[k];
+
+	/* Search for the maximum cross-correlation and coding of the LTP lag
+	 */
+	L_max = 0;
+	Nc    = 40;	/* index for the maximum cross-correlation */
+
+	for (lambda = 40; lambda <= 120; lambda += 9) {
+
+		/*  Calculate L_result for l = lambda .. lambda + 9.
+		 */
+		register float *lp = dp_float - lambda;
+
+		register float	W;
+		register float	a = lp[-8], b = lp[-7], c = lp[-6],
+				d = lp[-5], e = lp[-4], f = lp[-3],
+				g = lp[-2], h = lp[-1];
+		register float  E; 
+		register float  S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
+				S5 = 0, S6 = 0, S7 = 0, S8 = 0;
+
+#		undef STEP
+#		define	STEP(K, a, b, c, d, e, f, g, h) \
+			W = wt_float[K];		\
+			E = W * a; S8 += E;		\
+			E = W * b; S7 += E;		\
+			E = W * c; S6 += E;		\
+			E = W * d; S5 += E;		\
+			E = W * e; S4 += E;		\
+			E = W * f; S3 += E;		\
+			E = W * g; S2 += E;		\
+			E = W * h; S1 += E;		\
+			a  = lp[K];			\
+			E = W * a; S0 += E
+
+#		define	STEP_A(K)	STEP(K, a, b, c, d, e, f, g, h)
+#		define	STEP_B(K)	STEP(K, b, c, d, e, f, g, h, a)
+#		define	STEP_C(K)	STEP(K, c, d, e, f, g, h, a, b)
+#		define	STEP_D(K)	STEP(K, d, e, f, g, h, a, b, c)
+#		define	STEP_E(K)	STEP(K, e, f, g, h, a, b, c, d)
+#		define	STEP_F(K)	STEP(K, f, g, h, a, b, c, d, e)
+#		define	STEP_G(K)	STEP(K, g, h, a, b, c, d, e, f)
+#		define	STEP_H(K)	STEP(K, h, a, b, c, d, e, f, g)
+
+		STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3);
+		STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7);
+
+		STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11);
+		STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15);
+
+		STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19);
+		STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23);
+
+		STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27);
+		STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31);
+
+		STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35);
+		STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39);
+
+		if (S0 > L_max) { L_max = S0; Nc = lambda;     }
+		if (S1 > L_max) { L_max = S1; Nc = lambda + 1; }
+		if (S2 > L_max) { L_max = S2; Nc = lambda + 2; }
+		if (S3 > L_max) { L_max = S3; Nc = lambda + 3; }
+		if (S4 > L_max) { L_max = S4; Nc = lambda + 4; }
+		if (S5 > L_max) { L_max = S5; Nc = lambda + 5; }
+		if (S6 > L_max) { L_max = S6; Nc = lambda + 6; }
+		if (S7 > L_max) { L_max = S7; Nc = lambda + 7; }
+		if (S8 > L_max) { L_max = S8; Nc = lambda + 8; }
+	}
+	*Nc_out = Nc;
+
+	L_max <<= 1;
+
+	/*  Rescaling of L_max
+	 */
+	assert(scal <= 100 && scal >=  -100);
+	L_max = L_max >> (6 - scal);	/* sub(6, scal) */
+
+	assert( Nc <= 120 && Nc >= 40);
+
+	/*   Compute the power of the reconstructed short term residual
+	 *   signal dp[..]
+	 */
+	L_power = 0;
+	for (k = 0; k <= 39; k++) {
+
+		register longword L_temp;
+
+		L_temp   = SASR( dp[k - Nc], 3 );
+		L_power += L_temp * L_temp;
+	}
+	L_power <<= 1;	/* from L_MULT */
+
+	/*  Normalization of L_max and L_power
+	 */
+
+	if (L_max <= 0)  {
+		*bc_out = 0;
+		return;
+	}
+	if (L_max >= L_power) {
+		*bc_out = 3;
+		return;
+	}
+
+	temp = gsm_norm( L_power );
+
+	R = SASR( L_max   << temp, 16 );
+	S = SASR( L_power << temp, 16 );
+
+	/*  Coding of the LTP gain
+	 */
+
+	/*  Table 4.3a must be used to obtain the level DLB[i] for the
+	 *  quantization of the LTP gain b to get the coded version bc.
+	 */
+	for (bc = 0; bc <= 2; bc++) if (R <= gsm_mult(S, gsm_DLB[bc])) break;
+	*bc_out = bc;
+}
+
+#ifdef	FAST
+#ifdef	LTP_CUT
+
+static void Cut_Fast_Calculation_of_the_LTP_parameters P5((st,
+							d,dp,bc_out,Nc_out),
+	struct gsm_state * st,		/*              IN	*/
+	register word	* d,		/* [0..39]	IN	*/
+	register word	* dp,		/* [-120..-1]	IN	*/
+	word		* bc_out,	/* 		OUT	*/
+	word		* Nc_out	/* 		OUT	*/
+)
+{
+	register int  	k, lambda;
+	register float	wt_float;
+	word		Nc, bc;
+	word		wt_max, best_k, ltp_cut;
+
+	float		dp_float_base[120], * dp_float = dp_float_base + 120;
+
+	register float	L_result, L_max, L_power;
+
+	wt_max = 0;
+
+	for (k = 0; k < 40; ++k) {
+		if      ( d[k] > wt_max) wt_max =  d[best_k = k];
+		else if (-d[k] > wt_max) wt_max = -d[best_k = k];
+	}
+
+	assert(wt_max >= 0);
+	wt_float = (float)wt_max;
+
+	for (k = -120; k < 0; ++k) dp_float[k] = (float)dp[k];
+
+	/* Search for the maximum cross-correlation and coding of the LTP lag
+	 */
+	L_max = 0;
+	Nc    = 40;	/* index for the maximum cross-correlation */
+
+	for (lambda = 40; lambda <= 120; lambda++) {
+		L_result = wt_float * dp_float[best_k - lambda];
+		if (L_result > L_max) {
+			Nc    = lambda;
+			L_max = L_result;
+		}
+	}
+
+	*Nc_out = Nc;
+	if (L_max <= 0.)  {
+		*bc_out = 0;
+		return;
+	}
+
+	/*  Compute the power of the reconstructed short term residual
+	 *  signal dp[..]
+	 */
+	dp_float -= Nc;
+	L_power = 0;
+	for (k = 0; k < 40; ++k) {
+		register float f = dp_float[k];
+		L_power += f * f;
+	}
+
+	if (L_max >= L_power) {
+		*bc_out = 3;
+		return;
+	}
+
+	/*  Coding of the LTP gain
+	 *  Table 4.3a must be used to obtain the level DLB[i] for the
+	 *  quantization of the LTP gain b to get the coded version bc.
+	 */
+	lambda = L_max / L_power * 32768.;
+	for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break;
+	*bc_out = bc;
+}
+
+#endif /* LTP_CUT */
+
+static void Fast_Calculation_of_the_LTP_parameters P4((d,dp,bc_out,Nc_out),
+	register word	* d,		/* [0..39]	IN	*/
+	register word	* dp,		/* [-120..-1]	IN	*/
+	word		* bc_out,	/* 		OUT	*/
+	word		* Nc_out	/* 		OUT	*/
+)
+{
+	register int  	k, lambda;
+	word		Nc, bc;
+
+	float		wt_float[40];
+	float		dp_float_base[120], * dp_float = dp_float_base + 120;
+
+	register float	L_max, L_power;
+
+	for (k = 0; k < 40; ++k) wt_float[k] = (float)d[k];
+	for (k = -120; k < 0; ++k) dp_float[k] = (float)dp[k];
+
+	/* Search for the maximum cross-correlation and coding of the LTP lag
+	 */
+	L_max = 0;
+	Nc    = 40;	/* index for the maximum cross-correlation */
+
+	for (lambda = 40; lambda <= 120; lambda += 9) {
+
+		/*  Calculate L_result for l = lambda .. lambda + 9.
+		 */
+		register float *lp = dp_float - lambda;
+
+		register float	W;
+		register float	a = lp[-8], b = lp[-7], c = lp[-6],
+				d = lp[-5], e = lp[-4], f = lp[-3],
+				g = lp[-2], h = lp[-1];
+		register float  E; 
+		register float  S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0,
+				S5 = 0, S6 = 0, S7 = 0, S8 = 0;
+
+#		undef STEP
+#		define	STEP(K, a, b, c, d, e, f, g, h) \
+			W = wt_float[K];		\
+			E = W * a; S8 += E;		\
+			E = W * b; S7 += E;		\
+			E = W * c; S6 += E;		\
+			E = W * d; S5 += E;		\
+			E = W * e; S4 += E;		\
+			E = W * f; S3 += E;		\
+			E = W * g; S2 += E;		\
+			E = W * h; S1 += E;		\
+			a  = lp[K];			\
+			E = W * a; S0 += E
+
+#		define	STEP_A(K)	STEP(K, a, b, c, d, e, f, g, h)
+#		define	STEP_B(K)	STEP(K, b, c, d, e, f, g, h, a)
+#		define	STEP_C(K)	STEP(K, c, d, e, f, g, h, a, b)
+#		define	STEP_D(K)	STEP(K, d, e, f, g, h, a, b, c)
+#		define	STEP_E(K)	STEP(K, e, f, g, h, a, b, c, d)
+#		define	STEP_F(K)	STEP(K, f, g, h, a, b, c, d, e)
+#		define	STEP_G(K)	STEP(K, g, h, a, b, c, d, e, f)
+#		define	STEP_H(K)	STEP(K, h, a, b, c, d, e, f, g)
+
+		STEP_A( 0); STEP_B( 1); STEP_C( 2); STEP_D( 3);
+		STEP_E( 4); STEP_F( 5); STEP_G( 6); STEP_H( 7);
+
+		STEP_A( 8); STEP_B( 9); STEP_C(10); STEP_D(11);
+		STEP_E(12); STEP_F(13); STEP_G(14); STEP_H(15);
+
+		STEP_A(16); STEP_B(17); STEP_C(18); STEP_D(19);
+		STEP_E(20); STEP_F(21); STEP_G(22); STEP_H(23);
+
+		STEP_A(24); STEP_B(25); STEP_C(26); STEP_D(27);
+		STEP_E(28); STEP_F(29); STEP_G(30); STEP_H(31);
+
+		STEP_A(32); STEP_B(33); STEP_C(34); STEP_D(35);
+		STEP_E(36); STEP_F(37); STEP_G(38); STEP_H(39);
+
+		if (S0 > L_max) { L_max = S0; Nc = lambda;     }
+		if (S1 > L_max) { L_max = S1; Nc = lambda + 1; }
+		if (S2 > L_max) { L_max = S2; Nc = lambda + 2; }
+		if (S3 > L_max) { L_max = S3; Nc = lambda + 3; }
+		if (S4 > L_max) { L_max = S4; Nc = lambda + 4; }
+		if (S5 > L_max) { L_max = S5; Nc = lambda + 5; }
+		if (S6 > L_max) { L_max = S6; Nc = lambda + 6; }
+		if (S7 > L_max) { L_max = S7; Nc = lambda + 7; }
+		if (S8 > L_max) { L_max = S8; Nc = lambda + 8; }
+	}
+	*Nc_out = Nc;
+
+	if (L_max <= 0.)  {
+		*bc_out = 0;
+		return;
+	}
+
+	/*  Compute the power of the reconstructed short term residual
+	 *  signal dp[..]
+	 */
+	dp_float -= Nc;
+	L_power = 0;
+	for (k = 0; k < 40; ++k) {
+		register float f = dp_float[k];
+		L_power += f * f;
+	}
+
+	if (L_max >= L_power) {
+		*bc_out = 3;
+		return;
+	}
+
+	/*  Coding of the LTP gain
+	 *  Table 4.3a must be used to obtain the level DLB[i] for the
+	 *  quantization of the LTP gain b to get the coded version bc.
+	 */
+	lambda = L_max / L_power * 32768.;
+	for (bc = 0; bc <= 2; ++bc) if (lambda <= gsm_DLB[bc]) break;
+	*bc_out = bc;
+}
+
+#endif	/* FAST 	 */
+#endif	/* USE_FLOAT_MUL */
+
+
+/* 4.2.12 */
+
+static void Long_term_analysis_filtering P6((bc,Nc,dp,d,dpp,e),
+	word		bc,	/* 					IN  */
+	word		Nc,	/* 					IN  */
+	register word	* dp,	/* previous d	[-120..-1]		IN  */
+	register word	* d,	/* d		[0..39]			IN  */
+	register word	* dpp,	/* estimate	[0..39]			OUT */
+	register word	* e	/* long term res. signal [0..39]	OUT */
+)
+/*
+ *  In this part, we have to decode the bc parameter to compute
+ *  the samples of the estimate dpp[0..39].  The decoding of bc needs the
+ *  use of table 4.3b.  The long term residual signal e[0..39]
+ *  is then calculated to be fed to the RPE encoding section.
+ */
+{
+	register int      k;
+	register longword ltmp;
+
+#	undef STEP
+#	define STEP(BP)					\
+	for (k = 0; k <= 39; k++) {			\
+		dpp[k]  = GSM_MULT_R( BP, dp[k - Nc]);	\
+		e[k]	= GSM_SUB( d[k], dpp[k] );	\
+	}
+
+	switch (bc) {
+	case 0:	STEP(  3277 ); break;
+	case 1:	STEP( 11469 ); break;
+	case 2: STEP( 21299 ); break;
+	case 3: STEP( 32767 ); break; 
+	}
+}
+
+void Gsm_Long_Term_Predictor P7((S,d,dp,e,dpp,Nc,bc), 	/* 4x for 160 samples */
+
+	struct gsm_state	* S,
+
+	word	* d,	/* [0..39]   residual signal	IN	*/
+	word	* dp,	/* [-120..-1] d'		IN	*/
+
+	word	* e,	/* [0..39] 			OUT	*/
+	word	* dpp,	/* [0..39] 			OUT	*/
+	word	* Nc,	/* correlation lag		OUT	*/
+	word	* bc	/* gain factor			OUT	*/
+)
+{
+
+// Wirlab
+	(void)S;
+
+	assert( d  ); assert( dp ); assert( e  );
+	assert( dpp); assert( Nc ); assert( bc );
+
+#if defined(FAST) && defined(USE_FLOAT_MUL)
+	if (S->fast) 
+#if   defined (LTP_CUT)
+		if (S->ltp_cut)
+			Cut_Fast_Calculation_of_the_LTP_parameters(S,
+				d, dp, bc, Nc);
+		else
+#endif /* LTP_CUT */
+			Fast_Calculation_of_the_LTP_parameters(d, dp, bc, Nc );
+	else 
+#endif /* FAST & USE_FLOAT_MUL */
+#ifdef LTP_CUT
+		if (S->ltp_cut)
+			Cut_Calculation_of_the_LTP_parameters(S, d, dp, bc, Nc);
+		else
+#endif
+			Calculation_of_the_LTP_parameters(d, dp, bc, Nc);
+
+	Long_term_analysis_filtering( *bc, *Nc, dp, d, dpp, e );
+}
+
+/* 4.3.2 */
+void Gsm_Long_Term_Synthesis_Filtering P5((S,Ncr,bcr,erp,drp),
+	struct gsm_state	* S,
+
+	word			Ncr,
+	word			bcr,
+	register word		* erp,	   /* [0..39]		  	 IN */
+	register word		* drp	   /* [-120..-1] IN, [-120..40] OUT */
+)
+/*
+ *  This procedure uses the bcr and Ncr parameter to realize the
+ *  long term synthesis filtering.  The decoding of bcr needs
+ *  table 4.3b.
+ */
+{
+
+	register longword	ltmp;	/* for ADD */
+	register int 		k;
+	word			brp, drpp, Nr;
+
+	/*  Check the limits of Nr.
+	 */
+	Nr = Ncr < 40 || Ncr > 120 ? S->nrp : Ncr;
+	S->nrp = Nr;
+	assert(Nr >= 40 && Nr <= 120);
+
+	/*  Decoding of the LTP gain bcr
+	 */
+	brp = gsm_QLB[ bcr ];
+
+	/*  Computation of the reconstructed short term residual 
+	 *  signal drp[0..39]
+	 */
+	assert(brp != MIN_WORD);
+
+	for (k = 0; k <= 39; k++) {
+		drpp   = GSM_MULT_R( brp, drp[ k - Nr ] );
+		drp[k] = GSM_ADD( erp[k], drpp );
+	}
+
+	/*
+	 *  Update of the reconstructed short term residual signal
+	 *  drp[ -1..-120 ]
+	 */
+
+	for (k = 0; k <= 119; k++) drp[ -120 + k ] = drp[ -80 + k ];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/lpc.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,345 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/lpc.c,v 1.5 1994/12/30 23:14:54 jutta Exp $ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "private.h"
+
+#include "gsm.h"
+#include "proto.h"
+
+#undef	P
+
+/*
+ *  4.2.4 .. 4.2.7 LPC ANALYSIS SECTION
+ */
+
+/* 4.2.4 */
+
+
+static void Autocorrelation P2((s, L_ACF),
+	word     * s,		/* [0..159]	IN/OUT  */
+ 	longword * L_ACF)	/* [0..8]	OUT     */
+/*
+ *  The goal is to compute the array L_ACF[k].  The signal s[i] must
+ *  be scaled in order to avoid an overflow situation.
+ */
+{
+	register int	k, i;
+
+	word		temp, smax, scalauto;
+
+#ifdef	USE_FLOAT_MUL
+	float		float_s[160];
+#endif
+
+	/*  Dynamic scaling of the array  s[0..159]
+	 */
+
+	/*  Search for the maximum.
+	 */
+	smax = 0;
+	for (k = 0; k <= 159; k++) {
+		temp = GSM_ABS( s[k] );
+		if (temp > smax) smax = temp;
+	}
+
+	/*  Computation of the scaling factor.
+	 */
+	if (smax == 0) scalauto = 0;
+	else {
+		assert(smax > 0);
+		scalauto = 4 - gsm_norm( (longword)smax << 16 );/* sub(4,..) */
+	}
+
+	/*  Scaling of the array s[0...159]
+	 */
+
+	if (scalauto > 0) {
+
+# ifdef USE_FLOAT_MUL
+#   define SCALE(n)	\
+	case n: for (k = 0; k <= 159; k++) \
+			float_s[k] = (float)	\
+				(s[k] = GSM_MULT_R(s[k], 16384 >> (n-1)));\
+		break;
+# else 
+#   define SCALE(n)	\
+	case n: for (k = 0; k <= 159; k++) \
+			s[k] = GSM_MULT_R( s[k], 16384 >> (n-1) );\
+		break;
+# endif /* USE_FLOAT_MUL */
+
+		switch (scalauto) {
+		SCALE(1)
+		SCALE(2)
+		SCALE(3)
+		SCALE(4)
+		}
+# undef	SCALE
+	}
+# ifdef	USE_FLOAT_MUL
+	else for (k = 0; k <= 159; k++) float_s[k] = (float) s[k];
+# endif
+
+	/*  Compute the L_ACF[..].
+	 */
+	{
+# ifdef	USE_FLOAT_MUL
+		register float * sp = float_s;
+		register float   sl = *sp;
+
+#		define STEP(k)	 L_ACF[k] += (longword)(sl * sp[ -(k) ]);
+# else
+		word  * sp = s;
+		word    sl = *sp;
+
+#		define STEP(k)	 L_ACF[k] += ((longword)sl * sp[ -(k) ]);
+# endif
+
+#	define NEXTI	 sl = *++sp
+
+
+	for (k = 9; k--; L_ACF[k] = 0) ;
+
+	STEP (0);
+	NEXTI;
+	STEP(0); STEP(1);
+	NEXTI;
+	STEP(0); STEP(1); STEP(2);
+	NEXTI;
+	STEP(0); STEP(1); STEP(2); STEP(3);
+	NEXTI;
+	STEP(0); STEP(1); STEP(2); STEP(3); STEP(4);
+	NEXTI;
+	STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5);
+	NEXTI;
+	STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6);
+	NEXTI;
+	STEP(0); STEP(1); STEP(2); STEP(3); STEP(4); STEP(5); STEP(6); STEP(7);
+
+	for (i = 8; i <= 159; i++) {
+
+		NEXTI;
+
+		STEP(0);
+		STEP(1); STEP(2); STEP(3); STEP(4);
+		STEP(5); STEP(6); STEP(7); STEP(8);
+	}
+
+	for (k = 9; k--; L_ACF[k] <<= 1) ; 
+
+	}
+	/*   Rescaling of the array s[0..159]
+	 */
+	if (scalauto > 0) {
+		assert(scalauto <= 4); 
+		for (k = 160; k--; *s++ <<= scalauto) ;
+	}
+}
+
+#if defined(USE_FLOAT_MUL) && defined(FAST)
+
+static void Fast_Autocorrelation P2((s, L_ACF),
+	word * s,		/* [0..159]	IN/OUT  */
+ 	longword * L_ACF)	/* [0..8]	OUT     */
+{
+	register int	k, i;
+	float f_L_ACF[9];
+	float scale;
+
+	float          s_f[160];
+	register float *sf = s_f;
+
+	for (i = 0; i < 160; ++i) sf[i] = s[i];
+	for (k = 0; k <= 8; k++) {
+		register float L_temp2 = 0;
+		register float *sfl = sf - k;
+		for (i = k; i < 160; ++i) L_temp2 += sf[i] * sfl[i];
+		f_L_ACF[k] = L_temp2;
+	}
+	scale = MAX_LONGWORD / f_L_ACF[0];
+
+	for (k = 0; k <= 8; k++) {
+		L_ACF[k] = f_L_ACF[k] * scale;
+	}
+}
+#endif	/* defined (USE_FLOAT_MUL) && defined (FAST) */
+
+/* 4.2.5 */
+
+static void Reflection_coefficients P2( (L_ACF, r),
+	longword	* L_ACF,		/* 0...8	IN	*/
+	register word	* r			/* 0...7	OUT 	*/
+)
+{
+	register int	i, m, n;
+	register word	temp;
+	register longword ltmp;
+	word		ACF[9];	/* 0..8 */
+	word		P[  9];	/* 0..8 */
+	word		K[  9]; /* 2..8 */
+
+	/*  Schur recursion with 16 bits arithmetic.
+	 */
+
+	if (L_ACF[0] == 0) {
+		for (i = 8; i--; *r++ = 0) ;
+		return;
+	}
+
+	assert( L_ACF[0] != 0 );
+	temp = gsm_norm( L_ACF[0] );
+
+	assert(temp >= 0 && temp < 32);
+
+	/* ? overflow ? */
+	for (i = 0; i <= 8; i++) ACF[i] = SASR( L_ACF[i] << temp, 16 );
+
+	/*   Initialize array P[..] and K[..] for the recursion.
+	 */
+
+	for (i = 1; i <= 7; i++) K[ i ] = ACF[ i ];
+	for (i = 0; i <= 8; i++) P[ i ] = ACF[ i ];
+
+	/*   Compute reflection coefficients
+	 */
+	for (n = 1; n <= 8; n++, r++) {
+
+		temp = P[1];
+		temp = GSM_ABS(temp);
+		if (P[0] < temp) {
+			for (i = n; i <= 8; i++) *r++ = 0;
+			return;
+		}
+
+		*r = gsm_div( temp, P[0] );
+
+		assert(*r >= 0);
+		if (P[1] > 0) *r = -*r;		/* r[n] = sub(0, r[n]) */
+		assert (*r != MIN_WORD);
+		if (n == 8) return; 
+
+		/*  Schur recursion
+		 */
+		temp = GSM_MULT_R( P[1], *r );
+		P[0] = GSM_ADD( P[0], temp );
+
+		for (m = 1; m <= 8 - n; m++) {
+			temp     = GSM_MULT_R( K[ m   ],    *r );
+			P[m]     = GSM_ADD(    P[ m+1 ],  temp );
+
+			temp     = GSM_MULT_R( P[ m+1 ],    *r );
+			K[m]     = GSM_ADD(    K[ m   ],  temp );
+		}
+	}
+}
+
+/* 4.2.6 */
+
+static void Transformation_to_Log_Area_Ratios P1((r),
+	register word	* r 			/* 0..7	   IN/OUT */
+)
+/*
+ *  The following scaling for r[..] and LAR[..] has been used:
+ *
+ *  r[..]   = integer( real_r[..]*32768. ); -1 <= real_r < 1.
+ *  LAR[..] = integer( real_LAR[..] * 16384 );
+ *  with -1.625 <= real_LAR <= 1.625
+ */
+{
+	register word	temp;
+	register int	i;
+
+
+	/* Computation of the LAR[0..7] from the r[0..7]
+	 */
+	for (i = 1; i <= 8; i++, r++) {
+
+		temp = *r;
+		temp = GSM_ABS(temp);
+		assert(temp >= 0);
+
+		if (temp < 22118) {
+			temp >>= 1;
+		} else if (temp < 31130) {
+			assert( temp >= 11059 );
+			temp -= 11059;
+		} else {
+			assert( temp >= 26112 );
+			temp -= 26112;
+			temp <<= 2;
+		}
+
+		*r = *r < 0 ? -temp : temp;
+		assert( *r != MIN_WORD );
+	}
+}
+
+/* 4.2.7 */
+
+static void Quantization_and_coding P1((LAR),
+	register word * LAR    	/* [0..7]	IN/OUT	*/
+)
+{
+	register word	temp;
+	longword	ltmp;
+
+
+	/*  This procedure needs four tables; the following equations
+	 *  give the optimum scaling for the constants:
+	 *  
+	 *  A[0..7] = integer( real_A[0..7] * 1024 )
+	 *  B[0..7] = integer( real_B[0..7] *  512 )
+	 *  MAC[0..7] = maximum of the LARc[0..7]
+	 *  MIC[0..7] = minimum of the LARc[0..7]
+	 */
+
+#	undef STEP
+#	define	STEP( A, B, MAC, MIC )		\
+		temp = GSM_MULT( A,   *LAR );	\
+		temp = GSM_ADD(  temp,   B );	\
+		temp = GSM_ADD(  temp, 256 );	\
+		temp = SASR(     temp,   9 );	\
+		*LAR  =  temp>MAC ? MAC - MIC : (temp<MIC ? 0 : temp - MIC); \
+		LAR++;
+
+	STEP(  20480,     0,  31, -32 );
+	STEP(  20480,     0,  31, -32 );
+	STEP(  20480,  2048,  15, -16 );
+	STEP(  20480, -2560,  15, -16 );
+
+	STEP(  13964,    94,   7,  -8 );
+	STEP(  15360, -1792,   7,  -8 );
+	STEP(   8534,  -341,   3,  -4 );
+	STEP(   9036, -1144,   3,  -4 );
+
+#	undef	STEP
+}
+
+void Gsm_LPC_Analysis P3((S, s,LARc),
+	struct gsm_state *S,
+	word 		 * s,		/* 0..159 signals	IN/OUT	*/
+        word 		 * LARc)	/* 0..7   LARc's	OUT	*/
+{
+	longword	L_ACF[9];
+
+// Wirlab
+	(void)S;
+
+	
+#if defined(USE_FLOAT_MUL) && defined(FAST)
+	if (S->fast) Fast_Autocorrelation (s,	  L_ACF );
+	else
+#endif
+	Autocorrelation			  (s,	  L_ACF	);
+	Reflection_coefficients		  (L_ACF, LARc	);
+	Transformation_to_Log_Area_Ratios (LARc);
+	Quantization_and_coding		  (LARc);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/preprocess.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/preprocess.c,v 1.2 1994/05/10 20:18:45 jutta Exp $ */
+
+#include	<stdio.h>
+#include	<assert.h>
+
+#include "private.h"
+
+#include	"gsm.h"
+#include 	"proto.h"
+
+/*	4.2.0 .. 4.2.3	PREPROCESSING SECTION
+ *  
+ *  	After A-law to linear conversion (or directly from the
+ *   	Ato D converter) the following scaling is assumed for
+ * 	input to the RPE-LTP algorithm:
+ *
+ *      in:  0.1.....................12
+ *	     S.v.v.v.v.v.v.v.v.v.v.v.v.*.*.*
+ *
+ *	Where S is the sign bit, v a valid bit, and * a "don't care" bit.
+ * 	The original signal is called sop[..]
+ *
+ *      out:   0.1................... 12 
+ *	     S.S.v.v.v.v.v.v.v.v.v.v.v.v.0.0
+ */
+
+
+void Gsm_Preprocess P3((S, s, so),
+	struct gsm_state * S,
+	word		 * s,
+	word 		 * so )		/* [0..159] 	IN/OUT	*/
+{
+
+	word       z1 = S->z1;
+	longword L_z2 = S->L_z2;
+	word 	   mp = S->mp;
+
+	word 	   	s1;
+	longword      L_s2;
+
+	longword      L_temp;
+
+	word		msp, lsp;
+	word		SO;
+
+	longword	ltmp;		/* for   ADD */
+	ulongword	utmp;		/* for L_ADD */
+
+	register int		k = 160;
+
+	while (k--) {
+
+	/*  4.2.1   Downscaling of the input signal
+	 */
+		SO = SASR( *s, 3 ) << 2;
+		s++;
+
+		assert (SO >= -0x4000);	/* downscaled by     */
+		assert (SO <=  0x3FFC);	/* previous routine. */
+
+
+	/*  4.2.2   Offset compensation
+	 * 
+	 *  This part implements a high-pass filter and requires extended
+	 *  arithmetic precision for the recursive part of this filter.
+	 *  The input of this procedure is the array so[0...159] and the
+	 *  output the array sof[ 0...159 ].
+	 */
+		/*   Compute the non-recursive part
+		 */
+
+		s1 = SO - z1;			/* s1 = gsm_sub( *so, z1 ); */
+		z1 = SO;
+
+		assert(s1 != MIN_WORD);
+
+		/*   Compute the recursive part
+		 */
+		L_s2 = s1;
+		L_s2 <<= 15;
+
+		/*   Execution of a 31 bv 16 bits multiplication
+		 */
+
+		msp = SASR( L_z2, 15 );
+		lsp = L_z2-((longword)msp<<15); /* gsm_L_sub(L_z2,(msp<<15)); */
+
+		L_s2  += GSM_MULT_R( lsp, 32735 );
+		L_temp = (longword)msp * 32735; /* GSM_L_MULT(msp,32735) >> 1;*/
+		L_z2   = GSM_L_ADD( L_temp, L_s2 );
+
+		/*    Compute sof[k] with rounding
+		 */
+		L_temp = GSM_L_ADD( L_z2, 16384 );
+
+	/*   4.2.3  Preemphasis
+	 */
+
+		msp   = GSM_MULT_R( mp, -28180 );
+		mp    = SASR( L_temp, 15 );
+		*so++ = GSM_ADD( mp, msp );
+	}
+
+	S->z1   = z1;
+	S->L_z2 = L_z2;
+	S->mp   = mp;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/private.h	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,268 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/*$Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/private.h,v 1.6 1996/07/02 10:15:26 jutta Exp $*/
+
+#ifndef	PRIVATE_H
+#define	PRIVATE_H
+
+typedef short			word;		/* 16 bit signed int	*/
+typedef long			longword;	/* 32 bit signed int	*/
+
+typedef unsigned short		uword;		/* unsigned word	*/
+typedef unsigned long		ulongword;	/* unsigned longword	*/
+
+struct gsm_state {
+
+	word		dp0[ 280 ];
+
+	word		z1;		/* preprocessing.c, Offset_com. */
+	longword	L_z2;		/*                  Offset_com. */
+	int		mp;		/*                  Preemphasis	*/
+
+	word		u[8];		/* short_term_aly_filter.c	*/
+	word		LARpp[2][8]; 	/*                              */
+	word		j;		/*                              */
+
+	word            ltp_cut;        /* long_term.c, LTP crosscorr.  */
+	word		nrp; /* 40 */	/* long_term.c, synthesis	*/
+	word		v[9];		/* short_term.c, synthesis	*/
+	word		msr;		/* decoder.c,	Postprocessing	*/
+
+	char		verbose;	/* only used if !NDEBUG		*/
+	char		fast;		/* only used if FAST		*/
+
+	char		wav_fmt;	/* only used if WAV49 defined	*/
+	unsigned char	frame_index;	/*            odd/even chaining	*/
+	unsigned char	frame_chain;	/*   half-byte to carry forward	*/
+};
+
+
+#define	MIN_WORD	(-32767 - 1)
+#define	MAX_WORD	  32767
+
+#define	MIN_LONGWORD	(-2147483647 - 1)
+#define	MAX_LONGWORD	  2147483647
+
+#ifdef	SASR		/* flag: >> is a signed arithmetic shift right */
+#undef	SASR
+#define	SASR(x, by)	((x) >> (by))
+#else
+#define	SASR(x, by)	((x) >= 0 ? (x) >> (by) : (~(-((x) + 1) >> (by))))
+#endif	/* SASR */
+
+#include "proto.h"
+
+/*
+ *	Prototypes from add.c
+ */
+extern word	gsm_mult 	P((word a, word b));
+extern longword gsm_L_mult 	P((word a, word b));
+extern word	gsm_mult_r	P((word a, word b));
+
+extern word	gsm_div  	P((word num, word denum));
+
+extern word	gsm_add 	P(( word a, word b ));
+extern longword gsm_L_add 	P(( longword a, longword b ));
+
+extern word	gsm_sub 	P((word a, word b));
+extern longword gsm_L_sub 	P((longword a, longword b));
+
+extern word	gsm_abs 	P((word a));
+
+extern word	gsm_norm 	P(( longword a ));
+
+extern longword gsm_L_asl  	P((longword a, int n));
+extern word	gsm_asl 	P((word a, int n));
+
+extern longword gsm_L_asr  	P((longword a, int n));
+extern word	gsm_asr  	P((word a, int n));
+
+/*
+ *  Inlined functions from add.h 
+ */
+
+/* 
+ * #define GSM_MULT_R(a, b) (* word a, word b, !(a == b == MIN_WORD) *)	\
+ *	(0x0FFFF & SASR(((longword)(a) * (longword)(b) + 16384), 15))
+ */
+#define GSM_MULT_R(a, b) /* word a, word b, !(a == b == MIN_WORD) */	\
+	(SASR( ((longword)(a) * (longword)(b) + 16384), 15 ))
+
+# define GSM_MULT(a,b)	 /* word a, word b, !(a == b == MIN_WORD) */	\
+	(SASR( ((longword)(a) * (longword)(b)), 15 ))
+
+# define GSM_L_MULT(a, b) /* word a, word b */	\
+	(((longword)(a) * (longword)(b)) << 1)
+
+# define GSM_L_ADD(a, b)	\
+	( (a) <  0 ? ( (b) >= 0 ? (a) + (b)	\
+		 : (utmp = (ulongword)-((a) + 1) + (ulongword)-((b) + 1)) \
+		   >= MAX_LONGWORD ? MIN_LONGWORD : -(longword)utmp-2 )   \
+	: ((b) <= 0 ? (a) + (b)   \
+	          : (utmp = (ulongword)(a) + (ulongword)(b)) >= MAX_LONGWORD \
+		    ? MAX_LONGWORD : utmp))
+
+/*
+ * # define GSM_ADD(a, b)	\
+ * 	((ltmp = (longword)(a) + (longword)(b)) >= MAX_WORD \
+ * 	? MAX_WORD : ltmp <= MIN_WORD ? MIN_WORD : ltmp)
+ */
+/* Nonportable, but faster: */
+
+#define	GSM_ADD(a, b)	\
+	((ulongword)((ltmp = (longword)(a) + (longword)(b)) - MIN_WORD) > \
+		MAX_WORD - MIN_WORD ? (ltmp > 0 ? MAX_WORD : MIN_WORD) : ltmp)
+
+# define GSM_SUB(a, b)	\
+	((ltmp = (longword)(a) - (longword)(b)) >= MAX_WORD \
+	? MAX_WORD : ltmp <= MIN_WORD ? MIN_WORD : ltmp)
+
+# define GSM_ABS(a)	((a) < 0 ? ((a) == MIN_WORD ? MAX_WORD : -(a)) : (a))
+
+/* Use these if necessary:
+
+# define GSM_MULT_R(a, b)	gsm_mult_r(a, b)
+# define GSM_MULT(a, b)		gsm_mult(a, b)
+# define GSM_L_MULT(a, b)	gsm_L_mult(a, b)
+
+# define GSM_L_ADD(a, b)	gsm_L_add(a, b)
+# define GSM_ADD(a, b)		gsm_add(a, b)
+# define GSM_SUB(a, b)		gsm_sub(a, b)
+
+# define GSM_ABS(a)		gsm_abs(a)
+
+*/
+
+/*
+ *  More prototypes from implementations..
+ */
+extern void Gsm_Coder P((
+		struct gsm_state	* S,
+		word	* s,	/* [0..159] samples		IN	*/
+		word	* LARc,	/* [0..7] LAR coefficients	OUT	*/
+		word	* Nc,	/* [0..3] LTP lag		OUT 	*/
+		word	* bc,	/* [0..3] coded LTP gain	OUT 	*/
+		word	* Mc,	/* [0..3] RPE grid selection	OUT     */
+		word	* xmaxc,/* [0..3] Coded maximum amplitude OUT	*/
+		word	* xMc	/* [13*4] normalized RPE samples OUT	*/));
+
+extern void Gsm_Long_Term_Predictor P((		/* 4x for 160 samples */
+		struct gsm_state * S,
+		word	* d,	/* [0..39]   residual signal	IN	*/
+		word	* dp,	/* [-120..-1] d'		IN	*/
+		word	* e,	/* [0..40] 			OUT	*/
+		word	* dpp,	/* [0..40] 			OUT	*/
+		word	* Nc,	/* correlation lag		OUT	*/
+		word	* bc	/* gain factor			OUT	*/));
+
+extern void Gsm_LPC_Analysis P((
+		struct gsm_state * S,
+		word * s,	 /* 0..159 signals	IN/OUT	*/
+	        word * LARc));   /* 0..7   LARc's	OUT	*/
+
+extern void Gsm_Preprocess P((
+		struct gsm_state * S,
+		word * s, word * so));
+
+extern void Gsm_Encoding P((
+		struct gsm_state * S,
+		word	* e,	
+		word	* ep,	
+		word	* xmaxc,
+		word	* Mc,	
+		word	* xMc));
+
+extern void Gsm_Short_Term_Analysis_Filter P((
+		struct gsm_state * S,
+		word	* LARc,	/* coded log area ratio [0..7]  IN	*/
+		word	* d	/* st res. signal [0..159]	IN/OUT	*/));
+
+extern void Gsm_Decoder P((
+		struct gsm_state * S,
+		word	* LARcr,	/* [0..7]		IN	*/
+		word	* Ncr,		/* [0..3] 		IN 	*/
+		word	* bcr,		/* [0..3]		IN	*/
+		word	* Mcr,		/* [0..3] 		IN 	*/
+		word	* xmaxcr,	/* [0..3]		IN 	*/
+		word	* xMcr,		/* [0..13*4]		IN	*/
+		word	* s));		/* [0..159]		OUT 	*/
+
+extern void Gsm_Decoding P((
+		struct gsm_state * S,
+		word 	xmaxcr,
+		word	Mcr,
+		word	* xMcr,  	/* [0..12]		IN	*/
+		word	* erp)); 	/* [0..39]		OUT 	*/
+
+extern void Gsm_Long_Term_Synthesis_Filtering P((
+		struct gsm_state* S,
+		word	Ncr,
+		word	bcr,
+		word	* erp,		/* [0..39]		  IN 	*/
+		word	* drp)); 	/* [-120..-1] IN, [0..40] OUT 	*/
+
+void Gsm_RPE_Decoding P((
+	struct gsm_state *S,
+		word xmaxcr,
+		word Mcr,
+		word * xMcr,  /* [0..12], 3 bits             IN      */
+		word * erp)); /* [0..39]                     OUT     */
+
+void Gsm_RPE_Encoding P((
+		struct gsm_state * S,
+		word    * e,            /* -5..-1][0..39][40..44     IN/OUT  */
+		word    * xmaxc,        /*                              OUT */
+		word    * Mc,           /*                              OUT */
+		word    * xMc));        /* [0..12]                      OUT */
+
+extern void Gsm_Short_Term_Synthesis_Filter P((
+		struct gsm_state * S,
+		word	* LARcr, 	/* log area ratios [0..7]  IN	*/
+		word	* drp,		/* received d [0...39]	   IN	*/
+		word	* s));		/* signal   s [0..159]	  OUT	*/
+
+extern void Gsm_Update_of_reconstructed_short_time_residual_signal P((
+		word	* dpp,		/* [0...39]	IN	*/
+		word	* ep,		/* [0...39]	IN	*/
+		word	* dp));		/* [-120...-1]  IN/OUT 	*/
+
+/*
+ *  Tables from table.c
+ */
+#ifndef	GSM_TABLE_C
+
+extern word gsm_A[8], gsm_B[8], gsm_MIC[8], gsm_MAC[8];
+extern word gsm_INVA[8];
+extern word gsm_DLB[4], gsm_QLB[4];
+extern word gsm_H[11];
+extern word gsm_NRFAC[8];
+extern word gsm_FAC[8];
+
+#endif	/* GSM_TABLE_C */
+
+/*
+ *  Debugging
+ */
+#ifdef NDEBUG
+
+#	define	gsm_debug_words(a, b, c, d)		/* nil */
+#	define	gsm_debug_longwords(a, b, c, d)		/* nil */
+#	define	gsm_debug_word(a, b)			/* nil */
+#	define	gsm_debug_longword(a, b)		/* nil */
+
+#else	/* !NDEBUG => DEBUG */
+
+	extern void  gsm_debug_words     P((char * name, int, int, word *));
+	extern void  gsm_debug_longwords P((char * name, int, int, longword *));
+	extern void  gsm_debug_longword  P((char * name, longword));
+	extern void  gsm_debug_word      P((char * name, word));
+
+#endif /* !NDEBUG */
+
+#include "unproto.h"
+
+#endif	/* PRIVATE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/proto.h	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/*$Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/proto.h,v 1.1 1992/10/28 00:11:08 jutta Exp $*/
+
+#ifndef	PROTO_H
+#define	PROTO_H
+
+#if __cplusplus
+#	define	NeedFunctionPrototypes	1
+#endif
+
+#if __STDC__
+#	define	NeedFunctionPrototypes	1
+#endif
+
+#ifdef	_NO_PROTO
+#	undef	NeedFunctionPrototypes
+#endif
+
+#undef	P	/* gnu stdio.h actually defines this... 	*/
+#undef	P0
+#undef	P1
+#undef	P2
+#undef	P3
+#undef	P4
+#undef	P5
+#undef	P6
+#undef	P7
+#undef	P8
+
+#if NeedFunctionPrototypes
+
+#	define	P( protos )	protos
+
+#	define	P0()				(void)
+#	define	P1(x, a)			(a)
+#	define	P2(x, a, b)			(a, b)
+#	define	P3(x, a, b, c)			(a, b, c)
+#	define	P4(x, a, b, c, d)		(a, b, c, d)	
+#	define	P5(x, a, b, c, d, e)		(a, b, c, d, e)
+#	define	P6(x, a, b, c, d, e, f)		(a, b, c, d, e, f)
+#	define	P7(x, a, b, c, d, e, f, g)	(a, b, c, d, e, f, g)
+#	define	P8(x, a, b, c, d, e, f, g, h)	(a, b, c, d, e, f, g, h)
+
+#else /* !NeedFunctionPrototypes */
+
+#	define	P( protos )	( /* protos */ )
+
+#	define	P0()				()
+#	define	P1(x, a)			x a;
+#	define	P2(x, a, b)			x a; b;
+#	define	P3(x, a, b, c)			x a; b; c;
+#	define	P4(x, a, b, c, d)		x a; b; c; d;
+#	define	P5(x, a, b, c, d, e)		x a; b; c; d; e;
+#	define	P6(x, a, b, c, d, e, f)		x a; b; c; d; e; f;
+#	define	P7(x, a, b, c, d, e, f, g)	x a; b; c; d; e; f; g;
+#	define	P8(x, a, b, c, d, e, f, g, h)	x a; b; c; d; e; f; g; h;
+
+#endif  /* !NeedFunctionPrototypes */
+
+#endif	/* PROTO_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/rpe.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,496 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/rpe.c,v 1.3 1994/05/10 20:18:46 jutta Exp $ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "private.h"
+
+#include "gsm.h"
+#include "proto.h"
+
+/*  4.2.13 .. 4.2.17  RPE ENCODING SECTION
+ */
+
+/* 4.2.13 */
+
+static void Weighting_filter P2((e, x),
+	register word	* e,		/* signal [-5..0.39.44]	IN  */
+	word		* x		/* signal [0..39]	OUT */
+)
+/*
+ *  The coefficients of the weighting filter are stored in a table
+ *  (see table 4.4).  The following scaling is used:
+ *
+ *	H[0..10] = integer( real_H[ 0..10] * 8192 ); 
+ */
+{
+	/* word			wt[ 50 ]; */
+
+	register longword	L_result;
+	register int		k /* , i */ ;
+
+	/*  Initialization of a temporary working array wt[0...49]
+	 */
+
+	/* for (k =  0; k <=  4; k++) wt[k] = 0;
+	 * for (k =  5; k <= 44; k++) wt[k] = *e++;
+	 * for (k = 45; k <= 49; k++) wt[k] = 0;
+	 *
+	 *  (e[-5..-1] and e[40..44] are allocated by the caller,
+	 *  are initially zero and are not written anywhere.)
+	 */
+	e -= 5;
+
+	/*  Compute the signal x[0..39]
+	 */ 
+	for (k = 0; k <= 39; k++) {
+
+		L_result = 8192 >> 1;
+
+		/* for (i = 0; i <= 10; i++) {
+		 *	L_temp   = GSM_L_MULT( wt[k+i], gsm_H[i] );
+		 *	L_result = GSM_L_ADD( L_result, L_temp );
+		 * }
+		 */
+
+#undef	STEP
+#define	STEP( i, H )	(e[ k + i ] * (longword)H)
+
+		/*  Every one of these multiplications is done twice --
+		 *  but I don't see an elegant way to optimize this. 
+		 *  Do you?
+		 */
+
+#ifdef	STUPID_COMPILER
+		L_result += STEP(	0, 	-134 ) ;
+		L_result += STEP(	1, 	-374 )  ;
+	               /* + STEP(	2, 	0    )  */
+		L_result += STEP(	3, 	2054 ) ;
+		L_result += STEP(	4, 	5741 ) ;
+		L_result += STEP(	5, 	8192 ) ;
+		L_result += STEP(	6, 	5741 ) ;
+		L_result += STEP(	7, 	2054 ) ;
+	 	       /* + STEP(	8, 	0    )  */
+		L_result += STEP(	9, 	-374 ) ;
+		L_result += STEP(	10, 	-134 ) ;
+#else
+		L_result +=
+		  STEP(	0, 	-134 ) 
+		+ STEP(	1, 	-374 ) 
+	     /* + STEP(	2, 	0    )  */
+		+ STEP(	3, 	2054 ) 
+		+ STEP(	4, 	5741 ) 
+		+ STEP(	5, 	8192 ) 
+		+ STEP(	6, 	5741 ) 
+		+ STEP(	7, 	2054 ) 
+	     /* + STEP(	8, 	0    )  */
+		+ STEP(	9, 	-374 ) 
+		+ STEP(10, 	-134 )
+		;
+#endif
+
+		/* L_result = GSM_L_ADD( L_result, L_result ); (* scaling(x2) *)
+		 * L_result = GSM_L_ADD( L_result, L_result ); (* scaling(x4) *)
+		 *
+		 * x[k] = SASR( L_result, 16 );
+		 */
+
+		/* 2 adds vs. >>16 => 14, minus one shift to compensate for
+		 * those we lost when replacing L_MULT by '*'.
+		 */
+
+		L_result = SASR( L_result, 13 );
+		x[k] =  (  L_result < MIN_WORD ? MIN_WORD
+			: (L_result > MAX_WORD ? MAX_WORD : L_result ));
+	}
+}
+
+/* 4.2.14 */
+
+static void RPE_grid_selection P3((x,xM,Mc_out),
+	word		* x,		/* [0..39]		IN  */ 
+	word		* xM,		/* [0..12]		OUT */
+	word		* Mc_out	/*			OUT */
+)
+/*
+ *  The signal x[0..39] is used to select the RPE grid which is
+ *  represented by Mc.
+ */
+{
+	/* register word	temp1;	*/
+	register int		/* m, */  i;
+	register longword	L_result, L_temp;
+	longword		EM;	/* xxx should be L_EM? */
+	word			Mc;
+
+	longword		L_common_0_3;
+
+	EM = 0;
+	Mc = 0;
+
+	/* for (m = 0; m <= 3; m++) {
+	 *	L_result = 0;
+	 *
+	 *
+	 *	for (i = 0; i <= 12; i++) {
+	 *
+	 *		temp1    = SASR( x[m + 3*i], 2 );
+	 *
+	 *		assert(temp1 != MIN_WORD);
+	 *
+	 *		L_temp   = GSM_L_MULT( temp1, temp1 );
+	 *		L_result = GSM_L_ADD( L_temp, L_result );
+	 *	}
+	 * 
+	 *	if (L_result > EM) {
+	 *		Mc = m;
+	 *		EM = L_result;
+	 *	}
+	 * }
+	 */
+
+#undef	STEP
+#define	STEP( m, i )		L_temp = SASR( x[m + 3 * i], 2 );	\
+				L_result += L_temp * L_temp;
+
+	/* common part of 0 and 3 */
+
+	L_result = 0;
+	STEP( 0, 1 ); STEP( 0, 2 ); STEP( 0, 3 ); STEP( 0, 4 );
+	STEP( 0, 5 ); STEP( 0, 6 ); STEP( 0, 7 ); STEP( 0, 8 );
+	STEP( 0, 9 ); STEP( 0, 10); STEP( 0, 11); STEP( 0, 12);
+	L_common_0_3 = L_result;
+
+	/* i = 0 */
+
+	STEP( 0, 0 );
+	L_result <<= 1;	/* implicit in L_MULT */
+	EM = L_result;
+
+	/* i = 1 */
+
+	L_result = 0;
+	STEP( 1, 0 );
+	STEP( 1, 1 ); STEP( 1, 2 ); STEP( 1, 3 ); STEP( 1, 4 );
+	STEP( 1, 5 ); STEP( 1, 6 ); STEP( 1, 7 ); STEP( 1, 8 );
+	STEP( 1, 9 ); STEP( 1, 10); STEP( 1, 11); STEP( 1, 12);
+	L_result <<= 1;
+	if (L_result > EM) {
+		Mc = 1;
+	 	EM = L_result;
+	}
+
+	/* i = 2 */
+
+	L_result = 0;
+	STEP( 2, 0 );
+	STEP( 2, 1 ); STEP( 2, 2 ); STEP( 2, 3 ); STEP( 2, 4 );
+	STEP( 2, 5 ); STEP( 2, 6 ); STEP( 2, 7 ); STEP( 2, 8 );
+	STEP( 2, 9 ); STEP( 2, 10); STEP( 2, 11); STEP( 2, 12);
+	L_result <<= 1;
+	if (L_result > EM) {
+		Mc = 2;
+	 	EM = L_result;
+	}
+
+	/* i = 3 */
+
+	L_result = L_common_0_3;
+	STEP( 3, 12 );
+	L_result <<= 1;
+	if (L_result > EM) {
+		Mc = 3;
+	 	EM = L_result;
+	}
+
+	/**/
+
+	/*  Down-sampling by a factor 3 to get the selected xM[0..12]
+	 *  RPE sequence.
+	 */
+	for (i = 0; i <= 12; i ++) xM[i] = x[Mc + 3*i];
+	*Mc_out = Mc;
+}
+
+/* 4.12.15 */
+
+static void APCM_quantization_xmaxc_to_exp_mant P3((xmaxc,exp_out,mant_out),
+	word		xmaxc,		/* IN 	*/
+	word		* exp_out,	/* OUT	*/
+	word		* mant_out )	/* OUT  */
+{
+	word	exp, mant;
+
+	/* Compute exponent and mantissa of the decoded version of xmaxc
+	 */
+
+	exp = 0;
+	if (xmaxc > 15) exp = SASR(xmaxc, 3) - 1;
+	mant = xmaxc - (exp << 3);
+
+	if (mant == 0) {
+		exp  = -4;
+		mant = 7;
+	}
+	else {
+		while (mant <= 7) {
+			mant = mant << 1 | 1;
+			exp--;
+		}
+		mant -= 8;
+	}
+
+	assert( exp  >= -4 && exp <= 6 );
+	assert( mant >= 0 && mant <= 7 );
+
+	*exp_out  = exp;
+	*mant_out = mant;
+}
+
+static void APCM_quantization P5((xM,xMc,mant_out,exp_out,xmaxc_out),
+	word		* xM,		/* [0..12]		IN	*/
+
+	word		* xMc,		/* [0..12]		OUT	*/
+	word		* mant_out,	/* 			OUT	*/
+	word		* exp_out,	/*			OUT	*/
+	word		* xmaxc_out	/*			OUT	*/
+)
+{
+	int	i, itest;
+
+	word	xmax, xmaxc, temp, temp1, temp2;
+	word	exp, mant;
+
+
+	/*  Find the maximum absolute value xmax of xM[0..12].
+	 */
+
+	xmax = 0;
+	for (i = 0; i <= 12; i++) {
+		temp = xM[i];
+		temp = GSM_ABS(temp);
+		if (temp > xmax) xmax = temp;
+	}
+
+	/*  Qantizing and coding of xmax to get xmaxc.
+	 */
+
+	exp   = 0;
+	temp  = SASR( xmax, 9 );
+	itest = 0;
+
+	for (i = 0; i <= 5; i++) {
+
+		itest |= (temp <= 0);
+		temp = SASR( temp, 1 );
+
+		assert(exp <= 5);
+		if (itest == 0) exp++;		/* exp = add (exp, 1) */
+	}
+
+	assert(exp <= 6 && exp >= 0);
+	temp = exp + 5;
+
+	assert(temp <= 11 && temp >= 0);
+	xmaxc = gsm_add( SASR(xmax, temp), exp << 3 );
+
+	/*   Quantizing and coding of the xM[0..12] RPE sequence
+	 *   to get the xMc[0..12]
+	 */
+
+	APCM_quantization_xmaxc_to_exp_mant( xmaxc, &exp, &mant );
+
+	/*  This computation uses the fact that the decoded version of xmaxc
+	 *  can be calculated by using the exponent and the mantissa part of
+	 *  xmaxc (logarithmic table).
+	 *  So, this method avoids any division and uses only a scaling
+	 *  of the RPE samples by a function of the exponent.  A direct 
+	 *  multiplication by the inverse of the mantissa (NRFAC[0..7]
+	 *  found in table 4.5) gives the 3 bit coded version xMc[0..12]
+	 *  of the RPE samples.
+	 */
+
+
+	/* Direct computation of xMc[0..12] using table 4.5
+	 */
+
+	assert( exp <= 4096 && exp >= -4096);
+	assert( mant >= 0 && mant <= 7 ); 
+
+	temp1 = 6 - exp;		/* normalization by the exponent */
+	temp2 = gsm_NRFAC[ mant ];  	/* inverse mantissa 		 */
+
+	for (i = 0; i <= 12; i++) {
+
+		assert(temp1 >= 0 && temp1 < 16);
+
+		temp = xM[i] << temp1;
+		temp = GSM_MULT( temp, temp2 );
+		temp = SASR(temp, 12);
+		xMc[i] = temp + 4;		/* see note below */
+	}
+
+	/*  NOTE: This equation is used to make all the xMc[i] positive.
+	 */
+
+	*mant_out  = mant;
+	*exp_out   = exp;
+	*xmaxc_out = xmaxc;
+}
+
+/* 4.2.16 */
+
+static void APCM_inverse_quantization P4((xMc,mant,exp,xMp),
+	register word	* xMc,	/* [0..12]			IN 	*/
+	word		mant,
+	word		exp,
+	register word	* xMp)	/* [0..12]			OUT 	*/
+/* 
+ *  This part is for decoding the RPE sequence of coded xMc[0..12]
+ *  samples to obtain the xMp[0..12] array.  Table 4.6 is used to get
+ *  the mantissa of xmaxc (FAC[0..7]).
+ */
+{
+	int	i;
+	word	temp, temp1, temp2, temp3;
+	longword	ltmp;
+
+	assert( mant >= 0 && mant <= 7 ); 
+
+	temp1 = gsm_FAC[ mant ];	/* see 4.2-15 for mant */
+	temp2 = gsm_sub( 6, exp );	/* see 4.2-15 for exp  */
+	temp3 = gsm_asl( 1, gsm_sub( temp2, 1 ));
+
+	for (i = 13; i--;) {
+
+		assert( *xMc <= 7 && *xMc >= 0 ); 	/* 3 bit unsigned */
+
+		/* temp = gsm_sub( *xMc++ << 1, 7 ); */
+		temp = (*xMc++ << 1) - 7;	        /* restore sign   */
+		assert( temp <= 7 && temp >= -7 ); 	/* 4 bit signed   */
+
+		temp <<= 12;				/* 16 bit signed  */
+		temp = GSM_MULT_R( temp1, temp );
+		temp = GSM_ADD( temp, temp3 );
+		*xMp++ = gsm_asr( temp, temp2 );
+	}
+}
+
+/* 4.2.17 */
+
+static void RPE_grid_positioning P3((Mc,xMp,ep),
+	word		Mc,		/* grid position	IN	*/
+	register word	* xMp,		/* [0..12]		IN	*/
+	register word	* ep		/* [0..39]		OUT	*/
+)
+/*
+ *  This procedure computes the reconstructed long term residual signal
+ *  ep[0..39] for the LTP analysis filter.  The inputs are the Mc
+ *  which is the grid position selection and the xMp[0..12] decoded
+ *  RPE samples which are upsampled by a factor of 3 by inserting zero
+ *  values.
+ */
+{
+	int	i = 13;
+
+	assert(0 <= Mc && Mc <= 3);
+
+        switch (Mc) {
+                case 3: *ep++ = 0;
+                case 2:  do {
+                                *ep++ = 0;
+                case 1:         *ep++ = 0;
+                case 0:         *ep++ = *xMp++;
+                         } while (--i);
+        }
+        while (++Mc < 4) *ep++ = 0;
+
+	/*
+
+	int i, k;
+	for (k = 0; k <= 39; k++) ep[k] = 0;
+	for (i = 0; i <= 12; i++) {
+		ep[ Mc + (3*i) ] = xMp[i];
+	}
+	*/
+}
+
+/* 4.2.18 */
+
+/*  This procedure adds the reconstructed long term residual signal
+ *  ep[0..39] to the estimated signal dpp[0..39] from the long term
+ *  analysis filter to compute the reconstructed short term residual
+ *  signal dp[-40..-1]; also the reconstructed short term residual
+ *  array dp[-120..-41] is updated.
+ */
+
+#if 0	/* Has been inlined in code.c */
+void Gsm_Update_of_reconstructed_short_time_residual_signal P3((dpp, ep, dp),
+	word	* dpp,		/* [0...39]	IN	*/
+	word	* ep,		/* [0...39]	IN	*/
+	word	* dp)		/* [-120...-1]  IN/OUT 	*/
+{
+	int 		k;
+
+	for (k = 0; k <= 79; k++) 
+		dp[ -120 + k ] = dp[ -80 + k ];
+
+	for (k = 0; k <= 39; k++)
+		dp[ -40 + k ] = gsm_add( ep[k], dpp[k] );
+}
+#endif	/* Has been inlined in code.c */
+
+void Gsm_RPE_Encoding P5((S,e,xmaxc,Mc,xMc),
+
+	struct gsm_state * S,
+
+	word	* e,		/* -5..-1][0..39][40..44	IN/OUT  */
+	word	* xmaxc,	/* 				OUT */
+	word	* Mc,		/* 			  	OUT */
+	word	* xMc)		/* [0..12]			OUT */
+{
+	word	x[40];
+	word	xM[13], xMp[13];
+	word	mant, exp;
+// Wirlab
+	(void)S;
+
+	
+
+	Weighting_filter(e, x);
+	RPE_grid_selection(x, xM, Mc);
+
+	APCM_quantization(	xM, xMc, &mant, &exp, xmaxc);
+	APCM_inverse_quantization(  xMc,  mant,  exp, xMp);
+
+	RPE_grid_positioning( *Mc, xMp, e );
+
+}
+
+void Gsm_RPE_Decoding P5((S, xmaxcr, Mcr, xMcr, erp),
+	struct gsm_state	* S,
+
+	word 		xmaxcr,
+	word		Mcr,
+	word		* xMcr,  /* [0..12], 3 bits 		IN	*/
+	word		* erp	 /* [0..39]			OUT 	*/
+)
+{
+	word	exp, mant;
+	word	xMp[ 13 ];
+// Wirlab
+	(void)S;
+
+	
+
+	APCM_quantization_xmaxc_to_exp_mant( xmaxcr, &exp, &mant );
+	APCM_inverse_quantization( xMcr, mant, exp, xMp );
+	RPE_grid_positioning( Mcr, xMp, erp );
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/short_term.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,429 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/short_term.c,v 1.2 1994/05/10 20:18:47 jutta Exp $ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "private.h"
+
+#include "gsm.h"
+#include "proto.h"
+
+/*
+ *  SHORT TERM ANALYSIS FILTERING SECTION
+ */
+
+/* 4.2.8 */
+
+static void Decoding_of_the_coded_Log_Area_Ratios P2((LARc,LARpp),
+	word 	* LARc,		/* coded log area ratio	[0..7] 	IN	*/
+	word	* LARpp)	/* out: decoded ..			*/
+{
+	register word	temp1 /* , temp2 */;
+	register long	ltmp;	/* for GSM_ADD */
+
+	/*  This procedure requires for efficient implementation
+	 *  two tables.
+ 	 *
+	 *  INVA[1..8] = integer( (32768 * 8) / real_A[1..8])
+	 *  MIC[1..8]  = minimum value of the LARc[1..8]
+	 */
+
+	/*  Compute the LARpp[1..8]
+	 */
+
+	/* 	for (i = 1; i <= 8; i++, B++, MIC++, INVA++, LARc++, LARpp++) {
+	 *
+	 *		temp1  = GSM_ADD( *LARc, *MIC ) << 10;
+	 *		temp2  = *B << 1;
+	 *		temp1  = GSM_SUB( temp1, temp2 );
+	 *
+	 *		assert(*INVA != MIN_WORD);
+	 *
+	 *		temp1  = GSM_MULT_R( *INVA, temp1 );
+	 *		*LARpp = GSM_ADD( temp1, temp1 );
+	 *	}
+	 */
+
+#undef	STEP
+#define	STEP( B, MIC, INVA )	\
+		temp1    = GSM_ADD( *LARc++, MIC ) << 10;	\
+		temp1    = GSM_SUB( temp1, B << 1 );		\
+		temp1    = GSM_MULT_R( INVA, temp1 );		\
+		*LARpp++ = GSM_ADD( temp1, temp1 );
+
+	STEP(      0,  -32,  13107 );
+	STEP(      0,  -32,  13107 );
+	STEP(   2048,  -16,  13107 );
+	STEP(  -2560,  -16,  13107 );
+
+	STEP(     94,   -8,  19223 );
+	STEP(  -1792,   -8,  17476 );
+	STEP(   -341,   -4,  31454 );
+	STEP(  -1144,   -4,  29708 );
+
+	/* NOTE: the addition of *MIC is used to restore
+	 * 	 the sign of *LARc.
+	 */
+}
+
+/* 4.2.9 */
+/* Computation of the quantized reflection coefficients 
+ */
+
+/* 4.2.9.1  Interpolation of the LARpp[1..8] to get the LARp[1..8]
+ */
+
+/*
+ *  Within each frame of 160 analyzed speech samples the short term
+ *  analysis and synthesis filters operate with four different sets of
+ *  coefficients, derived from the previous set of decoded LARs(LARpp(j-1))
+ *  and the actual set of decoded LARs (LARpp(j))
+ *
+ * (Initial value: LARpp(j-1)[1..8] = 0.)
+ */
+
+static void Coefficients_0_12 P3((LARpp_j_1, LARpp_j, LARp),
+	register word * LARpp_j_1,
+	register word * LARpp_j,
+	register word * LARp)
+{
+	register int 	i;
+	register longword ltmp;
+
+	for (i = 1; i <= 8; i++, LARp++, LARpp_j_1++, LARpp_j++) {
+		*LARp = GSM_ADD( SASR( *LARpp_j_1, 2 ), SASR( *LARpp_j, 2 ));
+		*LARp = GSM_ADD( *LARp,  SASR( *LARpp_j_1, 1));
+	}
+}
+
+static void Coefficients_13_26 P3((LARpp_j_1, LARpp_j, LARp),
+	register word * LARpp_j_1,
+	register word * LARpp_j,
+	register word * LARp)
+{
+	register int i;
+	register longword ltmp;
+	for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) {
+		*LARp = GSM_ADD( SASR( *LARpp_j_1, 1), SASR( *LARpp_j, 1 ));
+	}
+}
+
+static void Coefficients_27_39 P3((LARpp_j_1, LARpp_j, LARp),
+	register word * LARpp_j_1,
+	register word * LARpp_j,
+	register word * LARp)
+{
+	register int i;
+	register longword ltmp;
+
+	for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++) {
+		*LARp = GSM_ADD( SASR( *LARpp_j_1, 2 ), SASR( *LARpp_j, 2 ));
+		*LARp = GSM_ADD( *LARp, SASR( *LARpp_j, 1 ));
+	}
+}
+
+
+static void Coefficients_40_159 P2((LARpp_j, LARp),
+	register word * LARpp_j,
+	register word * LARp)
+{
+	register int i;
+
+	for (i = 1; i <= 8; i++, LARp++, LARpp_j++)
+		*LARp = *LARpp_j;
+}
+
+/* 4.2.9.2 */
+
+static void LARp_to_rp P1((LARp),
+	register word * LARp)	/* [0..7] IN/OUT  */
+/*
+ *  The input of this procedure is the interpolated LARp[0..7] array.
+ *  The reflection coefficients, rp[i], are used in the analysis
+ *  filter and in the synthesis filter.
+ */
+{
+	register int 		i;
+	register word		temp;
+	register longword	ltmp;
+
+	for (i = 1; i <= 8; i++, LARp++) {
+
+		/* temp = GSM_ABS( *LARp );
+	         *
+		 * if (temp < 11059) temp <<= 1;
+		 * else if (temp < 20070) temp += 11059;
+		 * else temp = GSM_ADD( temp >> 2, 26112 );
+		 *
+		 * *LARp = *LARp < 0 ? -temp : temp;
+		 */
+
+		if (*LARp < 0) {
+			temp = *LARp == MIN_WORD ? MAX_WORD : -(*LARp);
+			*LARp = - ((temp < 11059) ? temp << 1
+				: ((temp < 20070) ? temp + 11059
+				:  GSM_ADD( temp >> 2, 26112 )));
+		} else {
+			temp  = *LARp;
+			*LARp =    (temp < 11059) ? temp << 1
+				: ((temp < 20070) ? temp + 11059
+				:  GSM_ADD( temp >> 2, 26112 ));
+		}
+	}
+}
+
+
+/* 4.2.10 */
+static void Short_term_analysis_filtering P4((S,rp,k_n,s),
+	struct gsm_state * S,
+	register word	* rp,	/* [0..7]	IN	*/
+	register int 	k_n, 	/*   k_end - k_start	*/
+	register word	* s	/* [0..n-1]	IN/OUT	*/
+)
+/*
+ *  This procedure computes the short term residual signal d[..] to be fed
+ *  to the RPE-LTP loop from the s[..] signal and from the local rp[..]
+ *  array (quantized reflection coefficients).  As the call of this
+ *  procedure can be done in many ways (see the interpolation of the LAR
+ *  coefficient), it is assumed that the computation begins with index
+ *  k_start (for arrays d[..] and s[..]) and stops with index k_end
+ *  (k_start and k_end are defined in 4.2.9.1).  This procedure also
+ *  needs to keep the array u[0..7] in memory for each call.
+ */
+{
+	register word		* u = S->u;
+	register int		i;
+	register word		di, zzz, ui, sav, rpi;
+	register longword 	ltmp;
+
+	for (; k_n--; s++) {
+
+		di = sav = *s;
+
+		for (i = 0; i < 8; i++) {		/* YYY */
+
+			ui    = u[i];
+			rpi   = rp[i];
+			u[i]  = sav;
+
+			zzz   = GSM_MULT_R(rpi, di);
+			sav   = GSM_ADD(   ui,  zzz);
+
+			zzz   = GSM_MULT_R(rpi, ui);
+			di    = GSM_ADD(   di,  zzz );
+		}
+
+		*s = di;
+	}
+}
+
+#if defined(USE_FLOAT_MUL) && defined(FAST)
+
+static void Fast_Short_term_analysis_filtering P4((S,rp,k_n,s),
+	struct gsm_state * S,
+	register word	* rp,	/* [0..7]	IN	*/
+	register int 	k_n, 	/*   k_end - k_start	*/
+	register word	* s	/* [0..n-1]	IN/OUT	*/
+)
+{
+	register word		* u = S->u;
+	register int		i;
+
+	float 	  uf[8],
+		 rpf[8];
+
+	register float scalef = 3.0517578125e-5;
+	register float		sav, di, temp;
+
+	for (i = 0; i < 8; ++i) {
+		uf[i]  = u[i];
+		rpf[i] = rp[i] * scalef;
+	}
+	for (; k_n--; s++) {
+		sav = di = *s;
+		for (i = 0; i < 8; ++i) {
+			register float rpfi = rpf[i];
+			register float ufi  = uf[i];
+
+			uf[i] = sav;
+			temp  = rpfi * di + ufi;
+			di   += rpfi * ufi;
+			sav   = temp;
+		}
+		*s = di;
+	}
+	for (i = 0; i < 8; ++i) u[i] = uf[i];
+}
+#endif /* ! (defined (USE_FLOAT_MUL) && defined (FAST)) */
+
+static void Short_term_synthesis_filtering P5((S,rrp,k,wt,sr),
+	struct gsm_state * S,
+	register word	* rrp,	/* [0..7]	IN	*/
+	register int	k,	/* k_end - k_start	*/
+	register word	* wt,	/* [0..k-1]	IN	*/
+	register word	* sr	/* [0..k-1]	OUT	*/
+)
+{
+	register word		* v = S->v;
+	register int		i;
+	register word		sri, tmp1, tmp2;
+	register longword	ltmp;	/* for GSM_ADD  & GSM_SUB */
+
+	while (k--) {
+		sri = *wt++;
+		for (i = 8; i--;) {
+
+			/* sri = GSM_SUB( sri, gsm_mult_r( rrp[i], v[i] ) );
+			 */
+			tmp1 = rrp[i];
+			tmp2 = v[i];
+			tmp2 =  ( tmp1 == MIN_WORD && tmp2 == MIN_WORD
+				? MAX_WORD
+				: 0x0FFFF & (( (longword)tmp1 * (longword)tmp2
+					     + 16384) >> 15)) ;
+
+			sri  = GSM_SUB( sri, tmp2 );
+
+			/* v[i+1] = GSM_ADD( v[i], gsm_mult_r( rrp[i], sri ) );
+			 */
+			tmp1  = ( tmp1 == MIN_WORD && sri == MIN_WORD
+				? MAX_WORD
+				: 0x0FFFF & (( (longword)tmp1 * (longword)sri
+					     + 16384) >> 15)) ;
+
+			v[i+1] = GSM_ADD( v[i], tmp1);
+		}
+		*sr++ = v[0] = sri;
+	}
+}
+
+
+#if defined(FAST) && defined(USE_FLOAT_MUL)
+
+static void Fast_Short_term_synthesis_filtering P5((S,rrp,k,wt,sr),
+	struct gsm_state * S,
+	register word	* rrp,	/* [0..7]	IN	*/
+	register int	k,	/* k_end - k_start	*/
+	register word	* wt,	/* [0..k-1]	IN	*/
+	register word	* sr	/* [0..k-1]	OUT	*/
+)
+{
+	register word		* v = S->v;
+	register int		i;
+
+	float va[9], rrpa[8];
+	register float scalef = 3.0517578125e-5, temp;
+
+	for (i = 0; i < 8; ++i) {
+		va[i]   = v[i];
+		rrpa[i] = (float)rrp[i] * scalef;
+	}
+	while (k--) {
+		register float sri = *wt++;
+		for (i = 8; i--;) {
+			sri -= rrpa[i] * va[i];
+			if     (sri < -32768.) sri = -32768.;
+			else if (sri > 32767.) sri =  32767.;
+
+			temp = va[i] + rrpa[i] * sri;
+			if     (temp < -32768.) temp = -32768.;
+			else if (temp > 32767.) temp =  32767.;
+			va[i+1] = temp;
+		}
+		*sr++ = va[0] = sri;
+	}
+	for (i = 0; i < 9; ++i) v[i] = va[i];
+}
+
+#endif /* defined(FAST) && defined(USE_FLOAT_MUL) */
+
+void Gsm_Short_Term_Analysis_Filter P3((S,LARc,s),
+
+	struct gsm_state * S,
+
+	word	* LARc,		/* coded log area ratio [0..7]  IN	*/
+	word	* s		/* signal [0..159]		IN/OUT	*/
+)
+{
+	word		* LARpp_j	= S->LARpp[ S->j      ];
+	word		* LARpp_j_1	= S->LARpp[ S->j ^= 1 ];
+
+	word		LARp[8];
+
+#undef	FILTER
+#if 	defined(FAST) && defined(USE_FLOAT_MUL)
+# 	define	FILTER 	(* (S->fast			\
+			   ? Fast_Short_term_analysis_filtering	\
+		    	   : Short_term_analysis_filtering	))
+
+#else
+# 	define	FILTER	Short_term_analysis_filtering
+#endif
+
+	Decoding_of_the_coded_Log_Area_Ratios( LARc, LARpp_j );
+
+	Coefficients_0_12(  LARpp_j_1, LARpp_j, LARp );
+	LARp_to_rp( LARp );
+	FILTER( S, LARp, 13, s);
+
+	Coefficients_13_26( LARpp_j_1, LARpp_j, LARp);
+	LARp_to_rp( LARp );
+	FILTER( S, LARp, 14, s + 13);
+
+	Coefficients_27_39( LARpp_j_1, LARpp_j, LARp);
+	LARp_to_rp( LARp );
+	FILTER( S, LARp, 13, s + 27);
+
+	Coefficients_40_159( LARpp_j, LARp);
+	LARp_to_rp( LARp );
+	FILTER( S, LARp, 120, s + 40);
+}
+
+void Gsm_Short_Term_Synthesis_Filter P4((S, LARcr, wt, s),
+	struct gsm_state * S,
+
+	word	* LARcr,	/* received log area ratios [0..7] IN  */
+	word	* wt,		/* received d [0..159]		   IN  */
+
+	word	* s		/* signal   s [0..159]		  OUT  */
+)
+{
+	word		* LARpp_j	= S->LARpp[ S->j     ];
+	word		* LARpp_j_1	= S->LARpp[ S->j ^=1 ];
+
+	word		LARp[8];
+
+#undef	FILTER
+#if 	defined(FAST) && defined(USE_FLOAT_MUL)
+
+# 	define	FILTER 	(* (S->fast			\
+			   ? Fast_Short_term_synthesis_filtering	\
+		    	   : Short_term_synthesis_filtering	))
+#else
+#	define	FILTER	Short_term_synthesis_filtering
+#endif
+
+	Decoding_of_the_coded_Log_Area_Ratios( LARcr, LARpp_j );
+
+	Coefficients_0_12( LARpp_j_1, LARpp_j, LARp );
+	LARp_to_rp( LARp );
+	FILTER( S, LARp, 13, wt, s );
+
+	Coefficients_13_26( LARpp_j_1, LARpp_j, LARp);
+	LARp_to_rp( LARp );
+	FILTER( S, LARp, 14, wt + 13, s + 13 );
+
+	Coefficients_27_39( LARpp_j_1, LARpp_j, LARp);
+	LARp_to_rp( LARp );
+	FILTER( S, LARp, 13, wt + 27, s + 27 );
+
+	Coefficients_40_159( LARpp_j, LARp );
+	LARp_to_rp( LARp );
+	FILTER(S, LARp, 120, wt + 40, s + 40);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/table.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,63 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/table.c,v 1.1 1992/10/28 00:15:50 jutta Exp $ */
+
+/*  Most of these tables are inlined at their point of use.
+ */
+
+/*  4.4 TABLES USED IN THE FIXED POINT IMPLEMENTATION OF THE RPE-LTP
+ *      CODER AND DECODER
+ *
+ *	(Most of them inlined, so watch out.)
+ */
+
+#define	GSM_TABLE_C
+#include "private.h"
+#include	"gsm.h"
+
+/*  Table 4.1  Quantization of the Log.-Area Ratios
+ */
+/* i 		     1      2      3        4      5      6        7       8 */
+word gsm_A[8]   = {20480, 20480, 20480,  20480,  13964,  15360,   8534,  9036};
+word gsm_B[8]   = {    0,     0,  2048,  -2560,     94,  -1792,   -341, -1144};
+word gsm_MIC[8] = { -32,   -32,   -16,    -16,     -8,     -8,     -4,    -4 };
+word gsm_MAC[8] = {  31,    31,    15,     15,      7,      7,      3,     3 };
+
+
+/*  Table 4.2  Tabulation  of 1/A[1..8]
+ */
+word gsm_INVA[8]={ 13107, 13107,  13107, 13107,  19223, 17476,  31454, 29708 };
+
+
+/*   Table 4.3a  Decision level of the LTP gain quantizer
+ */
+/*  bc		      0	        1	  2	     3			*/
+word gsm_DLB[4] = {  6554,    16384,	26214,	   32767	};
+
+
+/*   Table 4.3b   Quantization levels of the LTP gain quantizer
+ */
+/* bc		      0          1        2          3			*/
+word gsm_QLB[4] = {  3277,    11469,	21299,	   32767	};
+
+
+/*   Table 4.4	 Coefficients of the weighting filter
+ */
+/* i		    0      1   2    3   4      5      6     7   8   9    10  */
+word gsm_H[11] = {-134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134 };
+
+
+/*   Table 4.5 	 Normalized inverse mantissa used to compute xM/xmax 
+ */
+/* i		 	0        1    2      3      4      5     6      7   */
+word gsm_NRFAC[8] = { 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 };
+
+
+/*   Table 4.6	 Normalized direct mantissa used to compute xM/xmax
+ */
+/* i                  0      1       2      3      4      5      6      7   */
+word gsm_FAC[8]	= { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/toast_alaw.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,334 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /home/kbs/jutta/src/gsm/gsm-1.0/src/RCS/toast_alaw.c,v 1.2 1996/07/05 17:23:46 jutta Exp $ */
+
+#include	"toast.h"
+
+/*  toast_alaw.c -- manipulate A-law encoded sound.
+ */
+
+extern FILE	* in, * out;
+
+#define	A2S(x)	(a2s[  (unsigned char )(x)       ])
+#define	S2A(x)	(s2a[ ((unsigned short)(x)) >> 4 ])
+
+static unsigned short a2s[] = {
+
+ 60032, 60288, 59520, 59776, 61056, 61312, 60544, 60800,
+ 57984, 58240, 57472, 57728, 59008, 59264, 58496, 58752,
+ 62784, 62912, 62528, 62656, 63296, 63424, 63040, 63168,
+ 61760, 61888, 61504, 61632, 62272, 62400, 62016, 62144,
+ 43520, 44544, 41472, 42496, 47616, 48640, 45568, 46592,
+ 35328, 36352, 33280, 34304, 39424, 40448, 37376, 38400,
+ 54528, 55040, 53504, 54016, 56576, 57088, 55552, 56064,
+ 50432, 50944, 49408, 49920, 52480, 52992, 51456, 51968,
+ 65192, 65208, 65160, 65176, 65256, 65272, 65224, 65240,
+ 65064, 65080, 65032, 65048, 65128, 65144, 65096, 65112,
+ 65448, 65464, 65416, 65432, 65512, 65528, 65480, 65496,
+ 65320, 65336, 65288, 65304, 65384, 65400, 65352, 65368,
+ 64160, 64224, 64032, 64096, 64416, 64480, 64288, 64352,
+ 63648, 63712, 63520, 63584, 63904, 63968, 63776, 63840,
+ 64848, 64880, 64784, 64816, 64976, 65008, 64912, 64944,
+ 64592, 64624, 64528, 64560, 64720, 64752, 64656, 64688,
+  5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
+  7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
+  2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
+  3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
+ 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+ 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+ 11008, 10496, 12032, 11520,  8960,  8448,  9984,  9472,
+ 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+   344,   328,   376,   360,   280,   264,   312,   296,
+   472,   456,   504,   488,   408,   392,   440,   424,
+    88,    72,   120,   104,    24,     8,    56,    40,
+   216,   200,   248,   232,   152,   136,   184,   168,
+  1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
+  1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
+   688,   656,   752,   720,   560,   528,   624,   592,
+   944,   912,  1008,   976,   816,   784,   880,   848
+
+};
+
+
+static unsigned char  s2a[] = {
+
+	213,212,215,214,209,208,211,210,221,220,223,222,217,216,219,218,
+	197,196,199,198,193,192,195,194,205,204,207,206,201,200,203,202,
+	245,245,244,244,247,247,246,246,241,241,240,240,243,243,242,242,
+	253,253,252,252,255,255,254,254,249,249,248,248,251,251,250,250,
+	229,229,229,229,228,228,228,228,231,231,231,231,230,230,230,230,
+	225,225,225,225,224,224,224,224,227,227,227,227,226,226,226,226,
+	237,237,237,237,236,236,236,236,239,239,239,239,238,238,238,238,
+	233,233,233,233,232,232,232,232,235,235,235,235,234,234,234,234,
+	149,149,149,149,149,149,149,149,148,148,148,148,148,148,148,148,
+	151,151,151,151,151,151,151,151,150,150,150,150,150,150,150,150,
+	145,145,145,145,145,145,145,145,144,144,144,144,144,144,144,144,
+	147,147,147,147,147,147,147,147,146,146,146,146,146,146,146,146,
+	157,157,157,157,157,157,157,157,156,156,156,156,156,156,156,156,
+	159,159,159,159,159,159,159,159,158,158,158,158,158,158,158,158,
+	153,153,153,153,153,153,153,153,152,152,152,152,152,152,152,152,
+	155,155,155,155,155,155,155,155,154,154,154,154,154,154,154,154,
+	133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
+	132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
+	135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
+	134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
+	129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
+	128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
+	131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
+	130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
+	141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
+	140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
+	143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+	142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
+	137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
+	136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
+	139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
+	138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
+	181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
+	181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
+	180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
+	180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
+	183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,
+	183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,
+	182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+	182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+	177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
+	177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
+	176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
+	176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
+	179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,
+	179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,
+	178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
+	178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
+	189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
+	189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
+	188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
+	188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
+	191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,
+	191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,
+	190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,
+	190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,
+	185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
+	185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
+	184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
+	184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
+	187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,
+	187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,
+	186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,
+	186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,
+	165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
+	165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
+	165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
+	165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
+	164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
+	164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
+	164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
+	164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
+	167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
+	167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
+	167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
+	167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
+	166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
+	166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
+	166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
+	166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
+	161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
+	161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
+	161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
+	161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
+	160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
+	160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
+	160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
+	160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
+	163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+	163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+	163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+	163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+	162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
+	162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
+	162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
+	162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
+	173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+	173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+	173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+	173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+	172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+	172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+	172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+	172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+	175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
+	175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
+	175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
+	175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
+	174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+	174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+	174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+	174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+	169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
+	169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
+	169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
+	169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
+	168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
+	168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
+	168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
+	168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
+	171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
+	171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
+	171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
+	171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
+	170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+	170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+	170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+	170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+	 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+	 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+	 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+	 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+	 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+	 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+	 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+	 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+	 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+	 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+	 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+	 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+	 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+	 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+	 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+	 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+	 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+	 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+	 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+	 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+	 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+	 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+	 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+	 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+	 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+	 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+	 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+	 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+	 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+	 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+	 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+	 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+	 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+	 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+	 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+	 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+	 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+	 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+	 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+	 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+	 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+	 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+	 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+	 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+	 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+	 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+	 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+	 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+	 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+	 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+	 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+	 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+	 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+	 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+	 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+	 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+	 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+	 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+	 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+	 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+	 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+	 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+	 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+	 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+	 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+	 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+	 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+	 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+	 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+	 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+	 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+	 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+	 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+	 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+	 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+	 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+	 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+	 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+	 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+	 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+	 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+	 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+	 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+	 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+	 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+	 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+	 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+	 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+	 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+	 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+	 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+	 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+	 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+	 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+	 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+	  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+	  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+	 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+	 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+	 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+	  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+	  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+	  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+	  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,
+	  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,
+	 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+	 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25,
+	 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31,
+	 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29,
+	 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
+	 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
+	 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+	 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21,
+	106,106,106,106,107,107,107,107,104,104,104,104,105,105,105,105,
+	110,110,110,110,111,111,111,111,108,108,108,108,109,109,109,109,
+	 98, 98, 98, 98, 99, 99, 99, 99, 96, 96, 96, 96, 97, 97, 97, 97,
+	102,102,102,102,103,103,103,103,100,100,100,100,101,101,101,101,
+	122,122,123,123,120,120,121,121,126,126,127,127,124,124,125,125,
+	114,114,115,115,112,112,113,113,118,118,119,119,116,116,117,117,
+	 74, 75, 72, 73, 78, 79, 76, 77, 66, 67, 64, 65, 70, 71, 68, 69,
+	 90, 91, 88, 89, 94, 95, 92, 93, 82, 83, 80, 81, 86, 87, 84, 85
+};
+
+int alaw_input P1((buf), gsm_signal * buf) 
+{
+	int  i, c;
+
+	for (i = 0; i < 160 && (c = fgetc(in)) != EOF; i++) buf[i] = A2S( c );
+	if (c == EOF && ferror(in)) return -1;
+	return i;
+}
+
+int alaw_output P1((buf), gsm_signal * buf) 
+{
+	int  i;
+
+	for (i = 0; i < 160; i++, buf++)
+		if (fputc( S2A( *buf ), out) == EOF) return -1;
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/toast_audio.c	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,113 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/* $Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/toast_audio.c,v 1.6 1995/03/07 21:21:24 jutta Exp $ */
+
+#include	"toast.h"
+
+/*  toast_audio -- functions to manipulate SunOS audio files.
+ *
+ *  This is reverse engineered from our present soundfiles
+ *  and in no way portable, durable or aesthetically pleasing.
+ */
+
+extern FILE	* in, 	  * out;
+extern char	* inname;
+extern char	* progname;
+
+extern int	(*output) P((gsm_signal *)),
+		(*input ) P((gsm_signal *));
+
+extern int	alaw_input   P((gsm_signal *)),
+		ulaw_input   P((gsm_signal *)),
+		linear_input P((gsm_signal *));
+
+extern int	ulaw_output P((gsm_signal *));
+
+static int put_u32 P2((f, u), FILE * f, unsigned long u)
+{
+	/*  Write a 32-bit unsigned value msb first. 
+	 */
+	if (  putc( (char)((u>>24) & 0x0FF), f) == EOF
+	   || putc( (char)((u>>16) & 0x0FF), f) == EOF
+	   || putc( (char)((u>> 8) & 0x0FF), f) == EOF
+	   || putc( (char)( u      & 0x0FF), f) == EOF) return -1;
+
+	return 0;
+}
+
+static int get_u32 P2((f, up), FILE * f, unsigned long * up)
+{
+	/*  Read a 32-bit unsigned value msb first.
+	 */
+	int		i;
+	unsigned long 	u;
+
+	if (  				      (i = getc(f)) == EOF
+	   || ((u =        (unsigned char)i), (i = getc(f)) == EOF)
+	   || ((u = (u<<8)|(unsigned char)i), (i = getc(f)) == EOF)
+	   || ((u = (u<<8)|(unsigned char)i), (i = getc(f)) == EOF)) return -1;
+	*up = 	    (u<<8)|(unsigned char)i;
+	return 0;
+}
+
+int audio_init_input P0()
+{
+	unsigned long	len, enc;	/* unsigned 32 bits	*/
+
+	if (  fgetc(in) != '.' 
+	   || fgetc(in) != 's'
+	   || fgetc(in) != 'n'
+	   || fgetc(in) != 'd'
+	   || get_u32( in, &len )
+	   || get_u32( in, &enc )	/* skip this */
+	   || get_u32( in, &enc )) {
+		fprintf(stderr, 
+	"%s: bad (missing?) header in Sun audio file \"%s\";\n\
+	Try one of -u, -a, -l instead (%s -h for help).\n",
+			progname, inname ? inname : "stdin", progname);
+		return -1;
+	}
+
+	switch (enc) {
+	case 1:	input = ulaw_input;  	break;
+	case 2: input = alaw_input;  	break;
+	case 3: input = linear_input; 	break;
+	default:
+		fprintf(stderr,
+"%s: warning: file format #%lu for %s not implemented, defaulting to u-law.\n",
+			progname, enc, inname);
+		input = ulaw_input;
+		break;
+	}
+
+	while (len > 4*4)
+		if (getc(in) == EOF) {
+			fprintf(stderr, 
+			"%s: EOF in header of Sun audio file \"%s\";\n\
+			Try one of -u, -a, -l instead (%s -h for help).\n",
+				progname, inname ? inname : "stdin", progname);
+			return -1;
+		}
+		else len--;
+
+	return 0;
+}
+
+int audio_init_output P0()
+{
+	if (  fputs(".snd", out) == EOF
+	   || put_u32(out, 32)
+	   || put_u32(out, ~(unsigned long)0)
+	   || put_u32(out, 1)
+	   || put_u32(out, 8000)
+	   || put_u32(out, 1)
+	   || put_u32(out, 0)
+	   || put_u32(out, 0)) return -1;
+
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jni/gsm/unproto.h	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,23 @@
+/*
+ * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+ * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+ * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+ */
+
+/*$Header: /tmp_amd/presto/export/kbs/jutta/src/gsm/RCS/unproto.h,v 1.1 1992/10/28 00:11:08 jutta Exp $*/
+
+#ifdef	PROTO_H		/* sic */
+#undef	PROTO_H
+
+#undef	P
+#undef	P0
+#undef	P1
+#undef	P2
+#undef	P3
+#undef	P4
+#undef	P5
+#undef	P6
+#undef	P7
+#undef	P8
+
+#endif	/* PROTO_H */
Binary file libs/armeabi/libOSNetworkSystem.so has changed
Binary file libs/armeabi/libg722.so has changed
Binary file libs/armeabi/libgsm.so has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/layout/call.xml	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:layout_height="fill_parent" android:layout_width="fill_parent"
+	android:orientation="vertical">
+	<LinearLayout android:layout_width="fill_parent"
+		android:layout_height="fill_parent" android:orientation="vertical"
+		android:layout_weight="1">
+		<ImageView android:id="@+id/call_logo_anim" android:src="@drawable/beem_launcher_icon_color"
+			android:layout_height="fill_parent" android:layout_width="fill_parent"
+			android:layout_weight="1" />
+		<TextView android:id="@+id/call_info" android:layout_width="fill_parent"
+			android:layout_height="fill_parent" android:text="Message pour savoir ou en est la conversation"
+			android:layout_gravity="bottom" android:layout_weight="1"
+			android:gravity="center" />
+	</LinearLayout>
+	<Button android:id="@+id/call_cancel_button"
+		android:layout_height="wrap_content" android:layout_width="fill_parent"
+		android:layout_gravity="bottom" android:text="~ Close Call ~" />
+	<Button android:id="@+id/call_accept_button"
+		android:layout_height="wrap_content" android:layout_width="fill_parent"
+		android:layout_gravity="bottom" android:text="~ Accept Call ~" android:visible="true" />
+</LinearLayout>
+
--- a/res/layout/jingle_call_activity.xml	Sat Jan 23 00:46:38 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-	android:layout_width="fill_parent" android:layout_height="wrap_content"
-	android:orientation="vertical">
-<!--         <TextView android:text="Jid:" android:id="@+id/jingledemocalljidlabel"
-		android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
-	<EditText android:id="@+id/jingledemocalljid"
-		android:layout_width="fill_parent" android:layout_height="wrap_content"></EditText>
-	<TextView android:text="Password:" android:id="@+id/jingledemocallpasswordlabel"
-		android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
-	<EditText android:id="@+id/jingledemocallpassword"
-		android:layout_width="fill_parent" android:layout_height="wrap_content" android:inputType="textPassword" ></EditText>
-
-	<Button android:text="Connexion" android:id="@+id/jingledemocallconnectbutton"
-		android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
-	<TextView android:text="Call who :" android:id="@+id/jingledemocallreceiverlabel"
-		android:layout_width="wrap_content" android:layout_height="wrap_content"></TextView>
-
-<EditText android:text="" android:id="@+id/jingledemocallreceiver" android:layout_width="fill_parent" android:layout_height="wrap_content"></EditText>
-
-<Button android:text="Call" android:id="@+id/jingledemocallbutton" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>       -->
-<ImageView android:id="@+id/log_as_logo"
-    android:layout_width="fill_parent" android:layout_height="wrap_content"
-    android:layout_marginBottom="25px" android:layout_marginTop="42px" />
-</LinearLayout>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/layout/ongoing_call_notification.xml	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Layout file for the custom "expanded view" used by the ongoing call
+     Notification; see NotificationMgr.updateInCallNotification(). -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:baselineAligned="false"
+    android:gravity="center_vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="65sp"
+    android:background="@android:drawable/status_bar_item_background"
+    >
+
+   <ImageView android:id="@+id/icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="4dip"
+        android:layout_marginRight="6dip" />
+
+   <LinearLayout
+       android:layout_width="wrap_content"
+       android:layout_height="wrap_content"
+       android:orientation="vertical"
+       >
+       <!-- The appearance of these 2 lines of text matches the other
+             kinds of notifications (see status_bar_latest_event.xml).
+             TODO: There should probably be common styles for these, though. -->
+       <Chronometer android:id="@+id/text1"
+           android:textStyle="bold"
+           android:textSize="18sp"
+           android:textColor="#ff000000"
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           android:singleLine="true"
+           />
+       <TextView android:id="@+id/text2"
+           android:textSize="14sp"
+           android:textColor="#ff000000"
+           android:layout_width="wrap_content"
+           android:layout_height="wrap_content"
+           android:singleLine="true"
+           android:text="@string/app_name"
+           />
+   </LinearLayout>
+</LinearLayout>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/res/menu/call.xml	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,10 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+	<item android:id="@+id/call_speaker_on" android:visible="true"
+		android:title="~ speaker on ~" android:icon="@android:drawable/ic_lock_silent_mode_off" />
+	<item android:id="@+id/call_speaker_off" android:visible="true"
+		android:title="~ speaker off ~" android:icon="@android:drawable/ic_lock_silent_mode" />
+	<item android:id="@+id/call_hold_on" android:visible="true"
+		android:title="~ hold on ~ " android:icon="@android:drawable/ic_lock_lock" />
+	<item android:id="@+id/call_hold_on" android:visible="true"
+		android:title="~ hold on ~ " android:icon="@android:drawable/ic_menu_call" /> 
+</menu>
--- a/res/menu/contactlist_context.xml	Sat Jan 23 00:46:38 2010 +0100
+++ b/res/menu/contactlist_context.xml	Sat Jan 23 00:51:15 2010 +0100
@@ -2,7 +2,7 @@
 	<item android:id="@+id/contact_list_context_menu_chat_item"
 		android:title="@string/CDChat" />
 	<item android:id="@+id/contact_list_context_menu_call_item"
-		android:title="@string/CDCall" android:visible="false" />
+		android:title="@string/CDCall" android:visible="true" />
 	<item android:id="@+id/contact_list_context_menu_user_info"
 		android:title="@string/CDInfos">
 		<menu>
--- a/res/values-fr/strings.xml	Sat Jan 23 00:46:38 2010 +0100
+++ b/res/values-fr/strings.xml	Sat Jan 23 00:51:15 2010 +0100
@@ -140,6 +140,7 @@
 	<string name="contact_list_name">Beem - Contacts</string>
 	<string name="contact_list_tag">Beem - ContactList Activity</string>
 	<string name="user_info_name">Beem - Informations</string>
+	<string name="call_screen">Beem - Appel</string>
 
 	<!--
     	Buttons
--- a/res/values/strings.xml	Sat Jan 23 00:46:38 2010 +0100
+++ b/res/values/strings.xml	Sat Jan 23 00:51:15 2010 +0100
@@ -134,6 +134,7 @@
 	<string name="contact_list_name">Beem - Contacts</string>
 	<string name="contact_list_tag">Beem - ContactList Activity</string>
 	<string name="user_info_name">Beem - User Info</string>
+	<string name="call_screen">Beem - Call Screen</string>
 
 	<!-- Buttons -->
 	<string name="button_reset">Reset</string>
--- a/src/com/beem/project/beem/BeemService.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/BeemService.java	Sat Jan 23 00:51:15 2010 +0100
@@ -148,6 +148,7 @@
 	    int pport = Integer.parseInt(mSettings.getString("settings_key_proxy_port", "1080"));
 	    ProxyInfo.ProxyType type = ProxyType.valueOf(stype);
 	    mProxyInfo = new ProxyInfo(type, phost, pport, puser, ppass);
+	    Log.d("Proxy", "type " + type);
 	    if (mService != null)
 		mConnectionConfiguration = new ConnectionConfiguration(mHost, mPort, mService, mProxyInfo);
 	    else
@@ -219,7 +220,7 @@
 	mConnection = new XmppConnectionAdapter(mConnectionConfiguration, mLogin, mPassword, this);
 
 	Roster.setDefaultSubscriptionMode(SubscriptionMode.manual);
-	mJingle = new JingleService(mConnection.getAdaptee());
+	mJingle = new JingleService(mConnection.getAdaptee(), this);
 	mBind = new XmppFacade(mConnection, mJingle);
 	Log.d(TAG, "ONCREATE");
     }
--- a/src/com/beem/project/beem/jingle/JingleService.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/jingle/JingleService.java	Sat Jan 23 00:51:15 2010 +0100
@@ -40,7 +40,7 @@
     Flavien Astraud, November 26, 2009
     Head of the EIP Laboratory.
 
-*/
+ */
 package com.beem.project.beem.jingle;
 
 import java.util.ArrayList;
@@ -57,31 +57,45 @@
 import org.jivesoftware.smackx.jingle.media.PayloadType;
 import org.jivesoftware.smackx.jingle.nat.BasicTransportManager;
 import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
+import org.sipdroid.media.codecs.CodecManager;
 
+import android.content.Context;
+import android.net.Uri;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
 import android.util.Log;
+import android.content.Intent;
 
-// TODO: Auto-generated Javadoc
+import com.beem.project.beem.ui.Call;
+import com.beem.project.beem.service.aidl.IBeemJingleListener;
+import com.beem.project.beem.service.aidl.IJingle;
+
 /**
  * Beem Jingle Service, manage jingle call.
  * @author nikita
  */
-public class JingleService {
+public class JingleService extends IJingle.Stub {
     private static final String TAG = "JingleService";
     private JingleManager mJingleManager;
     private final List<JingleMediaManager> mMediaManagers;
+    private final RemoteCallbackList<IBeemJingleListener> mRemoteJingleListeners = new RemoteCallbackList<IBeemJingleListener>();
     private JingleSession mIn;
     private JingleSession mOut;
+    private JingleSessionRequest mRequest;
+    private Context mContext;
+    private boolean isCaller;
+    private boolean isAccepted;
 
     /**
      * JingleService constructor.
      * @param xmppConnection a valid XMPPConnection
      */
-    public JingleService(final XMPPConnection xmppConnection) {
+    public JingleService(final XMPPConnection xmppConnection,final Context ctx) {
 	BasicTransportManager bt = new BasicTransportManager();
-	// JingleTransportManager tm = new ICETransportManager();
-
 	mMediaManagers = new ArrayList<JingleMediaManager>();
-	mMediaManagers.add(new MicrophoneRTPManager(bt));
+	mMediaManagers.add(new MicrophoneRTPManager(bt, ctx));
+	CodecManager.load();
+	mContext = ctx;
     }
 
     /**
@@ -94,75 +108,162 @@
     }
 
     /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void addJingleListener(IBeemJingleListener listen) throws RemoteException {
+	if (listen != null)
+	    mRemoteJingleListeners.register(listen);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void removeJingleListener(IBeemJingleListener listen) throws RemoteException {
+	if (listen != null)
+	    mRemoteJingleListeners.unregister(listen);
+    }
+
+    /**
      * begin a jingle call.
      * @param receiver the call receiver
      */
-    public void call(final String receiver) {
+    @Override
+    public void call(final String receiver) throws RemoteException {
 	try {
 	    mOut = mJingleManager.createOutgoingJingleSession(receiver);
-	    // TODO configure out avec addMediaSession et addNegociator
-	    mOut.addListener(new BeemJingleCallerSessionListener());
+	    mOut.addListener(new BeemJingleSessionListener());
 	    mOut.startOutgoing();
+	    isCaller = true;
 	} catch (XMPPException e) {
-	    // TODO Auto-generated catch block
 	    e.printStackTrace();
 	}
     }
 
-    /*
-     * private void receiveData(String ip, int port) throws IOException { Socket s = null; try { s = new Socket(ip,
-     * port); System.out.println("Waiting data"); InputStream in = s.getInputStream(); int a; while ((a = in.read()) !=
-     * -1) { System.out.println("Received " + a); } System.out.println("End receiving data"); } finally { if (s != null)
-     * s.close(); } }
+
+    @Override
+    public void acceptCall() throws RemoteException {
+	mIn.startIncoming();
+	isCaller = false;
+    }
+
+    /**
+     * close a jingle call.
      */
+    @Override
+    public void closeCall() throws RemoteException {
+	if (isCaller) {
+	    try {
+		if (isAccepted) {
+		    mOut.terminate();
+		} else {
+		    mOut.close();
+		}
+	    } catch (XMPPException e) {
+		e.printStackTrace();
+	    }
+	    mOut = null;
+	} else {
+	    try {
+		if (isAccepted) {
+		    mIn.terminate();
+		} else {
+		    mIn.close();
+		}		    
+	    } catch (XMPPException e) {
+		e.printStackTrace();
+	    }
+	    mIn = null;
+	}
+    }
+
     /**
-     * Listen on receiver session events.
+     * Listen on session events.
      * @author nikita
      */
-    private class BeemJingleReceiverSessionListener implements JingleSessionListener {
+    private class BeemJingleSessionListener implements JingleSessionListener {
 
 	/**
 	 * constructor.
 	 */
-	public BeemJingleReceiverSessionListener() {
+	public BeemJingleSessionListener() {
 	    super();
-	    // TODO Auto-generated constructor stub
 	}
 
 	@Override
 	public void sessionClosed(String reason, JingleSession jingleSession) {
-	    // System.out.println("Session " + jingleSession.getResponder() +
-	    // "closedd because " + reason);
+	    System.out.println("Session " + jingleSession.getResponder() + "closedd because " + reason);
+
+	    final int n = mRemoteJingleListeners.beginBroadcast();
+	    for (int i = 0; i < n; i++) {
+		IBeemJingleListener listener = mRemoteJingleListeners.getBroadcastItem(i);
+		try {
+		    listener.sessionClosed(reason);
+		} catch (RemoteException e) {
+		    e.printStackTrace();
+		}
+	    }
+	    mRemoteJingleListeners.finishBroadcast();
 	}
 
 	@Override
 	public void sessionClosedOnError(XMPPException e, JingleSession jingleSession) {
-	    // TODO Auto-generated method stub
-	    // System.out.println("Session " + jingleSession.getResponder() +
-	    // " closed");
+	    System.out.println("Session " + jingleSession.getResponder() + " closed");
 
+	    final int n = mRemoteJingleListeners.beginBroadcast();
+	    for (int i = 0; i < n; i++) {
+		IBeemJingleListener listener = mRemoteJingleListeners.getBroadcastItem(i);
+		try {
+		    listener.sessionClosedOnError(e.getMessage());
+		} catch (RemoteException err) {
+		    err.printStackTrace();
+		}
+	    }
+	    mRemoteJingleListeners.finishBroadcast();
 	}
 
 	@Override
 	public void sessionDeclined(String reason, JingleSession jingleSession) {
 	    Log.d(TAG, "Session " + jingleSession.getResponder() + "declined because " + reason);
+	    isAccepted = false;
+
+	    final int n = mRemoteJingleListeners.beginBroadcast();
+	    for (int i = 0; i < n; i++) {
+		IBeemJingleListener listener = mRemoteJingleListeners.getBroadcastItem(i);
+		try {
+		    listener.sessionDeclined(reason);
+		} catch (RemoteException e) {
+		    e.printStackTrace();
+		}
+	    }
+	    mRemoteJingleListeners.finishBroadcast();
+
 	}
 
 	@Override
 	public void sessionEstablished(PayloadType pt, TransportCandidate remoteCandidate,
 	    TransportCandidate localCandidate, JingleSession jingleSession) {
-	    // System.out.println("Session established");
-	    // System.out.println("Je recois sur " + remoteCandidate.getIp() +
-	    // ":" + remoteCandidate.getPort());
-	    // TODO choose the right RTPReceiver depending on the payload type
-	    // RTPReceiver rtpReceiver = new
-	    // RTPReceiver(remoteCandidate.getPort());
 	    Log.d(TAG, "Session " + jingleSession.getResponder() + "established");
+	    isAccepted = true;
+
+	    jingleSession.getSession().getMediaSession(pt.getName());
+	    final int n = mRemoteJingleListeners.beginBroadcast();
+
+	    for (int i = 0; i < n; i++) {
+		IBeemJingleListener listener = mRemoteJingleListeners.getBroadcastItem(i);
+		try {
+		    listener.sessionEstablished();
+		} catch (RemoteException e) {
+		    e.printStackTrace();
+		}
+	    }
+	    mRemoteJingleListeners.finishBroadcast();
 	}
 
 	@Override
 	public void sessionMediaReceived(JingleSession jingleSession, String participant) {
-	    // System.out.println("Session Media received from " + participant);
+	    Log.d(TAG, "Session Media received from " + participant);
 	}
 
 	@Override
@@ -170,77 +271,6 @@
 	}
     }
 
-    /**
-     * Listen on caller session events.
-     * @author nikita
-     */
-    private class BeemJingleCallerSessionListener implements JingleSessionListener {
-
-	private static final int SLP_DURATION = 20000;
-
-	/**
-	 * constructor.
-	 */
-	public BeemJingleCallerSessionListener() {
-	    super();
-	    // TODO Auto-generated constructor stub
-	}
-
-	@Override
-	public void sessionClosed(final String reason, final JingleSession jingleSession) {
-	    // System.out.println("Session " + jingleSession.getResponder() +
-	    // "closed because " + reason);
-	}
-
-	@Override
-	public void sessionClosedOnError(final XMPPException e, final JingleSession jingleSession) {
-	    // System.out.println("Session " + jingleSession.getResponder() +
-	    // " closed on error");
-
-	}
-
-	@Override
-	public void sessionDeclined(final String reason, final JingleSession jingleSession) {
-	    // System.out.println("Session " + jingleSession.getResponder() +
-	    // "declined because " + reason);
-	    Log.d(TAG, "Session " + jingleSession.getResponder() + "declined because " + reason);
-	}
-
-	@Override
-	public void sessionEstablished(final PayloadType pt, final TransportCandidate remoteCandidate,
-	    final TransportCandidate localCandidate, final JingleSession jingleSession) {
-	    Log.d(TAG, "Session " + jingleSession.getResponder() + "established");
-	    // String name = localCandidate.getName();
-	    String ip = localCandidate.getIp();
-	    int port = localCandidate.getPort();
-	    // System.out.println("Session established waiting connection on " +
-	    // ip + ":" + port);
-
-	    RTPTransmitter transm = new PCMTransmitter(ip, port);
-
-	    transm.run();
-	    try {
-		Thread.sleep(SLP_DURATION);
-	    } catch (InterruptedException e) {
-		// TODO Auto-generated catch block
-		e.printStackTrace();
-	    }
-	    transm.stop();
-	    // System.out.println("End of transfer");
-
-	}
-
-	@Override
-	public void sessionMediaReceived(final JingleSession jingleSession, final String participant) {
-	    // TODO Auto-generated method stub
-	    System.out.println("Session Media received from " + participant);
-	}
-
-	@Override
-	public void sessionRedirected(final String redirection, final JingleSession jingleSession) {
-	    // TODO Auto-generated method stub
-	}
-    }
 
     /**
      * Listen for a Jingle session request.
@@ -257,14 +287,20 @@
 
 	@Override
 	public void sessionRequested(JingleSessionRequest request) {
-	    System.out.println("Jingle Session request from " + request.getFrom());
+	    mRequest = request;
 	    try {
-		mIn = request.accept();
-		mIn.addListener(new BeemJingleReceiverSessionListener());
-		mIn.startIncoming();
+		mIn = mJingleManager.createIncomingJingleSession(mRequest);
+		mIn.addListener(new BeemJingleSessionListener());
 	    } catch (XMPPException e) {
 		e.printStackTrace();
 	    }
+	    System.out.println("Jingle Session request from " + request.getFrom());
+	    isCaller = false;
+	    isAccepted = false;
+	    Intent intent = new Intent(mContext, Call.class);
+	    intent.setData(Uri.parse("jingle:"+request.getFrom()));
+	    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+	    mContext.startActivity(intent);
 	}
     }
 
--- a/src/com/beem/project/beem/jingle/MicrophoneRTPManager.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/jingle/MicrophoneRTPManager.java	Sat Jan 23 00:51:15 2010 +0100
@@ -53,61 +53,64 @@
 import org.jivesoftware.smackx.jingle.nat.JingleTransportManager;
 import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
 
-// TODO: Auto-generated Javadoc
+import android.content.Context;
+
 /**
  * RTPMediaManager, gere les payloads et renvoie une session RTP.
  * @author nikita
  */
 public class MicrophoneRTPManager extends JingleMediaManager {
-    
-    /** RTP media name. */
-    public static final String MEDIA_NAME = "Microphone";
+	/**
+	 * RTP media name.
+	 */
+	public static final String MEDIA_NAME = "Microphone";
 
-    private List<PayloadType> mPayloads;
+	private List<PayloadType> mPayloads;
+
+	private Context mCtx;
 
-    /**
-     * Manage Microphone data transmission trough RTP.
-     * @param transportManager current jingle transport manager(basic,upnp,ice...).
-     */
-    public MicrophoneRTPManager(final JingleTransportManager transportManager) {
-	super(transportManager);
-	// TODO Auto-generated constructor stub
-	setupPayloads();
-    }
+	/**
+	 * Manage Microphone data transmission trough RTP.
+	 * @param transportManager current jingle transport manager(basic,upnp,ice...).
+	 */
+	public MicrophoneRTPManager(final JingleTransportManager transportManager, Context ctx) {
+		super(transportManager);
+		setupPayloads();
+		mCtx = ctx;
+	}
 
     /* (non-Javadoc)
      * @see org.jivesoftware.smackx.jingle.media.JingleMediaManager#createMediaSession(org.jivesoftware.smackx.jingle.media.PayloadType, org.jivesoftware.smackx.jingle.nat.TransportCandidate, org.jivesoftware.smackx.jingle.nat.TransportCandidate, org.jivesoftware.smackx.jingle.JingleSession)
      */
-    @Override
-    public JingleMediaSession createMediaSession(PayloadType payloadType, TransportCandidate remote,
-	TransportCandidate local, JingleSession jingleSession) {
-	// TODO Auto-generated method stub
-	return new MicrophoneRTPSession(payloadType, remote, local, null, jingleSession);
-    }
+	@Override
+	public JingleMediaSession createMediaSession(PayloadType payloadType, TransportCandidate remote,
+			TransportCandidate local, JingleSession jingleSession) {
+		return new RTPAudioSession(payloadType, remote, local, null, jingleSession, mCtx);
+	}
 
     /* (non-Javadoc)
      * @see org.jivesoftware.smackx.jingle.media.JingleMediaManager#getName()
      */
-    @Override
-    public String getName() {
-	return MEDIA_NAME;
-    }
+	@Override
+	public String getName() {
+		return MEDIA_NAME;
+	}
 
     /* (non-Javadoc)
      * @see org.jivesoftware.smackx.jingle.media.JingleMediaManager#getPayloads()
      */
-    @Override
-    public List<PayloadType> getPayloads() {
-	// TODO Auto-generated method stub
-	return mPayloads;
-    }
+	@Override
+	public List<PayloadType> getPayloads() {
+		return mPayloads;
+	}
 
-    /**
-     * Supported payload list.
-     */
-    private void setupPayloads() {
-	mPayloads = new ArrayList<PayloadType>();
-	mPayloads.add(new PayloadType.Audio(0, "PCMU"));
-	mPayloads.add(new PayloadType.Audio(8, "PCMA"));
-    }
+	/**
+	 * Supported payload list.
+	 */
+	private void setupPayloads() {
+		mPayloads = new ArrayList<PayloadType>();
+		mPayloads.add(new PayloadType.Audio(8, "PCMA"));
+//		mPayloads.add(new PayloadType.Audio(9, "G722"));
+//		mPayloads.add(new PayloadType.Audio(3, "GSM"));
+	}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/jingle/RTPAudioSession.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,107 @@
+package com.beem.project.beem.jingle;
+
+import jlibrtp.Participant;
+import jlibrtp.RTPSession;
+
+import org.jivesoftware.smackx.jingle.JingleSession;
+import org.jivesoftware.smackx.jingle.media.JingleMediaSession;
+import org.jivesoftware.smackx.jingle.media.PayloadType;
+import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
+import org.sipdroid.media.RtpStreamReceiver;
+import org.sipdroid.media.RtpStreamSender;
+import org.sipdroid.media.codecs.CodecManager;
+import org.sipdroid.net.SipdroidSocket;
+
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * Manage microphone RTP session.
+ * @author nikita
+ */
+public class RTPAudioSession extends JingleMediaSession {
+	
+	private RtpStreamSender mSender=null;
+	private RtpStreamReceiver mReceiver=null;
+
+	private RTPSession rtpSession;
+
+	/**
+	 * constructor.
+	 * @param payloadType the payload typ used
+	 * @param remote the remote transport info
+	 * @param local the local tranport info
+	 * @param mediaLocator don't know
+	 * @param jingleSession the current jingle session
+	 * @param ctx 
+	 */
+	public RTPAudioSession(final PayloadType pt, final TransportCandidate remote,
+			final TransportCandidate local, final String mediaLocator, final JingleSession jingleSession, Context ctx) {
+		super(pt, remote, local, mediaLocator, jingleSession);
+		
+		prepareRtpSession(local.getPort(), remote.getIp(), remote.getPort());
+		Log.d("AUDIO", String.format("payload type : %s ipdest %s port dest %d port src %d",pt.getName(), remote.getIp(), remote.getPort(), local.getPort()));
+		
+		mSender = new RtpStreamSender(CodecManager.getCodecByRtpName(pt.getName()), rtpSession);
+
+		mReceiver = new RtpStreamReceiver(CodecManager.getCodecByRtpName(pt.getName()), rtpSession, ctx);
+	}
+
+	@Override
+	public void initialize() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void setTrasmit(boolean active) {
+	}
+
+	@Override
+	public void startReceive() {
+		if (mReceiver != null) {
+			mReceiver.start();
+		}
+	}
+
+	@Override
+	public void startTrasmit() {
+		if (mSender != null) {
+			mSender.start();
+		}
+		rtpSession.RTPSessionRegister(mReceiver, null, null);
+	}
+
+	@Override
+	public void stopReceive() {
+		if (mReceiver != null) {
+			mReceiver.halt();
+			mReceiver = null;
+		}
+		rtpSession.endSession();
+	}
+
+	@Override
+	public void stopTrasmit() {
+		if (mSender != null) {
+			mSender.halt();
+			mSender = null;
+		}
+	}
+	
+	private void prepareRtpSession(int src_port, String dest_addr, int dest_port) {
+		SipdroidSocket rtpSocket = null;
+		SipdroidSocket rtcpSocket = null;
+
+		try {
+			rtpSocket = new SipdroidSocket(src_port);
+			rtcpSocket = new SipdroidSocket(src_port + 1);
+		} catch (Exception e) {
+		}
+		rtpSession = new RTPSession(rtpSocket, rtcpSocket);
+		Participant p = new Participant(dest_addr,dest_port, dest_port + 1);
+		rtpSession.addParticipant(p);
+		rtpSession.naivePktReception(true);
+		rtpSession.packetBufferBehavior(3);
+	}
+}
--- a/src/com/beem/project/beem/jingle/RTPReceiver.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/jingle/RTPReceiver.java	Sat Jan 23 00:51:15 2010 +0100
@@ -46,9 +46,9 @@
 import java.net.DatagramSocket;
 import java.net.SocketException;
 
-import org.jlibrtp.jlibrtp.Participant;
-import org.jlibrtp.jlibrtp.RTPAppIntf;
-import org.jlibrtp.jlibrtp.RTPSession;
+import jlibrtp.Participant;
+import jlibrtp.RTPAppIntf;
+import jlibrtp.RTPSession;
 
 // TODO: Auto-generated Javadoc
 /**
--- a/src/com/beem/project/beem/jingle/RTPTransmitter.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/jingle/RTPTransmitter.java	Sat Jan 23 00:51:15 2010 +0100
@@ -46,10 +46,10 @@
 import java.net.DatagramSocket;
 import java.net.SocketException;
 
-import org.jlibrtp.jlibrtp.DataFrame;
-import org.jlibrtp.jlibrtp.Participant;
-import org.jlibrtp.jlibrtp.RTPAppIntf;
-import org.jlibrtp.jlibrtp.RTPSession;
+import jlibrtp.DataFrame;
+import jlibrtp.Participant;
+import jlibrtp.RTPAppIntf;
+import jlibrtp.RTPSession;
 
 import com.beem.project.beem.utils.FreePort;
 
--- a/src/com/beem/project/beem/jingle/demo/JingleCallActivity.java	Sat Jan 23 00:46:38 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,147 +0,0 @@
-/*
-    BEEM is a videoconference application on the Android Platform.
-
-    Copyright (C) 2009 by Frederic-Charles Barthelery,
-                          Jean-Manuel Da Silva,
-                          Nikita Kozlov,
-                          Philippe Lago,
-                          Jean Baptiste Vergely,
-                          Vincent Veronis.
-
-    This file is part of BEEM.
-
-    BEEM is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    BEEM is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with BEEM.  If not, see <http://www.gnu.org/licenses/>.
-
-    Please send bug reports with examples or suggestions to
-    contact@beem-project.com or http://dev.beem-project.com/
-
-    Epitech, hereby disclaims all copyright interest in the program "Beem"
-    written by Frederic-Charles Barthelery,
-               Jean-Manuel Da Silva,
-               Nikita Kozlov,
-               Philippe Lago,
-               Jean Baptiste Vergely,
-               Vincent Veronis.
-
-    Nicolas Sadirac, November 26, 2009
-    President of Epitech.
-
-    Flavien Astraud, November 26, 2009
-    Head of the EIP Laboratory.
-
-*/
-package com.beem.project.beem.jingle.demo;
-/*
-import org.jivesoftware.smack.ConnectionConfiguration;
-import org.jivesoftware.smack.XMPPConnection;
-import org.jivesoftware.smack.XMPPException;
-import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
-import org.jivesoftware.smack.util.StringUtils;
-
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import com.beem.project.beem.R;
-import com.beem.project.beem.jingle.JingleService;
-*/
-import android.app.Activity;
-
-/**
- * Activity used to test Jingle call.
- * @author darisk
- */
-public class JingleCallActivity extends Activity {
-/*
-    private static final int SLP_DURATION = 3000;
-    private static final int DEFAULT_XMPP_PORT = 5222;
-
-    private XMPPConnection mConnection;
-    private ConnectionConfiguration mConf;
-    private JingleService mJingle;
-
-    private Button mBtconnect;
-    private Button mBtcall;
-    private EditText mEdJID;
-    private EditText mEdPassword;
-    private EditText mEdReceiver;
-
-    /**
-     * Constructor.
-     *
-    public JingleCallActivity() {
-    }
-
-    /* (non-Javadoc)
-     * @see android.app.Activity#onCreate(android.os.Bundle)
-     *
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-	java.security.Security.addProvider(new com.sun.security.sasl.Provider());
-	super.onCreate(savedInstanceState);
-	setContentView(R.layout.jingle_call_activity);
-	mConf = new ConnectionConfiguration("10.0.2.2", DEFAULT_XMPP_PORT);
-	// mConf = new ConnectionConfiguration("elyzion.net",
-	// DEFAULT_XMPP_PORT);
-	mConf.setSecurityMode(SecurityMode.required);
-	mEdJID = (EditText) findViewById(R.id.jingledemocalljid);
-	mEdPassword = (EditText) findViewById(R.id.jingledemocallpassword);
-	mEdReceiver = (EditText) findViewById(R.id.jingledemocallreceiver);
-	mBtconnect = (Button) findViewById(R.id.jingledemocallconnectbutton);
-	mBtconnect.setOnClickListener(new OnClickListener() {
-
-	    @Override
-	    public void onClick(View arg0) {
-		String jid = mEdJID.getText().toString();
-		String login = StringUtils.parseName(jid);
-		mConnection = new XMPPConnection(mConf);
-		String password = mEdPassword.getText().toString();
-		try {
-		    mConnection.connect();
-		    Thread.sleep(SLP_DURATION);
-		    mConnection.login(login, password);
-		    mJingle = new JingleService(mConnection);
-		    mJingle.initWhenConntected(mConnection);
-		    mBtcall.setEnabled(true);
-		    Toast.makeText(JingleCallActivity.this, "Connected", Toast.LENGTH_SHORT);
-		} catch (XMPPException e) {
-		    // TODO Auto-generated catch block
-		    e.printStackTrace();
-		} catch (InterruptedException e) {
-		    // TODO Auto-generated catch block
-		    e.printStackTrace();
-		}
-	    }
-
-	});
-	mBtcall = (Button) findViewById(R.id.jingledemocallbutton);
-	mBtcall.setOnClickListener(new OnClickListener() {
-	    @Override
-	    public void onClick(View arg0) {
-		String jid = mEdReceiver.getText().toString();
-		if (!"".equals(jid)) {
-		    mJingle.call(jid);
-		    Toast.makeText(JingleCallActivity.this, "Appel en cours", Toast.LENGTH_SHORT);
-		} else
-		    Toast.makeText(JingleCallActivity.this, "Remplir le champ (JID complet en  toto@tutu.com/truc)",
-			Toast.LENGTH_SHORT);
-	    }
-	});
-
-    }
-*/
-}
--- a/src/com/beem/project/beem/jingle/demo/package-info.java	Sat Jan 23 00:46:38 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
-    BEEM is a videoconference application on the Android Platform.
-
-    Copyright (C) 2009 by Frederic-Charles Barthelery,
-                          Jean-Manuel Da Silva,
-                          Nikita Kozlov,
-                          Philippe Lago,
-                          Jean Baptiste Vergely,
-                          Vincent Veronis.
-
-    This file is part of BEEM.
-
-    BEEM is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    BEEM is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with BEEM.  If not, see <http://www.gnu.org/licenses/>.
-
-    Please send bug reports with examples or suggestions to
-    contact@beem-project.com or http://dev.beem-project.com/
-
-    Epitech, hereby disclaims all copyright interest in the program "Beem"
-    written by Frederic-Charles Barthelery,
-               Jean-Manuel Da Silva,
-               Nikita Kozlov,
-               Philippe Lago,
-               Jean Baptiste Vergely,
-               Vincent Veronis.
-
-    Nicolas Sadirac, November 26, 2009
-    President of Epitech.
-
-    Flavien Astraud, November 26, 2009
-    Head of the EIP Laboratory.
-
-*/
-package com.beem.project.beem.jingle.demo;
-
--- a/src/com/beem/project/beem/service/Contact.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/service/Contact.java	Sat Jan 23 00:51:15 2010 +0100
@@ -194,7 +194,6 @@
      */
     @Override
     public int describeContents() {
-	// TODO Auto-generated method stub
 	return 0;
     }
 
--- a/src/com/beem/project/beem/service/RosterAdapter.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/service/RosterAdapter.java	Sat Jan 23 00:51:15 2010 +0100
@@ -64,6 +64,7 @@
 import com.beem.project.beem.R;
 import com.beem.project.beem.service.aidl.IBeemRosterListener;
 import com.beem.project.beem.utils.Status;
+import com.beem.project.beem.service.aidl.IRoster;
 
 /**
  * This class implement a Roster adapter for BEEM.
@@ -371,8 +372,6 @@
 	 */
 	@Override
 	public void presenceChanged(Presence presence) {
-	    // Log.i(TAG, "presence Changed");
-	    /* redispatch vers les IBeemRosterListener */
 	    final int n = mRemoteRosListeners.beginBroadcast();
 
 	    for (int i = 0; i < n; i++) {
@@ -385,8 +384,6 @@
 		    }
 		    listener.onPresenceChanged(new PresenceAdapter(presence));
 		} catch (RemoteException e) {
-		    // The RemoteCallbackList will take care of removing the
-		    // dead listeners.
 		    Log.w(TAG, "Error while updating roster presence entries", e);
 		}
 	    }
--- a/src/com/beem/project/beem/service/XmppFacade.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/service/XmppFacade.java	Sat Jan 23 00:51:15 2010 +0100
@@ -55,6 +55,7 @@
 import com.beem.project.beem.service.aidl.IRoster;
 import com.beem.project.beem.service.aidl.IXmppConnection;
 import com.beem.project.beem.service.aidl.IXmppFacade;
+import com.beem.project.beem.service.aidl.IJingle;
 import com.beem.project.beem.utils.PresenceType;
 
 /**
@@ -123,6 +124,14 @@
     public IChatManager getChatManager() throws RemoteException {
 	return mConnexion.getChatManager();
     }
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IJingle getJingleService() throws RemoteException {
+	return mJingle;
+    }
 
     /**
      * {@inheritDoc}
@@ -148,14 +157,6 @@
     }
 
     /* (non-Javadoc)
-     * @see com.beem.project.beem.service.aidl.IXmppFacade#call(java.lang.String)
-     */
-    @Override
-    public void call(String jid) throws RemoteException {
-	mJingle.call(jid);
-    }
-
-    /* (non-Javadoc)
      * @see com.beem.project.beem.service.aidl.IXmppFacade#getVcardAvatar(java.lang.String)
      */
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/service/aidl/IBeemJingleListener.aidl	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,77 @@
+/*
+    BEEM is a videoconference application on the Android Platform.
+
+    Copyright (C) 2009 by Frederic-Charles Barthelery,
+                          Jean-Manuel Da Silva,
+                          Nikita Kozlov,
+                          Philippe Lago,
+                          Jean Baptiste Vergely,
+                          Vincent Veronis.
+
+    This file is part of BEEM.
+
+    BEEM is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    BEEM is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with BEEM.  If not, see <http://www.gnu.org/licenses/>.
+
+    Please send bug reports with examples or suggestions to
+    contact@beem-project.com or http://dev.beem-project.com/
+
+    Epitech, hereby disclaims all copyright interest in the program "Beem"
+    written by Frederic-Charles Barthelery,
+               Jean-Manuel Da Silva,
+               Nikita Kozlov,
+               Philippe Lago,
+               Jean Baptiste Vergely,
+               Vincent Veronis.
+
+    Nicolas Sadirac, November 26, 2009
+    President of Epitech.
+
+    Flavien Astraud, November 26, 2009
+    Head of the EIP Laboratory.
+
+*/
+package com.beem.project.beem.service.aidl;
+
+/**
+ * Interface to listen for jingle sessions events
+ * @author Nikita Kozlov <nikita@beem-project.com>
+ */
+interface IBeemJingleListener {
+
+    /**
+     *  Callback to call when the session is closed
+     */
+    void sessionClosed(in String reason);
+
+    /**
+     *  Callback to call when the session is declined
+     */
+    void sessionDeclined(in String reason);
+
+    
+    /**
+     *  Callback to call when the session is closed on error
+     */
+    void sessionClosedOnError(in String error);
+
+    /**
+     * Callback to call when session is established
+     */
+    void sessionEstablished();
+    
+    /**
+     * Callback to call when session is requested
+     */
+    void sessionRequested(in String fromJID);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/service/aidl/IJingle.aidl	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,70 @@
+/*
+    BEEM is a videoconference application on the Android Platform.
+
+    Copyright (C) 2009 by Frederic-Charles Barthelery,
+                          Jean-Manuel Da Silva,
+                          Nikita Kozlov,
+                          Philippe Lago,
+                          Jean Baptiste Vergely,
+                          Vincent Veronis.
+
+    This file is part of BEEM.
+
+    BEEM is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    BEEM is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with BEEM.  If not, see <http://www.gnu.org/licenses/>.
+
+    Please send bug reports with examples or suggestions to
+    contact@beem-project.com or http://dev.beem-project.com/
+
+    Epitech, hereby disclaims all copyright interest in the program "Beem"
+    written by Frederic-Charles Barthelery,
+               Jean-Manuel Da Silva,
+               Nikita Kozlov,
+               Philippe Lago,
+               Jean Baptiste Vergely,
+               Vincent Veronis.
+
+    Nicolas Sadirac, November 26, 2009
+    President of Epitech.
+
+    Flavien Astraud, November 26, 2009
+    Head of the EIP Laboratory.
+
+*/
+package com.beem.project.beem.service.aidl;
+
+import com.beem.project.beem.service.aidl.IBeemJingleListener;
+
+
+interface IJingle {
+
+    void addJingleListener(in IBeemJingleListener listen);
+    void removeJingleListener(in IBeemJingleListener listen);
+    
+        /**
+     * make a jingle audio call
+     * @param jid the receiver id
+     */
+     void call(in String jid);
+     
+     /**
+     * Accept call a jingle audio call
+     */
+     void acceptCall();
+     
+     /**
+     * close a jingle audio call
+     */
+     void closeCall();
+
+}
--- a/src/com/beem/project/beem/service/aidl/IXmppFacade.aidl	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/service/aidl/IXmppFacade.aidl	Sat Jan 23 00:51:15 2010 +0100
@@ -45,9 +45,10 @@
 
 import  com.beem.project.beem.service.aidl.IXmppConnection;
 import  com.beem.project.beem.service.aidl.IRoster;
+import  com.beem.project.beem.service.aidl.IJingle;
 import  com.beem.project.beem.service.aidl.IChatManager;
 import  com.beem.project.beem.service.aidl.IPrivacyListManager;
-import com.beem.project.beem.service.PresenceAdapter;
+import  com.beem.project.beem.service.PresenceAdapter;
 
 interface IXmppFacade {
 
@@ -80,6 +81,11 @@
      * Get the chat manager.
      */
     IChatManager getChatManager();
+    
+    /**
+     * Get the Jingle service.
+     */
+    IJingle getJingleService();
 
     /**
      * Change the status of the user.
@@ -90,12 +96,6 @@
 
     void sendPresencePacket(in PresenceAdapter presence);
 
-    /**
-     * make a jingle audio call
-     * @param jid the receiver id
-     */
-     void call(in String jid);
-
      /**
       * get the user vcard avatar
       * @param jid the user jid
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/ui/Call.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,228 @@
+/*
+    BEEM is a videoconference application on the Android Platform.
+
+    Copyright (C) 2009 by Frederic-Charles Barthelery,
+                          Jean-Manuel Da Silva,
+                          Nikita Kozlov,
+                          Philippe Lago,
+                          Jean Baptiste Vergely,
+                          Vincent Veronis.
+
+    This file is part of BEEM.
+
+    BEEM is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    BEEM is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with BEEM.  If not, see <http://www.gnu.org/licenses/>.
+
+    Please send bug reports with examples or suggestions to
+    contact@beem-project.com or http://dev.beem-project.com/
+
+    Epitech, hereby disclaims all copyright interest in the program "Beem"
+    written by Frederic-Charles Barthelery,
+               Jean-Manuel Da Silva,
+               Nikita Kozlov,
+               Philippe Lago,
+               Jean Baptiste Vergely,
+               Vincent Veronis.
+
+    Nicolas Sadirac, November 26, 2009
+    President of Epitech.
+
+    Flavien Astraud, November 26, 2009
+    Head of the EIP Laboratory.
+
+ */
+package com.beem.project.beem.ui;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+
+import com.beem.project.beem.R;
+import com.beem.project.beem.service.aidl.IXmppFacade;
+import com.beem.project.beem.service.aidl.IJingle;
+import com.beem.project.beem.service.aidl.IBeemJingleListener;
+
+/**
+ * This class is an activity which display an animation during the connection with the server.
+ * @author Da Risk <darisk972@gmail.com>
+ */
+public class Call extends Activity {
+
+    private static final Intent SERVICE_INTENT = new Intent();
+    static {
+	SERVICE_INTENT.setComponent(new ComponentName("com.beem.project.beem", "com.beem.project.beem.BeemService"));
+    }
+    private ImageView mLogo;
+    private TextView mCallInfo;
+    private Animation mRotateAnim;
+    private final ServiceConnection mServConn = new BeemServiceConnection();
+    private BeemJingleSessionListener mJingleListener = new BeemJingleSessionListener();
+    private IXmppFacade mXmppFacade;
+    private Button mCloseCall;
+    private Button mAcceptCall;
+    private IJingle mJingle;
+
+    /**
+     * Constructor.
+     */
+    public Call() {
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+	super.onCreate(savedInstanceState);
+	setContentView(R.layout.call);
+	Intent callingIntent = this.getIntent();
+
+	mLogo = (ImageView) findViewById(R.id.call_logo_anim);
+	mRotateAnim = AnimationUtils.loadAnimation(this, R.anim.rotate_and_scale);
+	mCloseCall = (Button) findViewById(R.id.call_cancel_button);
+	mCloseCall.setOnClickListener(new ClickListener());
+	if (callingIntent.getData().equals("")) {
+	    mAcceptCall = (Button) findViewById(R.id.call_accept_button);
+	    mAcceptCall.setOnClickListener(new ClickListener());
+	}
+	mCallInfo = (TextView) findViewById(R.id.call_info);
+    }
+
+    @Override
+    protected void onStart() {
+	super.onStart();
+	mLogo.startAnimation(mRotateAnim);
+    }
+
+    @Override
+    protected void onResume() {
+	super.onResume();
+	if (mXmppFacade == null)
+	    bindService(Call.SERVICE_INTENT, mServConn, BIND_AUTO_CREATE);
+    }
+
+    @Override
+    protected void onPause() {
+	super.onPause();
+	if (mXmppFacade != null) {
+	    try {
+		mJingle.removeJingleListener(mJingleListener);
+	    } catch (RemoteException e) {
+		e.printStackTrace();
+	    }
+	    unbindService(mServConn);
+	    mXmppFacade = null;
+	}
+    }
+
+    @Override
+    public final boolean onCreateOptionsMenu(Menu menu) {
+	super.onCreateOptionsMenu(menu);
+	MenuInflater inflater = getMenuInflater();
+	inflater.inflate(R.menu.call, menu);
+	return true;
+    }
+
+    /**
+     * Click event listener on cancel button.
+     */
+    private class ClickListener implements OnClickListener {
+
+	/**
+	 * Constructor.
+	 */
+	ClickListener() {
+	}
+
+	@Override
+	public void onClick(View v) {
+	    try {
+		mJingle.closeCall();
+	    } catch (RemoteException e) {
+		e.printStackTrace();
+	    }
+	    finish();
+	}
+    }
+
+    private class BeemJingleSessionListener extends IBeemJingleListener.Stub {
+
+	public BeemJingleSessionListener() {
+	    mCallInfo.setText("test");
+	}
+
+	@Override
+	public void sessionClosed(final String reason) {
+	    mCallInfo.setText(reason);
+	}
+
+	@Override
+	public void sessionDeclined(final String reason)  {
+	    mCallInfo.setText(reason);
+	}
+
+	@Override
+	public void sessionClosedOnError(final String error) {
+	    mCallInfo.setText(error);
+	}
+
+	@Override
+	public void sessionEstablished() {
+	    mCallInfo.setText("established");
+	}
+
+	@Override
+	public void sessionRequested(final String fromJID) {
+	    mCallInfo.setText("request by " + fromJID);
+	}
+    }
+
+    /**
+     * The service connection used to connect to the Beem service.
+     */
+    private class BeemServiceConnection implements ServiceConnection {
+
+	/**
+	 * Constructor.
+	 */
+	public BeemServiceConnection() {
+	}
+
+	@Override
+	public void onServiceConnected(ComponentName name, IBinder service) {
+	    mXmppFacade = IXmppFacade.Stub.asInterface(service);
+	    try {
+		mJingle = mXmppFacade.getJingleService();
+		mJingle.addJingleListener(mJingleListener);
+	    } catch (RemoteException e) {
+		e.printStackTrace();
+	    }
+	}
+
+	@Override
+	public void onServiceDisconnected(ComponentName name) {
+	    mXmppFacade = null;
+	}
+    }
+}
--- a/src/com/beem/project/beem/ui/ContactList.java	Sat Jan 23 00:46:38 2010 +0100
+++ b/src/com/beem/project/beem/ui/ContactList.java	Sat Jan 23 00:51:15 2010 +0100
@@ -85,6 +85,7 @@
 import com.beem.project.beem.service.Contact;
 import com.beem.project.beem.service.PresenceAdapter;
 import com.beem.project.beem.service.aidl.IBeemRosterListener;
+import com.beem.project.beem.service.aidl.IJingle;
 import com.beem.project.beem.service.aidl.IRoster;
 import com.beem.project.beem.service.aidl.IXmppFacade;
 import com.beem.project.beem.ui.dialogs.builders.Alias;
@@ -123,6 +124,7 @@
     private String mCurGroup;
     private Contact mContact;
     private IXmppFacade mXmppFacade;
+    private IJingle mJingle;
     private SharedPreferences mSettings;
     private LayoutInflater mInflater;
 
@@ -200,7 +202,10 @@
 		    break;
 		case R.id.contact_list_context_menu_call_item:
 		    try {
-			mXmppFacade.call(mContact.getJID() + "/psi");
+			mJingle.call(mContact.getJID() + "/Beem");
+			in = new Intent(this, Call.class);
+		    in.setData(mContact.toUri());
+		    startActivity(in);
 			result = true;
 		    } catch (RemoteException e) {
 			e.printStackTrace();
@@ -757,6 +762,7 @@
 	    mXmppFacade = IXmppFacade.Stub.asInterface(service);
 	    try {
 		mRoster = mXmppFacade.getRoster();
+		mJingle = mXmppFacade.getJingleService();
 		if (mRoster != null) {
 		    mRoster.addRosterListener(mBeemRosterListener);
 		    List<Contact> tmpContactList = mRoster.getContactList();
@@ -803,6 +809,7 @@
 	    }
 	    mXmppFacade = null;
 	    mRoster = null;
+	    mJingle = null;
 	    mListContact.clear();
 	    mListGroup.clear();
 	    mContactOnGroup.clear();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/AppCallerThread.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,170 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.util.Enumeration;
+
+/**
+ * The purpose of this thread is to check whether there are packets ready from
+ * any participants.
+ * 
+ * It should sleep when not in use, and be woken up by a condition variable.
+ * 
+ * Optionally, if we do jitter-control, the condition variable should have a max
+ * waiting period equal to how often we need to push data.
+ * 
+ * @author Arne Kepp
+ */
+public class AppCallerThread extends Thread {
+	/** The parent RTP Session */
+	RTPSession rtpSession;
+	/** The applications interface, where the callback methods are called */
+	RTPAppIntf appl;
+
+	/**
+	 * Instatiates the AppCallerThread
+	 * 
+	 * @param session
+	 *            the RTPSession with participants etc
+	 * @param rtpApp
+	 *            the interface to which data is given
+	 */
+	protected AppCallerThread(RTPSession session, RTPAppIntf rtpApp) {
+		rtpSession = session;
+		appl = rtpApp;
+		if (RTPSession.rtpDebugLevel > 1) {
+			System.out.println("<-> AppCallerThread created");
+		}
+	}
+
+	/**
+	 * The AppCallerThread will run in this loop until the RTPSession is
+	 * terminated.
+	 * 
+	 * Whenever an RTP packet is received it will loop over the participants to
+	 * check for packet buffers that have available frame.
+	 */
+	public void run() {
+		if (RTPSession.rtpDebugLevel > 3) {
+			System.out.println("-> AppCallerThread.run()");
+		}
+
+		while (rtpSession.endSession == false) {
+
+			rtpSession.pktBufLock.lock();
+			try {
+				if (RTPSession.rtpDebugLevel > 4) {
+					System.out.println("<-> AppCallerThread going to Sleep");
+				}
+
+				try {
+					rtpSession.pktBufDataReady.await();
+				} catch (Exception e) {
+					System.out.println("AppCallerThread:" + e.getMessage());
+				}
+
+				// Next loop over all participants and check whether they have
+				// anything for us.
+				Enumeration<Participant> enu = rtpSession.partDb
+				.getParticipants();
+
+				while (enu.hasMoreElements()) {
+					Participant p = enu.nextElement();
+
+					boolean done = false;
+					// System.out.println(p.ssrc + " " + !done +" " +
+					// p.rtpAddress
+					// + " " + rtpSession.naiveReception + " " + p.pktBuffer);
+					// System.out.println("done: " + done + "  p.unexpected: " +
+					// p.unexpected);
+					while (!done
+							&& (!p.unexpected || rtpSession.naiveReception)
+							&& p.pktBuffer != null && p.pktBuffer.length > 0) {
+
+						DataFrame aFrame = p.pktBuffer.popOldestFrame();
+						if (aFrame == null) {
+							done = true;
+						} else {
+							appl.receiveData(aFrame, p);
+						}
+					}
+				}
+
+			} finally {
+				rtpSession.pktBufLock.unlock();
+			}
+		}
+		if (RTPSession.rtpDebugLevel > 3) {
+			System.out.println("<- AppCallerThread.run() terminating");
+		}
+	}
+
+	public DataFrame getNextDataFrame() {
+		if (RTPSession.rtpDebugLevel > 3) {
+			System.out.println("-> AppCallerThread.run()");
+		}
+		//rtpSession.pktBufLock.lock();
+		try {
+			if (RTPSession.rtpDebugLevel > 4) {
+				System.out.println("<-> AppCallerThread going to Sleep");
+			}
+
+			/*try {
+				rtpSession.pktBufDataReady.await();
+			} catch (Exception e) {
+				System.out.println("AppCallerThread:" + e.getMessage());
+			}*/
+
+			// Next loop over all participants and check whether they have
+			// anything for us.
+			/*Enumeration<Participant> enu = rtpSession.partDb
+			.getParticipants();
+
+			while (enu.hasMoreElements()) {*/
+				Participant p = rtpSession.firstPart;
+
+				boolean done = false;
+				// System.out.println(p.ssrc + " " + !done +" " +
+				// p.rtpAddress
+				// + " " + rtpSession.naiveReception + " " + p.pktBuffer);
+				// System.out.println("done: " + done + "  p.unexpected: " +
+				// p.unexpected);
+				while (!done
+						&& (!p.unexpected || rtpSession.naiveReception)
+						&& p.pktBuffer != null && p.pktBuffer.length > 0) {
+
+					DataFrame aFrame = p.pktBuffer.popOldestFrame();
+					if (aFrame == null) {
+						done = true;
+					} else {
+						return aFrame;
+					}
+				}
+			//}
+
+		} finally {
+			//rtpSession.pktBufLock.unlock();
+		}
+		if (RTPSession.rtpDebugLevel > 3) {
+			System.out.println("<- AppCallerThread.run() terminating");
+		}
+		return null;
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/CompRtcpPkt.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,268 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.InetSocketAddress;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * Compound RTCP packet class.
+ * 
+ * It basically holds a list of packets. This list can either be constructed by
+ * providing a byte[] of a compound packet, or by adding individual packets.
+ * 
+ * Upon encode(), the packet will call encode on all the added packets.
+ * 
+ * problem == 0 indicates the parsing succeeded.
+ * 
+ * 
+ * @author Arne Kepp
+ */
+
+public class CompRtcpPkt {
+	/** Problem indicator, negative values denote packet type that cause problem */
+	protected int problem = 0;
+	/**
+	 * Stores the different subclasses of RtcpPkt that make up the compound
+	 * packet
+	 */
+	protected LinkedList<RtcpPkt> rtcpPkts = new LinkedList<RtcpPkt>();
+
+	/**
+	 * Instantiates an empty Compound RTCP packet to which you can add RTCP
+	 * packets
+	 */
+	protected CompRtcpPkt() {
+		// Will have to add packets directly to rtcpPkts.
+		if (RTPSession.rtpDebugLevel > 7) {
+			System.out.println("<-> CompRtcpPkt()");
+		}
+	}
+
+	/**
+	 * Add a RTCP packet to the compound packet. Pakcets are added in order, so
+	 * you have to ensure that a Sender Report or Receiver Report is added
+	 * first.
+	 * 
+	 * @param aPkt
+	 *            the packet to be added
+	 */
+	protected void addPacket(RtcpPkt aPkt) {
+		if (RTPSession.rtpDebugLevel > 11) {
+			System.out.println("  <-> CompRtcpPkt.addPacket( "
+					+ aPkt.getClass() + " )");
+		}
+
+		if (aPkt.problem == 0) {
+			rtcpPkts.add(aPkt);
+		} else {
+			this.problem = aPkt.problem;
+		}
+	}
+	
+	/**
+	 * Picks a received Compound RTCP packet apart.
+	 * 
+	 * Only SDES packets are processed directly, other packets are parsed and
+	 * put into aComptRtcpPkt.rtcpPkts, but not
+	 * 
+	 * Check the aComptRtcpPkt.problem , if the value is non-zero the packets
+	 * should probably be discarded.
+	 * 
+	 * @param rawPkt
+	 *            the byte array received from the socket
+	 * @param packetSize
+	 *            the actual number of used bytes
+	 * @param adr
+	 *            the socket address from which the packet was received
+	 * @param rtpSession
+	 *            the RTPSession with the participant database
+	 */
+	
+	protected void init(byte[] rawPkt, int packetSize, InetSocketAddress adr,
+			RTPSession rtpSession) {
+		if (RTPSession.rtcpDebugLevel > 7) {
+			System.out.println("-> CompRtcpPkt(" + rawPkt.getClass()
+					+ ", size " + packetSize + ", from " + adr.toString()
+					+ ", " + rtpSession.getClass() + ")");
+		}
+		// System.out.println("rawPkt.length:" + rawPkt.length + " packetSize:"
+		// + packetSize);
+
+		// Chop it up
+		int start = 0;
+
+		while (start < packetSize && problem == 0) {
+			int length = (StaticProcs.bytesToUIntInt(rawPkt, start + 2)) + 1;
+
+			if (length * 4 + start > rawPkt.length) {
+				System.out.println("!!!! CompRtcpPkt.(rawPkt,..,..) length ("
+						+ (length * 4 + start)
+						+ ") exceeds size of raw packet (" + rawPkt.length
+						+ ") !");
+				this.problem = -3;
+			}
+
+			int pktType = (int) rawPkt[start + 1];
+
+			if (pktType < 0) {
+				pktType += 256;
+			}
+
+			if (start == 0) {
+				// Compound packets need to start with SR or RR
+				if (pktType != 200 && pktType != 201) {
+					if (RTPSession.rtcpDebugLevel > 3) {
+						System.out
+								.println("!!!! CompRtcpPkt(rawPkt...) packet did not start with SR or RR");
+					}
+					this.problem = -1;
+				}
+
+				// Padding bit should be zero for the first packet
+				if (((rawPkt[start] & 0x20) >>> 5) == 1) {
+					if (RTPSession.rtcpDebugLevel > 3) {
+						System.out
+								.println("!!!! CompRtcpPkt(rawPkt...) first packet was padded");
+					}
+					this.problem = -2;
+				}
+			}
+
+			// System.out.println("start: " + start + "   pktType: " + pktType +
+			// "  length:" + length );
+			if (pktType == 200) {
+				addPacket(new RtcpPktSR(rawPkt, start, length * 4));
+			} else if (pktType == 201) {
+				addPacket(new RtcpPktRR(rawPkt, start, -1));
+			} else if (pktType == 202) {
+				addPacket(new RtcpPktSDES(rawPkt, start, adr, rtpSession.partDb));
+			} else if (pktType == 203) {
+				addPacket(new RtcpPktBYE(rawPkt, start));
+			} else if (pktType == 204) {
+				addPacket(new RtcpPktAPP(rawPkt, start));
+			} else if (pktType == 205) {
+				addPacket(new RtcpPktRTPFB(rawPkt, start, rtpSession));
+			} else if (pktType == 206) {
+				addPacket(new RtcpPktPSFB(rawPkt, start, rtpSession));
+			} else {
+				System.out
+						.println("!!!! CompRtcpPkt(byte[] rawPkt, int packetSize...) "
+								+ "UNKNOWN RTCP PACKET TYPE:" + pktType);
+			}
+
+			// System.out.println(" start:" + start + "  pktType:" + pktType +
+			// " length:" + length);
+
+			start += length * 4;
+
+			if (RTPSession.rtcpDebugLevel > 12) {
+				System.out.println(" start:" + start + "  parsing pktType "
+						+ pktType + " length: " + length);
+			}
+		}
+		if (RTPSession.rtcpDebugLevel > 7) {
+			System.out.println("<- CompRtcpPkt(rawPkt....)");
+		}
+	}
+
+	/**
+	 * Encode combines the RTCP packets in this.rtcpPkts into a byte[] by
+	 * calling the encode() function on each of them individually.
+	 * 
+	 * The order of rtcpPkts is preserved, so a RR or SR packet must be first.
+	 * 
+	 * @return the trimmed byte[] representation of the packet, ready to go into
+	 *         a UDP packet.
+	 */
+	protected byte[] encode() {
+		if (RTPSession.rtpDebugLevel > 9) {
+			System.out.println(" <- CompRtcpPkt.encode()");
+		}
+
+		ListIterator<RtcpPkt> iter = rtcpPkts.listIterator();
+
+		byte[] rawPkt = new byte[1500];
+		int index = 0;
+
+		while (iter.hasNext()) {
+			RtcpPkt aPkt = (RtcpPkt) iter.next();
+
+			if (aPkt.packetType == 200) {
+				RtcpPktSR pkt = (RtcpPktSR) aPkt;
+				pkt.encode();
+				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
+						pkt.rawPkt.length);
+				index += pkt.rawPkt.length;
+			} else if (aPkt.packetType == 201) {
+				RtcpPktRR pkt = (RtcpPktRR) aPkt;
+				pkt.encode();
+				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
+						pkt.rawPkt.length);
+				index += pkt.rawPkt.length;
+			} else if (aPkt.packetType == 202) {
+				RtcpPktSDES pkt = (RtcpPktSDES) aPkt;
+				pkt.encode();
+				// System.out.println(" ENCODE SIZE: " + pkt.rawPkt.length);
+				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
+						pkt.rawPkt.length);
+				index += pkt.rawPkt.length;
+			} else if (aPkt.packetType == 203) {
+				RtcpPktBYE pkt = (RtcpPktBYE) aPkt;
+				pkt.encode();
+				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
+						pkt.rawPkt.length);
+				index += pkt.rawPkt.length;
+			} else if (aPkt.packetType == 204) {
+				RtcpPktAPP pkt = (RtcpPktAPP) aPkt;
+				pkt.encode();
+				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
+						pkt.rawPkt.length);
+				index += pkt.rawPkt.length;
+			} else if (aPkt.packetType == 205) {
+				RtcpPktRTPFB pkt = (RtcpPktRTPFB) aPkt;
+				pkt.encode();
+				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
+						pkt.rawPkt.length);
+				index += pkt.rawPkt.length;
+			} else if (aPkt.packetType == 206) {
+				RtcpPktPSFB pkt = (RtcpPktPSFB) aPkt;
+				pkt.encode();
+				System.arraycopy(pkt.rawPkt, 0, rawPkt, index,
+						pkt.rawPkt.length);
+				index += pkt.rawPkt.length;
+			} else {
+				System.out.println("CompRtcpPkt aPkt.packetType:"
+						+ aPkt.packetType);
+			}
+			// System.out.println(" packetType:" + aPkt.packetType + " length:"
+			// + aPkt.rawPkt.length + " index:" + index);
+		}
+
+		byte[] output = new byte[index];
+
+		System.arraycopy(rawPkt, 0, output, 0, index);
+
+		if (RTPSession.rtpDebugLevel > 9) {
+			System.out.println(" -> CompRtcpPkt.encode()");
+		}
+		return output;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/DataFrame.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,295 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import org.sipdroid.net.tools.DatagramPool;
+import org.sipdroid.net.tools.PktBufNodePool;
+import org.sipdroid.net.tools.RtpPktPool;
+
+/**
+ * Data structure to hold a complete frame if frame reconstruction is enabled,
+ * or the data from an individual packet if it is not
+ * 
+ * It also contains most of the data from the individual packets that it is
+ * based on.
+ * 
+ * @author Arne Kepp
+ */
+public class DataFrame {
+	/** The share RTP timestamp */
+	private long rtpTimestamp;
+	/** The calculated UNIX timestamp, guessed after 2 Sender Reports */
+	private long timestamp = -1;
+	/** the SSRC from which this frame originated */
+	private long SSRC;
+	/** contributing CSRCs, only read from the first packet */
+	private long[] CSRCs;
+	/** RTP payload type */
+	private int payloadType;
+	/** The marks on individual packets, ordered */
+	//private boolean[] marks;
+	/** Whether any packets were marked or not */
+	private boolean anyMarked = false;
+	/** Whether the frame contains the expected number of packets */
+	private int isComplete = 0;
+	// private int dataLength;
+	/** The data from the individual packets, ordered */
+	//private byte[][] data;
+	/** The sequence numbers of the individual packets, ordered */
+	//private int[] seqNum;
+	/** The total amount of data bytes in this frame */
+	private int totalLength = 0;
+	/** The last sequence number in this frame */
+	protected int lastSeqNum;
+	/** The first sequence number in this frame */
+	protected int firstSeqNum;
+	/** The number of packets expected for a complete frame */
+	protected int noPkts;
+	private RtpPkt[] pkts = new RtpPkt[5];
+
+	/**
+	 * The usual way to construct a frame is by giving it a PktBufNode, which
+	 * contains links to all the other pkts that make it up.
+	 */
+	protected DataFrame(PktBufNode aBufNode, Participant p, int noPkts) {
+		initDataFrame(aBufNode, p, noPkts);
+	}
+
+	protected void initDataFrame(PktBufNode aBufNode, Participant p, int noPkts) {
+		if (RTPSession.rtpDebugLevel > 6) {
+			System.out.println("-> DataFrame(PktBufNode, noPkts = " + noPkts
+					+ ")");
+		}
+		this.noPkts = noPkts;
+		RtpPkt aPkt = aBufNode.pkt;
+		int pktCount = aBufNode.pktCount;
+		firstSeqNum = aBufNode.pktCount;
+		PktBufNode tempNode;
+
+		// All this data should be shared, so we just get it from the first one
+		this.rtpTimestamp = aBufNode.timeStamp;
+		SSRC = aPkt.getSsrc();
+		CSRCs = aPkt.getCsrcArray();
+
+		// Check whether we can compute an NTPish timestamp? Requires two SR
+		// reports
+		if (p.ntpGradient > 0) {
+			// System.out.print(Long.toString(p.ntpOffset)+" "
+			timestamp = p.ntpOffset
+			+ (long) (p.ntpGradient * (double) (this.rtpTimestamp - p.lastSRRtpTs));
+		}
+
+		// Make data the right length
+		int payloadLength = aPkt.getPayloadLength();
+		//seqNum = new int[aBufNode.pktCount];
+		//marks = new boolean[aBufNode.pktCount];
+		if (pktCount > 5) {
+			System.out.println("PKT COUNT TOO HIGH " + pktCount);
+		}
+		// Concatenate the data of the packets
+		int i;
+		for (i = 0; i < pktCount; i++) {
+			aPkt = aBufNode.pkt;
+			pkts[i] = aPkt;
+			// System.out.println("i " + i + " seqNum[i] " + seqNum[i] +
+			// " aBufNode" + aBufNode);
+			//seqNum[i] = aBufNode.seqNum;
+			if (aBufNode.pkt.isMarked())
+				anyMarked = true;
+
+			// Get next node
+			tempNode = aBufNode;
+			aBufNode = aBufNode.nextFrameNode;
+			PktBufNodePool.getInstance().returnBufNode(tempNode);
+			lastSeqNum = aPkt.getSeqNumber();
+		}
+
+		if (noPkts > 0) {
+			int seqDiff = firstSeqNum - lastSeqNum;
+			if (seqDiff < 0)
+				seqDiff = (Integer.MAX_VALUE - firstSeqNum) + lastSeqNum;
+			if (seqDiff == pktCount && pktCount == noPkts)
+				isComplete = 1;
+		} else {
+			isComplete = -1;
+		}
+
+		if (RTPSession.rtpDebugLevel > 6) {
+			System.out.println("<- DataFrame(PktBufNode, noPkt), data length: "
+					+ pkts.length);
+		}
+	}
+
+	public DataFrame(){
+	}
+
+	/**
+	 * Returns a two dimensial array where the first dimension represents
+	 * individual packets, from which the frame is made up, in order of
+	 * increasing sequence number. These indeces can be matched to the sequence
+	 * numbers returned by sequenceNumbers().
+	 * 
+	 * @return 2-dim array with raw data from packets
+	 */
+	/*public byte[][] getData() {
+		return this.data;
+	}*/
+
+	public RtpPkt[] getPkt(){
+		return this.pkts ;
+	}
+
+	/**
+	 * Returns a concatenated version of the data from getData() It ignores
+	 * missing sequence numbers, but then isComplete() will return false
+	 * provided that RTPAppIntf.frameSize() provides a non-negative number for
+	 * this payload type.
+	 * 
+	 * @return byte[] with all the data concatenated
+	 */
+	/*public byte[] getConcatenatedData() {
+		if (this.noPkts < 2) {
+			byte[] ret = new byte[this.totalLength];
+			int pos = 0;
+
+			for (int i = 0; i < data.length; i++) {
+				int length = data[i].length;
+
+				// Last packet may be shorter
+				if (pos + length > totalLength)
+					length = totalLength - pos;
+
+				System.arraycopy(data[i], 0, ret, pos, length);
+				pos += data[i].length;
+			}
+			return ret;
+		} else {
+			return data[0];
+		}
+	}*/
+
+	/**
+	 * If two SR packet have been received jlibrtp will attempt to calculate the
+	 * local UNIX timestamp (in milliseconds) of all packets received.
+	 * 
+	 * This value should ideally correspond to the local time when the SSRC sent
+	 * the packet. Note that the source may not be reliable.
+	 * 
+	 * Returns -1 if less than two SRs have been received
+	 * 
+	 * @return the UNIX timestamp, similar to System.currentTimeMillis() or -1;
+	 */
+	public long timestamp() {
+		return this.timestamp;
+
+	}
+
+	/**
+	 * Returns the RTP timestamp of all the packets in the frame.
+	 * 
+	 * @return unmodified RTP timestamp
+	 */
+	public long rtpTimestamp() {
+		return this.rtpTimestamp;
+	}
+
+	/**
+	 * Returns the payload type of the packets
+	 * 
+	 * @return the payload type of the packets
+	 */
+	public int payloadType() {
+		return this.payloadType;
+	}
+
+	/**
+	 * Returns an array whose values, for the same index, correpond to the
+	 * sequence number of the packet from which the data came.
+	 * 
+	 * This information can be valuable in conjunction with getData(), to
+	 * identify what parts of a frame are missing.
+	 * 
+	 * @return array with sequence numbers
+	 */
+	/*public int[] sequenceNumbers() {
+		return seqNum;
+	}*/
+
+	/**
+	 * Returns an array whose values, for the same index, correpond to whether
+	 * the data was marked or not.
+	 * 
+	 * This information can be valuable in conjunction with getData().
+	 * 
+	 * @return array of booleans
+	 */
+	/*public boolean[] marks() {
+		return this.marks;
+	}*/
+
+	/**
+	 * Returns true if any packet in the frame was marked.
+	 * 
+	 * This function should be used if all your frames fit into single packets.
+	 * 
+	 * @return true if any packet was marked, false otherwise
+	 */
+	public boolean marked() {
+		return this.anyMarked;
+	}
+
+	/**
+	 * The SSRC associated with this frame.
+	 * 
+	 * @return the ssrc that created this frame
+	 */
+	public long ssrc() {
+		return this.SSRC;
+	}
+
+	/**
+	 * The SSRCs that contributed to this frame
+	 * 
+	 * @return an array of contributing SSRCs, or null
+	 */
+	public long[] csrcs() {
+		return this.CSRCs;
+	}
+
+	/**
+	 * Checks whether the difference in sequence numbers corresponds to the
+	 * number of packets received for the current timestamp, and whether this
+	 * value corresponds to the expected number of packets.
+	 * 
+	 * @return true if the right number of packets make up the frame
+	 */
+	public int complete() {
+		return this.isComplete;
+	}
+
+	public void release() {
+		for(RtpPkt pkt : this.pkts) {
+			if (pkt != null) {
+				if (pkt.getDatagramPacket() != null)
+					DatagramPool.getInstance().returnPacket(pkt.getDatagramPacket());
+				RtpPktPool.getInstance().returnPkt(pkt);
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/DebugAppIntf.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,90 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.InetSocketAddress;
+
+/**
+ * DebugAppIntf can be registered on RTPSession to provide simple debugging
+ * functionality. This is particularly useful to determine whether the client is
+ * receing any data at all.
+ * 
+ * @author Arne Kepp
+ * 
+ */
+
+public interface DebugAppIntf {
+	/**
+	 * This function wil notify you of any packets received, valid or not.
+	 * Useful for network debugging, and finding bugs in jlibrtp.
+	 * 
+	 * Type is an integer describing the type of event -2 - Invalid RTCP packet
+	 * received -1 - Invalid RTP packet received 0 - RTP packet received 1 -
+	 * RTCP packet received
+	 * 
+	 * Description is a string that should be meaningful to advanced users, such
+	 * as"RTP packet received from 127.0.0.1:12312, SSRC: 1380912 , payload type 1, packet size 16 octets"
+	 * or "Invalid RTP packet received from 127.0.0.1:12312"
+	 * 
+	 * This function is synchonous and should return quickly.
+	 * 
+	 * @param type
+	 *            , the type of event, see above.
+	 * @param socket
+	 *            , taken directly from the UDP packet
+	 * @param description
+	 *            , see above.
+	 */
+	public void packetReceived(int type, InetSocketAddress socket,
+			String description);
+
+	/**
+	 * This function will notify you of any packets sent from this instance of
+	 * RTPSession. Useful for network debugging, and finding bugs in jlibrtp.
+	 * 
+	 * Type is an integer describing the type of event 0 - RTP unicast packet
+	 * sent 1 - RTP multicast packet sent 2 - RTCP unicast packet sent 3 - RTCP
+	 * multicast packet sent
+	 * 
+	 * Description is a string that should be meaningful to advanced users, such
+	 * as
+	 * 
+	 * This function is synchonous and should return quickly.
+	 * 
+	 * @param type
+	 *            , the type of event, see above
+	 * @param socket
+	 *            , taken directly from the UDP packet
+	 * @param description
+	 *            , see above
+	 */
+	public void packetSent(int type, InetSocketAddress socket,
+			String description);
+
+	/**
+	 * Other important events that can occur in session -1 SSRC conflict 0
+	 * Session is terminating
+	 * 
+	 * @param type
+	 *            see above
+	 * @param description
+	 *            , see above
+	 */
+	public void importantEvent(int type, String description);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/LICENSE.txt	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,490 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+    
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/Participant.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,464 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.InetSocketAddress;
+
+/**
+ * A participant represents a peer in an RTPSession. Based on the information
+ * stored on these objects, packets are processed and statistics generated for
+ * RTCP.
+ */
+public class Participant {
+	/**
+	 * Whether the participant is unexpected, e.g. arrived through unicast with
+	 * SDES
+	 */
+	protected boolean unexpected = false;
+	/** Where to send RTP packets (unicast) */
+	protected InetSocketAddress rtpAddress = null;
+	/** Where to send RTCP packets (unicast) */
+	protected InetSocketAddress rtcpAddress = null;
+	/** Where the first RTP packet was received from */
+	protected InetSocketAddress rtpReceivedFromAddress = null;
+	/** Where the first RTCP packet was received from */
+	protected InetSocketAddress rtcpReceivedFromAddress = null;
+
+	/** SSRC of participant */
+	protected long ssrc = -1;
+	/** SDES CNAME */
+	protected String cname = null;
+	/** SDES The participant's real name */
+	protected String name = null;
+	/** SDES The participant's email */
+	protected String email = null;
+	/** SDES The participant's phone number */
+	protected String phone = null;
+	/** SDES The participant's location */
+	protected String loc = null;
+	/** SDES The tool the participants is using */
+	protected String tool = null;
+	/** SDES A note */
+	protected String note = null;
+	/** SDES A priv string, loosely defined */
+	protected String priv = null;
+
+	// Receiver Report Items
+	/** RR First sequence number */
+	protected int firstSeqNumber = -1;
+	/** RR Last sequence number */
+	protected int lastSeqNumber = 0;
+	/** RR Number of times sequence number has rolled over */
+	protected long seqRollOverCount = 0;
+	/** RR Number of packets received */
+	protected long receivedPkts = 0;
+	/** RR Number of octets received */
+	protected long receivedOctets = 0;
+	/** RR Number of packets received since last SR */
+	protected int receivedSinceLastSR = 0;
+	/** RR Sequence number associated with last SR */
+	protected int lastSRRseqNumber = 0;
+	/** RR Interarrival jitter */
+	protected double interArrivalJitter = -1.0;
+	/** RR Last received RTP Timestamp */
+	protected long lastRtpTimestamp = 0;
+
+	/** RR Middle 32 bits of the NTP timestamp in the last SR */
+	protected long timeStampLSR = 0;
+	/** RR The time when we actually got the last SR */
+	protected long timeReceivedLSR = 0;
+
+	/** Gradient where UNIX timestamp = ntpGradient*RTPTimestamp * ntpOffset */
+	protected double ntpGradient = -1;
+	/** Offset where UNIX timestamp = ntpGradient*RTPTimestamp * ntpOffset */
+	protected long ntpOffset = -1;
+	/** Last NTP received in SR packet, MSB */
+	protected long lastNtpTs1 = 0; // 32 bits
+	/** Last NTP received in SR packet, LSB */
+	protected long lastNtpTs2 = 0; // 32 bits
+	/** RTP Timestamp in last SR packet */
+	protected long lastSRRtpTs = 0; // 32 bits
+
+	/** UNIX time when a BYE was received from this participant, for pruning */
+	protected long timestampBYE = -1; // The user said BYE at this time
+
+	/** Store the packets received from this participant */
+	protected PktBuffer pktBuffer = null;
+
+	/**
+	 * UNIX time of last RTP packet, to check whether this participant has sent
+	 * anything recently
+	 */
+	protected long lastRtpPkt = -1; // Time of last RTP packet
+	/**
+	 * UNIX time of last RTCP packet, to check whether this participant has sent
+	 * anything recently
+	 */
+	protected long lastRtcpPkt = -1; // Time of last RTCP packet
+	/**
+	 * UNIX time this participant was added by application, to check whether we
+	 * ever heard back
+	 */
+	protected long addedByApp = -1; // Time the participant was added by
+									// application
+	/** UNIX time of last time we sent an RR to this user */
+	protected long lastRtcpRRPkt = -1; // Timestamp of last time we sent this
+										// person an RR packet
+	/** Unix time of second to last time we sent and RR to this user */
+	protected long secondLastRtcpRRPkt = -1; // Timestamp of 2nd to last time we
+												// sent this person an RR Packet
+
+	/**
+	 * Create a basic participant. If this is a <b>unicast</b> session you must
+	 * provide network address (ipv4 or ipv6) and ports for RTP and RTCP, as
+	 * well as a cname for this contact. These things should be negotiated
+	 * through SIP or a similar protocol.
+	 * 
+	 * jlibrtp will listen for RTCP packets to obtain a matching SSRC for this
+	 * participant, based on cname.
+	 * 
+	 * @param networkAddress
+	 *            string representation of network address (ipv4 or ipv6). Use
+	 *            "127.0.0.1" for multicast session.
+	 * @param rtpPort
+	 *            port on which peer expects RTP packets. Use 0 if this is a
+	 *            sender-only, or this is a multicast session.
+	 * @param rtcpPort
+	 *            port on which peer expects RTCP packets. Use 0 if this is a
+	 *            sender-only, or this is a multicast session.
+	 */
+	public Participant(String networkAddress, int rtpPort, int rtcpPort) {
+		if (RTPSession.rtpDebugLevel > 6) {
+			System.out.println("Creating new participant: " + networkAddress);
+		}
+
+		// RTP
+		if (rtpPort > 0) {
+			try {
+				rtpAddress = new InetSocketAddress(networkAddress, rtpPort);
+			} catch (Exception e) {
+				System.out.println("Couldn't resolve " + networkAddress);
+			}
+			// isReceiver = true;
+		}
+
+		// RTCP
+		if (rtcpPort > 0) {
+			try {
+				rtcpAddress = new InetSocketAddress(networkAddress, rtcpPort);
+			} catch (Exception e) {
+				System.out.println("Couldn't resolve " + networkAddress);
+			}
+		}
+
+		// By default this is a sender
+		// isSender = true;
+	}
+
+	// We got a packet, but we don't know this person yet.
+	protected Participant(InetSocketAddress rtpAdr, InetSocketAddress rtcpAdr,
+			long SSRC) {
+		rtpReceivedFromAddress = rtpAdr;
+		rtcpReceivedFromAddress = rtcpAdr;
+		ssrc = SSRC;
+		unexpected = true;
+	}
+
+	// Dummy constructor to ease testing
+	protected Participant() {
+		System.out.println("Don't use the Participan(void) Constructor!");
+	}
+
+	/**
+	 * RTP Address registered with this participant.
+	 * 
+	 * @return address of participant
+	 */
+	InetSocketAddress getRtpSocketAddress() {
+		return rtpAddress;
+	}
+
+	/**
+	 * RTCP Address registered with this participant.
+	 * 
+	 * @return address of participant
+	 */
+	InetSocketAddress getRtcpSocketAddress() {
+		return rtcpAddress;
+	}
+
+	/**
+	 * InetSocketAddress this participant has used to send us RTP packets.
+	 * 
+	 * @return address of participant
+	 */
+	InetSocketAddress getRtpReceivedFromAddress() {
+		return rtpAddress;
+	}
+
+	/**
+	 * InetSocketAddress this participant has used to send us RTCP packets.
+	 * 
+	 * @return address of participant
+	 */
+	InetSocketAddress getRtcpReceivedFromAddress() {
+		return rtcpAddress;
+	}
+
+	/**
+	 * CNAME registered for this participant.
+	 * 
+	 * @return the cname
+	 */
+	public String getCNAME() {
+		return cname;
+	}
+
+	/**
+	 * NAME registered for this participant.
+	 * 
+	 * @return the name
+	 */
+	public String getNAME() {
+		return name;
+	}
+
+	/**
+	 * EMAIL registered for this participant.
+	 * 
+	 * @return the email address
+	 */
+	public String getEmail() {
+		return email;
+	}
+
+	/**
+	 * PHONE registered for this participant.
+	 * 
+	 * @return the phone number
+	 */
+	public String getPhone() {
+		return phone;
+	}
+
+	/**
+	 * LOCATION registered for this participant.
+	 * 
+	 * @return the location
+	 */
+	public String getLocation() {
+		return loc;
+	}
+
+	/**
+	 * NOTE registered for this participant.
+	 * 
+	 * @return the note
+	 */
+	public String getNote() {
+		return note;
+	}
+
+	/**
+	 * PRIVATE something registered for this participant.
+	 * 
+	 * @return the private-string
+	 */
+	public String getPriv() {
+		return priv;
+	}
+
+	/**
+	 * TOOL something registered for this participant.
+	 * 
+	 * @return the tool
+	 */
+	public String getTool() {
+		return tool;
+	}
+
+	/**
+	 * SSRC for participant, determined through RTCP SDES
+	 * 
+	 * @return SSRC (32 bit unsigned integer as long)
+	 */
+	public long getSSRC() {
+		return this.ssrc;
+	}
+
+	/**
+	 * Updates the participant with information for receiver reports.
+	 * 
+	 * @param packetLength
+	 *            to keep track of received octets
+	 * @param pkt
+	 *            the most recently received packet
+	 */
+	protected void updateRRStats(int packetLength, RtpPkt pkt) {
+		int curSeqNum = pkt.getSeqNumber();
+
+		if (firstSeqNumber < 0) {
+			firstSeqNumber = curSeqNum;
+		}
+
+		receivedOctets += packetLength;
+		receivedSinceLastSR++;
+		receivedPkts++;
+
+		long curTime = System.currentTimeMillis();
+
+		if (this.lastSeqNumber < curSeqNum) {
+			// In-line packet, best thing you could hope for
+			this.lastSeqNumber = curSeqNum;
+
+		} else if (this.lastSeqNumber - this.lastSeqNumber < -100) {
+			// Sequence counter rolled over
+			this.lastSeqNumber = curSeqNum;
+			seqRollOverCount++;
+
+		} else {
+			// This was probably a duplicate or a late arrival.
+		}
+
+		// Calculate jitter
+		if (this.lastRtpPkt > 0) {
+
+			long D = (pkt.getTimeStamp() - curTime)
+					- (this.lastRtpTimestamp - this.lastRtpPkt);
+			if (D < 0)
+				D = (-1) * D;
+
+			this.interArrivalJitter += ((double) D - this.interArrivalJitter) / 16.0;
+		}
+
+		lastRtpPkt = curTime;
+		lastRtpTimestamp = pkt.getTimeStamp();
+	}
+
+	/**
+	 * Calculates the extended highest sequence received by adding the last
+	 * sequence number to 65536 times the number of times the sequence counter
+	 * has rolled over.
+	 * 
+	 * @return extended highest sequence
+	 */
+	protected long getExtHighSeqRecv() {
+		return (65536 * seqRollOverCount + lastSeqNumber);
+	}
+
+	/**
+	 * Get the fraction of lost packets, calculated as described in RFC 3550 as
+	 * a fraction of 256.
+	 * 
+	 * @return the fraction of lost packets since last SR received
+	 */
+	protected int getFractionLost() {
+		int expected = (lastSeqNumber - lastSRRseqNumber);
+		if (expected < 0)
+			expected = 65536 + expected;
+
+		int fraction = 256 * (expected - receivedSinceLastSR);
+		if (expected > 0) {
+			fraction = (fraction / expected);
+		} else {
+			fraction = 0;
+		}
+
+		// Clear counters
+		receivedSinceLastSR = 0;
+		lastSRRseqNumber = lastSeqNumber;
+
+		return fraction;
+	}
+
+	/**
+	 * The total number of packets lost during the session.
+	 * 
+	 * Returns zero if loss is negative, i.e. duplicates have been received.
+	 * 
+	 * @return number of lost packets, or zero.
+	 */
+	protected long getLostPktCount() {
+		long lost = (this.getExtHighSeqRecv() - this.firstSeqNumber)
+				- receivedPkts;
+
+		if (lost < 0)
+			lost = 0;
+		return lost;
+	}
+
+	/**
+	 * 
+	 * @return the interArrivalJitter, calculated continuously
+	 */
+	protected double getInterArrivalJitter() {
+		return this.interArrivalJitter;
+	}
+
+	/**
+	 * Set the timestamp for last sender report
+	 * 
+	 * @param ntp1
+	 *            high order bits
+	 * @param ntp2
+	 *            low order bits
+	 */
+	protected void setTimeStampLSR(long ntp1, long ntp2) {
+		// Use what we've got
+		byte[] high = StaticProcs.uIntLongToByteWord(ntp1);
+		byte[] low = StaticProcs.uIntLongToByteWord(ntp2);
+		low[3] = low[1];
+		low[2] = low[0];
+		low[1] = high[3];
+		low[0] = high[2];
+
+		this.timeStampLSR = StaticProcs.bytesToUIntLong(low, 0);
+	}
+
+	/**
+	 * Calculate the delay between the last received sender report and now.
+	 * 
+	 * @return the delay in units of 1/65.536ms
+	 */
+	protected long delaySinceLastSR() {
+		if (this.timeReceivedLSR < 1)
+			return 0;
+
+		long delay = System.currentTimeMillis() - this.timeReceivedLSR;
+
+		// Convert ms into 1/65536s = 1/65.536ms
+		return (long) ((double) delay * 65.536);
+	}
+
+	/**
+	 * Only for debugging purposes
+	 */
+	public void debugPrint() {
+		System.out.print(" Participant.debugPrint() SSRC:" + this.ssrc
+				+ " CNAME:" + this.cname);
+		if (this.rtpAddress != null)
+			System.out.print(" RTP:" + this.rtpAddress.toString());
+		if (this.rtcpAddress != null)
+			System.out.print(" RTCP:" + this.rtcpAddress.toString());
+		System.out.println("");
+
+		System.out.println("                          Packets received:"
+				+ this.receivedPkts);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/ParticipantDatabase.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,277 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The participant database maintains three hashtables with participants.
+ * 
+ * The key issue is to be fast for operations that happen every time an RTP
+ * packet is sent or received. We allow linear searching in cases where we need
+ * to update participants with information.
+ * 
+ * The keying is therefore usually the SSRC. In cases where we have the cname,
+ * but no SSRC is known (no SDES packet has been received), a simple hash i
+ * calculated based on the CNAME. The RTCP code should, when receiving SDES
+ * packets, check whether the participant is known and update the copy in this
+ * database with SSRC if needed.
+ * 
+ * @author Arne Kepp
+ */
+public class ParticipantDatabase {
+	/** The parent RTP Session */
+	RTPSession rtpSession = null;
+	/**
+	 * A linked list to hold participants explicitly added by the application In
+	 * unicast mode this is the list used for RTP and RTCP transmission, in
+	 * multicast it should not be in use.
+	 */
+	LinkedList<Participant> receivers = new LinkedList<Participant>();
+	/**
+	 * The hashtable holds participants added through received RTP and RTCP
+	 * packets, as well as participants that have been linked to an SSRC by ip
+	 * address (in unicast mode).
+	 */
+	ConcurrentHashMap<Long, Participant> ssrcTable = new ConcurrentHashMap<Long, Participant>();
+
+	/**
+	 * Simple constructor
+	 * 
+	 * @param parent
+	 *            parent RTPSession
+	 */
+	protected ParticipantDatabase(RTPSession parent) {
+		rtpSession = parent;
+	}
+
+	/**
+	 * 
+	 * @param cameFrom
+	 *            0: Application, 1: RTP packet, 2: RTCP
+	 * @param p
+	 *            the participant
+	 * @return 0 if okay, -1 if not
+	 */
+	protected int addParticipant(int cameFrom, Participant p) {
+		// Multicast or not?
+		if (this.rtpSession.mcSession) {
+			return this.addParticipantMulticast(cameFrom, p);
+		} else {
+			return this.addParticipantUnicast(cameFrom, p);
+		}
+
+	}
+
+	/**
+	 * Add a multicast participant to the database
+	 * 
+	 * @param cameFrom
+	 *            0: Application, 1,2: discovered through RTP or RTCP
+	 * @param p
+	 *            the participant to add
+	 * @return 0 if okay, -2 if redundant, -1 if adding participant to multicast
+	 */
+	private int addParticipantMulticast(int cameFrom, Participant p) {
+		if (cameFrom == 0) {
+			System.out
+					.println("ParticipantDatabase.addParticipant() doesnt expect"
+							+ " application to add participants to multicast session.");
+			return -1;
+		} else {
+			// Check this one is not redundant
+			if (this.ssrcTable.contains(p.ssrc)) {
+				System.out.println("ParticipantDatabase.addParticipant() SSRC "
+						+ "already known " + Long.toString(p.ssrc));
+				return -2;
+			} else {
+				this.ssrcTable.put(p.ssrc, p);
+				return 0;
+			}
+		}
+	}
+
+	/**
+	 * Add a unicast participant to the database
+	 * 
+	 * Result will be reported back through tpSession.appIntf.userEvent
+	 * 
+	 * @param cameFrom
+	 *            0: Application, 1,2: discovered through RTP or RTCP
+	 * @param p
+	 *            the participant to add
+	 * @return 0 if new, 1 if
+	 */
+	private int addParticipantUnicast(int cameFrom, Participant p) {
+		if (cameFrom == 0) {
+			// Check whether there is a match in the ssrcTable
+			boolean notDone = true;
+
+			Enumeration<Participant> enu = this.ssrcTable.elements();
+			while (notDone && enu.hasMoreElements()) {
+				Participant part = enu.nextElement();
+				if (part.unexpected
+						&& (part.rtcpReceivedFromAddress
+								.equals(part.rtcpAddress.getAddress()) || part.rtpReceivedFromAddress
+								.equals(part.rtpAddress.getAddress()))) {
+
+					part.rtpAddress = p.rtpAddress;
+					part.rtcpAddress = p.rtcpAddress;
+					part.unexpected = false;
+
+					// Report the match back to the application
+					Participant[] partArray = { part };
+					this.rtpSession.appIntf.userEvent(5, partArray);
+
+					notDone = false;
+					p = part;
+				}
+			}
+
+			// Add to the table of people that we send packets to
+			this.receivers.add(p);
+			return 0;
+
+		} else {
+			// Check whether there's a match in the receivers table
+			boolean notDone = true;
+			// System.out.println("GOT " + p.cname);
+			Iterator<Participant> iter = this.receivers.iterator();
+
+			while (notDone && iter.hasNext()) {
+				Participant part = iter.next();
+
+				// System.out.println(part.rtpAddress.getAddress().toString()
+				// + " " + part.rtcpAddress.getAddress().toString()
+				// + " " + p.rtpReceivedFromAddress.getAddress().toString()
+				// + " " + p.rtcpReceivedFromAddress.getAddress().toString());
+
+				// System.out.println(" HUUHHHH?  " +
+				// p.rtcpReceivedFromAddress.getAddress().equals(part.rtcpAddress.getAddress()));
+				if ((cameFrom == 1 && p.rtpReceivedFromAddress.getAddress()
+						.equals(part.rtpAddress.getAddress()))
+						|| (cameFrom == 2 && p.rtcpReceivedFromAddress
+								.getAddress().equals(
+										part.rtcpAddress.getAddress()))) {
+
+					part.rtpReceivedFromAddress = p.rtpReceivedFromAddress;
+					part.rtcpReceivedFromAddress = p.rtcpReceivedFromAddress;
+
+					// Move information
+					part.ssrc = p.ssrc;
+					part.cname = p.cname;
+					part.name = p.name;
+					part.loc = p.loc;
+					part.phone = p.phone;
+					part.email = p.email;
+					part.note = p.note;
+					part.tool = p.tool;
+					part.priv = p.priv;
+
+					this.ssrcTable.put(part.ssrc, part);
+
+					// Report the match back to the application
+					Participant[] partArray = { part };
+					this.rtpSession.appIntf.userEvent(5, partArray);
+					return 0;
+				}
+			}
+
+			// No match? ok
+			this.ssrcTable.put(p.ssrc, p);
+			return 0;
+		}
+	}
+
+	/**
+	 * Remove a participant from all tables
+	 * 
+	 * @param p
+	 *            the participant to be removed
+	 */
+	protected void removeParticipant(Participant p) {
+		if (!this.rtpSession.mcSession)
+			this.receivers.remove(p);
+
+		this.ssrcTable.remove(p.ssrc, p);
+	}
+
+	/**
+	 * Find a participant based on the ssrc
+	 * 
+	 * @param ssrc
+	 *            of the participant to be found
+	 * @return the participant, null if unknonw
+	 */
+	protected Participant getParticipant(long ssrc) {
+		Participant p = null;
+		p = ssrcTable.get(ssrc);
+		return p;
+	}
+
+	/**
+	 * Iterator for all the unicast receivers.
+	 * 
+	 * This one is used by both RTP for sending packets, as well as RTCP.
+	 * 
+	 * @return iterator for unicast participants
+	 */
+	protected Iterator<Participant> getUnicastReceivers() {
+		if (!this.rtpSession.mcSession) {
+			return this.receivers.iterator();
+		} else {
+			System.out
+					.println("Request for ParticipantDatabase.getUnicastReceivers in multicast session");
+			return null;
+		}
+	}
+
+	/**
+	 * Enumeration of all the participants with known ssrcs.
+	 * 
+	 * This is primarily used for sending packets in multicast sessions.
+	 * 
+	 * @return enumerator with all the participants with known SSRCs
+	 */
+	protected Enumeration<Participant> getParticipants() {
+		return this.ssrcTable.elements();
+	}
+
+	protected void debugPrint() {
+		System.out.println("   ParticipantDatabase.debugPrint()");
+		Participant p;
+		Enumeration enu = ssrcTable.elements();
+		while (enu.hasMoreElements()) {
+			p = (Participant) enu.nextElement();
+			System.out.println("           ssrcTable ssrc:" + p.ssrc
+					+ " cname:" + p.cname + " loc:" + p.loc + " rtpAddress:"
+					+ p.rtpAddress + " rtcpAddress:" + p.rtcpAddress);
+		}
+
+		Iterator<Participant> iter = receivers.iterator();
+		while (iter.hasNext()) {
+			p = iter.next();
+			System.out.println("           receivers: "
+					+ p.rtpAddress.toString());
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/PktBufNode.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,71 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+/**
+ * This is a four-directional data structures used for the frame buffer, i.e.
+ * buffer for pkts that need to be assimilated into complete frames.
+ * 
+ * All the actual work is done by PktBuffer.
+ * 
+ * @author Arne Kepp
+ * 
+ */
+public class PktBufNode {
+	/** The next node (RTP Timestamp), looking from the back -> next means older */
+	protected PktBufNode nextFrameQueueNode = null;
+	/**
+	 * The previous node (RTP Timestmap), looking from the back -> prev means
+	 * newer
+	 */
+	protected PktBufNode prevFrameQueueNode = null;
+	/**
+	 * The next node within the frame, i.e. higher sequence number, same RTP
+	 * timestamp
+	 */
+	protected PktBufNode nextFrameNode = null;
+	/** Number of packets with the same RTP timestamp */
+	protected int pktCount;
+	/** The RTP timeStamp associated with this node */
+	protected long timeStamp;
+	/** The sequence number associated with this node */
+	protected int seqNum;
+	/** The payload, a parsed RTP Packet */
+	protected RtpPkt pkt = null;
+
+	/**
+	 * Create a new packet buffer node based on a packet
+	 * 
+	 * @param aPkt
+	 *            the packet
+	 */
+	protected PktBufNode(RtpPkt aPkt) {
+		initPktBufNode(aPkt);
+	}
+	
+	public PktBufNode(){
+	}
+	
+	public void initPktBufNode(RtpPkt aPkt) {
+		pkt = aPkt;
+		timeStamp = aPkt.getTimeStamp();
+		seqNum = aPkt.getSeqNumber();
+		pktCount = 1;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/PktBuffer.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,533 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import org.sipdroid.net.tools.DataFramePool;
+import org.sipdroid.net.tools.PktBufNodePool;
+
+/**
+ * A PktBuffer stores packets either for buffering purposes, or because they
+ * need to be assimilated to create a complete frame.
+ * 
+ * This behavior can be controlled through rtpSession.pktBufBehavior()
+ * 
+ * It optionally drops duplicate packets.
+ * 
+ * Note that newest is the most recently received, i.e. highest timeStamp Next
+ * means new to old (from recently received to previously received)
+ * 
+ * @author Arne Kepp
+ */
+public class PktBuffer {
+	/**
+	 * The RTPSession holds information common to all packetBuffers, such as max
+	 * size
+	 */
+	RTPSession rtpSession;
+	/** SSRC of the the participant that this buffer is for */
+	long SSRC;
+	/** The parent participant */
+	Participant p;
+	/** The length of the buffer */
+	int length = 0;
+	/** The oldest, least recently received, packet */
+	PktBufNode oldest = null;
+	/** The newest, most recently received, packet */
+	PktBufNode newest = null;
+
+	/** The last sequence number received */
+	int lastSeqNumber = -1;
+	/** The last timestamp */
+	long lastTimestamp = -1;
+
+	/**
+	 * Creates a new PktBuffer, a linked list of PktBufNode
+	 * 
+	 * @param rtpSession
+	 *            the parent RTPSession
+	 * @param p
+	 *            the participant to which this packetbuffer belongs.
+	 * @param aPkt
+	 *            The first RTP packet, to be added to the buffer
+	 */
+	protected PktBuffer(RTPSession rtpSession, Participant p, RtpPkt aPkt) {
+		this.rtpSession = rtpSession;
+		this.p = p;
+		SSRC = aPkt.getSsrc();
+		PktBufNode newNode = PktBufNodePool.getInstance().borrowBufNode();
+		newNode.initPktBufNode(aPkt);
+		oldest = newNode;
+		newest = newNode;
+		// lastSeqNumber = (aPkt.getSeqNumber() - 1);
+		// lastTimestamp = aPkt.getTimeStamp();
+		length = 1;
+	}
+
+	/**
+	 * Adds a packet, this happens in constant time if they arrive in order.
+	 * Optimized for the case where each pkt is a complete frame.
+	 * 
+	 * @param aPkt
+	 *            the packet to be added to the buffer.
+	 * @return integer, negative if operation failed (see code)
+	 */
+	protected synchronized int addPkt(RtpPkt aPkt) {
+		if (aPkt == null) {
+			System.out.println("! PktBuffer.addPkt(aPkt) aPkt was null");
+			return -5;
+		}
+
+		long timeStamp = aPkt.getTimeStamp();
+		if (RTPSession.rtpDebugLevel > 7) {
+			System.out.println("-> PktBuffer.addPkt() , length:" + length
+					+ " , timeStamp of Pkt: " + Long.toString(timeStamp));
+		}
+
+		PktBufNode newNode = PktBufNodePool.getInstance().borrowBufNode();
+		newNode.initPktBufNode(aPkt);
+		if (aPkt.getSsrc() != SSRC) {
+			System.out.println("PktBuffer.addPkt() SSRCs don't match!");
+		}
+
+		int retVal = 0;
+		if (this.rtpSession.pktBufBehavior > 0) {
+			retVal = bufferedAddPkt(newNode);
+		} else if (this.rtpSession.pktBufBehavior == 0) {
+			retVal = filteredAddPkt(newNode);
+		} else if (this.rtpSession.pktBufBehavior == -1) {
+			retVal = unfilteredAddPkt(newNode);
+		}
+
+		if (RTPSession.rtpDebugLevel > 7) {
+			if (RTPSession.rtpDebugLevel > 10) {
+				this.debugPrint();
+			}
+			System.out.println("<- PktBuffer.addPkt() , length:" + length
+					+ " returning " + retVal);
+		}
+		return retVal;
+	}
+
+	/**
+	 * Adds packets in the same order that they arrive, doesn't do any filering
+	 * or processing.
+	 * 
+	 * @param newNode
+	 *            the node to add to the packet buffer
+	 * @return 0 if everything is okay, -1 otherwise
+	 */
+	private int unfilteredAddPkt(PktBufNode newNode) {
+		if (RTPSession.rtpDebugLevel > 8) {
+			System.out.println("<->    PktBuffer.unfilteredAddPkt()");
+		}
+		// No magic, just add to the end
+		if (oldest != null) {
+			oldest.nextFrameQueueNode = newNode;
+			newNode.prevFrameQueueNode = oldest;
+			oldest = newNode;
+		} else {
+			oldest = newNode;
+			newest = newNode;
+		}
+		return 0;
+	}
+
+	/**
+	 * Takes care of duplicate packets
+	 * 
+	 * @param newNode
+	 *            the node to add to the packet buffer
+	 * @return 0 if everything is okay, -1 otherwise
+	 */
+	private int filteredAddPkt(PktBufNode newNode) {
+		if (RTPSession.rtpDebugLevel > 8) {
+			System.out.println("<->    PktBuffer.filteredAddPkt()");
+		}
+
+		if (length == 0) {
+			// The buffer was empty, this packet is the one and only.
+			newest = newNode;
+			oldest = newNode;
+			length = 1;
+		} else {
+			// The packetbuffer is not empty.
+			if (newNode.timeStamp > newest.timeStamp
+					|| newNode.seqNum > newest.seqNum
+					&& (newNode.seqNum - newest.seqNum) < 10) {
+				// Packet came in order
+				newNode.nextFrameQueueNode = newest;
+				newest.prevFrameQueueNode = newNode;
+				newest = newNode;
+				length++;
+			} else {
+				if (RTPSession.rtpDebugLevel > 2) {
+					System.out
+							.println("PktBuffer.filteredAddPkt Dropped a packet due to lag! "
+									+ newNode.timeStamp
+									+ " "
+									+ newNode.seqNum
+									+ " vs "
+									+ oldest.timeStamp
+									+ " "
+									+ oldest.seqNum);
+				}
+				return -1;
+			}
+		}
+
+		return 0;
+	}
+
+	/**
+	 * Does most of the packet organization for the application. Packets are put
+	 * in order, duplicate packets or late arrivals are discarded
+	 * 
+	 * If multiple packets make up a frame, these will also be organized by RTP
+	 * timestamp and sequence number, and returned as a complete frame.
+	 * 
+	 * @param newNode
+	 *            the node to add to the packet buffer
+	 * @return 0 if everything is okay, -1 otherwise
+	 */
+	private int bufferedAddPkt(PktBufNode newNode) {
+		if (RTPSession.rtpDebugLevel > 8) {
+			System.out.println("<->    PktBuffer.bufferedAddPkt()");
+		}
+		if (length == 0) {
+			// The buffer was empty, this packet is the one and only.
+			newest = newNode;
+			oldest = newNode;
+		} else {
+			// The packetbuffer is not empty.
+			if (newNode.timeStamp > newest.timeStamp
+					|| newNode.seqNum > newest.seqNum) {
+				// Packet came in order
+				newNode.nextFrameQueueNode = newest;
+				newest.prevFrameQueueNode = newNode;
+				newest = newNode;
+			} else {
+				// There are packets, we need to order this one right.
+				if (!pktOnTime(newNode.timeStamp, newNode.seqNum)
+						&& rtpSession.pktBufBehavior > -1) {
+					// We got this too late, can't put it in order anymore.
+					if (RTPSession.rtpDebugLevel > 2) {
+						System.out
+								.println("PktBuffer.addPkt Dropped a packet due to lag! "
+										+ newNode.timeStamp
+										+ " "
+										+ newNode.seqNum
+										+ " vs "
+										+ oldest.timeStamp
+										+ " "
+										+ oldest.seqNum);
+					}
+					return -1;
+				}
+
+				// Need to do some real work, find out where it belongs (linear
+				// search from the back).
+				PktBufNode tmpNode = newest;
+				while (tmpNode.timeStamp > newNode.timeStamp) {
+					tmpNode = tmpNode.nextFrameQueueNode;
+				}
+
+				if (tmpNode.timeStamp == newNode.timeStamp
+						&& rtpSession.frameReconstruction
+						&& newNode.seqNum != tmpNode.seqNum) {
+					// Packet has same timestamp, presumably belongs to frame.
+					// Need to order within frame.
+					if (RTPSession.rtpDebugLevel > 8) {
+						System.out
+								.println("Found pkt with existing timeStamp: "
+										+ newNode.timeStamp);
+					}
+					int ret = addToFrame(tmpNode, newNode);
+					if (ret != 0) {
+						return ret;
+					}
+				} else {
+
+					// Check that it's not a duplicate
+					if (tmpNode.timeStamp == newNode.timeStamp
+							&& newNode.seqNum == tmpNode.seqNum) {
+						if (RTPSession.rtpDebugLevel > 2) {
+							System.out
+									.println("PktBuffer.addPkt Dropped a duplicate packet! "
+											+ newNode.timeStamp
+											+ " "
+											+ newNode.seqNum);
+						}
+						return -1;
+					}
+
+					// Insert into buffer
+					newNode.nextFrameQueueNode = tmpNode;
+					newNode.prevFrameQueueNode = tmpNode.prevFrameQueueNode;
+
+					// Update the node behind
+					if (newNode.prevFrameQueueNode != null) {
+						newNode.prevFrameQueueNode.nextFrameQueueNode = newNode;
+					}
+					tmpNode.prevFrameQueueNode = newNode;
+
+					if (newNode.timeStamp > newest.timeStamp) {
+						newest = newNode;
+					}
+				}
+			}
+		}
+		// Update the length of this buffer
+		length++;
+		return 0;
+	}
+
+	/**
+	 * 
+	 * @param frameNode
+	 *            the node currently representing the frame in the packet buffer
+	 * @param newNode
+	 *            the new node to be added to the frame
+	 * @return 0 if no error, -2 if this is a duplicate packet
+	 */
+	private int addToFrame(PktBufNode frameNode, PktBufNode newNode) {
+		// Node has same timeStamp, assume pkt belongs to frame
+
+		if (frameNode.seqNum < newNode.seqNum) {
+			// this is not the first packet in the frame
+			frameNode.pktCount++;
+
+			// Find the right spot
+			while (frameNode.nextFrameNode != null
+					&& frameNode.nextFrameNode.seqNum < newNode.seqNum) {
+				frameNode = frameNode.nextFrameNode;
+			}
+
+			// Check whether packet is duplicate
+			if (frameNode.nextFrameNode != null
+					&& frameNode.nextFrameNode.seqNum == newNode.seqNum) {
+				if (RTPSession.rtpDebugLevel > 2) {
+					System.out
+							.println("PktBuffer.addPkt Dropped a duplicate packet!");
+				}
+				return -2;
+			}
+
+			newNode.nextFrameNode = frameNode.nextFrameNode;
+			frameNode.nextFrameNode = newNode;
+
+		} else {
+			// newNode has the lowest sequence number
+			newNode.nextFrameNode = frameNode;
+			newNode.pktCount = frameNode.pktCount + 1;
+
+			// Update the queue
+			if (frameNode.nextFrameQueueNode != null) {
+				frameNode.nextFrameQueueNode.prevFrameQueueNode = newNode;
+				newNode.nextFrameQueueNode = frameNode.nextFrameQueueNode;
+				frameNode.nextFrameQueueNode = null;
+			}
+			if (frameNode.prevFrameQueueNode != null) {
+				frameNode.prevFrameQueueNode.nextFrameQueueNode = newNode;
+				newNode.prevFrameQueueNode = frameNode.prevFrameQueueNode;
+				frameNode.prevFrameQueueNode = null;
+			}
+			if (newest.timeStamp == newNode.timeStamp) {
+				newest = newNode;
+			}
+		}
+
+		return 0;
+	}
+
+	/**
+	 * Checks the oldest frame, if there is one, sees whether it is complete.
+	 * 
+	 * @return Returns null if there are no complete frames available.
+	 */
+	protected synchronized DataFrame popOldestFrame() {
+		if (RTPSession.rtpDebugLevel > 7) {
+			System.out.println("-> PktBuffer.popOldestFrame()");
+		}
+		if (RTPSession.rtpDebugLevel > 10) {
+			this.debugPrint();
+		}
+
+		if (this.rtpSession.pktBufBehavior > 0) {
+			return this.bufferedPopFrame();
+		} else {
+			return this.unbufferedPopFrame();
+		}
+	}
+
+	/**
+	 * Will return the oldest frame without checking whether it is in the right
+	 * order, or whether we should wate for late arrivals.
+	 * 
+	 * @return the first frame on the queue, null otherwise
+	 */
+	private DataFrame unbufferedPopFrame() {
+		if (oldest != null) {
+			PktBufNode retNode = oldest;
+
+			popFrameQueueCleanup(retNode, retNode.seqNum);
+			DataFrame df = DataFramePool.getInstance().borrowFrame();
+			df.initDataFrame(retNode, this.p, rtpSession.appIntf
+					.frameSize(oldest.pkt.getPayloadType()));
+			return df;
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * Only returns if the buffer is full, i.e. length exceeds
+	 * rtpSession.pktBufBehavior, or if the next packet directly follows the
+	 * previous one returned to the application.
+	 * 
+	 * @return first frame in order, null otherwise
+	 */
+	private DataFrame bufferedPopFrame() {
+		PktBufNode retNode = oldest;
+		/**
+		 * Three scenarios: 1) There are no packets available 2) The first
+		 * packet is vailable and in order 3) The first packet is not the next
+		 * on in the sequence a) We have exceeded the wait buffer b) We wait
+		 */
+		// System.out.println(" Debug:" +(retNode != null) + " " +
+		// (retNode.seqNum == this.lastSeqNumber + 1)
+		// + " " + ( retNode.seqNum == 0 ) + " " + (this.length >
+		// this.rtpSession.maxReorderBuffer)
+		// + " " + (this.lastSeqNumber < 0));
+
+		// Pop it off, null all references.
+		if (retNode != null
+				&& (retNode.seqNum == this.lastSeqNumber + 1
+						|| retNode.seqNum == 0
+						|| this.length > this.rtpSession.pktBufBehavior || this.lastSeqNumber < 0)) {
+
+			// if(tmpNode.pktCount == compLen) {
+			if (RTPSession.rtpDebugLevel > 7) {
+				System.out
+						.println("<- PktBuffer.popOldestFrame() returns frame");
+			}
+
+			DataFrame df = DataFramePool.getInstance().borrowFrame();
+			df.initDataFrame(retNode, this.p, rtpSession.appIntf
+					.frameSize(oldest.pkt.getPayloadType()));
+
+			// DataFrame df = new DataFrame(retNode, this.p, 1);
+			popFrameQueueCleanup(retNode, df.lastSeqNum);
+
+			return df;
+
+		} else {
+			// If we get here we have little to show for.
+			if (RTPSession.rtpDebugLevel > 2) {
+				System.out
+						.println("<- PktBuffer.popOldestFrame() returns null "
+								+ retNode.seqNum + " " + this.lastSeqNumber);
+				this.debugPrint();
+			}
+			return null;
+		}
+	}
+
+	/**
+	 * Cleans the packet buffer before returning the frame, i.e. making sure the
+	 * queue has a head etc.
+	 * 
+	 * @param retNode
+	 *            the node that is about to be popped
+	 * @param highestSeq
+	 *            the highest sequence number returned to the application
+	 */
+	private void popFrameQueueCleanup(PktBufNode retNode, int highestSeq) {
+		if (1 == length) {
+			// There's only one frame
+			newest = null;
+			oldest = null;
+		} else {
+			// There are more frames
+			oldest = oldest.prevFrameQueueNode;
+			oldest.nextFrameQueueNode = null;
+		}
+
+		// Update counters
+		length--;
+
+		// Find the highest sequence number associated with this timestamp
+		this.lastSeqNumber = highestSeq;
+		this.lastTimestamp = retNode.timeStamp;
+	}
+
+	/**
+	 * Returns the length of the packetbuffer.
+	 * 
+	 * @return number of frames (complete or not) in packetbuffer.
+	 */
+	protected int getLength() {
+		return length;
+	}
+
+	/**
+	 * Checks whether a packet is not too late, i.e. the next packet has already
+	 * been returned.
+	 * 
+	 * @param timeStamp
+	 *            the RTP timestamp of the packet under consideration
+	 * @param seqNum
+	 *            the sequence number of the packet under consideration
+	 * @return true if newer packets have not been handed to the application
+	 */
+	protected boolean pktOnTime(long timeStamp, int seqNum) {
+		if (this.lastSeqNumber == -1) {
+			// First packet
+			return true;
+		} else {
+			if (seqNum >= this.lastSeqNumber) {
+				if (this.lastSeqNumber < 3 && timeStamp < this.lastTimestamp) {
+					return false;
+				}
+			} else {
+				if (seqNum > 3 || timeStamp < this.lastTimestamp) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	/**
+	 * Prints out the packet buffer, oldest node first (on top).
+	 */
+	protected void debugPrint() {
+		System.out.println("PktBuffer.debugPrint() : length " + length
+				+ " SSRC " + SSRC + " lastSeqNum:" + lastSeqNumber);
+		PktBufNode tmpNode = oldest;
+		int i = 0;
+		while (tmpNode != null) {
+			// String str = tmpNode.timeStamp.toString();
+			System.out.println("   " + i + " seqNum:" + tmpNode.seqNum
+					+ " timeStamp: " + tmpNode.timeStamp + " pktCount:"
+					+ tmpNode.pktCount);
+			i++;
+			tmpNode = tmpNode.prevFrameQueueNode;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/README.txt	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,39 @@
+jlibrtp - Java RTP Library
+
+Kepp, Arne
+ak2618@columbia.edu
+
+Columbia University
+New York, NY 10027
+USA
+
+This library was started as a term project in VoIP Security, a class taught by 
+Prof. Henning Schulzrinne at Columbia University. Version 0.1 (not released as such)
+was written by Vaishnav Janardhan (vj2135@columbia.edu) and Arne Kepp (ak2618@columbia.edu).
+
+This version was rewritten by Arne Kepp, as a student project under the supervision of 
+Prof. Henning Schulzrinne, Columbia University.
+
+------Abstract
+jlibrtp is a library that implements the Real-Time Transport Protocol (RTP), 
+a well-established standard for streaming media across IP-based networks, in Java. 
+The purpose  of this library is to make it easy for application developers to 
+create applications for peer to peer streaming of audio, video and other data. 
+In addition, developers will need a protocol to establish contact with peers, 
+such as Session Initialization Protocol (SIP) and/or SDP.
+
+The library accepts any kind of binary data, handles packet parsing and reordering, 
+maintains a participant database and the control connection associated with the 
+protocol. The application is notified of received data through a callback-interface. 
+The library supports IPv4, IPv6 and multicast. It does currently not support encryption, 
+and should not be used in cases where confidentiality is important before this has 
+been remedied.
+
+Please refer to http://jlibrtp.org for more information and newer versions.
+
+The library requires Sun Microsystems Java 1.5.0 or greater, or equivalent.
+
+The Library is licensed under the GNU Lesser General Public License, see LICENSE.txt
+
+The demonstration programs can be compiled as follows:
+javac ./jlibrtpDemos/SoundSenderDemo.java jlibrtp/*.java
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RTCPAVPFIntf.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,102 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+package jlibrtp;
+
+/**
+ * This is the callback interface for the AVPF profile (RFC 4585)
+ * 
+ * It is optional, you do not have to register it.
+ * 
+ * If there are specific events you wish to ignore, you can simply implement
+ * empty functions.
+ * 
+ * These are all syncrhonous, make sure to return quickly or do the handling in
+ * a new thread.
+ * 
+ * @author Arne Kepp
+ */
+public interface RTCPAVPFIntf {
+
+	/**
+	 * This function is called when a Picture Loss Indication (PLI, FMT = 1) is
+	 * received
+	 * 
+	 * @param ssrcPacketSender
+	 *            the SSRC of the participant reporting loss of picture
+	 */
+	public void PSFBPktPictureLossReceived(long ssrcPacketSender);
+
+	/**
+	 * This function is called when a Slice Loss Indication (SLI, FMT=2) is
+	 * received
+	 * 
+	 * @param ssrcPacketSender
+	 *            the SSRC of the participant reporting loss of slice(s)
+	 * @param sliceFirst
+	 *            macroblock address of first macroblock
+	 * @param sliceNumber
+	 *            number of lost macroblocks, in scan order
+	 * @param slicePictureId
+	 *            the six least significant bits of the picture identifier
+	 */
+	public void PSFBPktSliceLossIndic(long ssrcPacketSender, int[] sliceFirst,
+			int[] sliceNumber, int[] slicePictureId);
+
+	/**
+	 * This function is called when a Reference Picture Selection Indication
+	 * (RPSI, FMT=3) is received
+	 * 
+	 * @param ssrcPacketSender
+	 *            the SSRC of the participant reporting the selection
+	 * @param rpsiPayloadType
+	 *            the RTP payload type related to the RPSI bit string
+	 * @param rpsiBitString
+	 *            the RPSI information as natively defined by the video codec
+	 * @param rpsiPaddingBits
+	 *            the number of padding bits at the end of the string
+	 */
+	public void PSFBPktRefPictureSelIndic(long ssrcPacketSender,
+			int rpsiPayloadType, byte[] rpsiBitString, int rpsiPaddingBits);
+
+	/**
+	 * This function is called when a Transport Layer Feedback Messages is
+	 * received
+	 * 
+	 * @param ssrcPacketSender
+	 * @param alfBitString
+	 */
+	public void PSFBPktAppLayerFBReceived(long ssrcPacketSender,
+			byte[] alfBitString);
+
+	/**
+	 * This function is called when a Transport Layer Feedback Messages is
+	 * received
+	 * 
+	 * @param ssrcPacketSender
+	 * @param FMT
+	 *            1: NACK, 0,2-30: unassigned, 31: reserved
+	 * @param packetID
+	 *            the RTP sequence number of the lost packet
+	 * @param bitmaskLostPackets
+	 *            the bitmask of following lost packets
+	 */
+	public void RTPFBPktReceived(long ssrcPacketSender, int FMT,
+			int[] packetID, int[] bitmaskLostPackets);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RTCPAppIntf.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,150 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+package jlibrtp;
+
+/**
+ * This is the callback interface for RTCP packets.
+ * 
+ * It is optional, you do not have to register it.
+ * 
+ * If there are specific events you wish to ignore, you can simply implement
+ * empty functions.
+ * 
+ * These are all syncrhonous, make sure to return quickly or do the handling in
+ * a new thread.
+ * 
+ * @author Arne Kepp
+ */
+public interface RTCPAppIntf {
+
+	/**
+	 * This function is called whenever a Sender Report (SR) packet is received
+	 * and returns unmodified values.
+	 * 
+	 * A sender report may optionally include Receiver Reports (RR), which are
+	 * returned as arrays. Index i corresponds to the same report throughout all
+	 * of the arrays.
+	 * 
+	 * @param ssrc
+	 *            the (SR) SSRC of the sender
+	 * @param ntpHighOrder
+	 *            (SR) NTP high order
+	 * @param ntpLowOrder
+	 *            (SR) NTP low order
+	 * @param rtpTimestamp
+	 *            (SR) RTP timestamp corresponding to the NTP timestamp
+	 * @param packetCount
+	 *            (SR) Packets sent since start of session
+	 * @param octetCount
+	 *            (SR) Octets sent since start of session
+	 * @param reporteeSsrc
+	 *            (RR) SSRC of sender the receiver is reporting in
+	 * @param lossFraction
+	 *            (RR) Loss fraction, see RFC 3550
+	 * @param cumulPacketsLost
+	 *            (RR) Cumulative number of packets lost
+	 * @param extHighSeq
+	 *            (RR) Extended highest sequence RTP packet received
+	 * @param interArrivalJitter
+	 *            (RR) Interarrival jitter, see RFC 3550
+	 * @param lastSRTimeStamp
+	 *            (RR) RTP timestamp when last SR was received
+	 * @param delayLastSR
+	 *            (RR) Delay, in RTP, since last SR was received
+	 */
+	public void SRPktReceived(long ssrc, long ntpHighOrder, long ntpLowOrder,
+			long rtpTimestamp, long packetCount,
+			long octetCount,
+			// Get the receiver reports, if any
+			long[] reporteeSsrc, int[] lossFraction, int[] cumulPacketsLost,
+			long[] extHighSeq, long[] interArrivalJitter,
+			long[] lastSRTimeStamp, long[] delayLastSR);
+
+	/**
+	 * This function is called whenever a Receiver Report (SR) packet is
+	 * received and returns unmodified values.
+	 * 
+	 * A receiver report may optionally include report blocks, which are
+	 * returned as arrays. Index i corresponds to the same report throughout all
+	 * of the arrays.
+	 * 
+	 * @param reporterSsrc
+	 *            SSRC of the receiver reporting
+	 * @param reporteeSsrc
+	 *            (RR) SSRC of sender the receiver is reporting in
+	 * @param lossFraction
+	 *            (RR) Loss fraction, see RFC 3550
+	 * @param cumulPacketsLost
+	 *            (RR) Cumulative number of packets lost
+	 * @param extHighSeq
+	 *            (RR) Extended highest sequence RTP packet received
+	 * @param interArrivalJitter
+	 *            (RR) Interarrival jitter, see RFC 3550
+	 * @param lastSRTimeStamp
+	 *            (RR) RTP timestamp when last SR was received
+	 * @param delayLastSR
+	 *            (RR) Delay, in RTP, since last SR was received
+	 */
+	public void RRPktReceived(long reporterSsrc, long[] reporteeSsrc,
+			int[] lossFraction, int[] cumulPacketsLost, long[] extHighSeq,
+			long[] interArrivalJitter, long[] lastSRTimeStamp,
+			long[] delayLastSR);
+
+	/**
+	 * This function is called whenever a Source Description (SDES) packet is
+	 * received.
+	 * 
+	 * It currently returns the updated participants AFTER they have been
+	 * updated.
+	 * 
+	 * @param relevantParticipants
+	 *            participants mentioned in the SDES packet
+	 */
+	public void SDESPktReceived(Participant[] relevantParticipants);
+
+	/**
+	 * This function is called whenever a Bye (BYE) packet is received.
+	 * 
+	 * The participants will automatically be deleted from the participant
+	 * database after some time, but in the mean time the application may still
+	 * receive RTP packets from this source.
+	 * 
+	 * @param relevantParticipants
+	 *            participants whose SSRC was in the packet
+	 * @param reason
+	 *            the reason provided in the packet
+	 */
+	public void BYEPktReceived(Participant[] relevantParticipants, String reason);
+
+	/**
+	 * This function is called whenever an Application (APP) packet is received.
+	 * 
+	 * @param part
+	 *            the participant associated with the SSRC
+	 * @param subtype
+	 *            specified in the packet
+	 * @param name
+	 *            ASCII description of packet
+	 * @param data
+	 *            in the packet
+	 */
+	public void APPPktReceived(Participant part, int subtype, byte[] name,
+			byte[] data);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RTCPReceiverThread.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,446 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetSocketAddress;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+import org.sipdroid.net.tools.DatagramPool;
+import org.sipdroid.net.tools.GenericPool;
+
+/**
+ * This thread hangs on the RTCP socket and waits for new packets
+ * 
+ * @author Arne Kepp
+ * 
+ */
+public class RTCPReceiverThread extends Thread {
+	/** Parent RTP Session */
+	private RTPSession rtpSession = null;
+	/** Parent RTCP Session */
+	private RTCPSession rtcpSession = null;
+
+	private GenericPool<CompRtcpPkt> rtcpPacketPool;
+
+	/**
+	 * Constructor for new thread
+	 * 
+	 * @param rtcpSession
+	 *            parent RTCP session
+	 * @param rtpSession
+	 *            parent RTP session
+	 */
+	RTCPReceiverThread(RTCPSession rtcpSession, RTPSession rtpSession) {
+		this.rtpSession = rtpSession;
+		this.rtcpSession = rtcpSession;
+
+		rtcpPacketPool = new GenericPool<CompRtcpPkt>(10);
+
+		if (RTPSession.rtpDebugLevel > 1) {
+			System.out.println("<-> RTCPReceiverThread created");
+		}
+
+	}
+
+	/**
+	 * Find out whether a participant with this SSRC is known.
+	 * 
+	 * If the user is unknown, and the system is operating in unicast mode, try
+	 * to match the ip-address of the sender to the ip address of a previously
+	 * unmatched target
+	 * 
+	 * @param ssrc
+	 *            the SSRC of the participant
+	 * @param packet
+	 *            the packet that notified us
+	 * @return the relevant participant, possibly newly created
+	 */
+	private Participant findParticipant(long ssrc, DatagramPacket packet) {
+		Participant p = rtpSession.partDb.getParticipant(ssrc);
+		if (p == null) {
+			Enumeration<Participant> enu = rtpSession.partDb.getParticipants();
+			while (enu.hasMoreElements()) {
+				Participant tmp = (Participant) enu.nextElement();
+				if (tmp.ssrc < 0
+						&& (tmp.rtcpAddress.getAddress().equals(
+								packet.getAddress()) || tmp.rtpAddress
+								.getAddress().equals(packet.getAddress()))) {
+
+					// Best guess
+					System.out
+					.println("RTCPReceiverThread: Got an unexpected packet from SSRC:"
+							+ ssrc
+							+ " @"
+							+ packet.getAddress().toString()
+							+ ", WAS able to match it.");
+
+					tmp.ssrc = ssrc;
+					return tmp;
+				}
+			}
+			// Create an unknown sender
+			System.out
+			.println("RTCPReceiverThread: Got an unexpected packet from SSRC:"
+					+ ssrc
+					+ " @"
+					+ packet.getAddress().toString()
+					+ ", was NOT able to match it.");
+			p = new Participant((InetSocketAddress) null,
+					(InetSocketAddress) packet.getSocketAddress(), ssrc);
+			rtpSession.partDb.addParticipant(2, p);
+		}
+		return p;
+	}
+
+	/**
+	 * Parse a received UDP packet
+	 * 
+	 * Perform the header checks and extract the RTCP packets in it
+	 * 
+	 * @param packet
+	 *            the packet to be parsed
+	 * @return -1 if there was a problem, 0 if successfully parsed
+	 */
+	private int parsePacket(DatagramPacket packet) {
+
+		if (packet.getLength() % 4 != 0) {
+			if (RTPSession.rtcpDebugLevel > 2) {
+				System.out
+				.println("RTCPReceiverThread.parsePacket got packet that had length "
+						+ packet.getLength());
+			}
+			return -1;
+		} else {
+			byte[] rawPkt = packet.getData();
+
+			// Parse the received compound RTCP (?) packet
+			CompRtcpPkt compPkt = rtcpPacketPool.borrowItem();
+			compPkt.init(rawPkt, packet.getLength(),
+					(InetSocketAddress) packet.getSocketAddress(), rtpSession);
+
+			if (this.rtpSession.debugAppIntf != null) {
+				String intfStr;
+
+				if (rtpSession.mcSession) {
+					intfStr = this.rtcpSession.rtcpMCSock
+					.getLocalSocketAddress().toString();
+				} else {
+					intfStr = this.rtpSession.rtpSock.getLocalSocketAddress()
+					.toString();
+				}
+
+				if (compPkt.problem == 0) {
+					String str = new String(
+							"Received compound RTCP packet of size "
+							+ packet.getLength() + " from "
+							+ packet.getSocketAddress().toString()
+							+ " via " + intfStr + " containing "
+							+ compPkt.rtcpPkts.size() + " packets");
+
+					this.rtpSession.debugAppIntf.packetReceived(1,
+							(InetSocketAddress) packet.getSocketAddress(), str);
+				} else {
+					String str = new String(
+							"Received invalid RTCP packet of size "
+							+ packet.getLength() + " from "
+							+ packet.getSocketAddress().toString()
+							+ " via " + intfStr + ": "
+							+ this.debugErrorString(compPkt.problem));
+
+					this.rtpSession.debugAppIntf.packetReceived(-2,
+							(InetSocketAddress) packet.getSocketAddress(), str);
+				}
+			}
+
+			if (RTPSession.rtcpDebugLevel > 5) {
+				Iterator<RtcpPkt> iter = compPkt.rtcpPkts.iterator();
+				String str = " ";
+				while (iter.hasNext()) {
+					RtcpPkt aPkt = iter.next();
+					str += (aPkt.getClass().toString() + ":" + aPkt.itemCount + ", ");
+				}
+				System.out.println("<-> RTCPReceiverThread.parsePacket() from "
+						+ packet.getSocketAddress().toString() + str);
+			}
+
+			// Loop over the information
+			Iterator iter = compPkt.rtcpPkts.iterator();
+
+			long curTime = System.currentTimeMillis();
+
+			while (iter.hasNext()) {
+				RtcpPkt aPkt = (RtcpPkt) iter.next();
+
+				// Our own packets should already have been filtered out.
+				if (aPkt.ssrc == rtpSession.ssrc) {
+					System.out
+					.println("RTCPReceiverThread() received RTCP packet"
+							+ " with conflicting SSRC from "
+							+ packet.getSocketAddress().toString());
+					rtpSession.resolveSsrcConflict();
+					return -1;
+				}
+
+				/** Receiver Reports **/
+				if (aPkt.getClass() == RtcpPktRR.class) {
+					RtcpPktRR rrPkt = (RtcpPktRR) aPkt;
+
+					Participant p = findParticipant(rrPkt.ssrc, packet);
+					p.lastRtcpPkt = curTime;
+
+					if (rtpSession.rtcpAppIntf != null) {
+						rtpSession.rtcpAppIntf.RRPktReceived(rrPkt.ssrc,
+								rrPkt.reporteeSsrc, rrPkt.lossFraction,
+								rrPkt.lostPktCount, rrPkt.extHighSeqRecv,
+								rrPkt.interArvJitter, rrPkt.timeStampLSR,
+								rrPkt.delaySR);
+					}
+
+					/** Sender Reports **/
+				} else if (aPkt.getClass() == RtcpPktSR.class) {
+					RtcpPktSR srPkt = (RtcpPktSR) aPkt;
+
+					Participant p = findParticipant(srPkt.ssrc, packet);
+					p.lastRtcpPkt = curTime;
+
+					if (p != null) {
+
+						if (p.ntpGradient < 0 && p.lastNtpTs1 > -1) {
+							// Calculate gradient NTP vs RTP
+							long newTime = StaticProcs.undoNtpMess(
+									srPkt.ntpTs1, srPkt.ntpTs2);
+							p.ntpGradient = ((double) (newTime - p.ntpOffset))
+							/ ((double) srPkt.rtpTs - p.lastSRRtpTs);
+							if (RTPSession.rtcpDebugLevel > 4) {
+								System.out
+								.println("RTCPReceiverThread calculated NTP vs RTP gradient: "
+										+ Double
+										.toString(p.ntpGradient));
+							}
+						} else {
+							// Calculate sum of ntpTs1 and ntpTs2 in
+							// milliseconds
+							p.ntpOffset = StaticProcs.undoNtpMess(srPkt.ntpTs1,
+									srPkt.ntpTs2);
+							p.lastNtpTs1 = srPkt.ntpTs1;
+							p.lastNtpTs2 = srPkt.ntpTs2;
+							p.lastSRRtpTs = srPkt.rtpTs;
+						}
+
+						// For the next RR
+						p.timeReceivedLSR = curTime;
+						p.setTimeStampLSR(srPkt.ntpTs1, srPkt.ntpTs2);
+
+					}
+
+					if (rtpSession.rtcpAppIntf != null) {
+						if (srPkt.rReports != null) {
+							rtpSession.rtcpAppIntf.SRPktReceived(srPkt.ssrc,
+									srPkt.ntpTs1, srPkt.ntpTs2, srPkt.rtpTs,
+									srPkt.sendersPktCount,
+									srPkt.sendersPktCount,
+									srPkt.rReports.reporteeSsrc,
+									srPkt.rReports.lossFraction,
+									srPkt.rReports.lostPktCount,
+									srPkt.rReports.extHighSeqRecv,
+									srPkt.rReports.interArvJitter,
+									srPkt.rReports.timeStampLSR,
+									srPkt.rReports.delaySR);
+						} else {
+							rtpSession.rtcpAppIntf.SRPktReceived(srPkt.ssrc,
+									srPkt.ntpTs1, srPkt.ntpTs2, srPkt.rtpTs,
+									srPkt.sendersPktCount,
+									srPkt.sendersPktCount, null, null, null,
+									null, null, null, null);
+						}
+					}
+
+					/** Source Descriptions **/
+				} else if (aPkt.getClass() == RtcpPktSDES.class) {
+					RtcpPktSDES sdesPkt = (RtcpPktSDES) aPkt;
+
+					// The the participant database is updated
+					// when the SDES packet is reconstructed by CompRtcpPkt
+					if (rtpSession.rtcpAppIntf != null) {
+						rtpSession.rtcpAppIntf
+						.SDESPktReceived(sdesPkt.participants);
+					}
+
+					/** Bye Packets **/
+				} else if (aPkt.getClass() == RtcpPktBYE.class) {
+					RtcpPktBYE byePkt = (RtcpPktBYE) aPkt;
+
+					long time = System.currentTimeMillis();
+					Participant[] partArray = new Participant[byePkt.ssrcArray.length];
+
+					for (int i = 0; i < byePkt.ssrcArray.length; i++) {
+						partArray[i] = rtpSession.partDb
+						.getParticipant(byePkt.ssrcArray[i]);
+						if (partArray[i] != null)
+							partArray[i].timestampBYE = time;
+					}
+
+					if (rtpSession.rtcpAppIntf != null) {
+						rtpSession.rtcpAppIntf.BYEPktReceived(partArray,
+								new String(byePkt.reason));
+					}
+
+					/** Application specific Packets **/
+				} else if (aPkt.getClass() == RtcpPktAPP.class) {
+					RtcpPktAPP appPkt = (RtcpPktAPP) aPkt;
+
+					Participant part = findParticipant(appPkt.ssrc, packet);
+
+					if (rtpSession.rtcpAppIntf != null) {
+						rtpSession.rtcpAppIntf.APPPktReceived(part,
+								appPkt.itemCount, appPkt.pktName,
+								appPkt.pktData);
+					}
+				}
+
+			}
+		}
+		return 0;
+	}
+
+	/**
+	 * Returns a legible message when an error occurs
+	 * 
+	 * @param errorCode
+	 *            the internal error code, commonly negative of packet type
+	 * @return a string that is hopefully somewhat informative
+	 */
+	private String debugErrorString(int errorCode) {
+		String aStr = "";
+		switch (errorCode) {
+		case -1:
+			aStr = "The first packet was not of type SR or RR.";
+			break;
+		case -2:
+			aStr = "The padding bit was set for the first packet.";
+			break;
+		case -200:
+			aStr = " Error parsing Sender Report packet.";
+			break;
+		case -201:
+			aStr = " Error parsing Receiver Report packet.";
+			break;
+		case -202:
+			aStr = " Error parsing SDES packet";
+			break;
+		case -203:
+			aStr = " Error parsing BYE packet.";
+			break;
+		case -204:
+			aStr = " Error parsing Application specific packet.";
+			break;
+		case -205:
+			aStr = " Error parsing RTP Feedback packet.";
+			break;
+		case -206:
+			aStr = " Error parsing Payload-Specific Feedback packet.";
+			break;
+		default:
+			aStr = "Unknown error code " + errorCode + ".";
+		}
+
+		return aStr;
+	}
+
+	/**
+	 * Start the RTCP receiver thread.
+	 * 
+	 * It will 1) run when it receives a packet 2) parse the packet 3) call any
+	 * relevant callback functions, update database 4) block until the next one
+	 * arrives.
+	 */
+	public void run() {
+		if (RTPSession.rtcpDebugLevel > 1) {
+			if (rtpSession.mcSession) {
+				System.out
+				.println("-> RTCPReceiverThread.run() starting on MC "
+						+ rtcpSession.rtcpMCSock.getLocalPort());
+			} else {
+				System.out.println("-> RTCPReceiverThread.run() starting on "
+						+ rtcpSession.rtcpSock.getLocalPort());
+			}
+		}
+
+		while (!rtpSession.endSession) {
+
+			if (RTPSession.rtcpDebugLevel > 4) {
+				if (rtpSession.mcSession) {
+					System.out
+					.println("-> RTCPReceiverThread.run() waiting for packet on MC "
+							+ rtcpSession.rtcpMCSock.getLocalPort());
+				} else {
+					System.out
+					.println("-> RTCPReceiverThread.run() waiting for packet on "
+							+ rtcpSession.rtcpSock.getLocalPort());
+				}
+			}
+
+			// Prepare a packet
+			DatagramPacket packet = DatagramPool.getInstance().borrowPacket();
+			
+			// Wait for it to arrive
+			if (!rtpSession.mcSession) {
+				// Unicast
+				try {
+					rtcpSession.rtcpSock.receive(packet);
+				} catch (IOException e) {
+					if (!rtpSession.endSession) {
+						e.printStackTrace();
+					} else {
+						continue;
+					}
+				}
+			} else {
+				// Multicast
+				try {
+					rtcpSession.rtcpMCSock.receive(packet);
+				} catch (IOException e) {
+					if (!rtpSession.endSession) {
+						e.printStackTrace();
+					} else {
+						continue;
+					}
+				}
+			}
+
+			// Check whether this is one of our own
+			if ((rtpSession.mcSession && !packet.getSocketAddress().equals(
+					rtcpSession.rtcpMCSock))
+					|| !packet.getSocketAddress().equals(rtcpSession.rtcpSock)) {
+				// System.out.println("Packet received from: " +
+				// packet.getSocketAddress().toString());
+				parsePacket(packet);
+				// rtpSession.partDb.debugPrint();
+			}
+		}
+
+		if (RTPSession.rtcpDebugLevel > 1) {
+			System.out.println("<-> RTCPReceiverThread terminating");
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RTCPSenderThread.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,496 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.DatagramPacket;
+import java.net.InetSocketAddress;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+/**
+ * This thread sends scheduled RTCP packets
+ * 
+ * It also performs maintenance of various queues and the participant database.
+ * 
+ * @author Arne Kepp
+ * 
+ */
+public class RTCPSenderThread extends Thread {
+	/** Parent RTP Session */
+	private RTPSession rtpSession = null;
+	/** Parent RTCP Session */
+	private RTCPSession rtcpSession = null;
+
+	/** Whether we have sent byes for the last conflict */
+	private boolean byesSent = false;
+
+	/**
+	 * Constructor for new thread
+	 * 
+	 * @param rtcpSession
+	 *            parent RTCP session
+	 * @param rtpSession
+	 *            parent RTP session
+	 */
+	protected RTCPSenderThread(RTCPSession rtcpSession, RTPSession rtpSession) {
+		this.rtpSession = rtpSession;
+		this.rtcpSession = rtcpSession;
+		if (RTPSession.rtpDebugLevel > 1) {
+			System.out.println("<-> RTCPSenderThread created");
+		}
+	}
+
+	/**
+	 * Send BYE messages to all the relevant participants
+	 * 
+	 */
+	protected void sendByes() {
+		// Create the packet
+		CompRtcpPkt compPkt = new CompRtcpPkt();
+
+		// Need a SR for validation
+		RtcpPktSR srPkt = new RtcpPktSR(this.rtpSession.ssrc,
+				this.rtpSession.sentPktCount, this.rtpSession.sentOctetCount,
+				null);
+		compPkt.addPacket(srPkt);
+
+		byte[] reasonBytes;
+
+		// Add the actualy BYE Pkt
+		long[] ssrcArray = { this.rtpSession.ssrc };
+		if (rtpSession.conflict) {
+			reasonBytes = "SSRC collision".getBytes();
+		} else {
+			reasonBytes = "jlibrtp says bye bye!".getBytes();
+		}
+		RtcpPktBYE byePkt = new RtcpPktBYE(ssrcArray, reasonBytes);
+
+		compPkt.addPacket(byePkt);
+
+		// Send it off
+		if (rtpSession.mcSession) {
+			mcSendCompRtcpPkt(compPkt);
+		} else {
+			Iterator<Participant> iter = rtpSession.partDb
+					.getUnicastReceivers();
+
+			while (iter.hasNext()) {
+				Participant part = (Participant) iter.next();
+				if (part.rtcpAddress != null)
+					sendCompRtcpPkt(compPkt, part.rtcpAddress);
+			}
+			// System.out.println("SENT BYE PACKETS!!!!!");
+		}
+	}
+
+	/**
+	 * Multicast version of sending a Compound RTCP packet
+	 * 
+	 * @param pkt
+	 *            the packet to best
+	 * @return 0 is successful, -1 otherwise
+	 */
+	protected int mcSendCompRtcpPkt(CompRtcpPkt pkt) {
+		byte[] pktBytes = pkt.encode();
+		DatagramPacket packet;
+
+		// Create datagram
+		try {
+			packet = new DatagramPacket(pktBytes, pktBytes.length,
+					rtpSession.mcGroup, rtcpSession.rtcpMCSock.getPort());
+		} catch (Exception e) {
+			System.out
+					.println("RCTPSenderThread.MCSendCompRtcpPkt() packet creation failed.");
+			e.printStackTrace();
+			return -1;
+		}
+
+		// Send packet
+		if (RTPSession.rtcpDebugLevel > 5) {
+			System.out
+					.println("<-> RTCPSenderThread.SendCompRtcpPkt() multicast");
+		}
+		try {
+			rtcpSession.rtcpMCSock.send(packet);
+			// Debug
+			if (this.rtpSession.debugAppIntf != null) {
+				this.rtpSession.debugAppIntf.packetSent(3,
+						(InetSocketAddress) packet.getSocketAddress(),
+						new String("Sent multicast RTCP packet of size "
+								+ packet.getLength()
+								+ " to "
+								+ packet.getSocketAddress().toString()
+								+ " via "
+								+ this.rtcpSession.rtcpMCSock
+										.getLocalSocketAddress().toString()));
+			}
+		} catch (Exception e) {
+			System.out
+					.println("RCTPSenderThread.MCSendCompRtcpPkt() multicast failed.");
+			e.printStackTrace();
+			return -1;
+		}
+		return packet.getLength();
+	}
+
+	/**
+	 * Unicast version of sending a Compound RTCP packet
+	 * 
+	 * @param pkt
+	 *            the packet to best
+	 * @param receiver
+	 *            the socket address of the recipient
+	 * @return 0 is successful, -1 otherwise
+	 */
+	protected int sendCompRtcpPkt(CompRtcpPkt pkt, InetSocketAddress receiver) {
+		byte[] pktBytes = pkt.encode();
+		DatagramPacket packet;
+
+		// Create datagram
+		try {
+			// System.out.println("receiver: " + receiver);
+			packet = new DatagramPacket(pktBytes, pktBytes.length, receiver);
+		} catch (Exception e) {
+			System.out
+					.println("RCTPSenderThread.SendCompRtcpPkt() packet creation failed.");
+			e.printStackTrace();
+			return -1;
+		}
+
+		// Send packet
+		if (RTPSession.rtcpDebugLevel > 5) {
+			Iterator<RtcpPkt> iter = pkt.rtcpPkts.iterator();
+			String str = " ";
+			while (iter.hasNext()) {
+				RtcpPkt aPkt = iter.next();
+				str += (aPkt.getClass().toString() + ":" + aPkt.itemCount + ", ");
+			}
+			System.out
+					.println("<-> RTCPSenderThread.SendCompRtcpPkt() unicast to "
+							+ receiver + str);
+		}
+		try {
+			rtcpSession.rtcpSock.send(packet);
+			// Debug
+			if (this.rtpSession.debugAppIntf != null) {
+				this.rtpSession.debugAppIntf.packetSent(2,
+						(InetSocketAddress) packet.getSocketAddress(),
+						new String("Sent unicast RTCP packet of size "
+								+ packet.getLength()
+								+ " to "
+								+ packet.getSocketAddress().toString()
+								+ " via "
+								+ this.rtcpSession.rtcpSock
+										.getLocalSocketAddress().toString()));
+			}
+		} catch (Exception e) {
+			System.out
+					.println("RTCPSenderThread.SendCompRtcpPkt() unicast failed.");
+			e.printStackTrace();
+			return -1;
+		}
+		return packet.getLength();
+	}
+
+	/**
+	 * Check whether we can send an immediate feedback packet to this person
+	 * 
+	 * @param ssrc
+	 *            SSRC of participant
+	 */
+	protected void reconsiderTiming(long ssrc) {
+		Participant part = this.rtpSession.partDb.getParticipant(ssrc);
+
+		if (part != null && this.rtcpSession.fbSendImmediately()) {
+			CompRtcpPkt compPkt = preparePacket(part, false);
+			/*********** Send the packet ***********/
+			// Keep track of sent packet length for average;
+			int datagramLength;
+			if (rtpSession.mcSession) {
+				datagramLength = this.mcSendCompRtcpPkt(compPkt);
+			} else {
+				// part.debugPrint();
+				datagramLength = this
+						.sendCompRtcpPkt(compPkt, part.rtcpAddress);
+			}
+			/*********** Administrative tasks ***********/
+			// Update average packet size
+			if (datagramLength > 0) {
+				rtcpSession.updateAvgPacket(datagramLength);
+			}
+		} else if (part != null && this.rtcpSession.fbAllowEarly
+				&& this.rtcpSession.fbSendEarly()) {
+
+			// Make sure we dont do it too often
+			this.rtcpSession.fbAllowEarly = false;
+
+			CompRtcpPkt compPkt = preparePacket(part, true);
+			/*********** Send the packet ***********/
+			// Keep track of sent packet length for average;
+			int datagramLength;
+			if (rtpSession.mcSession) {
+				datagramLength = this.mcSendCompRtcpPkt(compPkt);
+			} else {
+				// part.debugPrint();
+				datagramLength = this
+						.sendCompRtcpPkt(compPkt, part.rtcpAddress);
+			}
+			/*********** Administrative tasks ***********/
+			// Update average packet size
+			if (datagramLength > 0) {
+				rtcpSession.updateAvgPacket(datagramLength);
+			}
+			rtcpSession.calculateDelay();
+		}
+
+		// Out of luck, fb message will have to go with next regular packet
+		// Sleep for the remaining time.
+		this.rtcpSession.nextDelay -= System.currentTimeMillis()
+				- this.rtcpSession.prevTime;
+		if (this.rtcpSession.nextDelay < 0)
+			this.rtcpSession.nextDelay = 0;
+
+	}
+
+	/**
+	 * Prepare a packet. The output depends on the participant and how the
+	 * packet is scheduled.
+	 * 
+	 * @param part
+	 *            the participant to report to
+	 * @param regular
+	 *            whether this is a regularly, or early scheduled RTCP packet
+	 * @return compound RTCP packet
+	 */
+	protected CompRtcpPkt preparePacket(Participant part, boolean regular) {
+		/*********** Figure out what we are going to send ***********/
+		// Check whether this person has sent RTP packets since the last RR.
+		boolean incRR = false;
+		if (part.secondLastRtcpRRPkt > part.lastRtcpRRPkt) {
+			incRR = true;
+			part.secondLastRtcpRRPkt = part.lastRtcpRRPkt;
+			part.lastRtcpRRPkt = System.currentTimeMillis();
+		}
+
+		// Are we sending packets? -> add SR
+		boolean incSR = false;
+		if (rtpSession.sentPktCount > 0 && regular) {
+			incSR = true;
+		}
+
+		/*********** Actually create the packet ***********/
+		// Create compound packet
+		CompRtcpPkt compPkt = new CompRtcpPkt();
+
+		// If we're sending packets we'll use a SR for header
+		if (incSR) {
+			RtcpPktSR srPkt = new RtcpPktSR(this.rtpSession.ssrc,
+					this.rtpSession.sentPktCount,
+					this.rtpSession.sentOctetCount, null);
+			compPkt.addPacket(srPkt);
+
+			if (part.ssrc > 0) {
+				RtcpPkt[] ar = this.rtcpSession.getFromFbQueue(part.ssrc);
+				if (ar != null) {
+					for (int i = 0; i < ar.length; i++) {
+						compPkt.addPacket(ar[i]);
+					}
+				}
+			}
+
+		}
+
+		// If we got anything from this participant since we sent the 2nd to
+		// last RtcpPkt
+		if (incRR || !incSR) {
+			Participant[] partArray = { part };
+
+			if (part.receivedPkts < 1)
+				partArray = null;
+
+			RtcpPktRR rrPkt = new RtcpPktRR(partArray, rtpSession.ssrc);
+			compPkt.addPacket(rrPkt);
+
+			if (!incSR && part.ssrc > 0) {
+				RtcpPkt[] ar = this.rtcpSession.getFromFbQueue(part.ssrc);
+				if (ar != null) {
+					for (int i = 0; i < ar.length; i++) {
+						compPkt.addPacket(ar[i]);
+					}
+				}
+			}
+		}
+
+		// APP packets
+		if (regular && part.ssrc > 0) {
+			RtcpPkt[] ar = this.rtcpSession.getFromAppQueue(part.ssrc);
+			if (ar != null) {
+				for (int i = 0; i < ar.length; i++) {
+					compPkt.addPacket(ar[i]);
+				}
+			} else {
+				// Nope
+			}
+		}
+
+		// For now we'll stick the SDES on every time, and only for us
+		// if(regular) {
+		RtcpPktSDES sdesPkt = new RtcpPktSDES(true, this.rtpSession, null);
+		compPkt.addPacket(sdesPkt);
+		// }
+
+		return compPkt;
+	}
+
+	/**
+	 * Start the RTCP sender thread.
+	 * 
+	 * RFC 4585 is more complicated, but in general it will 1) Wait a
+	 * precalculated amount of time 2) Determine the next RTCP recipient 3)
+	 * Construct a compound packet with all the relevant information 4) Send the
+	 * packet 5) Calculate next delay before going to sleep
+	 */
+	public void run() {
+		if (RTPSession.rtcpDebugLevel > 1) {
+			System.out.println("<-> RTCPSenderThread running");
+		}
+
+		// Give the application a chance to register some participants
+		try {
+			Thread.sleep(10);
+		} catch (Exception e) {
+			System.out.println("RTCPSenderThread didn't get any initial rest.");
+		}
+
+		// Set up an iterator for the member list
+		Enumeration<Participant> enu = null;
+		Iterator<Participant> iter = null;
+
+		// TODO Change to rtcpReceivers
+		if (rtpSession.mcSession) {
+			enu = rtpSession.partDb.getParticipants();
+		} else {
+			iter = rtpSession.partDb.getUnicastReceivers();
+		}
+		while (!rtpSession.endSession) {
+			if (RTPSession.rtcpDebugLevel > 5) {
+				System.out.println("<-> RTCPSenderThread sleeping for "
+						+ rtcpSession.nextDelay + " ms");
+			}
+
+			try {
+				Thread.sleep(rtcpSession.nextDelay);
+			} catch (Exception e) {
+				System.out.println("RTCPSenderThread Exception message:"
+						+ e.getMessage());
+				// Is the party over?
+				if (this.rtpSession.endSession) {
+					continue;
+				}
+
+				if (rtcpSession.fbWaiting != -1) {
+					reconsiderTiming(rtcpSession.fbWaiting);
+					continue;
+				}
+			}
+
+			/** Came here the regular way */
+			this.rtcpSession.fbAllowEarly = true;
+
+			if (RTPSession.rtcpDebugLevel > 5) {
+				System.out.println("<-> RTCPSenderThread waking up");
+			}
+
+			// Regenerate nextDelay, before anything happens.
+			rtcpSession.calculateDelay();
+
+			// We'll wait here until a conflict (if any) has been resolved,
+			// so that the bye packets for our current SSRC can be sent.
+			if (rtpSession.conflict) {
+				if (!this.byesSent) {
+					sendByes();
+					this.byesSent = true;
+				}
+				continue;
+			}
+			this.byesSent = false;
+
+			// Grab the next person
+			Participant part = null;
+
+			// Multicast
+			if (this.rtpSession.mcSession) {
+				if (!enu.hasMoreElements())
+					enu = rtpSession.partDb.getParticipants();
+
+				if (enu.hasMoreElements()) {
+					part = enu.nextElement();
+				} else {
+					continue;
+				}
+
+				// Unicast
+			} else {
+				if (!iter.hasNext()) {
+					iter = rtpSession.partDb.getUnicastReceivers();
+				}
+
+				if (iter.hasNext()) {
+					while (iter.hasNext()
+							&& (part == null || part.rtcpAddress == null)) {
+						part = iter.next();
+					}
+				}
+
+				if (part == null || part.rtcpAddress == null)
+					continue;
+			}
+
+			CompRtcpPkt compPkt = preparePacket(part, true);
+
+			/*********** Send the packet ***********/
+			// Keep track of sent packet length for average;
+			int datagramLength;
+			if (rtpSession.mcSession) {
+				datagramLength = this.mcSendCompRtcpPkt(compPkt);
+			} else {
+				// part.debugPrint();
+				datagramLength = this
+						.sendCompRtcpPkt(compPkt, part.rtcpAddress);
+			}
+
+			/*********** Administrative tasks ***********/
+			// Update average packet size
+			if (datagramLength > 0) {
+				rtcpSession.updateAvgPacket(datagramLength);
+			}
+		}
+
+		// Be polite, say Bye to everone
+		sendByes();
+		try {
+			Thread.sleep(200);
+		} catch (Exception e) {
+		}
+
+		if (RTPSession.rtcpDebugLevel > 0) {
+			System.out.println("<-> RTCPSenderThread terminating");
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RTCPSession.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,565 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * This class acts as an organizer for most of the information and functions
+ * pertaining to RTCP packet generation and reception
+ * 
+ * @author Arne Kepp
+ * 
+ */
+public class RTCPSession {
+	/** Parent session */
+	protected RTPSession rtpSession = null;
+
+	/** Unicast socket */
+	protected DatagramSocket rtcpSock = null;
+	/** Multicast socket */
+	protected MulticastSocket rtcpMCSock = null;
+	/** Multicast group */
+	protected InetAddress mcGroup = null;
+
+	/** RTCP Receiver thread */
+	protected RTCPReceiverThread recvThrd = null;
+	/** RTCP Sender thread */
+	protected RTCPSenderThread senderThrd = null;
+
+	/** Previous time a delay was calculated */
+	protected long prevTime = System.currentTimeMillis();
+	/** Delay between RTCP transmissions, in ms. Initialized in start() */
+	protected int nextDelay = -1; //
+	/**
+	 * The average compound RTCP packet size, in octets, including UDP and IP
+	 * headers
+	 */
+	protected int avgPktSize = 200; //
+	/** Pessimistic case estimate of the current number of senders */
+	protected int senderCount = 1;
+	/** Whether next RTCP packet can be sent early */
+	protected boolean fbAllowEarly = false;
+	/** Feedback queue , index is SSRC of target */
+	protected Hashtable<Long, LinkedList<RtcpPkt>> fbQueue = null;
+	/** APP queue , index is SSRC of target */
+	protected Hashtable<Long, LinkedList<RtcpPktAPP>> appQueue = null;
+	/** Are we just starting up? */
+	protected boolean initial = true;
+	/** Is there a feedback packet waiting? SSRC of destination */
+	protected long fbWaiting = -1;
+
+	/**
+	 * Constructor for unicast sessions
+	 * 
+	 * @param parent
+	 *            RTPSession that started this
+	 * @param rtcpSocket
+	 *            the socket to use for listening and sending
+	 */
+	protected RTCPSession(RTPSession parent, DatagramSocket rtcpSocket) {
+		this.rtcpSock = rtcpSocket;
+		rtpSession = parent;
+	}
+
+	/**
+	 * Constructor for multicast sessions
+	 * 
+	 * @param parent
+	 *            parent RTPSession
+	 * @param rtcpSocket
+	 *            parent RTPSession that started this
+	 * @param multicastGroup
+	 *            multicast group to bind the socket to
+	 */
+	protected RTCPSession(RTPSession parent, MulticastSocket rtcpSocket,
+			InetAddress multicastGroup) {
+		mcGroup = multicastGroup;
+		this.rtcpSock = rtcpSocket;
+		rtpSession = parent;
+	}
+
+	/**
+	 * Starts the session, calculates delays and fires up the threads.
+	 * 
+	 */
+	protected void start() {
+		// nextDelay = 2500 + rtpSession.random.nextInt(1000) - 500;
+		this.calculateDelay();
+		recvThrd = new RTCPReceiverThread(this, this.rtpSession);
+		senderThrd = new RTCPSenderThread(this, this.rtpSession);
+		recvThrd.start();
+		senderThrd.start();
+	}
+
+	/**
+	 * Send bye packets, handled by RTCP Sender thread
+	 * 
+	 */
+	protected void sendByes() {
+		senderThrd.sendByes();
+	}
+
+	/**
+	 * Calculate the delay before the next RTCP packet can be sent
+	 * 
+	 */
+	protected void calculateDelay() {
+		switch (rtpSession.rtcpMode) {
+		case 0:
+			calculateRegularDelay();
+			break;
+		default:
+			System.out.println("RTCPSession.calculateDelay() unknown .mode");
+		}
+	}
+
+	/**
+	 * Calculates a delay value in accordance with RFC 3550
+	 * 
+	 */
+	protected void calculateRegularDelay() {
+		long curTime = System.currentTimeMillis();
+
+		if (rtpSession.bandwidth != 0 && !this.initial
+				&& rtpSession.partDb.ssrcTable.size() > 4) {
+			// RTPs mechanisms for RTCP scalability
+			int rand = rtpSession.random.nextInt(10000) - 5000; // between -500
+																// and +500
+			double randDouble = ((double) 1000 + rand) / 1000.0;
+
+			Enumeration<Participant> enu = rtpSession.partDb.getParticipants();
+			while (enu.hasMoreElements()) {
+				Participant part = enu.nextElement();
+				if (part.lastRtpPkt > this.prevTime)
+					senderCount++;
+			}
+
+			double bw;
+			if (rtpSession.rtcpBandwidth > -1) {
+				bw = rtpSession.rtcpBandwidth;
+			} else {
+				bw = rtpSession.bandwidth * 0.05;
+			}
+			if (senderCount * 2 > rtpSession.partDb.ssrcTable.size()) {
+				if (rtpSession.lastTimestamp > this.prevTime) {
+					// We're a sender
+					double numerator = ((double) this.avgPktSize)
+							* ((double) senderCount);
+					double denominator = 0.25 * bw;
+					this.nextDelay = (int) Math.round((numerator / denominator)
+							* randDouble);
+				} else {
+					// We're a receiver
+					double numerator = ((double) this.avgPktSize)
+							* ((double) rtpSession.partDb.ssrcTable.size());
+					double denominator = 0.75 * bw;
+					this.nextDelay = (int) Math.round((numerator / denominator)
+							* randDouble);
+				}
+			} else {
+				double numerator = ((double) this.avgPktSize)
+						* ((double) rtpSession.partDb.ssrcTable.size());
+				;
+				double denominator = bw;
+				this.nextDelay = (int) Math
+						.round(1000.0 * (numerator / denominator))
+						* (1000 + rand);
+			}
+		} else {
+			// Not enough data to scale, use random values
+			int rand = rtpSession.random.nextInt(1000) - 500; // between -500
+																// and +500
+			if (this.initial) {
+				// 2.5 to 3.5 seconds, randomly
+				this.nextDelay = 3000 + rand;
+				this.initial = false;
+			} else {
+				// 4.5 to 5.5 seconds, randomly
+				this.nextDelay = 5500 + rand;
+			}
+
+		}
+
+		// preflight check
+		if (this.nextDelay < 1000) {
+			int rand = rtpSession.random.nextInt(1000) - 500; // between -500
+																// and +500
+			System.out
+					.println("RTCPSession.calculateDelay() nextDelay was too short ("
+							+ this.nextDelay
+							+ "ms), setting to "
+							+ (this.nextDelay = 2000 + rand));
+		}
+		this.prevTime = curTime;
+	}
+
+	/**
+	 * Update the average packet size
+	 * 
+	 * @param length
+	 *            of latest packet
+	 */
+	synchronized protected void updateAvgPacket(int length) {
+		double tempAvg = (double) this.avgPktSize;
+		tempAvg = (15 * tempAvg + ((double) length)) / 16;
+		this.avgPktSize = (int) tempAvg;
+	}
+
+	/**
+	 * Adds an RTCP APP (application) packet to the queue
+	 * 
+	 * @param targetSsrc
+	 *            the SSRC of the recipient
+	 * @param aPkt
+	 */
+	synchronized protected void addToAppQueue(long targetSsrc, RtcpPktAPP aPkt) {
+		aPkt.time = System.currentTimeMillis();
+
+		if (this.appQueue == null)
+			this.appQueue = new Hashtable<Long, LinkedList<RtcpPktAPP>>();
+
+		LinkedList<RtcpPktAPP> ll = this.appQueue.get(targetSsrc);
+		if (ll == null) {
+			// No list, create and add
+			ll = new LinkedList<RtcpPktAPP>();
+			this.appQueue.put(targetSsrc, ll);
+		}
+
+		ll.add(aPkt);
+	}
+
+	/**
+	 * Adds an RTCP APP (application) packet to the queue
+	 * 
+	 * @param targetSsrc
+	 *            the SSRC of the recipient
+	 * @return array of RTCP Application packets
+	 */
+	synchronized protected RtcpPktAPP[] getFromAppQueue(long targetSsrc) {
+		if (this.appQueue == null)
+			return null;
+
+		LinkedList<RtcpPktAPP> ll = this.appQueue.get(targetSsrc);
+		if (ll == null || ll.isEmpty()) {
+			return null;
+		} else {
+			RtcpPktAPP[] ret = new RtcpPktAPP[ll.size()];
+			ListIterator<RtcpPktAPP> li = ll.listIterator();
+			int i = 0;
+			while (li.hasNext()) {
+				ret[i] = li.next();
+				i++;
+			}
+			return ret;
+		}
+	}
+
+	/**
+	 * Cleans the TCP APP (application) packet queues of any packets that are
+	 * too old, defined as 60 seconds since insertion.
+	 * 
+	 * @param ssrc
+	 *            The SSRC of the user who has left, negative value -> general
+	 *            cleanup
+	 */
+	synchronized protected void cleanAppQueue(long ssrc) {
+		if (this.appQueue == null)
+			return;
+
+		if (ssrc > 0) {
+			this.appQueue.remove(ssrc);
+		} else {
+			Enumeration<LinkedList<RtcpPktAPP>> enu = this.appQueue.elements();
+			long curTime = System.currentTimeMillis();
+
+			while (enu.hasMoreElements()) {
+				ListIterator<RtcpPktAPP> li = enu.nextElement().listIterator();
+				while (li.hasNext()) {
+					RtcpPkt aPkt = li.next();
+					// Remove after 60 seconds
+					if (curTime - aPkt.time > 60000) {
+						li.remove();
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Check the feedback queue for similar packets and adds the new packet if
+	 * it is not redundant
+	 * 
+	 * @param aPkt
+	 * @return 0 if the packet was added, 1 if it was dropped
+	 */
+	synchronized protected int addToFbQueue(long targetSsrc, RtcpPkt aPkt) {
+		if (this.fbQueue == null)
+			this.fbQueue = new Hashtable<Long, LinkedList<RtcpPkt>>();
+
+		LinkedList<RtcpPkt> ll = this.fbQueue.get(targetSsrc);
+		if (ll == null) {
+			// No list, create and add
+			ll = new LinkedList<RtcpPkt>();
+			ll.add(aPkt);
+			this.fbQueue.put(targetSsrc, ll);
+		} else {
+			// Check for matching packets, else add to end
+			ListIterator<RtcpPkt> li = ll.listIterator();
+			while (li.hasNext()) {
+				RtcpPkt tmp = li.next();
+				if (equivalent(tmp, aPkt))
+					return -1;
+			}
+			ll.addLast(aPkt);
+		}
+		return 0;
+	}
+
+	/**
+	 * Checks whether there are ny feedback packets waiting to be sent.
+	 * 
+	 * @param ssrc
+	 *            of the participant we are notifying
+	 * @return all relevant feedback packets, or null
+	 */
+	synchronized protected RtcpPkt[] getFromFbQueue(long ssrc) {
+		if (this.fbQueue == null)
+			return null;
+
+		LinkedList<RtcpPkt> ll = this.fbQueue.get(ssrc);
+
+		if (ll == null)
+			return null;
+
+		ListIterator<RtcpPkt> li = ll.listIterator();
+		if (li.hasNext()) {
+			long curTime = System.currentTimeMillis();
+			long maxDelay = curTime - rtpSession.fbMaxDelay;
+			long keepDelay = curTime - 2000;
+			int count = 0;
+
+			// TODO below the indeces should be collected instead of looping
+			// twice
+
+			// Clean out what we dont want and count what we want
+			while (li.hasNext()) {
+				RtcpPkt aPkt = li.next();
+				if (aPkt.received) {
+					// This is a packet received, we keep these for
+					// 2000ms to avoid redundant feedback
+					if (aPkt.time < keepDelay)
+						li.remove();
+				} else {
+					// This is a packet we havent sent yet
+					if (aPkt.time < maxDelay) {
+						li.remove();
+					} else {
+						count++;
+					}
+				}
+			}
+
+			// Gather what we want to return
+			if (count != 0) {
+				li = ll.listIterator();
+				RtcpPkt[] ret = new RtcpPkt[count];
+
+				while (count > 0) {
+					RtcpPkt aPkt = li.next();
+					if (!aPkt.received) {
+						ret[ret.length - count] = aPkt;
+						count--;
+					}
+				}
+				return ret;
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * Cleans the feeback queue of any packets that have expired, ie feedback
+	 * packet that are no longer relevant.
+	 * 
+	 * @param ssrc
+	 *            The SSRC of the user who has left, negative value -> general
+	 *            cleanup
+	 */
+	synchronized protected void cleanFbQueue(long ssrc) {
+		if (this.fbQueue == null)
+			return;
+
+		if (ssrc > 0) {
+			this.fbQueue.remove(ssrc);
+		} else {
+			Enumeration<LinkedList<RtcpPkt>> enu = this.fbQueue.elements();
+			long curTime = System.currentTimeMillis();
+			long maxDelay = curTime - rtpSession.fbMaxDelay;
+			long keepDelay = curTime - 2000;
+
+			while (enu.hasMoreElements()) {
+				ListIterator<RtcpPkt> li = enu.nextElement().listIterator();
+				while (li.hasNext()) {
+					RtcpPkt aPkt = li.next();
+					if (aPkt.received) {
+						// This is a packet received, we keep these for
+						// 2000ms to avoid redundant feedback
+						if (aPkt.time < keepDelay)
+							li.remove();
+					} else {
+						// This is a packet we havent sent yet
+						if (aPkt.time < maxDelay)
+							li.remove();
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * Check whether the conditions are satisfied to send a feedbkac packet
+	 * immediately.
+	 * 
+	 * @return true if they are, false otherwise
+	 */
+	protected boolean fbSendImmediately() {
+		if (rtpSession.partDb.ssrcTable.size() > this.rtpSession.fbEarlyThreshold
+				&& rtpSession.partDb.receivers.size() > this.rtpSession.fbEarlyThreshold)
+			return false;
+
+		return true;
+	}
+
+	/**
+	 * Check whether the conditions are satisfied to send a feedbkac packet
+	 * immediately.
+	 * 
+	 * @return true if they are, false otherwise
+	 */
+	protected boolean fbSendEarly() {
+		if (rtpSession.partDb.ssrcTable.size() > this.rtpSession.fbRegularThreshold
+				&& rtpSession.partDb.receivers.size() > this.rtpSession.fbRegularThreshold)
+			return false;
+
+		return true;
+	}
+
+	/**
+	 * Wake the sender thread because of this ssrc
+	 * 
+	 * @param ssrc
+	 *            that has feedback waiting.
+	 */
+	protected void wakeSenderThread(long ssrc) {
+		this.fbWaiting = ssrc;
+		this.senderThrd.interrupt();
+
+		// Give it a chance to catch up
+		try {
+			Thread.sleep(0, 1);
+		} catch (Exception e) {
+		}
+		;
+	}
+
+	/**
+	 * Compares two packets to check whether they are equivalent feedback
+	 * messages, to avoid sending the same feedback to a host twice.
+	 * 
+	 * Expect false negatives, but not false positives.
+	 * 
+	 * @param one
+	 *            packet
+	 * @param two
+	 *            packet
+	 * @return true if they are equivalent, false otherwise
+	 */
+	private boolean equivalent(RtcpPkt one, RtcpPkt two) {
+		// Cheap checks
+		if (one.packetType != two.packetType)
+			return false;
+
+		if (one.itemCount != two.itemCount)
+			return false;
+
+		if (one.packetType == 205) {
+			// RTP Feedback, i.e. a NACK
+			RtcpPktRTPFB pktone = (RtcpPktRTPFB) one;
+			RtcpPktRTPFB pkttwo = (RtcpPktRTPFB) two;
+
+			if (pktone.ssrcMediaSource != pkttwo.ssrcMediaSource)
+				return false;
+
+			if (Arrays.equals(pktone.BLP, pkttwo.BLP)
+					&& Arrays.equals(pktone.BLP, pkttwo.BLP))
+				return true;
+
+			return true;
+		} else if (one.packetType == 206) {
+			RtcpPktPSFB pktone = (RtcpPktPSFB) one;
+			RtcpPktPSFB pkttwo = (RtcpPktPSFB) two;
+
+			if (pktone.ssrcMediaSource != pkttwo.ssrcMediaSource)
+				return false;
+
+			switch (one.itemCount) {
+			case 1: // Picture Loss Indication
+				return true;
+
+			case 2: // Slice Loss Indication
+				// This will not work if the slice loss indicators are in
+				// different order
+				if (pktone.sliFirst.length == pkttwo.sliFirst.length
+						&& Arrays.equals(pktone.sliFirst, pkttwo.sliFirst)
+						&& Arrays.equals(pktone.sliNumber, pkttwo.sliNumber)
+						&& Arrays.equals(pktone.sliPictureId,
+								pkttwo.sliPictureId))
+					return true;
+				break;
+			case 3: // Reference Picture Selection Indication
+				if (Arrays.equals(pktone.rpsiBitString, pkttwo.rpsiBitString))
+					return true;
+				break;
+			case 15: // Application Layer Feedback Messages
+				// This will not work if the padding scheme is different
+				if (pktone.sliFirst.length == pkttwo.sliFirst.length
+						&& Arrays.equals(pktone.alfBitString,
+								pkttwo.alfBitString))
+					return true;
+				break;
+			default:
+
+			}
+			return true;
+		} else {
+			System.out
+					.println("!!!! RTCPSession.equivalentPackets() encountered unexpected packet type!");
+		}
+		return false;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RTPAppIntf.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,74 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+package jlibrtp;
+
+/**
+ * This is the callback interface for RTP packets.
+ * 
+ * It is mandatory, but you can inore the data if you like.
+ * 
+ * @author Arne Kepp
+ */
+public interface RTPAppIntf {
+
+	/**
+	 * The callback method through which the application will receive data from
+	 * jlibrtp. These calls are synchronous, so you will not receive any new
+	 * packets until this call returns.
+	 * 
+	 * @param frame
+	 *            the frame containing the data
+	 * @param participant
+	 *            the participant from which the data came
+	 */
+	public void receiveData(DataFrame frame, Participant participant);
+
+	/**
+	 * The callback method through which the application will receive
+	 * notifications about user updates, additions and byes. Types: 1 - Bye 2 -
+	 * New through RTP, check .getRtpSendSock() 3 - New through RTCP, check
+	 * .getRtcpSendSock() 4 - SDES packet received, check the getCname() etc
+	 * methods 5 - Matched SSRC to ip-address provided by application
+	 * 
+	 * @param type
+	 *            the type of event
+	 * @param participant
+	 *            the participants in question
+	 */
+	public void userEvent(int type, Participant[] participant);
+
+	/**
+	 * The callback method through which the application can specify the number
+	 * of packets that make up a frame for a given payload type.
+	 * 
+	 * A negative value denotes frames of variable length, so jlibrtp will
+	 * return whatever it has at the time.
+	 * 
+	 * In most applications, this function can simply return 1.
+	 * 
+	 * This should be implemented as something fast, such as an integer array
+	 * with the indeces being the payload type.
+	 * 
+	 * @param payloadType
+	 *            the payload type specified in the RTP packet
+	 * @return the number of packets that make up a frame
+	 */
+	public int frameSize(int payloadType);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RTPReceiverThread.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,369 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetSocketAddress;
+import java.net.SocketException;
+
+import org.sipdroid.net.tools.DatagramPool;
+import org.sipdroid.net.tools.RtpPktPool;
+
+/**
+ * The RTP receiver thread waits on the designated UDP socket for new packets.
+ * 
+ * Once one arrives, it is parsed and tested. We also check the ip-address of
+ * the sender. If accepted, the packet is added onto the packet buffer of the
+ * participant.
+ * 
+ * A separate thread moves the packet from the packet buffer to the application.
+ * 
+ * @author Arne Kepp
+ */
+public class RTPReceiverThread extends Thread {
+	/** Parent RTP Session */
+	RTPSession rtpSession = null;
+	DatagramPool datagramPool = null;
+
+	RTPReceiverThread(RTPSession session) {
+		rtpSession = session;
+		datagramPool = DatagramPool.getInstance();
+		if (RTPSession.rtpDebugLevel > 1) {
+			System.out.println("<-> RTPReceiverThread created");
+		}
+	}
+	public void init() {
+		if (RTPSession.rtpDebugLevel > 1) {
+			if (rtpSession.mcSession) {
+				System.out.println("-> RTPReceiverThread.run() starting on MC "
+						+ rtpSession.rtpMCSock.getLocalPort());
+			} else {
+				System.out.println("-> RTPReceiverThread.run() starting on "
+						+ rtpSession.rtpSock.getLocalPort());
+			}
+		}
+
+		android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
+
+		DatagramPacket packet = datagramPool.borrowPacket();
+		try {
+			rtpSession.rtpSock.setSoTimeout(1);
+			for (;;)
+				rtpSession.rtpSock.receive(packet);
+		} catch (SocketException e2) {
+
+		} catch (IOException e) {
+		}	
+		datagramPool.returnPacket(packet);
+		try {
+			rtpSession.rtpSock.setSoTimeout(1000);
+		} catch (SocketException e2) {
+		}
+	}
+	
+	public void readPacketToBuffer() {
+		if (RTPSession.rtpDebugLevel > 6) {
+			if (rtpSession.mcSession) {
+				System.out
+				.println("-> RTPReceiverThread.run() waiting for MC packet on "
+						+ rtpSession.rtpMCSock.getLocalPort());
+			} else {
+				System.out
+				.println("-> RTPReceiverThread.run() waiting for packet on "
+						+ rtpSession.rtpSock.getLocalPort());
+			}
+		}
+
+		// Prepare a packet
+		//DatagramPacket packet = new DatagramPacket(rawPkt, rawPkt.length);
+		DatagramPacket packet = datagramPool.borrowPacket();
+		// Wait for it to arrive
+		if (!rtpSession.mcSession) {
+			// Unicast
+			try {
+				rtpSession.rtpSock.receive(packet);
+			} catch (IOException e) {
+				if (!rtpSession.endSession) {
+					e.printStackTrace();
+				} else {
+					return;
+				}
+			}
+		} else {
+			// Multicast
+			try {
+				rtpSession.rtpMCSock.receive(packet);
+			} catch (IOException e) {
+				if (!rtpSession.endSession) {
+					e.printStackTrace();
+				} else {
+					return;
+				}
+			}
+		}
+		// Parse the received RTP (?) packet
+		RtpPkt pkt = RtpPktPool.getInstance().borrowPkt();
+		pkt.initPacket(packet.getData(), packet.getLength(), packet);
+
+		// Check whether it was valid.
+		if (pkt == null) {
+			System.out.println("Received invalid RTP packet. Ignoring");
+			return;
+		}
+
+		long pktSsrc = pkt.getSsrc();
+
+		// Check for loops and SSRC collisions
+		if (rtpSession.ssrc == pktSsrc)
+			rtpSession.resolveSsrcConflict();
+
+		long[] csrcArray = pkt.getCsrcArray();
+		if (csrcArray != null) {
+			for (int i = 0; i < csrcArray.length; i++) {
+				if (csrcArray[i] == rtpSession.ssrc)
+					;
+				rtpSession.resolveSsrcConflict();
+			}
+		}
+
+		if (RTPSession.rtpDebugLevel > 17) {
+			System.out
+			.println("-> RTPReceiverThread.run() rcvd packet, seqNum "
+					+ pktSsrc);
+			if (RTPSession.rtpDebugLevel > 10) {
+				System.out.println("-> RTPReceiverThread.run() payload is "
+						+ pkt.getPayloadLength());
+			}
+		}
+
+		// Find the participant in the database based on SSRC
+		//Participant part = rtpSession.partDb.getParticipant(pktSsrc);
+		Participant part = rtpSession.firstPart;
+		if (part == null) {
+			InetSocketAddress nullSocket = null;
+			part = new Participant((InetSocketAddress) packet
+					.getSocketAddress(), nullSocket, pkt.getSsrc());
+			part.unexpected = true;
+			rtpSession.partDb.addParticipant(1, part);
+		}
+
+		// Do checks on whether the datagram came from the expected source
+		// for that SSRC.
+		
+		if (part.rtpAddress == null
+				|| packet.getAddress().equals(part.rtpAddress.getAddress())) {
+			PktBuffer pktBuffer = part.pktBuffer;
+
+			if (pktBuffer != null) {
+				// A buffer already exists, append to it
+				pktBuffer.addPkt(pkt);
+			} else {
+				// Create a new packet/frame buffer
+				pktBuffer = new PktBuffer(this.rtpSession, part, pkt);
+				part.pktBuffer = pktBuffer;
+			}
+		} else {
+			System.out
+			.println("RTPReceiverThread: Got an unexpected packet from "
+					+ pkt.getSsrc()
+					+ " the sending ip-address was "
+					+ packet.getAddress().toString()
+					+ ", we expected from "
+					+ part.rtpAddress.toString());
+		}
+
+		// Statistics for receiver report.
+		part.updateRRStats(packet.getLength(), pkt);
+		// Upate liveness
+		part.lastRtpPkt = System.currentTimeMillis();
+
+		if (RTPSession.rtpDebugLevel > 5) {
+			System.out
+			.println("<-> RTPReceiverThread signalling pktBufDataReady");
+		}
+
+		// Signal the thread that pushes data to application
+		/*rtpSession.pktBufLock.lock();
+		try {
+			rtpSession.pktBufDataReady.signalAll();
+		} finally {
+			rtpSession.pktBufLock.unlock();
+		}*/
+	}
+
+	public void run() {
+		if (RTPSession.rtpDebugLevel > 1) {
+			if (rtpSession.mcSession) {
+				System.out.println("-> RTPReceiverThread.run() starting on MC "
+						+ rtpSession.rtpMCSock.getLocalPort());
+			} else {
+				System.out.println("-> RTPReceiverThread.run() starting on "
+						+ rtpSession.rtpSock.getLocalPort());
+			}
+		}
+
+		android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
+
+		DatagramPacket packet = datagramPool.borrowPacket();
+		try {
+			rtpSession.rtpSock.setSoTimeout(1);
+			for (;;)
+				rtpSession.rtpSock.receive(packet);
+		} catch (SocketException e2) {
+
+		} catch (IOException e) {
+		}	
+		datagramPool.returnPacket(packet);
+		try {
+			rtpSession.rtpSock.setSoTimeout(0);
+		} catch (SocketException e2) {
+		}
+		while (!rtpSession.endSession) {
+			if (RTPSession.rtpDebugLevel > 6) {
+				if (rtpSession.mcSession) {
+					System.out
+					.println("-> RTPReceiverThread.run() waiting for MC packet on "
+							+ rtpSession.rtpMCSock.getLocalPort());
+				} else {
+					System.out
+					.println("-> RTPReceiverThread.run() waiting for packet on "
+							+ rtpSession.rtpSock.getLocalPort());
+				}
+			}
+
+			// Prepare a packet
+			//DatagramPacket packet = new DatagramPacket(rawPkt, rawPkt.length);
+			packet = datagramPool.borrowPacket();
+			// Wait for it to arrive
+			if (!rtpSession.mcSession) {
+				// Unicast
+				try {
+					rtpSession.rtpSock.receive(packet);
+				} catch (IOException e) {
+					if (!rtpSession.endSession) {
+						e.printStackTrace();
+					} else {
+						continue;
+					}
+				}
+			} else {
+				// Multicast
+				try {
+					rtpSession.rtpMCSock.receive(packet);
+				} catch (IOException e) {
+					if (!rtpSession.endSession) {
+						e.printStackTrace();
+					} else {
+						continue;
+					}
+				}
+			}
+			// Parse the received RTP (?) packet
+			RtpPkt pkt = RtpPktPool.getInstance().borrowPkt();
+			pkt.initPacket(packet.getData(), packet.getLength(), packet);
+
+			// Check whether it was valid.
+			if (pkt == null) {
+				System.out.println("Received invalid RTP packet. Ignoring");
+				continue;
+			}
+
+			long pktSsrc = pkt.getSsrc();
+
+			// Check for loops and SSRC collisions
+			if (rtpSession.ssrc == pktSsrc)
+				rtpSession.resolveSsrcConflict();
+
+			long[] csrcArray = pkt.getCsrcArray();
+			if (csrcArray != null) {
+				for (int i = 0; i < csrcArray.length; i++) {
+					if (csrcArray[i] == rtpSession.ssrc)
+						;
+					rtpSession.resolveSsrcConflict();
+				}
+			}
+
+			if (RTPSession.rtpDebugLevel > 17) {
+				System.out
+				.println("-> RTPReceiverThread.run() rcvd packet, seqNum "
+						+ pktSsrc);
+				if (RTPSession.rtpDebugLevel > 10) {
+					System.out.println("-> RTPReceiverThread.run() payload is "
+							+ pkt.getPayloadLength());
+				}
+			}
+
+			// Find the participant in the database based on SSRC
+			Participant part = rtpSession.partDb.getParticipant(pktSsrc);
+
+			if (part == null) {
+				InetSocketAddress nullSocket = null;
+				part = new Participant((InetSocketAddress) packet
+						.getSocketAddress(), nullSocket, pkt.getSsrc());
+				part.unexpected = true;
+				rtpSession.partDb.addParticipant(1, part);
+			}
+
+			// Do checks on whether the datagram came from the expected source
+			// for that SSRC.
+			if (part.rtpAddress == null
+					|| packet.getAddress().equals(part.rtpAddress.getAddress())) {
+				PktBuffer pktBuffer = part.pktBuffer;
+
+				if (pktBuffer != null) {
+					// A buffer already exists, append to it
+					pktBuffer.addPkt(pkt);
+				} else {
+					// Create a new packet/frame buffer
+					pktBuffer = new PktBuffer(this.rtpSession, part, pkt);
+					part.pktBuffer = pktBuffer;
+				}
+			} else {
+				System.out
+				.println("RTPReceiverThread: Got an unexpected packet from "
+						+ pkt.getSsrc()
+						+ " the sending ip-address was "
+						+ packet.getAddress().toString()
+						+ ", we expected from "
+						+ part.rtpAddress.toString());
+			}
+
+			// Statistics for receiver report.
+			part.updateRRStats(packet.getLength(), pkt);
+			// Upate liveness
+			part.lastRtpPkt = System.currentTimeMillis();
+
+			if (RTPSession.rtpDebugLevel > 5) {
+				System.out
+				.println("<-> RTPReceiverThread signalling pktBufDataReady");
+			}
+
+			// Signal the thread that pushes data to application
+			rtpSession.pktBufLock.lock();
+			try {
+				rtpSession.pktBufDataReady.signalAll();
+			} finally {
+				rtpSession.pktBufLock.unlock();
+			}
+
+		}
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RTPSession.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,1301 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.MulticastSocket;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Random;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.sipdroid.net.tools.DataFramePool;
+import org.sipdroid.net.tools.DatagramPool;
+import org.sipdroid.net.tools.PktBufNodePool;
+import org.sipdroid.net.tools.RtpPktPool;
+
+import android.util.Log;
+
+/**
+ * The RTPSession object is the core of jlibrtp.
+ * 
+ * One should be instantiated for every communication channel, i.e. if you send
+ * voice and video, you should create one for each.
+ * 
+ * The instance holds a participant database, as well as other information about
+ * the session. When the application registers with the session, the necessary
+ * threads for receiving and processing RTP packets are spawned.
+ * 
+ * RTP Packets are sent synchronously, all other operations are asynchronous.
+ * 
+ * @author Arne Kepp
+ */
+public class RTPSession {
+	/**
+	 * The debug level is final to avoid compilation of if-statements.</br> 0
+	 * provides no debugging information, 20 provides everything </br> Debug
+	 * output is written to System.out</br> Debug level for RTP related things.
+	 */
+	final static public int rtpDebugLevel = 1;
+	/**
+	 * The debug level is final to avoid compilation of if-statements.</br> 0
+	 * provides no debugging information, 20 provides everything </br> Debug
+	 * output is written to System.out</br> Debug level for RTCP related things.
+	 */
+	final static public int rtcpDebugLevel = 1;
+
+	/** RTP unicast socket */
+	protected DatagramSocket rtpSock = null;
+	/** RTP multicast socket */
+	protected MulticastSocket rtpMCSock = null;
+	/** RTP multicast group */
+	protected InetAddress mcGroup = null;
+
+	// Internal state
+	/** Whether this session is a multicast session or not */
+	protected boolean mcSession = false;
+	/** Current payload type, can be changed by application */
+	protected int payloadType = 0;
+	/** SSRC of this session */
+	protected long ssrc;
+	/** The last timestamp when we sent something */
+	protected long lastTimestamp = 0;
+	/** Current sequence number */
+	protected int seqNum = 0;
+	/** Number of packets sent by this session */
+	protected int sentPktCount = 0;
+	/** Number of octets sent by this session */
+	protected int sentOctetCount = 0;
+
+	/** The random seed */
+	protected Random random = null;
+
+	/** Session bandwidth in BYTES per second */
+	protected int bandwidth = 8000;
+
+	/** By default we do not return packets from strangers in unicast mode */
+	protected boolean naiveReception = false;
+
+	/** Should the library attempt frame reconstruction? */
+	protected boolean frameReconstruction = true;
+
+	/** Maximum number of packets used for reordering */
+	protected int pktBufBehavior = 3;
+
+	/** Participant database */
+	protected ParticipantDatabase partDb = new ParticipantDatabase(this);
+	/** First participant */
+	protected Participant firstPart;
+	/** Handle to application interface for RTP */
+	protected RTPAppIntf appIntf = null;
+	/** Handle to application interface for RTCP (optional) */
+	protected RTCPAppIntf rtcpAppIntf = null;
+	/** Handle to application interface for AVPF, RFC 4585 (optional) */
+	protected RTCPAVPFIntf rtcpAVPFIntf = null;
+	/** Handle to application interface for debugging */
+	protected DebugAppIntf debugAppIntf = null;
+
+	/** The RTCP session associated with this RTP Session */
+	protected RTCPSession rtcpSession = null;
+	/** The thread for receiving RTP packets */
+	protected RTPReceiverThread recvThrd = null;
+	/** The thread for invoking callbacks for RTP packets */
+	protected AppCallerThread appCallerThrd = null;
+
+	/** Lock to protect the packet buffers */
+	final protected Lock pktBufLock = new ReentrantLock();
+	/** Condition variable, to tell the */
+	final protected Condition pktBufDataReady = pktBufLock.newCondition();
+
+	/** Enough is enough, set to true when you want to quit. */
+	protected boolean endSession = false;
+	/** Only one registered application, please */
+	protected boolean registered = false;
+	/** We're busy resolving a SSRC conflict, please try again later */
+	protected boolean conflict = false;
+	/** Number of conflicts observed, exessive number suggests loop in network */
+	protected int conflictCount = 0;
+
+	/** SDES CNAME */
+	protected String cname = null;
+	/** SDES The participant's real name */
+	public String name = null;
+	/** SDES The participant's email */
+	public String email = null;
+	/** SDES The participant's phone number */
+	public String phone = null;
+	/** SDES The participant's location */
+	public String loc = null;
+	/** SDES The tool the participants is using */
+	public String tool = null;
+	/** SDES A note */
+	public String note = null;
+	/** SDES A priv string, loosely defined */
+	public String priv = null;
+
+	// RFC 4585 stuff. This should live on RTCPSession, but we need to have this
+	// infromation ready by the time the RTCP Session starts
+	// 0 = RFC 3550 , -1 = ACK , 1 = Immediate feedback, 2 = Early RTCP,
+	protected int rtcpMode = 0;
+	protected int fbEarlyThreshold = -1; // group size, immediate -> early
+	// transition point
+	protected int fbRegularThreshold = -1; // group size, early -> regular
+	// transition point
+	protected int minInterval = 5000; // minimum interval
+	protected int fbMaxDelay = 1000; // how long the information is useful
+	// RTCP bandwidth
+	protected int rtcpBandwidth = -1;
+
+	/**
+	 * Returns an instance of a <b>unicast</b> RTP session. Following this you
+	 * should adjust any settings and then register your application.
+	 * 
+	 * The sockets should have external ip addresses, else your CNAME
+	 * automatically generated CNAMe will be bad.
+	 * 
+	 * @param rtpSocket
+	 *            UDP socket to receive RTP communication on
+	 * @param rtcpSocket
+	 *            UDP socket to receive RTCP communication on, null if none.
+	 */
+	public RTPSession(DatagramSocket rtpSocket, DatagramSocket rtcpSocket) {
+		mcSession = false;
+		rtpSock = rtpSocket;
+		this.generateCNAME();
+		this.generateSsrc();
+		this.rtcpSession = new RTCPSession(this, rtcpSocket);
+		// The sockets are not always imediately available?
+		try {
+			Thread.sleep(1);
+		} catch (InterruptedException e) {
+			System.out.println("RTPSession sleep failed");
+		}
+	}
+
+	/**
+	 * Returns an instance of a <b>multicast</b> RTP session. Following this you
+	 * should register your application.
+	 * 
+	 * The sockets should have external ip addresses, else your CNAME
+	 * automatically generated CNAMe will be bad.
+	 * 
+	 * @param rtpSock
+	 *            a multicast socket to receive RTP communication on
+	 * @param rtcpSock
+	 *            a multicast socket to receive RTP communication on
+	 * @param multicastGroup
+	 *            the multicast group that we want to communicate with.
+	 */
+	public RTPSession(MulticastSocket rtpSock, MulticastSocket rtcpSock,
+			InetAddress multicastGroup) throws Exception {
+		mcSession = true;
+		rtpMCSock = rtpSock;
+		mcGroup = multicastGroup;
+		rtpMCSock.joinGroup(mcGroup);
+		rtcpSock.joinGroup(mcGroup);
+		this.generateCNAME();
+		this.generateSsrc();
+		this.rtcpSession = new RTCPSession(this, rtcpSock, mcGroup);
+
+		// The sockets are not always imediately available?
+		try {
+			Thread.sleep(1);
+		} catch (InterruptedException e) {
+			System.out.println("RTPSession sleep failed");
+		}
+	}
+
+	/**
+	 * Registers an application (RTPAppIntf) with the RTP session. The session
+	 * will call receiveData() on the supplied instance whenever data has been
+	 * received.
+	 * 
+	 * Following this you should set the payload type and add participants to
+	 * the session.
+	 * 
+	 * @param rtpApp
+	 *            an object that implements the RTPAppIntf-interface
+	 * @param rtcpApp
+	 *            an object that implements the RTCPAppIntf-interface (optional)
+	 * @return -1 if this RTPSession-instance already has an application
+	 *         registered.
+	 */
+	public int RTPSessionRegister(RTPAppIntf rtpApp, RTCPAppIntf rtcpApp,
+			DebugAppIntf debugApp) {
+		if (registered) {
+			System.out
+			.println("RTPSessionRegister(): Can\'t register another application!");
+			return -1;
+		} else {
+
+			registered = true;
+			generateSeqNum();
+			if (RTPSession.rtpDebugLevel > 0) {
+				System.out.println("-> RTPSessionRegister");
+			}
+			this.appIntf = rtpApp;
+			this.rtcpAppIntf = rtcpApp;
+			this.debugAppIntf = debugApp;
+
+			recvThrd = new RTPReceiverThread(this);
+			appCallerThrd = new AppCallerThread(this, rtpApp);
+			//recvThrd.start();
+			//appCallerThrd.start();
+			//rtcpSession.start();
+			return 0;
+		}
+	}
+
+	public AppCallerThread getAppCallerThrd() {
+		return appCallerThrd;
+	}
+
+	public RTPReceiverThread getRTPRecvThrd() {
+		return recvThrd;
+	}
+
+	/**
+	 * Send data to all participants registered as receivers, using the current
+	 * timeStamp, dynamic sequence number and the current payload type specified
+	 * for the session.
+	 * 
+	 * @param buf
+	 *            A buffer of bytes, less than 1496 bytes
+	 * @return null if there was a problem, {RTP Timestamp, Sequence number}
+	 *         otherwise
+	 */
+	public long[] sendData(byte[] buf) {
+		byte[][] tmp = { buf };
+		long[][] ret = this.sendData(tmp, null, null, -1, null);
+
+		if (ret != null)
+			return ret[0];
+
+		return null;
+	}
+
+	/**
+	 * Send data to all participants registered as receivers, using the
+	 * specified timeStamp, sequence number and the current payload type
+	 * specified for the session.
+	 * 
+	 * @param buf
+	 *            A buffer of bytes, less than 1496 bytes
+	 * @param rtpTimestamp
+	 *            the RTP timestamp to be used in the packet
+	 * @param seqNum
+	 *            the sequence number to be used in the packet
+	 * @return null if there was a problem, {RTP Timestamp, Sequence number}
+	 *         otherwise
+	 */
+	public long[] sendData(byte[] buf, long rtpTimestamp, long seqNum) {
+		byte[][] tmp = { buf };
+		long[][] ret = this.sendData(tmp, null, null, -1, null);
+
+		if (ret != null)
+			return ret[0];
+
+		return null;
+	}
+
+	/**
+	 * Send data to all participants registered as receivers, using the current
+	 * timeStamp and payload type. The RTP timestamp will be the same for all
+	 * the packets.
+	 * 
+	 * @param buffers
+	 *            A buffer of bytes, should not bed padded and less than 1500
+	 *            bytes on most networks.
+	 * @param csrcArray
+	 *            an array with the SSRCs of contributing sources
+	 * @param markers
+	 *            An array indicating what packets should be marked. Rarely
+	 *            anything but the first one
+	 * @param rtpTimestamp
+	 *            The RTP timestamp to be applied to all packets
+	 * @param seqNumbers
+	 *            An array with the sequence number associated with each byte[]
+	 * @return null if there was a problem sending the packets, 2-dim array with
+	 *         {RTP Timestamp, Sequence number}
+	 */
+	public long[][] sendData(byte[][] buffers, long[] csrcArray,
+			boolean[] markers, long rtpTimestamp, long[] seqNumbers) {
+		if (RTPSession.rtpDebugLevel > 5) {
+			System.out.println("-> RTPSession.sendData(byte[])");
+		}
+
+		// Same RTP timestamp for all
+		if (rtpTimestamp < 0)
+			rtpTimestamp = System.currentTimeMillis();
+
+		// Return values
+		long[][] ret = new long[buffers.length][2];
+
+		for (int i = 0; i < buffers.length; i++) {
+			byte[] buf = buffers[i];
+
+			boolean marker = false;
+			if (markers != null)
+				marker = markers[i];
+
+			if (buf.length > 1500) {
+				System.out
+				.println("RTPSession.sendData() called with buffer exceeding 1500 bytes ("
+						+ buf.length + ")");
+			}
+
+			// Get the return values
+			ret[i][0] = rtpTimestamp;
+			if (seqNumbers == null) {
+				ret[i][1] = getNextSeqNum();
+			} else {
+				ret[i][1] = seqNumbers[i];
+			}
+			// Create a new RTP Packet
+			RtpPkt pkt = RtpPktPool.getInstance().borrowPkt();
+			pkt.initPacket(rtpTimestamp, this.ssrc, (int) ret[i][1],
+					this.payloadType, buf);
+
+			if (csrcArray != null)
+				pkt.setCsrcs(csrcArray);
+
+			pkt.setMarked(marker);
+
+			// Creates a raw packet
+			byte[] pktBytes = pkt.encode();
+
+			// System.out.println(Integer.toString(StaticProcs.bytesToUIntInt(pktBytes,
+			// 2)));
+
+			// Pre-flight check, are resolving an SSRC conflict?
+			if (this.conflict) {
+				System.out
+				.println("RTPSession.sendData() called while trying to resolve conflict.");
+				return null;
+			}
+
+			if (this.mcSession) {
+				DatagramPacket packet = null;
+
+				try {
+					packet = new DatagramPacket(pktBytes, pktBytes.length,
+							this.mcGroup, this.rtpMCSock.getPort());
+				} catch (Exception e) {
+					System.out
+					.println("RTPSession.sendData() packet creation failed.");
+					e.printStackTrace();
+					return null;
+				}
+
+				try {
+					rtpMCSock.send(packet);
+					// Debug
+					if (this.debugAppIntf != null) {
+						this.debugAppIntf.packetSent(1,
+								(InetSocketAddress) packet.getSocketAddress(),
+								new String("Sent multicast RTP packet of size "
+										+ packet.getLength()
+										+ " to "
+										+ packet.getSocketAddress().toString()
+										+ " via "
+										+ rtpMCSock.getLocalSocketAddress()
+										.toString()));
+					}
+				} catch (Exception e) {
+					System.out
+					.println("RTPSession.sendData() multicast failed.");
+					e.printStackTrace();
+					return null;
+				}
+
+			} else {
+				// Loop over recipients
+				Iterator<Participant> iter = partDb.getUnicastReceivers();
+				while (iter.hasNext()) {
+					InetSocketAddress receiver = iter.next().rtpAddress;
+					DatagramPacket packet = null;
+
+					if (RTPSession.rtpDebugLevel > 15) {
+						System.out.println("   Sending to "
+								+ receiver.toString());
+					}
+
+					try {
+						packet = new DatagramPacket(pktBytes, pktBytes.length,
+								receiver);
+					} catch (Exception e) {
+						System.out
+						.println("RTPSession.sendData() packet creation failed.");
+						e.printStackTrace();
+						return null;
+					}
+
+					// Actually send the packet
+					try {
+						rtpSock.send(packet);
+						// Debug
+						if (this.debugAppIntf != null) {
+							this.debugAppIntf
+							.packetSent(
+									0,
+									(InetSocketAddress) packet
+									.getSocketAddress(),
+									new String(
+											"Sent unicast RTP packet of size "
+											+ packet
+											.getLength()
+											+ " to "
+											+ packet
+											.getSocketAddress()
+											.toString()
+											+ " via "
+											+ rtpSock
+											.getLocalSocketAddress()
+											.toString()));
+						}
+					} catch (Exception e) {
+						System.out
+						.println("RTPSession.sendData() unicast failed.");
+						e.printStackTrace();
+						return null;
+					}
+				}
+			}
+
+			// Update our stats
+			this.sentPktCount++;
+			this.sentOctetCount++;
+
+			if (RTPSession.rtpDebugLevel > 5) {
+				System.out.println("<- RTPSession.sendData(byte[]) "
+						+ pkt.getSeqNumber());
+			}
+		}
+
+		return ret;
+	}
+
+	public void sendData(DatagramPacket packet, RtpPkt pkt) {
+		if (RTPSession.rtpDebugLevel > 5) {
+			System.out.println("-> RTPSession.sendData(byte[])");
+		}
+
+		pkt.setTimeStamp(System.currentTimeMillis());
+		pkt.setSsrc(ssrc);
+		pkt.setSeqNumber(getNextSeqNum());
+
+		// Creates a raw packet
+		pkt.writeHeader();
+
+		// Pre-flight check, are resolving an SSRC conflict?
+		if (this.conflict) {
+			System.out
+			.println("RTPSession.sendData() called while trying to resolve conflict.");
+			return;
+		}
+
+		if (this.mcSession) {
+			try {
+				packet.setPort(this.rtpMCSock.getPort());
+				packet.setAddress(this.mcGroup);
+			} catch (Exception e) {
+				System.out
+				.println("RTPSession.sendData() packet creation failed.");
+				e.printStackTrace();
+				return;
+			}
+			try {
+				rtpMCSock.send(packet);
+				// Debug
+				if (this.debugAppIntf != null) {
+					this.debugAppIntf.packetSent(1,
+							(InetSocketAddress) packet.getSocketAddress(),
+							new String("Sent multicast RTP packet of size "
+									+ packet.getLength()
+									+ " to "
+									+ packet.getSocketAddress().toString()
+									+ " via "
+									+ rtpMCSock.getLocalSocketAddress()
+									.toString()));
+				}
+			} catch (Exception e) {
+				System.out
+				.println("RTPSession.sendData() multicast failed.");
+				e.printStackTrace();
+				return;
+			}
+
+		} else {
+			try {
+				packet.setSocketAddress(firstPart.rtpAddress);
+			} catch (Exception e) {
+				System.out
+				.println("RTPSession.sendData() packet creation failed.");
+				e.printStackTrace();
+				return;
+			}
+
+			// Actually send the packet
+			try {
+				
+				rtpSock.send(packet);
+				//Log.d("RTP", "packet");
+				// Debug
+				if (this.debugAppIntf != null) {
+					this.debugAppIntf
+					.packetSent(
+							0,
+							(InetSocketAddress) packet
+							.getSocketAddress(),
+							new String(
+									"Sent unicast RTP packet of size "
+									+ packet
+									.getLength()
+									+ " to "
+									+ packet
+									.getSocketAddress()
+									.toString()
+									+ " via "
+									+ rtpSock
+									.getLocalSocketAddress()
+									.toString()));
+				}
+			} catch (Exception e) {
+				System.out
+				.println("RTPSession.sendData() unicast failed.");
+				e.printStackTrace();
+				return;
+			}
+		}
+
+		// Update our stats
+		this.sentPktCount++;
+		this.sentOctetCount++;
+		if (RTPSession.rtpDebugLevel > 5) {
+			System.out.println("<- RTPSession.sendData(byte[]) "
+					+ pkt.getSeqNumber());
+		}
+	}
+
+	/**
+	 * Send RTCP App packet to receiver specified by ssrc
+	 * 
+	 * 
+	 * 
+	 * Return values: 0 okay -1 no RTCP session established -2 name is not
+	 * byte[4]; -3 data is not byte[x], where x = 4*y for syme y -4 type is not
+	 * a 5 bit unsigned integer
+	 * 
+	 * Note that a return value of 0 does not guarantee delivery. The
+	 * participant must also exist in the participant database, otherwise the
+	 * message will eventually be deleted.
+	 * 
+	 * @param ssrc
+	 *            of the participant you want to reach
+	 * @param type
+	 *            the RTCP App packet subtype, default 0
+	 * @param name
+	 *            the ASCII (in byte[4]) representation
+	 * @param data
+	 *            the data itself
+	 * @return 0 if okay, negative value otherwise (see above)
+	 */
+
+	public int sendRTCPAppPacket(long ssrc, int type, byte[] name, byte[] data) {
+		if (this.rtcpSession == null)
+			return -1;
+
+		if (name.length != 4)
+			return -2;
+
+		if (data.length % 4 != 0)
+			return -3;
+
+		if (type > 63 || type < 0)
+			return -4;
+
+		RtcpPktAPP pkt = new RtcpPktAPP(ssrc, type, name, data);
+		this.rtcpSession.addToAppQueue(ssrc, pkt);
+
+		return 0;
+	}
+
+	/**
+	 * Add a participant object to the participant database.
+	 * 
+	 * If packets have already been received from this user, we will try to
+	 * update the automatically inserted participant with the information
+	 * provided here.
+	 * 
+	 * @param p
+	 *            A participant.
+	 */
+	public int addParticipant(Participant p) {
+		// For now we make all participants added this way persistent
+		firstPart = p;
+		p.unexpected = false;
+		return this.partDb.addParticipant(0, p);
+	}
+
+	/**
+	 * Remove a participant from the database. All buffered packets will be
+	 * destroyed.
+	 * 
+	 * @param p
+	 *            A participant.
+	 */
+	public void removeParticipant(Participant p) {
+		partDb.removeParticipant(p);
+	}
+
+	public Iterator<Participant> getUnicastReceivers() {
+		return partDb.getUnicastReceivers();
+	}
+
+	public Enumeration<Participant> getParticipants() {
+		return partDb.getParticipants();
+	}
+
+	/**
+	 * End the RTP Session. This will halt all threads and send bye-messages to
+	 * other participants.
+	 * 
+	 * RTCP related threads may require several seconds to wake up and
+	 * terminate.
+	 */
+	public void endSession() {
+		this.endSession = true;
+
+		// No more RTP packets, please
+		if (this.mcSession) {
+			this.rtpMCSock.close();
+		} else {
+			this.rtpSock.close();
+		}
+
+		// Signal the thread that pushes data to application
+		this.pktBufLock.lock();
+		try {
+			this.pktBufDataReady.signalAll();
+		} finally {
+			this.pktBufLock.unlock();
+		}
+		// Interrupt what may be sleeping
+		//this.rtcpSession.senderThrd.interrupt();
+
+		// Give things a chance to cool down.
+		try {
+			Thread.sleep(50);
+		} catch (Exception e) {
+		}
+		;
+
+		this.appCallerThrd.interrupt();
+
+		// Give things a chance to cool down.
+		try {
+			Thread.sleep(50);
+		} catch (Exception e) {
+		}
+		;
+
+		if (this.rtcpSession != null) {
+			// No more RTP packets, please
+			if (this.mcSession) {
+				this.rtcpSession.rtcpMCSock.close();
+			} else {
+				this.rtcpSession.rtcpSock.close();
+			}
+		}
+		DatagramPool.removeInstance();
+		PktBufNodePool.removeInstance();
+		DataFramePool.removeInstance();
+		RtpPktPool.removeInstance();
+	}
+
+	/**
+	 * Check whether this session is ending.
+	 * 
+	 * @return true if session and associated threads are terminating.
+	 */
+	boolean isEnding() {
+		return this.endSession;
+	}
+
+	/**
+	 * Overrides CNAME, used for outgoing RTCP packets.
+	 * 
+	 * @param cname
+	 *            a string, e.g. username@hostname. Must be unique for session.
+	 */
+	public void CNAME(String cname) {
+		this.cname = cname;
+	}
+
+	/**
+	 * Get the current CNAME, used for outgoing SDES packets
+	 */
+	public String CNAME() {
+		return this.cname;
+	}
+
+	public long getSsrc() {
+		return this.ssrc;
+	}
+
+	private void generateCNAME() {
+		String hostname;
+
+		if (this.mcSession) {
+			hostname = this.rtpMCSock.getLocalAddress().getCanonicalHostName();
+		} else {
+			hostname = this.rtpSock.getLocalAddress().getCanonicalHostName();
+		}
+
+		// if(hostname.equals("0.0.0.0") && System.getenv("HOSTNAME") != null) {
+		// hostname = System.getenv("HOSTNAME");
+		// }
+
+		cname = System.getProperty("user.name") + "@" + hostname;
+	}
+
+	/**
+	 * Change the RTP socket of the session. Peers must be notified through SIP
+	 * or other signalling protocol. Only valid if this is a unicast session to
+	 * begin with.
+	 * 
+	 * @param newSock
+	 *            integer for new port number, check it is free first.
+	 */
+	public int updateRTPSock(DatagramSocket newSock) {
+		if (!mcSession) {
+			rtpSock = newSock;
+			return 0;
+		} else {
+			System.out.println("Can't switch from multicast to unicast.");
+			return -1;
+		}
+	}
+
+	/**
+	 * Change the RTCP socket of the session. Peers must be notified through SIP
+	 * or other signalling protocol. Only valid if this is a unicast session to
+	 * begin with.
+	 * 
+	 * @param newSock
+	 *            the new unicast socket for RTP communication.
+	 */
+	public int updateRTCPSock(DatagramSocket newSock) {
+		if (!mcSession) {
+			this.rtcpSession.rtcpSock = newSock;
+			return 0;
+		} else {
+			System.out.println("Can't switch from multicast to unicast.");
+			return -1;
+		}
+	}
+
+	/**
+	 * Change the RTP multicast socket of the session. Peers must be notified
+	 * through SIP or other signalling protocol. Only valid if this is a
+	 * multicast session to begin with.
+	 * 
+	 * @param newSock
+	 *            the new multicast socket for RTP communication.
+	 */
+	public int updateRTPSock(MulticastSocket newSock) {
+		if (mcSession) {
+			this.rtpMCSock = newSock;
+			return 0;
+		} else {
+			System.out.println("Can't switch from unicast to multicast.");
+			return -1;
+		}
+	}
+
+	/**
+	 * Change the RTCP multicast socket of the session. Peers must be notified
+	 * through SIP or other signalling protocol. Only valid if this is a
+	 * multicast session to begin with.
+	 * 
+	 * @param newSock
+	 *            the new multicast socket for RTCP communication.
+	 */
+	public int updateRTCPSock(MulticastSocket newSock) {
+		if (mcSession) {
+			this.rtcpSession.rtcpMCSock = newSock;
+			return 0;
+		} else {
+			System.out.println("Can't switch from unicast to multicast.");
+			return -1;
+		}
+	}
+
+	/**
+	 * Update the payload type used for the session. It is represented as a 7
+	 * bit integer, whose meaning must be negotiated elsewhere (see IETF RFCs <a
+	 * href="http://www.ietf.org/rfc/rfc3550.txt">3550</a> and <a
+	 * href="http://www.ietf.org/rfc/rfc3550.txt">3551</a>)
+	 * 
+	 * @param payloadT
+	 *            an integer representing the payload type of any subsequent
+	 *            packets that are sent.
+	 */
+	public int payloadType(int payloadT) {
+		if (payloadT > 128 || payloadT < 0) {
+			return -1;
+		} else {
+			this.payloadType = payloadT;
+			return this.payloadType;
+		}
+	}
+
+	/**
+	 * Get the payload type that is currently used for outgoing RTP packets.
+	 * 
+	 * @return payload type as integer
+	 */
+	public int payloadType() {
+		return this.payloadType;
+	}
+
+	/**
+	 * Should packets from unknown participants be returned to the application?
+	 * This can be dangerous.
+	 * 
+	 * @param doAccept
+	 *            packets from participants not added by the application.
+	 */
+	public void naivePktReception(boolean doAccept) {
+		naiveReception = doAccept;
+	}
+
+	/**
+	 * Are packets from unknown participants returned to the application?
+	 * 
+	 * @return whether we accept packets from participants not added by the
+	 *         application.
+	 */
+	public boolean naivePktReception() {
+		return naiveReception;
+	}
+
+	/**
+	 * Set the number of RTP packets that should be buffered when a packet is
+	 * missing or received out of order. Setting this number high increases the
+	 * chance of correctly reordering packets, but increases latency when a
+	 * packet is dropped by the network.
+	 * 
+	 * Packets that arrive in order are not affected, they are passed straight
+	 * to the application.
+	 * 
+	 * The maximum delay is numberofPackets * packet rate , where the packet
+	 * rate depends on the codec and profile used by the sender.
+	 * 
+	 * Valid values: >0 - The maximum number of packets (based on RTP Timestamp)
+	 * that may accumulate 0 - All valid packets received in order will be given
+	 * to the application -1 - All valid packets will be given to the
+	 * application
+	 * 
+	 * @param behavior
+	 *            the be
+	 * @return the behavior set, unchanged in the case of a erroneous value
+	 */
+	public int packetBufferBehavior(int behavior) {
+		if (behavior > -2) {
+			this.pktBufBehavior = behavior;
+			// Signal the thread that pushes data to application
+			this.pktBufLock.lock();
+			try {
+				this.pktBufDataReady.signalAll();
+			} finally {
+				this.pktBufLock.unlock();
+			}
+			return this.pktBufBehavior;
+		} else {
+			return this.pktBufBehavior;
+		}
+	}
+
+	/**
+	 * The number of RTP packets that should be buffered when a packet is
+	 * missing or received out of order. A high number increases the chance of
+	 * correctly reordering packets, but increases latency when a packet is
+	 * dropped by the network.
+	 * 
+	 * A negative value disables the buffering, out of order packets will simply
+	 * be dropped.
+	 * 
+	 * @return the maximum number of packets that can accumulate before the
+	 *         first is returned
+	 */
+	public int packetBufferBehavior() {
+		return this.pktBufBehavior;
+	}
+
+	/**
+	 * Set whether the stack should operate in RFC 4585 mode.
+	 * 
+	 * This will automatically call adjustPacketBufferBehavior(-1), i.e. disable
+	 * all RTP packet buffering in jlibrtp, and disable frame reconstruction
+	 * 
+	 * @param rtcpAVPFIntf
+	 *            the in
+	 */
+	public int registerAVPFIntf(RTCPAVPFIntf rtcpAVPFIntf, int maxDelay,
+			int earlyThreshold, int regularThreshold) {
+		if (this.rtcpSession != null) {
+			this.packetBufferBehavior(-1);
+			this.frameReconstruction = false;
+			this.rtcpAVPFIntf = rtcpAVPFIntf;
+			this.fbEarlyThreshold = earlyThreshold;
+			this.fbRegularThreshold = regularThreshold;
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+
+	/**
+	 * Unregisters the RTCP AVPF interface, thereby going from RFC 4585 mode to
+	 * RFC 3550
+	 * 
+	 * You still have to adjust packetBufferBehavior() and frameReconstruction.
+	 * 
+	 */
+	public void unregisterAVPFIntf() {
+		this.fbEarlyThreshold = -1;
+		this.fbRegularThreshold = -1;
+		this.rtcpAVPFIntf = null;
+	}
+
+	/**
+	 * Enable / disable frame reconstruction in the packet buffers. This is only
+	 * relevant if getPacketBufferBehavior > 0;
+	 * 
+	 * Default is true.
+	 */
+	public void frameReconstruction(boolean toggle) {
+		this.frameReconstruction = toggle;
+	}
+
+	/**
+	 * Whether the packet buffer will attempt to reconstruct packet
+	 * automatically.
+	 * 
+	 * @return the status
+	 */
+	public boolean frameReconstruction() {
+		return this.frameReconstruction;
+	}
+
+	/**
+	 * The bandwidth currently allocated to the session, in bytes per second.
+	 * The default is 8000.
+	 * 
+	 * This value is not enforced and currently only used to calculate the RTCP
+	 * interval to ensure the control messages do not exceed 5% of the total
+	 * bandwidth described here.
+	 * 
+	 * Since the actual value may change a conservative estimate should be used
+	 * to avoid RTCP flooding.
+	 * 
+	 * see rtcpBandwidth(void)
+	 * 
+	 * @return current bandwidth setting
+	 */
+	public int sessionBandwidth() {
+		return this.bandwidth;
+	}
+
+	/**
+	 * Set the bandwidth of the session.
+	 * 
+	 * See sessionBandwidth(void) for details.
+	 * 
+	 * @param bandwidth
+	 *            the new value requested, in bytes per second
+	 * @return the actual value set
+	 */
+	public int sessionBandwidth(int bandwidth) {
+		if (bandwidth < 1) {
+			this.bandwidth = 8000;
+		} else {
+			this.bandwidth = bandwidth;
+		}
+		return this.bandwidth;
+	}
+
+	/**
+	 * RFC 3550 dictates that 5% of the total bandwidth, as set by
+	 * sessionBandwidth, should be dedicated to RTCP traffic. This
+	 * 
+	 * This should normally not be done, but is permissible in conjunction with
+	 * feedback (RFC 4585) and possibly other profiles.
+	 * 
+	 * Also see sessionBandwidth(void)
+	 * 
+	 * @return current RTCP bandwidth setting, -1 means not in use
+	 */
+	public int rtcpBandwidth() {
+		return this.rtcpBandwidth;
+	}
+
+	/**
+	 * Set the RTCP bandwidth, see rtcpBandwidth(void) for details.
+	 * 
+	 * This function must be
+	 * 
+	 * @param bandwidth
+	 *            the new value requested, in bytes per second or -1 to disable
+	 * @return the actual value set
+	 */
+	public int rtcpBandwidth(int bandwidth) {
+		if (bandwidth < -1) {
+			this.rtcpBandwidth = -1;
+		} else {
+			this.rtcpBandwidth = bandwidth;
+		}
+		return this.rtcpBandwidth;
+	}
+
+	/********************************************* Feedback message stuff ***************************************/
+
+	/**
+	 * Adds a Picture Loss Indication to the feedback queue
+	 * 
+	 * @param ssrcMediaSource
+	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
+	 */
+	public int fbPictureLossIndication(long ssrcMediaSource) {
+		int ret = 0;
+
+		if (this.rtcpAVPFIntf == null)
+			return -1;
+
+		RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource);
+		pkt.makePictureLossIndication();
+		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
+		if (ret == 0)
+			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
+		return ret;
+	}
+
+	/**
+	 * Adds a Slice Loss Indication to the feedback queue
+	 * 
+	 * @param ssrcMediaSource
+	 * @param sliFirst
+	 *            macroblock (MB) address of the first lost macroblock
+	 * @param sliNumber
+	 *            number of lost macroblocks
+	 * @param sliPictureId
+	 *            six least significant bits of the codec-specific identif
+	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
+	 */
+	public int fbSlicLossIndication(long ssrcMediaSource, int[] sliFirst,
+			int[] sliNumber, int[] sliPictureId) {
+		int ret = 0;
+		if (this.rtcpAVPFIntf == null)
+			return -1;
+
+		RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource);
+		pkt.makeSliceLossIndication(sliFirst, sliNumber, sliPictureId);
+
+		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
+		if (ret == 0)
+			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
+		return ret;
+	}
+
+	/**
+	 * Adds a Reference Picture Selection Indication to the feedback queue
+	 * 
+	 * @param ssrcMediaSource
+	 * @param bitPadding
+	 *            number of padded bits at end of bitString
+	 * @param payloadType
+	 *            RTP payload type for codec
+	 * @param bitString
+	 *            RPSI information as natively defined by the video codec
+	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
+	 */
+	public int fbRefPictureSelIndic(long ssrcMediaSource, int bitPadding,
+			int payloadType, byte[] bitString) {
+		int ret = 0;
+
+		if (this.rtcpAVPFIntf == null)
+			return -1;
+
+		RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource);
+		pkt.makeRefPictureSelIndic(bitPadding, payloadType, bitString);
+		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
+		if (ret == 0)
+			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
+		return ret;
+	}
+
+	/**
+	 * Adds a Picture Loss Indication to the feedback queue
+	 * 
+	 * @param ssrcMediaSource
+	 * @param bitString
+	 *            the original application message
+	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
+	 */
+	public int fbAppLayerFeedback(long ssrcMediaSource, byte[] bitString) {
+		int ret = 0;
+
+		if (this.rtcpAVPFIntf == null)
+			return -1;
+
+		RtcpPktPSFB pkt = new RtcpPktPSFB(this.ssrc, ssrcMediaSource);
+		pkt.makeAppLayerFeedback(bitString);
+		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
+		if (ret == 0)
+			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
+		return ret;
+	}
+
+	/**
+	 * Adds a RTP Feedback packet to the feedback queue.
+	 * 
+	 * These are mostly used for NACKs.
+	 * 
+	 * @param ssrcMediaSource
+	 * @param FMT
+	 *            the Feedback Message Subtype
+	 * @param PID
+	 *            RTP sequence numbers of lost packets
+	 * @param BLP
+	 *            bitmask of following lost packets, shared index with PID
+	 * @return 0 if packet was queued, -1 if no feedback support, 1 if redundant
+	 */
+	public int fbPictureLossIndication(long ssrcMediaSource, int FMT,
+			int[] PID, int[] BLP) {
+		int ret = 0;
+
+		if (this.rtcpAVPFIntf == null)
+			return -1;
+
+		RtcpPktRTPFB pkt = new RtcpPktRTPFB(this.ssrc, ssrcMediaSource, FMT,
+				PID, BLP);
+		ret = this.rtcpSession.addToFbQueue(ssrcMediaSource, pkt);
+		if (ret == 0)
+			this.rtcpSession.wakeSenderThread(ssrcMediaSource);
+		return ret;
+	}
+
+	/**
+	 * Fetches the next sequence number for RTP packets.
+	 * 
+	 * @return the next sequence number
+	 */
+	private int getNextSeqNum() {
+		seqNum++;
+		// 16 bit number
+		if (seqNum > 65536) {
+			seqNum = 0;
+		}
+		return seqNum;
+	}
+
+	/**
+	 * Initializes a random variable
+	 * 
+	 */
+	private void createRandom() {
+		this.random = new Random(System.currentTimeMillis()
+				+ Thread.currentThread().getId()
+				- Thread.currentThread().hashCode() + this.cname.hashCode());
+	}
+
+	/**
+	 * Generates a random sequence number
+	 */
+	private void generateSeqNum() {
+		if (this.random == null)
+			createRandom();
+
+		seqNum = this.random.nextInt();
+		if (seqNum < 0)
+			seqNum = -seqNum;
+		while (seqNum > 65535) {
+			seqNum = seqNum / 10;
+		}
+	}
+
+	/**
+	 * Generates a random SSRC
+	 */
+	private void generateSsrc() {
+		if (this.random == null)
+			createRandom();
+
+		// Set an SSRC
+		this.ssrc = this.random.nextInt();
+		if (this.ssrc < 0) {
+			this.ssrc = this.ssrc * -1;
+		}
+	}
+
+	/**
+	 * Resolve an SSRC conflict.
+	 * 
+	 * Also increments the SSRC conflict counter, after 5 conflicts it is
+	 * assumed there is a loop somewhere and the session will terminate.
+	 * 
+	 */
+	protected void resolveSsrcConflict() {
+		System.out
+		.println("!!!!!!! Beginning SSRC conflict resolution !!!!!!!!!");
+		this.conflictCount++;
+
+		if (this.conflictCount < 5) {
+			// Don't send any more regular packets out until we have this sorted
+			// out.
+			this.conflict = true;
+
+			// Send byes
+			rtcpSession.sendByes();
+
+			// Calculate the next delay
+			rtcpSession.calculateDelay();
+
+			// Generate a new Ssrc for ourselves
+			generateSsrc();
+
+			// Get the SDES packets out faster
+			rtcpSession.initial = true;
+
+			this.conflict = false;
+			System.out.println("SSRC conflict resolution complete");
+
+		} else {
+			System.out
+			.println("Too many conflicts. There is probably a loop in the network.");
+			this.endSession();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPkt.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,143 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.InetAddress;
+
+/**
+ * Common RTCP packet headers.
+ * 
+ * @author Arne Kepp
+ */
+public class RtcpPkt {
+	/** Whether a problem has been encountered during parsing */
+	protected int problem = 0;
+	/** The version, always 2, 2 bits */
+	protected int version = 2;
+	/** Padding , 1 bit */
+	protected int padding = 0;
+	/** Number of items, e.g. receiver report blocks. Usage may vary. 5 bits */
+	protected int itemCount = 0;
+	/** The type of RTCP packet, 8 bits */
+	protected int packetType = -1;
+	/** The length of the RTCP packet, in 32 bit blocks minus 1. 16 bits */
+	protected int length = -1;
+	/** The ssrc that sent this, usually dictated by RTP Session */
+	protected long ssrc = -1;
+
+	/** Contains the actual data (eventually) */
+	protected byte[] rawPkt = null;
+
+	/** Only used for feedback messages: Time message was generated */
+	protected long time = -1;
+	/** Only used for feedback message: Whether this packet was received */
+	protected boolean received = false;
+
+	/**
+	 * Parses the common header of an RTCP packet
+	 * 
+	 * @param start
+	 *            where in this.rawPkt the headers start
+	 * @return true if parsing succeeded and header cheks
+	 */
+	protected boolean parseHeaders(int start) {
+		version = ((rawPkt[start + 0] & 0xC0) >>> 6);
+		padding = ((rawPkt[start + 0] & 0x20) >>> 5);
+		itemCount = (rawPkt[start + 0] & 0x1F);
+		packetType = (int) rawPkt[start + 1];
+		if (packetType < 0) {
+			packetType += 256;
+		}
+		length = StaticProcs.bytesToUIntInt(rawPkt, start + 2);
+
+		if (RTPSession.rtpDebugLevel > 9) {
+			System.out.println(" <-> RtcpPkt.parseHeaders() version:" + version
+					+ " padding:" + padding + " itemCount:" + itemCount
+					+ " packetType:" + packetType + " length:" + length);
+		}
+
+		if (packetType > 207 || packetType < 200)
+			System.out
+					.println("RtcpPkt.parseHeaders problem discovered, packetType "
+							+ packetType);
+
+		if (version == 2 && length < 65536) {
+			return true;
+		} else {
+			System.out
+					.println("RtcpPkt.parseHeaders() failed header checks, check size and version");
+			this.problem = -1;
+			return false;
+		}
+	}
+
+	/**
+	 * Writes the common header of RTCP packets. The values should be filled in
+	 * when the packet is initiliazed and this function called at the very end
+	 * of .encode()
+	 */
+	protected void writeHeaders() {
+		byte aByte = 0;
+		aByte |= (version << 6);
+		aByte |= (padding << 5);
+		aByte |= (itemCount);
+		rawPkt[0] = aByte;
+		aByte = 0;
+		aByte |= packetType;
+		rawPkt[1] = aByte;
+		if (rawPkt.length % 4 != 0)
+			System.out
+					.println("!!!! RtcpPkt.writeHeaders() rawPkt was not a multiple of 32 bits / 4 octets!");
+		StaticProcs.uIntIntToByteWord((rawPkt.length / 4) - 1, rawPkt, 2);
+	}
+
+	/**
+	 * This is just a dummy to make Eclipse complain less.
+	 */
+	protected void encode() {
+		System.out.println("RtcpPkt.encode() should never be invoked!! "
+				+ this.packetType);
+	}
+
+	/**
+	 * Check whether this packet came from the source we expected.
+	 * 
+	 * Not currently used!
+	 * 
+	 * @param adr
+	 *            address that packet came from
+	 * @param partDb
+	 *            the participant database for the session
+	 * @return true if this packet came from the expected source
+	 */
+	protected boolean check(InetAddress adr, ParticipantDatabase partDb) {
+		// Multicast -> We have to be naive
+		if (partDb.rtpSession.mcSession
+				&& adr.equals(partDb.rtpSession.mcGroup))
+			return true;
+
+		// See whether this participant is known
+		Participant part = partDb.getParticipant(this.ssrc);
+		if (part != null && part.rtcpAddress.getAddress().equals(adr))
+			return true;
+
+		// If not, we should look for someone without SSRC with his ip-address?
+		return false;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktAPP.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,101 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+/**
+ * Application specific RTCP packets
+ * 
+ * @author Arne Kepp
+ */
+public class RtcpPktAPP extends RtcpPkt {
+	/** Name of packet, 4 bytes ASCII */
+	protected byte[] pktName = null;
+	/** Data of packet */
+	protected byte[] pktData = null;
+
+	/**
+	 * Constructor for a new Application RTCP packet
+	 * 
+	 * @param ssrc
+	 *            the SSRC of the sender, presumably taken from RTPSession
+	 * @param subtype
+	 *            the subtype of packet, application specific
+	 * @param pktName
+	 *            byte[4] representing ASCII name of packet
+	 * @param pktData
+	 *            the byte[4x] data that represents the message itself
+	 */
+	protected RtcpPktAPP(long ssrc, int subtype, byte[] pktName, byte[] pktData) {
+		// Fetch all the right stuff from the database
+		super.ssrc = ssrc;
+		super.packetType = 204;
+		super.itemCount = subtype;
+		this.pktName = pktName;
+		this.pktData = pktData;
+	}
+
+	/**
+	 * Constructor that parses a received Application RTCP packet
+	 * 
+	 * @param aRawPkt
+	 *            the raw packet containing the date
+	 * @param start
+	 *            where in the raw packet this packet starts
+	 */
+	protected RtcpPktAPP(byte[] aRawPkt, int start) {
+		super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, 4);
+		super.rawPkt = aRawPkt;
+
+		if (!super.parseHeaders(start) || packetType != 204) {
+			if (RTPSession.rtpDebugLevel > 2) {
+				System.out
+						.println(" <-> RtcpPktAPP.parseHeaders() etc. problem");
+			}
+			super.problem = -204;
+		} else {
+			// System.out.println("super.length:  " + super.length);
+			if (super.length > 1) {
+				pktName = new byte[4];
+				System.arraycopy(aRawPkt, 8, pktName, 0, 4);
+			}
+			if (super.length > 2) {
+				pktData = new byte[(super.length + 1) * 4 - 12];
+				System.arraycopy(aRawPkt, 12, pktData, 0, pktData.length);
+			}
+		}
+	}
+
+	/**
+	 * Encode the packet into a byte[], saved in .rawPkt
+	 * 
+	 * CompRtcpPkt will call this automatically
+	 */
+	protected void encode() {
+		super.rawPkt = new byte[12 + this.pktData.length];
+		byte[] tmp = StaticProcs.uIntLongToByteWord(super.ssrc);
+		System.arraycopy(tmp, 0, super.rawPkt, 4, 4);
+		System.arraycopy(this.pktName, 0, super.rawPkt, 8, 4);
+		System
+				.arraycopy(this.pktData, 0, super.rawPkt, 12,
+						this.pktData.length);
+		writeHeaders();
+		// System.out.println("ENCODE: " + super.length + " " + rawPkt.length +
+		// " " + pktData.length);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktBYE.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,115 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+/**
+ * RTCP packets for sending Bye messages
+ * 
+ * @author Arne Kepp
+ */
+public class RtcpPktBYE extends RtcpPkt {
+	/** SSRCs saying bye, 32xn bits, n<16 */
+	protected long[] ssrcArray = null;
+	/** Optional reason */
+	protected byte[] reason = null;
+
+	protected RtcpPktBYE(long[] ssrcs, byte[] aReason) {
+		super.packetType = 203;
+		// Fetch all the right stuff from the database
+		reason = aReason;
+		ssrcArray = ssrcs;
+		if (ssrcs.length < 1) {
+			System.out
+					.println("RtcpBYE.RtcpPktBYE(long[] ssrcs, byte[] aReason) requires at least one SSRC!");
+		}
+	}
+
+	protected RtcpPktBYE(byte[] aRawPkt, int start) {
+		rawPkt = aRawPkt;
+		if (!super.parseHeaders(start) || packetType != 203) {
+			if (RTPSession.rtpDebugLevel > 2) {
+				System.out
+						.println(" <-> RtcpPktBYE.parseHeaders() etc. problem");
+			}
+			super.problem = -203;
+		} else {
+			ssrcArray = new long[super.itemCount];
+
+			for (int i = 0; i < super.itemCount; i++) {
+				ssrcArray[i] = StaticProcs.bytesToUIntLong(aRawPkt, start
+						+ (i + 1) * 4);
+			}
+			if (super.length > (super.itemCount + 1)) {
+				int reasonLength = (int) aRawPkt[start + (super.itemCount + 1)
+						* 4];
+				// System.out.println("super.itemCount:"+super.itemCount+" reasonLength:"+reasonLength+" start:"+(super.itemCount*4
+				// + 4 + 1));
+				reason = new byte[reasonLength];
+				System.arraycopy(aRawPkt,
+						start + (super.itemCount + 1) * 4 + 1, reason, 0,
+						reasonLength);
+				// System.out.println("test:" + new String(reason));
+			}
+		}
+	}
+
+	protected void encode() {
+		itemCount = ssrcArray.length;
+		length = 4 * ssrcArray.length;
+
+		if (reason != null) {
+			length += (reason.length + 1) / 4;
+			if ((reason.length + 1) % 4 != 0) {
+				length += 1;
+			}
+		}
+		rawPkt = new byte[length * 4 + 4];
+
+		int i;
+		byte[] someBytes;
+
+		// SSRCs
+		for (i = 0; i < ssrcArray.length; i++) {
+			someBytes = StaticProcs.uIntLongToByteWord(ssrcArray[i]);
+			System.arraycopy(someBytes, 0, rawPkt, 4 + 4 * i, 4);
+		}
+
+		// Reason for leaving
+		if (reason != null) {
+			// System.out.println("Writing to:"+(4+4*ssrcArray.length)+
+			// " reason.length:"+reason.length );
+			rawPkt[(4 + 4 * ssrcArray.length)] = (byte) reason.length;
+			System.arraycopy(reason, 0, rawPkt, 4 + 4 * i + 1, reason.length);
+		}
+		super.writeHeaders();
+	}
+
+	public void debugPrint() {
+		System.out.println("RtcpPktBYE.debugPrint() ");
+		if (ssrcArray != null) {
+			for (int i = 0; i < ssrcArray.length; i++) {
+				long anSsrc = ssrcArray[i];
+				System.out.println("     ssrc: " + anSsrc);
+			}
+		}
+		if (reason != null) {
+			System.out.println("     Reason: " + new String(reason));
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktPSFB.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,411 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+/**
+ * RTCP packets for Payload-Specific Feedback Messages
+ * 
+ * @author Arne Kepp
+ */
+public class RtcpPktPSFB extends RtcpPkt {
+	/** If this packet was for a different SSRC */
+	protected boolean notRelevant = false;
+	/** Parent RTP Session */
+	private RTPSession rtpSession;
+	/** SSRC we are sending feeback to */
+	protected long ssrcMediaSource = -1;
+
+	/** SLI macroblock (MB) address of the first lost macroblock number */
+	protected int[] sliFirst;
+	/** SLI number of lost macroblocks */
+	protected int[] sliNumber;
+	/** SLI six least significant bits of the codec-specific identifier */
+	protected int[] sliPictureId;
+
+	// Picture loss indication
+	/** RPSI number of padded bits at end of bitString */
+	protected int rpsiPadding = -1;
+	/** RPSI payloadType RTP payload type */
+	protected int rpsiPayloadType = -1;
+	/** RPSI information as natively defined by the video codec */
+	protected byte[] rpsiBitString;
+
+	/** Application Layer Feedback Message */
+	protected byte[] alfBitString;
+
+	/**
+	 * Generic constructor, then call make<something>
+	 * 
+	 * @param ssrcPacketSender
+	 * @param ssrcMediaSource
+	 */
+	protected RtcpPktPSFB(long ssrcPacketSender, long ssrcMediaSource) {
+		super.ssrc = ssrcPacketSender;
+		this.ssrcMediaSource = ssrcMediaSource;
+		super.packetType = 206; // PSFB
+	}
+
+	/**
+	 * Make this packet a Picture loss indication
+	 */
+	protected void makePictureLossIndication() {
+		super.itemCount = 1; // FMT
+	}
+
+	/**
+	 * Make this packet a Slice Loss Indication
+	 * 
+	 * @param sliFirst
+	 *            macroblock (MB) address of the first lost macroblock
+	 * @param sliNumber
+	 *            number of lost macroblocks
+	 * @param sliPictureId
+	 *            six least significant bits of the codec-specific identifier
+	 */
+	protected void makeSliceLossIndication(int[] sliFirst, int[] sliNumber,
+			int[] sliPictureId) {
+		super.itemCount = 2; // FMT
+		this.sliFirst = sliFirst;
+		this.sliNumber = sliNumber;
+		this.sliPictureId = sliPictureId;
+	}
+
+	/**
+	 * Make this packet a Reference Picture Selection Indication
+	 * 
+	 * @param bitPadding
+	 *            number of padded bits at end of bitString
+	 * @param payloadType
+	 *            RTP payload type for codec
+	 * @param bitString
+	 *            RPSI information as natively defined by the video codec
+	 */
+	protected void makeRefPictureSelIndic(int bitPadding, int payloadType,
+			byte[] bitString) {
+		super.itemCount = 3; // FMT
+		this.rpsiPadding = bitPadding;
+		this.rpsiPayloadType = payloadType;
+		this.rpsiBitString = bitString;
+	}
+
+	/**
+	 * Make this packet an Application specific feedback message
+	 * 
+	 * @param bitString
+	 *            the original application message
+	 */
+	protected void makeAppLayerFeedback(byte[] bitString) {
+		super.itemCount = 15; // FMT
+		this.alfBitString = bitString;
+	}
+
+	/**
+	 * Constructor that parses a raw packet to retrieve information
+	 * 
+	 * @param aRawPkt
+	 *            the raw packet to be parsed
+	 * @param start
+	 *            the start of the packet, in bytes
+	 * @param rtpSession
+	 *            the session on which the callback interface resides
+	 */
+	protected RtcpPktPSFB(byte[] aRawPkt, int start, RTPSession rtpSession) {
+		if (RTPSession.rtpDebugLevel > 8) {
+			System.out.println("  -> RtcpPktPSFB(byte[], int start)");
+		}
+		this.rtpSession = rtpSession;
+
+		rawPkt = aRawPkt;
+
+		if (!super.parseHeaders(start) || packetType != 206 || super.length < 2) {
+			if (RTPSession.rtpDebugLevel > 2) {
+				System.out
+						.println(" <-> RtcpPktRTPFB.parseHeaders() etc. problem");
+			}
+			super.problem = -206;
+		} else {
+			// FMT = super.itemCount;
+			ssrcMediaSource = StaticProcs.bytesToUIntLong(aRawPkt, 8 + start);
+
+			if (ssrcMediaSource == rtpSession.ssrc) {
+				super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, 4 + start);
+
+				switch (super.itemCount) {
+				case 1: // Picture Loss Indication
+					decPictureLossIndic();
+					break;
+				case 2: // Slice Loss Indication
+					decSliceLossIndic(aRawPkt, start + 12);
+					break;
+				case 3: // Reference Picture Selection Indication
+					decRefPictureSelIndic(aRawPkt, start + 12);
+					break;
+				case 15: // Application Layer Feedback Messages
+					decAppLayerFB(aRawPkt, start + 12);
+					break;
+				default:
+					System.out
+							.println("!!!! RtcpPktPSFB(byte[], int start) unexpected FMT "
+									+ super.itemCount);
+				}
+			} else {
+				this.notRelevant = true;
+			}
+		}
+		if (RTPSession.rtpDebugLevel > 8) {
+			System.out.println("  <- RtcpPktPSFB()");
+		}
+	}
+
+	/**
+	 * Decode Picture Loss indication
+	 * 
+	 */
+	private void decPictureLossIndic() {
+		if (this.rtpSession.rtcpAVPFIntf != null) {
+			this.rtpSession.rtcpAVPFIntf.PSFBPktPictureLossReceived(super.ssrc);
+		}
+	}
+
+	/**
+	 * Decode Slice Loss Indication
+	 * 
+	 * @param aRawPkt
+	 * @param start
+	 */
+	private void decSliceLossIndic(byte[] aRawPkt, int start) {
+		// 13 bit off-boundary numbers? That's rather cruel
+		// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+		// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+		// | First | Number | PictureID |
+		// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+		int count = super.length - 2;
+
+		sliFirst = new int[count];
+		sliNumber = new int[count];
+		sliPictureId = new int[count];
+
+		// Loop over the FCI lines
+		for (int i = 0; i < count; i++) {
+			sliFirst[i] = StaticProcs.bytesToUIntInt(aRawPkt, start) >> 3;
+			sliNumber[i] = (int) (StaticProcs.bytesToUIntInt(aRawPkt, start) & 0x0007FFC0) >> 6;
+			sliPictureId[i] = (StaticProcs.bytesToUIntInt(aRawPkt, start + 2) & 0x003F);
+			start += 4;
+		}
+
+		if (this.rtpSession.rtcpAVPFIntf != null) {
+			this.rtpSession.rtcpAVPFIntf.PSFBPktSliceLossIndic(super.ssrc,
+					sliFirst, sliNumber, sliPictureId);
+		}
+	}
+
+	/**
+	 * Decode Reference Picture Selection Indication
+	 * 
+	 * @param aRawPkt
+	 * @param start
+	 */
+	private void decRefPictureSelIndic(byte[] aRawPkt, int start) {
+		// 0 1 2 3
+		// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+		// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+		// | PB |0| Payload Type| Native RPSI bit string |
+		// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+		// | defined per codec ... | Padding (0) |
+		// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+		rpsiPadding = aRawPkt[start];
+
+		if (rpsiPadding > 32) {
+			System.out
+					.println("!!!! RtcpPktPSFB.decRefPictureSelcIndic paddingBits: "
+							+ rpsiPadding);
+		}
+
+		rpsiPayloadType = (int) rawPkt[start];
+		if (rpsiPayloadType < 0) {
+			System.out
+					.println("!!!! RtcpPktPSFB.decRefPictureSelcIndic 8th bit not zero: "
+							+ rpsiPayloadType);
+		}
+
+		rpsiBitString = new byte[(super.length - 2) * 4 - 2];
+		System.arraycopy(aRawPkt, start + 2, rpsiBitString, 0,
+				rpsiBitString.length);
+
+		if (this.rtpSession.rtcpAVPFIntf != null) {
+			this.rtpSession.rtcpAVPFIntf.PSFBPktRefPictureSelIndic(super.ssrc,
+					rpsiPayloadType, rpsiBitString, rpsiPadding);
+		}
+
+	}
+
+	/**
+	 * Decode Application specific feedback message
+	 * 
+	 * @param aRawPkt
+	 * @param start
+	 */
+	private void decAppLayerFB(byte[] aRawPkt, int start) {
+		// Application Message (FCI): variable length
+		int stringLength = (super.length - 2) * 4;
+
+		alfBitString = new byte[stringLength];
+
+		System.arraycopy(aRawPkt, start, alfBitString, 0, stringLength);
+
+		if (this.rtpSession.rtcpAVPFIntf != null) {
+			this.rtpSession.rtcpAVPFIntf.PSFBPktAppLayerFBReceived(super.ssrc,
+					alfBitString);
+		}
+	}
+
+	/**
+	 * Encode a Slice Loss Indication
+	 */
+	private void encSliceLossIndic() {
+		byte[] firstBytes;
+		byte[] numbBytes;
+		byte[] picBytes;
+
+		int offset = 8;
+		// Loop over the FCI lines
+		for (int i = 0; i < sliFirst.length; i++) {
+			offset = 8 + 8 * i;
+			firstBytes = StaticProcs.uIntLongToByteWord(sliFirst[i] << 3);
+			numbBytes = StaticProcs.uIntLongToByteWord(sliNumber[i] << 2);
+			picBytes = StaticProcs.uIntIntToByteWord(sliPictureId[i]);
+
+			super.rawPkt[offset] = firstBytes[2];
+			super.rawPkt[offset + 1] = (byte) (firstBytes[3] | numbBytes[2]);
+			super.rawPkt[offset + 2] = numbBytes[3];
+			super.rawPkt[offset + 3] = (byte) (numbBytes[3] | picBytes[1]);
+		}
+	}
+
+	/**
+	 * Encode a Reference Picture Selection Indication
+	 * 
+	 */
+	private void encRefPictureSelIndic() {
+		byte[] someBytes;
+		someBytes = StaticProcs.uIntIntToByteWord(rpsiPadding);
+		super.rawPkt[8] = someBytes[1];
+		someBytes = StaticProcs.uIntIntToByteWord(rpsiPayloadType);
+		super.rawPkt[9] = someBytes[1];
+
+		System.arraycopy(rpsiBitString, 0, super.rawPkt, 10,
+				rpsiBitString.length);
+	}
+
+	/**
+	 * Encode Application Layer Feedback
+	 * 
+	 */
+	private void encAppLayerFB() {
+		// Application Message (FCI): variable length
+		System.arraycopy(alfBitString, 0, super.rawPkt, 8, alfBitString.length);
+	}
+
+	/**
+	 * Get the FMT (Feedback Message Type)
+	 * 
+	 * @return value stored in .itemcount, same field
+	 */
+	protected int getFMT() {
+		return this.itemCount;
+	}
+
+	/**
+	 * Encode the packet into a byte[], saved in .rawPkt
+	 * 
+	 * CompRtcpPkt will call this automatically
+	 */
+	protected void encode() {
+		switch (super.itemCount) {
+		case 1: // Picture Loss Indication
+			// Nothing to do really
+			super.rawPkt = new byte[24];
+			break;
+		case 2: // Slice Loss Indication
+			super.rawPkt = new byte[24 + 4 * this.sliFirst.length];
+			encSliceLossIndic();
+			break;
+		case 3: // Reference Picture Selection Indication
+			super.rawPkt = new byte[24 + 2 + this.rpsiBitString.length / 4];
+			encRefPictureSelIndic();
+			break;
+		case 15: // Application Layer Feedback Messages
+			super.rawPkt = new byte[24 + this.alfBitString.length / 4];
+			encAppLayerFB();
+			break;
+		}
+
+		byte[] someBytes = StaticProcs.uIntLongToByteWord(super.ssrc);
+		System.arraycopy(someBytes, 0, super.rawPkt, 4, 4);
+		someBytes = StaticProcs.uIntLongToByteWord(this.ssrcMediaSource);
+		System.arraycopy(someBytes, 0, super.rawPkt, 8, 4);
+
+		writeHeaders();
+	}
+
+	/**
+	 * Debug purposes only
+	 */
+	public void debugPrint() {
+		System.out.println("->RtcpPktPSFB.debugPrint() ");
+
+		String str;
+		switch (super.itemCount) {
+		case 1: // Picture Loss Indication
+			System.out.println("  FMT: Picture Loss Indication");
+			break;
+		case 2: // Slice Loss Indication
+			if (sliFirst != null) {
+				str = "sliFirst[].length: " + sliFirst.length;
+			} else {
+				str = "sliFirst[] is null";
+			}
+			System.out.println("  FMT: Slice Loss Indication, " + str);
+			break;
+		case 3: // Reference Picture Selection Indication
+			if (rpsiBitString != null) {
+				str = "rpsiBitString[].length: " + rpsiBitString.length;
+			} else {
+				str = "rpsiBitString[] is null";
+			}
+			System.out
+					.println("  FMT: Reference Picture Selection Indication, "
+							+ str + " payloadType: " + this.rpsiPayloadType);
+			break;
+		case 15: // Application Layer Feedback Messages
+			if (alfBitString != null) {
+				str = "alfBitString[].length: " + alfBitString.length;
+			} else {
+				str = "alfBitString[] is null";
+			}
+			System.out.println("  FMT: Application Layer Feedback Messages, "
+					+ str);
+			break;
+		}
+
+		System.out.println("<-RtcpPktPSFB.debugPrint() ");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktRR.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,235 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+/**
+ * RTCP packets for Receiver Reports
+ * 
+ * @author Arne Kepp
+ */
+public class RtcpPktRR extends RtcpPkt {
+	/** Array of participants to send Receiver Reports to */
+	protected Participant[] reportees = null;
+	/** SSRC of participants the reports are for */
+	protected long[] reporteeSsrc = null;// -1; //32 bits
+	/** Fraction (over 256) of packets lost */
+	protected int[] lossFraction = null;// -1; //8 bits
+	/** Number of lost packets */
+	protected int[] lostPktCount = null;// -1; //24 bits
+	/** Extended highest sequence received */
+	protected long[] extHighSeqRecv = null;// -1; //32 bits
+	/** Interarrival jitter */
+	protected long[] interArvJitter = null;// -1; //32 bits
+	/** Middle 32 bits of NTP when last SR was received */
+	protected long[] timeStampLSR = null;// -1; //32 bits
+	/** Delay on last SRC */
+	protected long[] delaySR = null;// -1; //32 bits
+
+	/**
+	 * Constructor for a packet with receiver reports
+	 * 
+	 * @param reportees
+	 *            the participants on which to generate reports
+	 * @param ssrc
+	 *            the SSRC of the sender, from the RTPSession
+	 */
+	protected RtcpPktRR(Participant[] reportees, long ssrc) {
+		super.packetType = 201;
+		// Fetch all the right stuff from the database
+		super.ssrc = ssrc;
+		this.reportees = reportees;
+	}
+
+	/**
+	 * 
+	 * 
+	 * If rcount < 0 we assume we have to parse the entire packet, otherwise
+	 * we'll just parse the receiver report blocks (ie. the data came from a
+	 * Sender Report packet)
+	 * 
+	 * @param aRawPkt
+	 *            the byte[] with the report(s)
+	 * @param start
+	 *            where in the raw packet to start reading
+	 * @param rrCount
+	 *            the number of receiver reports, -1 if this does not come from
+	 *            an SR
+	 */
+	protected RtcpPktRR(byte[] aRawPkt, int start, int rrCount) {
+		// System.out.println("RtcpPktRR: " + rrCount + "  start: " + start);
+		super.rawPkt = aRawPkt;
+
+		if (rrCount < 0
+				&& (!super.parseHeaders(start) || packetType != 201 || super.length < 1)) {
+			if (RTPSession.rtpDebugLevel > 2) {
+				System.out
+						.println(" <-> RtcpPktRR.parseHeaders() etc. problem: "
+								+ (!super.parseHeaders(start)) + " "
+								+ packetType + " " + super.length);
+			}
+			super.problem = -201;
+		}
+
+		int base;
+		if (rrCount > 0) {
+			base = start + 28;
+		} else {
+			base = start + 8;
+			rrCount = super.itemCount;
+			super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, start + 4);
+		}
+
+		if (rrCount > 0) {
+			reporteeSsrc = new long[rrCount];
+			lossFraction = new int[rrCount];
+			lostPktCount = new int[rrCount];
+			extHighSeqRecv = new long[rrCount];
+			interArvJitter = new long[rrCount];
+			timeStampLSR = new long[rrCount];
+			delaySR = new long[rrCount];
+
+			for (int i = 0; i < rrCount; i++) {
+				int pos = base + i * 24;
+				reporteeSsrc[i] = StaticProcs.bytesToUIntLong(aRawPkt, pos);
+				lossFraction[i] = (int) aRawPkt[pos + 4];
+				aRawPkt[pos + 4] = (byte) 0;
+				lostPktCount[i] = (int) StaticProcs.bytesToUIntLong(aRawPkt,
+						pos + 4);
+				extHighSeqRecv[i] = StaticProcs.bytesToUIntLong(aRawPkt,
+						pos + 8);
+				interArvJitter[i] = StaticProcs.bytesToUIntLong(aRawPkt,
+						pos + 12);
+				timeStampLSR[i] = StaticProcs
+						.bytesToUIntLong(aRawPkt, pos + 16);
+				delaySR[i] = StaticProcs.bytesToUIntLong(aRawPkt, pos + 20);
+			}
+		}
+	}
+
+	/**
+	 * Encode the packet into a byte[], saved in .rawPkt
+	 * 
+	 * CompRtcpPkt will call this automatically
+	 */
+	protected void encode() {
+		if (RTPSession.rtpDebugLevel > 9) {
+			System.out.println("  -> RtcpPktRR.encode()");
+		}
+
+		byte[] rRs = null;
+		// Gather up the actual receiver reports
+		if (this.reportees != null) {
+			rRs = this.encodeRR();
+			super.rawPkt = new byte[rRs.length + 8];
+			System.arraycopy(rRs, 0, super.rawPkt, 8, rRs.length);
+			super.itemCount = reportees.length;
+		} else {
+			super.rawPkt = new byte[8];
+			super.itemCount = 0;
+		}
+
+		// Write the common header
+		super.writeHeaders();
+
+		// Add our SSRC (as sender)
+		StaticProcs.uIntLongToByteWord(super.ssrc, super.rawPkt, 4);
+
+		if (RTPSession.rtpDebugLevel > 9) {
+			System.out.println("  <- RtcpPktRR.encode()");
+		}
+
+	}
+
+	/**
+	 * Encodes the individual Receiver Report blocks,
+	 * 
+	 * so they can be used either in RR packets or appended to SR
+	 * 
+	 * @return the encoded packets
+	 */
+	protected byte[] encodeRR() {
+		if (RTPSession.rtpDebugLevel > 10) {
+			System.out.println("   -> RtcpPktRR.encodeRR()");
+		}
+		// assuming we will always create complete reports:
+		byte[] ret = new byte[24 * reportees.length];
+
+		// Write SR stuff
+		for (int i = 0; i < reportees.length; i++) {
+			int offset = 24 * i;
+			StaticProcs.uIntLongToByteWord(reportees[i].ssrc, ret, offset);
+
+			// Cumulative number of packets lost
+			StaticProcs.uIntLongToByteWord(reportees[i]
+					.getLostPktCount(), ret, 4 + offset);
+
+			// Write Cumulative number of packets lost and loss fraction to
+			// packet:
+			System.arraycopy(reportees[i].getFractionLost(), 0, ret, 4 + offset, 1);
+
+			// Extended highest sequence received
+			StaticProcs.uIntLongToByteWord(reportees[i]
+					.getExtHighSeqRecv(), ret, 8 + offset);
+
+			// Interarrival jitter
+			if (reportees[i].interArrivalJitter >= 0) {
+				StaticProcs
+						.uIntLongToByteWord((long) reportees[i].interArrivalJitter, ret, 12 + offset);
+			} else {
+				StaticProcs.uIntLongToByteWord(0, ret, 12 + offset);
+			}
+
+			// Timestamp last sender report received
+			StaticProcs
+					.uIntLongToByteWord(reportees[i].timeStampLSR, ret, 16 + offset);
+
+			// Delay since last sender report received, in terms of 1/655536 s =
+			// 0.02 ms
+			if (reportees[i].timeReceivedLSR > 0) {
+				StaticProcs.uIntLongToByteWord(reportees[i]
+						.delaySinceLastSR(), ret, 20 + offset);
+			} else {
+				StaticProcs.uIntLongToByteWord(0,ret, 20 + offset);
+			}
+		}
+		if (RTPSession.rtpDebugLevel > 10) {
+			System.out.println("   <- RtcpPktRR.encodeRR()");
+		}
+		return ret;
+	}
+
+	/**
+	 * Debug purposes only
+	 */
+	public void debugPrint() {
+		System.out.println("RtcpPktRR.debugPrint() ");
+		if (reportees != null) {
+			for (int i = 0; i < reportees.length; i++) {
+				Participant part = reportees[i];
+				System.out.println("     part.ssrc: " + part.ssrc
+						+ "  part.cname: " + part.cname);
+			}
+		} else {
+			for (int i = 0; i < reporteeSsrc.length; i++) {
+				System.out.println("     reporteeSSRC: " + reporteeSsrc[i]
+						+ "  timeStampLSR: " + timeStampLSR[i]);
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktRTPFB.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,165 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+/**
+ * RTCP packets for RTP Feedback Messages
+ * 
+ * In line with RFC 4585, this packet currently only supports NACKs
+ * 
+ * @author Arne Kepp
+ */
+public class RtcpPktRTPFB extends RtcpPkt {
+	/** If this packet was for a different SSRC */
+	protected boolean notRelevant = false;
+	/** SSRC we are sending feeback to */
+	protected long ssrcMediaSource = -1;
+	/** RTP sequence numbers of lost packets */
+	protected int PID[];
+	/** bitmask of following lost packets, shared index with PID */
+	protected int BLP[];
+
+	/**
+	 * Constructor for RTP Feedback Message
+	 * 
+	 * @param ssrcPacketSender
+	 *            SSRC of sender, taken from RTPSession
+	 * @param ssrcMediaSource
+	 *            SSRC of recipient of this message
+	 * @param FMT
+	 *            the Feedback Message Subtype
+	 * @param PID
+	 *            RTP sequence numbers of lost packets
+	 * @param BLP
+	 *            bitmask of following lost packets, shared index with PID
+	 */
+	protected RtcpPktRTPFB(long ssrcPacketSender, long ssrcMediaSource,
+			int FMT, int[] PID, int[] BLP) {
+		super.packetType = 205; // RTPFB
+		super.itemCount = FMT;
+		this.PID = PID;
+		this.BLP = BLP;
+	}
+
+	/**
+	 * Constructor that parses a raw packet to retrieve information
+	 * 
+	 * @param aRawPkt
+	 *            the raw packet to be parsed
+	 * @param start
+	 *            the start of the packet, in bytes
+	 * @param rtpSession
+	 *            the session on which the callback interface resides
+	 */
+	protected RtcpPktRTPFB(byte[] aRawPkt, int start, RTPSession rtpSession) {
+		if (RTPSession.rtpDebugLevel > 8) {
+			System.out.println("  -> RtcpPktRTPFB(byte[], int start)");
+		}
+
+		rawPkt = aRawPkt;
+
+		if (!super.parseHeaders(start) || packetType != 205 || super.length < 2) {
+			if (RTPSession.rtpDebugLevel > 2) {
+				System.out
+						.println(" <-> RtcpPktRTPFB.parseHeaders() etc. problem");
+			}
+			super.problem = -205;
+		} else {
+			// FMT = super.itemCount;
+
+			ssrcMediaSource = StaticProcs.bytesToUIntLong(aRawPkt, 8 + start);
+
+			if (ssrcMediaSource == rtpSession.ssrc) {
+				super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, 4 + start);
+				int loopStop = super.length - 2;
+				PID = new int[loopStop];
+				BLP = new int[loopStop];
+				int curStart = 12;
+
+				// Loop over Feedback Control Information (FCI) fields
+				for (int i = 0; i < loopStop; i++) {
+					PID[i] = StaticProcs.bytesToUIntInt(aRawPkt, curStart);
+					BLP[i] = StaticProcs.bytesToUIntInt(aRawPkt, curStart + 2);
+					curStart += 4;
+				}
+
+				rtpSession.rtcpAVPFIntf.RTPFBPktReceived(super.ssrc,
+						super.itemCount, PID, BLP);
+			}
+		}
+
+		if (RTPSession.rtpDebugLevel > 8) {
+			System.out.println("  <- RtcpPktRTPFB()");
+		}
+	}
+
+	/**
+	 * Encode the packet into a byte[], saved in .rawPkt
+	 * 
+	 * CompRtcpPkt will call this automatically
+	 */
+	protected void encode() {
+		super.rawPkt = new byte[12 + this.PID.length * 4];
+
+		byte[] someBytes = StaticProcs.uIntLongToByteWord(super.ssrc);
+		System.arraycopy(someBytes, 0, super.rawPkt, 4, 4);
+		someBytes = StaticProcs.uIntLongToByteWord(this.ssrcMediaSource);
+		System.arraycopy(someBytes, 0, super.rawPkt, 8, 4);
+
+		// Loop over Feedback Control Information (FCI) fields
+		int curStart = 12;
+		for (int i = 0; i < this.PID.length; i++) {
+			someBytes = StaticProcs.uIntIntToByteWord(PID[i]);
+			super.rawPkt[curStart++] = someBytes[0];
+			super.rawPkt[curStart++] = someBytes[1];
+			someBytes = StaticProcs.uIntIntToByteWord(BLP[i]);
+			super.rawPkt[curStart++] = someBytes[0];
+			super.rawPkt[curStart++] = someBytes[1];
+		}
+		writeHeaders();
+	}
+
+	/**
+	 * Get the FMT (Feedback Message Type)
+	 * 
+	 * @return value stored in .itemcount, same field
+	 */
+	protected int getFMT() {
+		return this.itemCount;
+	}
+
+	/**
+	 * Debug purposes only
+	 */
+	protected void debugPrint() {
+		System.out.println("->RtcpPktRTPFB.debugPrint() ");
+		System.out.println("  ssrcPacketSender: " + super.ssrc
+				+ "  ssrcMediaSource: " + ssrcMediaSource);
+
+		if (this.PID != null && this.PID.length < 1) {
+			System.out
+					.println("  No Feedback Control Information (FCI) fields");
+		}
+
+		for (int i = 0; i < this.PID.length; i++) {
+			System.out.println("  FCI -> PID: " + PID[i] + "  BLP: " + BLP[i]);
+		}
+		System.out.println("<-RtcpPktRTPFB.debugPrint() ");
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktSDES.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,308 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.InetSocketAddress;
+
+/**
+ * RTCP packets for Source Descriptions
+ * 
+ * @author Arne Kepp
+ */
+public class RtcpPktSDES extends RtcpPkt {
+	/** Whether the RTP Session object should be inclduded */
+	boolean reportSelf = true;
+	/** The parent RTP Session object, holds participant database */
+	RTPSession rtpSession = null;
+	/** The participants to create SDES packets for */
+	protected Participant[] participants = null;
+
+	/**
+	 * Constructor to create a new SDES packet
+	 * 
+	 * TODO: Currently the added participants are not actually encoded because
+	 * the library lacks some support for acting as mixer or relay in other
+	 * areas.
+	 * 
+	 * @param reportThisSession
+	 *            include information from RTPSession as a participant
+	 * @param rtpSession
+	 *            the session itself
+	 * @param additionalParticipants
+	 *            additional participants to include
+	 */
+	protected RtcpPktSDES(boolean reportThisSession, RTPSession rtpSession,
+			Participant[] additionalParticipants) {
+		super.packetType = 202;
+		// Fetch all the right stuff from the database
+		reportSelf = reportThisSession;
+		participants = additionalParticipants;
+		this.rtpSession = rtpSession;
+	}
+
+	/**
+	 * Constructor that parses a received packet
+	 * 
+	 * @param aRawPkt
+	 *            the byte[] containing the packet
+	 * @param start
+	 *            where in the byte[] this packet starts
+	 * @param socket
+	 *            the address from which the packet was received
+	 * @param partDb
+	 *            the participant database
+	 */
+	protected RtcpPktSDES(byte[] aRawPkt, int start, InetSocketAddress socket,
+			ParticipantDatabase partDb) {
+		if (RTPSession.rtcpDebugLevel > 8) {
+			System.out.println("  -> RtcpPktSDES(byte[], ParticipantDabase)");
+		}
+		rawPkt = aRawPkt;
+
+		if (!super.parseHeaders(start) || packetType != 202) {
+			if (RTPSession.rtpDebugLevel > 2) {
+				System.out
+						.println(" <-> RtcpPktSDES.parseHeaders() etc. problem");
+			}
+			super.problem = -202;
+		} else {
+			// System.out.println(" DECODE SIZE: " + super.length +
+			// " itemcount " + itemCount );
+
+			int curPos = 4 + start;
+			int curLength;
+			int curType;
+			long ssrc;
+			boolean endReached = false;
+			boolean newPart;
+			this.participants = new Participant[itemCount];
+
+			// Loop over SSRC SDES chunks
+			for (int i = 0; i < itemCount; i++) {
+				ssrc = StaticProcs.bytesToUIntLong(aRawPkt, curPos);
+				Participant part = partDb.getParticipant(ssrc);
+				if (part == null) {
+					if (RTPSession.rtcpDebugLevel > 1) {
+						System.out
+								.println("RtcpPktSDES(byte[], ParticipantDabase) adding new participant, ssrc:"
+										+ ssrc + " " + socket);
+					}
+
+					part = new Participant(socket, socket, ssrc);
+					newPart = true;
+				} else {
+					newPart = false;
+				}
+
+				curPos += 4;
+
+				// System.out.println("PRE endReached " + endReached +
+				// " curPos: " + curPos + " length:" + this.length +
+				// (!endReached && (curPos/4) < this.length));
+
+				while (!endReached && (curPos / 4) <= this.length) {
+					// System.out.println("endReached " + endReached +
+					// " curPos: " + curPos + " length:" + this.length);
+					curType = (int) aRawPkt[curPos];
+
+					if (curType == 0) {
+						curPos += 4 - (curPos % 4);
+						endReached = true;
+					} else {
+						curLength = (int) aRawPkt[curPos + 1];
+						// System.out.println("curPos:"+curPos+" curType:"+curType+" curLength:"+curLength+" read from:"+(curPos
+						// + 1));
+
+						if (curLength > 0) {
+							byte[] item = new byte[curLength];
+							// System.out.println("curPos:"+curPos+" arawPkt.length:"+aRawPkt.length+" curLength:"+curLength);
+							System.arraycopy(aRawPkt, curPos + 2, item, 0,
+									curLength);
+
+							switch (curType) {
+							case 1:
+								part.cname = new String(item);
+								break;
+							case 2:
+								part.name = new String(item);
+								break;
+							case 3:
+								part.email = new String(item);
+								break;
+							case 4:
+								part.phone = new String(item);
+								break;
+							case 5:
+								part.loc = new String(item);
+								break;
+							case 6:
+								part.tool = new String(item);
+								break;
+							case 7:
+								part.note = new String(item);
+								break;
+							case 8:
+								part.priv = new String(item);
+								break;
+							}
+							// System.out.println("TYPE " + curType + " value:"
+							// + new String(item) );
+
+						} else {
+							switch (curType) {
+							case 1:
+								part.cname = null;
+								break;
+							case 2:
+								part.name = null;
+								break;
+							case 3:
+								part.email = null;
+								break;
+							case 4:
+								part.phone = null;
+								break;
+							case 5:
+								part.loc = null;
+								break;
+							case 6:
+								part.tool = null;
+								break;
+							case 7:
+								part.note = null;
+								break;
+							case 8:
+								part.priv = null;
+								break;
+							}
+
+						}
+						curPos = curPos + curLength + 2;
+					}
+				}
+
+				// Save the participant
+				this.participants[i] = part;
+				if (newPart)
+					partDb.addParticipant(2, part);
+
+				// System.out.println("HEPPPPPP " + participants[i].cname );
+			}
+		}
+		if (RTPSession.rtcpDebugLevel > 8) {
+			System.out.println("  <- RtcpPktSDES()");
+		}
+	}
+
+	/**
+	 * Encode the packet into a byte[], saved in .rawPkt
+	 * 
+	 * CompRtcpPkt will call this automatically
+	 */
+	protected void encode() {
+		byte[] temp = new byte[1450];
+		byte[] someBytes = StaticProcs.uIntLongToByteWord(this.rtpSession.ssrc);
+		System.arraycopy(someBytes, 0, temp, 4, 4);
+		int pos = 8;
+
+		String tmpString = null;
+		for (int i = 1; i < 9; i++) {
+			switch (i) {
+			case 1:
+				tmpString = this.rtpSession.cname;
+				break;
+			case 2:
+				tmpString = this.rtpSession.name;
+				break;
+			case 3:
+				tmpString = this.rtpSession.email;
+				break;
+			case 4:
+				tmpString = this.rtpSession.phone;
+				break;
+			case 5:
+				tmpString = this.rtpSession.loc;
+				break;
+			case 6:
+				tmpString = this.rtpSession.tool;
+				break;
+			case 7:
+				tmpString = this.rtpSession.note;
+				break;
+			case 8:
+				tmpString = this.rtpSession.priv;
+				break;
+			}
+
+			if (tmpString != null) {
+				someBytes = tmpString.getBytes();
+				temp[pos] = (byte) i;
+				temp[pos + 1] = (byte) someBytes.length;
+				System.arraycopy(someBytes, 0, temp, pos + 2, someBytes.length);
+				// System.out.println("i: "+i+" pos:"+pos+" someBytes.length:"+someBytes.length);
+				pos = pos + someBytes.length + 2;
+				// if(i == 1 ) {
+				// System.out.println("trueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" +
+				// tmpString);
+				// }
+			}
+		}
+		int leftover = pos % 4;
+		if (leftover == 1) {
+			temp[pos] = (byte) 0;
+			temp[pos + 1] = (byte) 1;
+			pos += 3;
+		} else if (leftover == 2) {
+			temp[pos] = (byte) 0;
+			temp[pos + 1] = (byte) 0;
+			pos += 2;
+		} else if (leftover == 3) {
+			temp[pos] = (byte) 0;
+			temp[pos + 1] = (byte) 3;
+			pos += 5;
+		}
+
+		// TODO Here we ought to loop over participants, if we're doing SDES for
+		// other participants.
+
+		super.rawPkt = new byte[pos];
+		itemCount = 1;
+		// This looks wrong, but appears to be fine..
+		System.arraycopy(temp, 0, super.rawPkt, 0, pos);
+		writeHeaders();
+	}
+
+	/**
+	 * Debug purposes only
+	 */
+	public void debugPrint() {
+		System.out.println("RtcpPktSDES.debugPrint() ");
+		if (participants != null) {
+			for (int i = 0; i < participants.length; i++) {
+				Participant part = participants[i];
+				System.out.println("     part.ssrc: " + part.ssrc
+						+ "  part.cname: " + part.cname + " part.loc: "
+						+ part.loc);
+			}
+		} else {
+			System.out
+					.println("     nothing to report (only valid for received packets)");
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtcpPktSR.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,190 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+/**
+ * RTCP packets for Sender Reports
+ * 
+ * @author Arne Kepp
+ */
+public class RtcpPktSR extends RtcpPkt {
+	/** NTP timestamp, MSB */
+	protected long ntpTs1 = -1; // 32 bits
+	/** NTP timestamp, LSB */
+	protected long ntpTs2 = -1; // 32 bits
+	/** RTP timestamp */
+	protected long rtpTs = -1; // 32 bits
+	/** Senders packet count */
+	protected long sendersPktCount = -1; // 32 bits
+	/** Senders octet count */
+	protected long sendersOctCount = -1; // 32 bits
+	/** RR packet with receiver reports that we can append */
+	protected RtcpPktRR rReports = null;
+
+	/**
+	 * Constructor for a new Sender Report packet
+	 * 
+	 * @param ssrc
+	 *            the senders SSRC, presumably from RTPSession
+	 * @param pktCount
+	 *            packets sent in this session
+	 * @param octCount
+	 *            octets sent in this session
+	 * @param rReports
+	 *            receiver reports, as RR packets, to be included in this packet
+	 */
+	protected RtcpPktSR(long ssrc, long pktCount, long octCount,
+			RtcpPktRR rReports) {
+		// Fetch all the right stuff from the database
+		super.ssrc = ssrc;
+		super.packetType = 200;
+		sendersPktCount = pktCount;
+		sendersOctCount = octCount;
+		this.rReports = rReports;
+	}
+
+	/**
+	 * Constructor that parses a received packet
+	 * 
+	 * @param aRawPkt
+	 *            the raw packet
+	 * @param start
+	 *            the position at which SR starts
+	 * @param length
+	 *            used to determine number of included receiver reports
+	 */
+	protected RtcpPktSR(byte[] aRawPkt, int start, int length) {
+		if (RTPSession.rtpDebugLevel > 9) {
+			System.out.println("  -> RtcpPktSR(rawPkt)");
+		}
+
+		super.rawPkt = aRawPkt;
+
+		if (!super.parseHeaders(start) || packetType != 200) {
+			if (RTPSession.rtpDebugLevel > 2) {
+				System.out
+						.println(" <-> RtcpPktSR.parseHeaders() etc. problem: "
+								+ (!super.parseHeaders(start)) + " "
+								+ packetType + " " + super.length);
+			}
+			super.problem = -200;
+		} else {
+			super.ssrc = StaticProcs.bytesToUIntLong(aRawPkt, 4 + start);
+			if (length > 11)
+				ntpTs1 = StaticProcs.bytesToUIntLong(aRawPkt, 8 + start);
+			if (length > 15)
+				ntpTs2 = StaticProcs.bytesToUIntLong(aRawPkt, 12 + start);
+			if (length > 19)
+				rtpTs = StaticProcs.bytesToUIntLong(aRawPkt, 16 + start);
+			if (length > 23)
+				sendersPktCount = StaticProcs.bytesToUIntLong(aRawPkt,
+						20 + start);
+			if (length > 27)
+				sendersOctCount = StaticProcs.bytesToUIntLong(aRawPkt,
+						24 + start);
+
+			// RRs attached?
+			if (itemCount > 0) {
+				rReports = new RtcpPktRR(rawPkt, start, itemCount);
+			}
+		}
+
+		if (RTPSession.rtpDebugLevel > 9) {
+			System.out.println("  <- RtcpPktSR(rawPkt)");
+		}
+	}
+
+	/**
+	 * Encode the packet into a byte[], saved in .rawPkt
+	 * 
+	 * CompRtcpPkt will call this automatically
+	 */
+	protected void encode() {
+		if (RTPSession.rtpDebugLevel > 9) {
+			if (this.rReports != null) {
+				System.out
+						.println("  -> RtcpPktSR.encode() receptionReports.length: "
+								+ this.rReports.length);
+			} else {
+				System.out
+						.println("  -> RtcpPktSR.encode() receptionReports: null");
+			}
+		}
+
+		if (this.rReports != null) {
+			super.itemCount = this.rReports.reportees.length;
+
+			byte[] tmp = this.rReports.encodeRR();
+			super.rawPkt = new byte[tmp.length + 28];
+			// super.length = (super.rawPkt.length / 4) - 1;
+
+			System.arraycopy(tmp, 0, super.rawPkt, 28, tmp.length);
+
+		} else {
+			super.itemCount = 0;
+			super.rawPkt = new byte[28];
+			// super.length = 6;
+		}
+		// Write the common header
+		super.writeHeaders();
+
+		// Convert to NTP and chop up
+		long timeNow = System.currentTimeMillis();
+		ntpTs1 = 2208988800L + (timeNow / 1000);
+		long ms = timeNow % 1000;
+		double tmp = ((double) ms) / 1000.0;
+		tmp = tmp * (double) 4294967295L;
+		ntpTs2 = (long) tmp;
+		rtpTs = System.currentTimeMillis();
+
+		// Write SR stuff
+		StaticProcs.uIntLongToByteWord(super.ssrc, super.rawPkt, 4);
+		StaticProcs.uIntLongToByteWord(ntpTs1, super.rawPkt, 8);
+		StaticProcs.uIntLongToByteWord(ntpTs2, super.rawPkt, 12);
+		StaticProcs.uIntLongToByteWord(rtpTs, super.rawPkt, 16);
+		StaticProcs.uIntLongToByteWord(sendersPktCount, super.rawPkt, 20);
+		StaticProcs.uIntLongToByteWord(sendersOctCount, super.rawPkt, 24);
+
+		if (RTPSession.rtpDebugLevel > 9) {
+			System.out.println("  <- RtcpPktSR.encode() ntpTs1: "
+					+ Long.toString(ntpTs1) + " ntpTs2: "
+					+ Long.toString(ntpTs2));
+		}
+	}
+
+	/**
+	 * Debug purposes only
+	 */
+	public void debugPrint() {
+		System.out.println("RtcpPktSR.debugPrint() ");
+		System.out.println("  SSRC:" + Long.toString(super.ssrc) + " ntpTs1:"
+				+ Long.toString(ntpTs1) + " ntpTS2:" + Long.toString(ntpTs2)
+				+ " rtpTS:" + Long.toString(rtpTs) + " senderPktCount:"
+				+ Long.toString(sendersPktCount) + " sendersOctetCount:"
+				+ Long.toString(sendersOctCount));
+		if (this.rReports != null) {
+			System.out.print("  Part of Sender Report: ");
+			this.rReports.debugPrint();
+			System.out.println("  End Sender Report");
+		} else {
+			System.out
+					.println("No Receiver Reports associated with this Sender Report.");
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/RtpPkt.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,465 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+import java.net.DatagramPacket;
+
+/**
+ * RtpPkt is the basic class for creating and parsing RTP packets.
+ * 
+ * There are two ways of instantiating an RtpPkt. One is for packets that you
+ * wish to send, which requires that you provide basic information about the
+ * packet and a payload. Upon calling encode() the fields of the structure are
+ * written into a bytebuffer, in the form that it would sent across the network,
+ * excluding the UDP headers.
+ * 
+ * The other way is by passing a bytebuffer. The assumption is that this is a
+ * packet that has been received from the network, excluding UDP headers, and
+ * the bytebuffer will be parsed into the correct fields.
+ * 
+ * The class keeps track of changes. Therefore, modifications are possible after
+ * calling encode(), if necessary, the raw version of the packet will be
+ * regenerated on subsequent requests.
+ * 
+ * @author Arne Kepp
+ */
+public class RtpPkt {
+	/** Whether the packet has been changed since encode() */
+	private boolean rawPktCurrent = false;
+	/** The version, always 2, 2 bits */
+	private int version = 2; // 2 bits
+	/** Whether the packet is padded, 1 bit */
+	private int padding; // 1 bit
+	/** Whether and extension is used, 1 bit */
+	private int extension = 0; // 1 bit
+	/** Whether the packet is marked, 1 bit */
+	private int marker = 0; // 1 bit
+	/** What payload type is used, 7 bits */
+	private int payloadType; //
+	/** The sequence number, taken from RTP Session, 16 bits */
+	private int seqNumber; // 16 bits
+	/** The RTP timestamp, 32bits */
+	private long timeStamp; // 32 bits
+	/** The SSRC of the packet sender, 32 bits */
+	private long ssrc; // 32 bits
+	/** SSRCs of contributing sources, 32xn bits, n<16 */
+	private long[] csrcArray = new long[0];//
+
+	/** Contains the actual data (eventually) */
+	private byte[] rawPkt = null;
+	
+
+
+	/** The actual data, without any RTP stuff */
+	//private byte[] payload = null;
+	private DatagramPacket datagramPacket;
+
+	/**
+	 * Construct a packet-instance. The ByteBuffer required for UDP transmission
+	 * can afterwards be obtained from getRawPkt(). If you need to set
+	 * additional parameters, such as the marker bit or contributing sources,
+	 * you should do so before calling getRawPkt;
+	 * 
+	 * @param aTimeStamp
+	 *            RTP timestamp for data
+	 * @param syncSource
+	 *            the SSRC, usually taken from RTPSession
+	 * @param seqNum
+	 *            Sequency number
+	 * @param plt
+	 *            Type of payload
+	 * @param pl
+	 *            Payload, the actual data
+	 */
+	protected void initPacket(long aTimeStamp, long syncSource, int seqNum, int plt,
+			byte[] pl) {
+		int test = 0;
+		test += setTimeStamp(aTimeStamp);
+		test += setSsrc(syncSource);
+		test += setSeqNumber(seqNum);
+		test += setPayloadType(plt);
+		//test += setPayload(pl); //TODO: faire d'une manière propre
+		datagramPacket = null;
+		if (test != 0) {
+			System.out.println("RtpPkt() failed, check with checkPkt()");
+		}
+		rawPktCurrent = true;
+		if (RTPSession.rtpDebugLevel > 5) {
+			System.out
+					.println("<--> RtpPkt(aTimeStamp, syncSource, seqNum, plt, pl)");
+		}
+	}
+
+	/**
+	 * Construct a packet-instance from an raw packet (believed to be RTP). The
+	 * UDP-headers must be removed before invoking this method. Call checkPkt on
+	 * the instance to verify that it was successfully parsed.
+	 * 
+	 * @param aRawPkt
+	 *            The data-part of a UDP-packet believed to be RTP
+	 * @param packetSize
+	 *            the number of valid octets in the packet, should be
+	 *            aRawPkt.length
+	 */
+	public RtpPkt(byte[] aRawPkt, int packetSize, DatagramPacket packet) {
+		initPacket(aRawPkt, packetSize, packet);
+	}
+	
+	public RtpPkt() {
+	}
+	
+	public RtpPkt(long aTimeStamp, long syncSource, int seqNum, int plt,
+			byte[] pl) {
+		initPacket(aTimeStamp, syncSource, seqNum, plt, pl);
+	}
+	
+	protected void initPacket(byte[] aRawPkt, int packetSize, DatagramPacket packet) {
+		if (RTPSession.rtpDebugLevel > 5) {
+			System.out.println("-> RtpPkt(aRawPkt)");
+		}
+		// Check size, need to have at least a complete header
+		if (aRawPkt == null) {
+			System.out.println("RtpPkt(byte[]) Packet null");
+		}
+
+		int remOct = packetSize - 12;
+		if (remOct >= 0) {
+			rawPkt = aRawPkt; // Store it
+			// Interrogate the packet
+			datagramPacket = packet;
+			sliceFirstLine();
+			if (version == 2) {
+				sliceTimeStamp();
+				sliceSSRC();
+				if (remOct > 4 && getCsrcCount() > 0) {
+					sliceCSRCs();
+					remOct -= csrcArray.length * 4; // 4 octets per CSRC
+				}
+				// TODO Extension
+				/*if (remOct > 0) {
+					slicePayload(remOct);
+				}*/
+
+				// Sanity checks
+				checkPkt();
+
+				// Mark the buffer as current
+				rawPktCurrent = true;
+			} else {
+				System.out
+						.println("RtpPkt(byte[]) Packet is not version 2, giving up.");
+			}
+		} else {
+			System.out.println("RtpPkt(byte[]) Packet too small to be sliced");
+		}
+		rawPktCurrent = true;
+		if (RTPSession.rtpDebugLevel > 5) {
+			System.out.println("<- RtpPkt(aRawPkt)");
+		}
+	}
+
+	/*********************************************************************************************************
+	 * Reading stuff
+	 *********************************************************************************************************/
+	protected int checkPkt() {
+		// TODO, check for version 2 etc
+		return 0;
+	}
+
+	protected int getHeaderLength() {
+		// TODO include extension
+		return 12 + 4 * getCsrcCount();
+	}
+
+	protected int getPayloadLength() {
+		return rawPkt.length - getHeaderLength();
+	}
+
+	// public int getPaddingLength() {
+	// return lenPadding;
+	// }
+	protected int getVersion() {
+		return version;
+	}
+
+	// public boolean isPadded() {
+	// if(lenPadding > 0) {
+	// return true;
+	// }else {
+	// return false;
+	// }
+	// }
+	// public int getHeaderExtension() {
+	// TODO
+	// }
+	protected boolean isMarked() {
+		return (marker != 0);
+	}
+
+	protected int getPayloadType() {
+		return payloadType;
+	}
+
+	public int getSeqNumber() {
+		return seqNumber;
+	}
+
+	protected long getTimeStamp() {
+		return timeStamp;
+	}
+
+	protected long getSsrc() {
+		return ssrc;
+	}
+
+	protected int getCsrcCount() {
+		if (csrcArray != null) {
+			return csrcArray.length;
+		} else {
+			return 0;
+		}
+	}
+
+	protected long[] getCsrcArray() {
+		return csrcArray;
+	}
+
+	/**
+	 * Encodes the a
+	 */
+	protected byte[] encode() {
+		if (!rawPktCurrent || rawPkt == null) {
+			writePkt();
+			android.util.Log.d("RtpPkt", "writePkt");
+		}
+		return rawPkt;
+	}
+
+	/* For debugging purposes */
+	protected void printPkt() {
+		System.out
+				.print("V:" + version + " P:" + padding + " EXT:" + extension);
+		System.out.println(" CC:" + getCsrcCount() + " M:" + marker + " PT:"
+				+ payloadType + " SN: " + seqNumber);
+		System.out.println("Timestamp:" + timeStamp
+				+ "(long output as int, may be 2s complement)");
+		System.out.println("SSRC:" + ssrc
+				+ "(long output as int, may be 2s complement)");
+		for (int i = 0; i < getCsrcCount(); i++) {
+			System.out.println("CSRC:" + csrcArray[i]
+					+ "(long output as int, may be 2s complement)");
+		}
+
+	}
+
+	/*********************************************************************************************************
+	 * Setting stuff
+	 *********************************************************************************************************/
+	protected void setMarked(boolean mark) {
+		rawPktCurrent = false;
+		if (mark) {
+			marker = 1;
+		} else {
+			marker = 0;
+		}
+	}
+
+	// public int setHeaderExtension() {
+	// TODO
+	// }
+	public int setPayloadType(int plType) {
+		int temp = (plType & 0x0000007F); // 7 bits, checks in RTPSession as
+											// well.
+		if (temp == plType) {
+			rawPktCurrent = false;
+			payloadType = temp;
+			return 0;
+		} else {
+			return -1;
+		}
+	}
+
+	protected int setSeqNumber(int number) {
+		if (number <= 65536 && number >= 0) {
+			rawPktCurrent = false;
+			seqNumber = number;
+			return 0;
+		} else {
+			System.out.println("RtpPkt.setSeqNumber: invalid number");
+			return -1;
+		}
+	}
+
+	protected int setTimeStamp(long time) {
+		rawPktCurrent = false;
+		timeStamp = time;
+		return 0; // Naive for now
+	}
+
+	protected int setSsrc(long source) {
+		rawPktCurrent = false;
+		ssrc = source;
+		return 0; // Naive for now
+	}
+
+	protected int setCsrcs(long[] contributors) {
+		if (contributors.length <= 16) {
+			csrcArray = contributors;
+			return 0;
+		} else {
+			System.out
+					.println("RtpPkt.setCsrcs: Cannot have more than 16 CSRCs");
+			return -1;
+		}
+	}
+
+	/*protected int setPayload(byte[] data) {
+		// TODO Padding
+		if (data.length < (1500 - 12)) {
+			rawPktCurrent = false;
+			payload = data;
+			return 0;
+		} else {
+			System.out
+					.println("RtpPkt.setPayload: Cannot carry more than 1480 bytes for now.");
+			return -1;
+		}
+	}*/
+
+	public byte[] getPayload() {
+		return rawPkt;
+	}
+
+	/*********************************************************************************************************
+	 * Private functions
+	 *********************************************************************************************************/
+	// Generate a bytebyffer representing the packet, store it.
+	private void writePkt() {
+		int bytes = getPayloadLength();
+		int headerLen = getHeaderLength();
+		int csrcLen = getCsrcCount();
+		rawPkt = new byte[headerLen + bytes];
+
+		// The first line contains, version and various bits
+		writeFirstLine();
+		byte[] someBytes = StaticProcs.uIntLongToByteWord(timeStamp);
+		for (int i = 0; i < 4; i++) {
+			rawPkt[i + 4] = someBytes[i];
+		}
+		// System.out.println("writePkt timeStamp:" + rawPkt[7]);
+
+		someBytes = StaticProcs.uIntLongToByteWord(ssrc);
+		System.arraycopy(someBytes, 0, rawPkt, 8, 4);
+		// System.out.println("writePkt ssrc:" + rawPkt[11]);
+
+		for (int i = 0; i < csrcLen; i++) {
+			someBytes = StaticProcs.uIntLongToByteWord(csrcArray[i]);
+			System.arraycopy(someBytes, 0, rawPkt, 12 + 4 * i, 4);
+		}
+		// TODO Extension
+
+		// Payload
+		//System.arraycopy(payload, 0, rawPkt, headerLen, bytes);
+		rawPktCurrent = true;
+	}
+	
+	void writeHeader() {
+		//int bytes = rawPkt.length - 12;
+		//int headerLen = getHeaderLength();
+		int csrcLen = getCsrcCount();
+
+		// The first line contains, version and various bits
+		writeFirstLine();
+		StaticProcs.uIntLongToByteWord(timeStamp, rawPkt, 4);
+		// System.out.println("writePkt timeStamp:" + rawPkt[7]);
+
+		StaticProcs.uIntLongToByteWord(ssrc, rawPkt, 8);
+		//System.arraycopy(someBytes, 0, rawPkt, 8, 4);
+		// System.out.println("writePkt ssrc:" + rawPkt[11]);
+
+		for (int i = 0; i < csrcLen; i++) {
+			StaticProcs.uIntLongToByteWord(csrcArray[i], rawPkt, 12 + 4 * i);
+			//System.arraycopy(someBytes, 0, rawPkt, 12 + 4 * i, 4);
+		}
+		// TODO Extension
+
+		// Payload
+		//System.arraycopy(payload, 0, rawPkt, headerLen, bytes);
+		rawPktCurrent = true;
+	}
+
+	// Writes the first 4 octets of the RTP packet
+	protected void writeFirstLine() {
+		byte aByte = 0;
+		aByte |= (version << 6);
+		aByte |= (padding << 5);
+		aByte |= (extension << 4);
+		aByte |= (getCsrcCount());
+		rawPkt[0] = aByte;
+		aByte = 0;
+		aByte |= (marker << 7);
+		aByte |= payloadType;
+		rawPkt[1] = aByte;
+		StaticProcs.uIntIntToByteWord(seqNumber, rawPkt, 2);
+	}
+
+	// Picks apart the first 4 octets of an RTP packet
+	private void sliceFirstLine() {
+		version = ((rawPkt[0] & 0xC0) >>> 6);
+		padding = ((rawPkt[0] & 0x20) >>> 5);
+		extension = ((rawPkt[0] & 0x10) >>> 4);
+		//csrcArray = new long[(rawPkt[0] & 0x0F)];
+		marker = ((rawPkt[1] & 0x80) >> 7);
+		payloadType = (rawPkt[1] & 0x7F);
+		seqNumber = StaticProcs.bytesToUIntInt(rawPkt, 2);
+	}
+
+	// Takes the 4 octets representing the timestamp
+	private void sliceTimeStamp() {
+		timeStamp = StaticProcs.bytesToUIntLong(rawPkt, 4);
+	}
+
+	// Takes the 4 octets representing the SSRC
+	private void sliceSSRC() {
+		ssrc = StaticProcs.bytesToUIntLong(rawPkt, 8);
+	}
+
+	// Check the length of the csrcArray (set during sliceFirstLine)
+	private void sliceCSRCs() {
+		for (int i = 0; i < csrcArray.length; i++) {
+			ssrc = StaticProcs.bytesToUIntLong(rawPkt, i * 4 + 12);
+		}
+	}
+
+	// Extensions //TODO
+	/*private void slicePayload(int bytes) {
+		payload = new byte[bytes];
+		int headerLen = getHeaderLength();
+
+		System.arraycopy(rawPkt, headerLen, payload, 0, bytes);
+	}*/
+	
+	public void setRawPkt(byte[] rawPkt) {
+		this.rawPkt = rawPkt;
+	}
+
+	public DatagramPacket getDatagramPacket() {
+		return datagramPacket;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/StaticProcs.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,298 @@
+/**
+ * Java RTP Library (jlibrtp)
+ * Copyright (C) 2006 Arne Kepp
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+package jlibrtp;
+
+/**
+ * Generic functions for converting between unsigned integers and byte[]s.
+ * 
+ * @author Arne Kepp
+ */
+public class StaticProcs {
+
+	/**
+	 * Converts an integer into an array of bytes. Primarily used for 16 bit
+	 * unsigned integers, ignore the first two octets.
+	 * 
+	 * @param i
+	 *            a 16 bit unsigned integer in an int
+	 * @return byte[2] representing the integer as unsigned, most significant
+	 *         bit first.
+	 */
+	public static byte[] uIntIntToByteWord(int i) {
+		byte[] byteWord = new byte[2];
+		byteWord[0] = (byte) ((i >> 8) & 0x000000FF);
+		byteWord[1] = (byte) (i & 0x00FF);
+		return byteWord;
+	}
+	
+	public static void uIntIntToByteWord(int i, byte[] byteWord, int srcPos) {
+		byteWord[0 + srcPos] = (byte) ((i >> 8) & 0x000000FF);
+		byteWord[1 + srcPos] = (byte) (i & 0x00FF);
+	}
+
+	/**
+	 * Converts an unsigned 32 bit integer, stored in a long, into an array of
+	 * bytes.
+	 * 
+	 * @param j
+	 *            a long
+	 * @return byte[4] representing the unsigned integer, most significant bit
+	 *         first.
+	 */
+	public static byte[] uIntLongToByteWord(long j) {
+		int i = (int) j;
+		byte[] byteWord = new byte[4];
+		byteWord[0] = (byte) ((i >>> 24) & 0x000000FF);
+		byteWord[1] = (byte) ((i >> 16) & 0x000000FF);
+		byteWord[2] = (byte) ((i >> 8) & 0x000000FF);
+		byteWord[3] = (byte) (i & 0x00FF);
+		return byteWord;
+	}
+	
+	public static void uIntLongToByteWord(long j, byte[] byteword, int srcPos) {
+		int i = (int) j;
+		byteword[0 + srcPos] = (byte) ((i >>> 24) & 0x000000FF);
+		byteword[1 + srcPos] = (byte) ((i >> 16) & 0x000000FF);
+		byteword[2 + srcPos] = (byte) ((i >> 8) & 0x000000FF);
+		byteword[3 + srcPos] = (byte) (i & 0x00FF);
+	}
+
+	/**
+	 * Combines two bytes (most significant bit first) into a 16 bit unsigned
+	 * integer.
+	 * 
+	 * @param index
+	 *            of most significant byte
+	 * @return int with the 16 bit unsigned integer
+	 */
+	public static int bytesToUIntInt(byte[] bytes, int index) {
+		int accum = 0;
+		int i = 1;
+		for (int shiftBy = 0; shiftBy < 16; shiftBy += 8) {
+			accum |= ((long) (bytes[index + i] & 0xff)) << shiftBy;
+			i--;
+		}
+		return accum;
+	}
+
+	/**
+	 * Combines four bytes (most significant bit first) into a 32 bit unsigned
+	 * integer.
+	 * 
+	 * @param bytes
+	 * @param index
+	 *            of most significant byte
+	 * @return long with the 32 bit unsigned integer
+	 */
+	public static long bytesToUIntLong(byte[] bytes, int index) {
+		long accum = 0;
+		int i = 3;
+		for (int shiftBy = 0; shiftBy < 32; shiftBy += 8) {
+			accum |= ((long) (bytes[index + i] & 0xff)) << shiftBy;
+			i--;
+		}
+		return accum;
+	}
+
+	/**
+	 * Converts an arbitrary number of bytes, assumed to represent an unsigned
+	 * integer, to a Java long
+	 */
+	/*
+	 * public static long bytesToUintLong(byte[] bytes, int firstByte, int
+	 * lastByte) { long accum = 0; int i = lastByte - firstByte; if(i > 7) {
+	 * System.out.println(
+	 * "!!!! StaticProcs.bytesToUintLong() Can't convert more than 63 bits!");
+	 * return -1; } int stop = (i+1)*8;
+	 * 
+	 * for (int shiftBy = 0; shiftBy < stop; shiftBy += 8 ) { accum |= ( (long)(
+	 * bytes[firstByte + i] & 0xff ) ) << shiftBy; i--; } return accum; }
+	 */
+
+	/**
+	 * Converts an arbitrary number of bytes, assumed to represent an unsigned
+	 * integer, to a Java int
+	 */
+	/*
+	 * public static int bytesToUintInt(byte[] bytes, int firstByte, int
+	 * lastByte) { int accum = 0; int i = lastByte - firstByte; if(i > 3) {
+	 * System.out.println(
+	 * "!!!! StaticProcs.bytesToUintLong() Can't convert more than 31 bits!");
+	 * return -1; } int stop = (i+1)*8;
+	 * 
+	 * for (int shiftBy = 0; shiftBy < stop; shiftBy += 8 ) { accum |= ( (long)(
+	 * bytes[firstByte + i] & 0xff ) ) << shiftBy; i--; } return accum; }
+	 */
+
+	/**
+	 * Recreates a UNIX timestamp based on the NTP representation used in RTCP
+	 * SR packets
+	 * 
+	 * @param ntpTs1
+	 *            from RTCP SR packet
+	 * @param ntpTs2
+	 *            from RTCP SR packet
+	 * @return the UNIX timestamp
+	 */
+	public static long undoNtpMess(long ntpTs1, long ntpTs2) {
+		long timeVal = (ntpTs1 - 2208988800L) * 1000;
+
+		double tmp = (1000.0 * (double) ntpTs2) / ((double) 4294967295L);
+		long ms = (long) tmp;
+		// System.out.println(" timeVal: " +Long.toString(timeVal)+ " ms " +
+		// Long.toString(ms));
+		timeVal += ms;
+
+		return timeVal;
+	}
+
+	/**
+	 * Get the bits of a byte
+	 * 
+	 * @param aByte
+	 *            the byte you wish to convert
+	 * @return a String of 1's and 0's
+	 */
+	public static String bitsOfByte(byte aByte) {
+		int temp;
+		String out = "";
+		for (int i = 7; i >= 0; i--) {
+			temp = (aByte >>> i);
+			temp &= 0x0001;
+			out += ("" + temp);
+		}
+		return out;
+	}
+
+	/**
+	 * Get the hex representation of a byte
+	 * 
+	 * @param aByte
+	 *            the byte you wish to convert
+	 * @return a String of two chars 0-1,A-F
+	 */
+	public static String hexOfByte(byte aByte) {
+		String out = "";
+
+		for (int i = 0; i < 2; i++) {
+			int temp = (int) aByte;
+			if (temp < 0) {
+				temp += 256;
+			}
+			if (i == 0) {
+				temp = temp / 16;
+			} else {
+				temp = temp % 16;
+			}
+
+			if (temp > 9) {
+				switch (temp) {
+				case 10:
+					out += "A";
+					break;
+				case 11:
+					out += "B";
+					break;
+				case 12:
+					out += "C";
+					break;
+				case 13:
+					out += "D";
+					break;
+				case 14:
+					out += "E";
+					break;
+				case 15:
+					out += "F";
+					break;
+				}
+			} else {
+				out += Integer.toString(temp);
+			}
+		}
+		return out;
+	}
+
+	/**
+	 * Get the hex representation of a byte
+	 * 
+	 * @param hex
+	 *            4 bytes the byte you wish to convert
+	 * @return a String of two chars 0-1,A-F
+	 */
+	public static byte byteOfHex(byte[] hex) {
+		byte retByte = 0;
+		Byte tmp;
+		int val = 0;
+
+		// First 4 bits
+		tmp = hex[0];
+		val = tmp.intValue();
+		if (val > 64) {
+			// Letter
+			val -= 55;
+		} else {
+			// Number
+			val -= 48;
+		}
+		retByte = ((byte) (val << 4));
+
+		// Last 4 bits
+		tmp = hex[1];
+		val = tmp.intValue();
+		if (val > 64) {
+			// Letter
+			val -= 55;
+		} else {
+			// Number
+			val -= 48;
+		}
+		retByte |= ((byte) val);
+
+		return retByte;
+	}
+
+	/**
+	 * Print the bits of a byte to standard out. For debugging.
+	 * 
+	 * @param aByte
+	 *            the byte you wish to print out.
+	 */
+	public static void printBits(byte aByte) {
+		int temp;
+		for (int i = 7; i >= 0; i--) {
+			temp = (aByte >>> i);
+			temp &= 0x0001;
+			System.out.print("" + temp);
+		}
+		System.out.println();
+	}
+
+	public static String bitsOfBytes(byte[] bytes) {
+		String str = "";
+		// Expensive, but who cares
+		for (int i = 0; i < bytes.length; i++) {
+			str += bitsOfByte(bytes[i]) + " ";
+			if ((i + 1) % 4 == 0)
+				str += "\n";
+		}
+
+		return str;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jlibrtp/package.html	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,22 @@
+<html>
+<body>
+<p>The jlibrtp package contains the core classes of jlibrtp. Most of these classes
+ are protected or private, developers looking to use jlibrtp should only concern
+ themselves with</p>
+ <ul>
+ <li>RTPSession - the main session object
+ <li>Participant - participant objects
+ <li>DataFrame - the containers in which data is returned
+ <li>RTPAppIntf - the mininum callback interface
+ <li>RTPCAppIntf - optional interface for receing RTCP packets
+ <li>RTCPAVPFIntf - optional interface for RTP with feedback
+ <li>DebugAppIntf - optional interface for debugging
+ </ul>
+ <p>
+ DebugAppIntf is great for checking network problems and keeping track of packets. 
+ If you need extensive debugging you should statically change the debug values in RTPSession.java
+ and pay attention to the standard output.
+ </p>
+ 
+</body>
+</html>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/RtpStreamReceiver.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
+ * 
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ * 
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package org.sipdroid.media;
+
+import jlibrtp.AppCallerThread;
+import jlibrtp.DataFrame;
+import jlibrtp.Participant;
+import jlibrtp.RTPAppIntf;
+import jlibrtp.RTPReceiverThread;
+import jlibrtp.RTPSession;
+
+import org.sipdroid.media.codecs.Codec;
+import org.sipdroid.net.tools.DataFramePool;
+import org.sipdroid.net.tools.DatagramPool;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences.Editor;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.ToneGenerator;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+
+/**
+ * RtpStreamReceiver is a generic stream receiver. It receives packets from RTP
+ * and writes them into an OutputStream.
+ */
+public class RtpStreamReceiver extends Thread implements RTPAppIntf{
+
+	/** Whether working in debug mode. */
+	public static boolean DEBUG = true;
+
+	/** Size of the read buffer */
+	public static final int BUFFER_SIZE = 1024;
+
+	/** Maximum blocking time, spent waiting for reading new bytes [milliseconds] */
+	public static final int SO_TIMEOUT = 200;
+
+	/** The RtpSocket */
+	//RtpSocket rtp_socket = null;
+	RTPSession rtpSession = null;
+	byte[] buffer;
+
+	/** The codec */
+	private Codec codec;
+	private Context mContext;
+
+	private int frame_size;
+	private int codec_frame_size;
+	private int sampling_rate;
+
+	/** Whether it is running */
+	boolean running;
+	AudioManager am;
+	ContentResolver cr;
+
+	private int codec_divider;
+	public static int speakermode;
+
+	short lin[];
+	short lin2[];
+	int user, server, lserver, luser, cnt, todo, headroom, len, timeout = 1, seq = 0, cnt2 = 0, m = 1,
+	expseq, getseq, vm = 1, gap, oldvol;
+	boolean islate;
+
+	Codec.Context codecCtx;
+
+	AudioTrack track;
+
+	/**
+	 * Constructs a RtpStreamReceiver.
+	 * @param ctx 
+	 * @param remoteAddr 
+	 * 
+	 * @param output_stream
+	 *            the stream sink
+	 * @param socket
+	 *            the local receiver SipdroidSocket
+	 */
+	public RtpStreamReceiver(Codec ci, RTPSession rtpSession, Context ctx) {
+		init(ci, rtpSession, ctx);
+	}
+
+	/** Inits the RtpStreamReceiver 
+	 * @param ctx 
+	 * @param remoteAddr
+	 **/
+	private void init(Codec ci, RTPSession rtpSession, Context ctx) {
+		this.rtpSession = rtpSession;
+		codec = ci;
+		codec_frame_size = codec.getInfo().codecFrameSize;		
+		codec_divider = codec.getInfo().rtpSampleDivider;
+		frame_size = 160 * codec_divider;
+		sampling_rate = codec.getInfo().samplingRate;
+		mContext = ctx;
+	}
+
+	/** Whether is running */
+	public boolean isRunning() {
+		return running;
+	}
+
+	/** Stops running */
+	public void halt() {
+		running = false;
+	}
+
+	public int speaker(int mode) {
+		int old = speakermode;
+
+		saveVolume();
+		speakermode = mode;
+		restoreVolume();
+		return old;
+	}
+
+	double smin = 200,s;
+
+	private int REAL_BUFFER_SIZE;
+	public static int nearend;
+
+	void calc(short[] lin,int off,int len) {
+		int i,j;
+		double sm = 30000,r;
+
+		for (i = 0; i < len; i += 5) {
+			j = lin[i+off];
+			s = 0.03*Math.abs(j) + 0.97*s;
+			if (s < sm) sm = s;
+			if (s > smin) nearend = 3000/5;
+			else if (nearend > 0) nearend--;
+		}
+		for (i = 0; i < len; i++) {
+			j = lin[i+off];
+			if (j > 6550)
+				lin[i+off] = 6550*5;
+			else if (j < -6550)
+				lin[i+off] = -6550*5;
+			else
+				lin[i+off] = (short)(j*5);
+		}
+		r = (double)len/100000;
+		smin = sm*r + smin*(1-r);
+	}
+
+	void restoreVolume() {
+		am.setStreamVolume(AudioManager.STREAM_MUSIC,
+				PreferenceManager.getDefaultSharedPreferences(mContext).getInt("volume"+speakermode, 
+						am.getStreamMaxVolume(AudioManager.STREAM_MUSIC)*
+						(speakermode == AudioManager.MODE_NORMAL?4:3)/4
+				),0);
+	}
+
+	void saveVolume() {
+		Editor edit = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+		edit.putInt("volume"+speakermode,am.getStreamVolume(AudioManager.STREAM_MUSIC));
+		edit.commit();
+	}
+
+	void saveSettings() {
+		if (!PreferenceManager.getDefaultSharedPreferences(mContext).getBoolean("oldvalid",false)) {
+			int oldvibrate = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
+			int oldvibrate2 = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
+			if (!PreferenceManager.getDefaultSharedPreferences(mContext).contains("oldvibrate2"))
+				oldvibrate2 = AudioManager.VIBRATE_SETTING_ON;
+			int oldpolicy = android.provider.Settings.System.getInt(cr, android.provider.Settings.System.WIFI_SLEEP_POLICY, 
+					Settings.System.WIFI_SLEEP_POLICY_DEFAULT);
+			Editor edit = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+			edit.putInt("oldvibrate", oldvibrate);
+			edit.putInt("oldvibrate2", oldvibrate2);
+			edit.putInt("oldpolicy", oldpolicy);
+			edit.putInt("oldring",am.getStreamVolume(AudioManager.STREAM_RING));
+			edit.putBoolean("oldvalid", true);
+			edit.commit();
+		}
+	}
+
+	void restoreSettings() {
+		int oldvibrate = PreferenceManager.getDefaultSharedPreferences(mContext).getInt("oldvibrate",0);
+		int oldvibrate2 = PreferenceManager.getDefaultSharedPreferences(mContext).getInt("oldvibrate2",0);
+		int oldpolicy = PreferenceManager.getDefaultSharedPreferences(mContext).getInt("oldpolicy",0);
+		am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,oldvibrate);
+		am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,oldvibrate2);
+		Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY, oldpolicy);
+		am.setStreamVolume(AudioManager.STREAM_RING, PreferenceManager.getDefaultSharedPreferences(mContext).getInt("oldring",0), 0);
+		Editor edit = PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+		edit.putBoolean("oldvalid", false);
+		edit.commit();
+	}
+
+	public static float good, late, lost, loss;
+
+	/** Runs it in a new Thread. */
+	@Override
+	public void run() {
+		REAL_BUFFER_SIZE = BUFFER_SIZE * codec_divider;
+		speakermode = AudioManager.MODE_IN_CALL;
+		android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
+		am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+		cr = mContext.getContentResolver();
+		//saveSettings();
+
+		Settings.System.putInt(cr, Settings.System.WIFI_SLEEP_POLICY,Settings.System.WIFI_SLEEP_POLICY_NEVER);
+		//am.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER,AudioManager.VIBRATE_SETTING_OFF);
+		//am.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION,AudioManager.VIBRATE_SETTING_OFF);
+		//oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
+		restoreVolume();
+
+		track = new AudioTrack(AudioManager.STREAM_MUSIC, sampling_rate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+				REAL_BUFFER_SIZE*2*2, AudioTrack.MODE_STREAM);
+		track.play();
+		lin = new short[REAL_BUFFER_SIZE];
+		lin2 = new short[REAL_BUFFER_SIZE];
+		user = 0; //number of samples written
+		server = 0; // number of samples played
+		lserver = 0; // last number of samples played
+		luser = -sampling_rate; // last number of samples written
+		cnt = 0;
+		codecCtx = codec.initDecoder(); 
+		System.gc();
+		println("DEBUG: rtpStreamReceiver session launch");
+		running = true;
+		AppCallerThread appCall = rtpSession.getAppCallerThrd();
+		RTPReceiverThread recv = rtpSession.getRTPRecvThrd();
+		DataFrame frame = null;
+		recv.init();
+		while (running) {
+			recv.readPacketToBuffer();
+			frame = appCall.getNextDataFrame();
+			if (frame == null)
+				continue;
+			buffer = (frame.getPkt()[0]).getPayload();
+			if (timeout != 0) { //on ecrit du blanc sur l'audiotrack
+				user += track.write(lin,0,REAL_BUFFER_SIZE);
+				user += track.write(lin,0,REAL_BUFFER_SIZE);
+			}
+			timeout = 0;
+			if (running) {
+
+				//println("seq " + seq + " frame seq " + (frame.getPkt()[0]).getSeqNumber());
+				if (seq == (frame.getPkt()[0]).getSeqNumber()) {
+					m++;
+					continue;
+				}
+
+				codec.decode(codecCtx, buffer, 12, codec_frame_size, lin, 0);
+				len = frame_size;
+
+				if (speakermode == AudioManager.MODE_NORMAL)
+					calc(lin,0,len);
+
+				server = track.getPlaybackHeadPosition(); // on récupère la position actuel de la tete de lecture
+				headroom = user-server; // on recalcule la différence entre la position de la tete de lecture et ce qu'on a écrit sur la piste
+				//println("headroom " + headroom + " user " + user + " server " + server);
+				if (headroom < 250 * codec_divider) { // si le headroom est trop petit, il faut rattraper le retard en écrivant du blanc/répétant ce qu'il y a à ecrire
+					todo = 625 * codec_divider - headroom;
+					//println("insert "+todo);
+					android.util.Log.d("RECV", "insert");
+					islate = true;
+					if (todo < len)
+						user += track.write(lin,0,todo); // on écrit le packet reçu tel quel
+					else
+						user += track.write(lin2,0,todo); // ecriture de blanc de taille 625 - headroom, avant l'écriture du packet
+				} else
+					islate = false;
+
+				if (headroom > 1000 * codec_divider) // si le headroom est trop grand, on calcule l'écart.
+					cnt += len; // on additione le nombre de sample ou il y a eu un headroom supérieur a 1000
+				else
+					cnt = 0;
+
+				if (lserver == server) // on compte le nombre de boucle que l'on a fait sans qu'aucun sample n'ai été joué.
+					cnt2++;
+				else
+					cnt2 = 0;
+
+				if (cnt > 1000 * codec_divider && cnt2 < 2) { // si la position de la tete de lecture n'a pas bougé durant 2 tours et que le nombre de sample ou le headroom a été supérieur à 1000 est > 1000
+					todo = headroom - 625 * codec_divider;
+					try {
+						//android.util.Log.d("RECV", "cut");
+						sleep(20);
+					} catch (InterruptedException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+				}
+				user += track.write(lin,0,len);
+				m = 1;
+				seq = (frame.getPkt()[0]).getSeqNumber();
+				DataFramePool.getInstance().returnFrame(frame);
+				//println("headroom " + headroom + " user " + user + " server " + server + " luser " + luser + " lserver " + lserver);
+				if (user >= luser + sampling_rate) {
+					/*if (am.getMode() != speakermode) {
+						am.setMode(speakermode);
+						switch (speakermode) {
+						case AudioManager.MODE_IN_CALL:
+							am.setStreamVolume(AudioManager.STREAM_RING,(int)(
+									am.getStreamMaxVolume(AudioManager.STREAM_RING)*
+									com.mbdsys.sfrdroid.ui.Settings.getEarGain()), 0);
+							track.setStereoVolume(AudioTrack.getMaxVolume()*
+									com.mbdsys.sfrdroid.ui.Settings.getEarGain()
+									,AudioTrack.getMaxVolume()*
+									com.mbdsys.sfrdroid.ui.Settings.getEarGain());
+							//running = false;
+						case AudioManager.MODE_NORMAL:
+							track.setStereoVolume(AudioTrack.getMaxVolume(),AudioTrack.getMaxVolume());
+							//running = false;
+						}
+					}*/
+					luser = user;
+				}
+				lserver = server;
+				System.arraycopy(lin, 0, lin2, 0, REAL_BUFFER_SIZE);
+			}
+		}
+		println("POOL SIZE " + DatagramPool.getInstance().getPoolSize());
+		track.stop();
+		//if (Receiver.pstn_state == null || Receiver.pstn_state.equals("IDLE"))
+		//	am.setMode(AudioManager.MODE_NORMAL);
+		//saveVolume();
+		//am.setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0);
+		//restoreSettings();
+		ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_RING,ToneGenerator.MAX_VOLUME/4*3);
+		tg.startTone(ToneGenerator.TONE_PROP_PROMPT);
+		try {
+			Thread.sleep(500);
+		} catch (InterruptedException e) {
+		}
+		tg.stopTone();
+		rtpSession = null;
+		track = null;
+		codec.cleanDecoder(codecCtx);
+		codec = null;
+		println("rtp receiver terminated");
+	}
+
+	/** Debug output */
+	static int i = 0;
+	private static void println(String str) {
+		System.out.println("RtpStreamReceiver "+ i++ +": " + str);
+	}
+
+	public static int byte2int(byte b) { // return (b>=0)? b : -((b^0xFF)+1);
+		// return (b>=0)? b : b+0x100;
+		return (b + 0x100) % 0x100;
+	}
+
+	public static int byte2int(byte b1, byte b2) {
+		return (((b1 + 0x100) % 0x100) << 8) + (b2 + 0x100) % 0x100;
+	}
+
+	@Override
+	public int frameSize(int payloadType) {
+		// TODO Auto-generated method stub
+		return 0;
+	}
+
+	@Override
+	public void receiveData(DataFrame frame, Participant participant) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void userEvent(int type, Participant[] participant) {
+		// TODO Auto-generated method stub
+
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/RtpStreamSender.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
+ * 
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ * 
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package org.sipdroid.media;
+
+import java.io.InputStream;
+import java.net.DatagramPacket;
+import java.util.Random;
+
+import jlibrtp.RTPSession;
+import jlibrtp.RtpPkt;
+
+import org.sipdroid.media.codecs.Codec;
+
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+
+/**
+ * RtpStreamSender is a generic stream sender. It takes an InputStream and sends
+ * it through RTP.
+ */
+public class RtpStreamSender extends Thread{
+
+	private static final boolean DEBUG = true;
+
+	/** The RtpSocket */
+	//private RtpSocket rtp_socket = null;
+	private RTPSession rtpSession = null;
+
+	/** Codec */
+	private Codec codec;
+
+	private int sampling_rate;
+
+	/** Number of bytes per frame */
+	private int frame_size;
+
+	private int codec_frame_size;
+
+	/**
+	 * Whether it works synchronously with a local clock, or it it acts as slave
+	 * of the InputStream
+	 */
+	boolean do_sync = true;
+
+	int sync_adj = 0;
+
+	/** Whether it is running */
+	boolean running = false;
+	boolean muted = false;
+
+	private int codec_divider;
+
+	/**
+	 * Constructs a RtpStreamSender.
+	 * 
+	 */
+	public RtpStreamSender(Codec co, RTPSession rtpSession) {
+		init(co, rtpSession);
+	}
+
+	/** Inits the RtpStreamSender */
+	private void init(Codec co,	RTPSession rtpSession) {
+		this.rtpSession = rtpSession;
+		codec = co;
+		sampling_rate = codec.getInfo().samplingRate;
+		codec_frame_size = codec.getInfo().codecFrameSize;
+		codec_divider = codec.getInfo().rtpSampleDivider;
+		frame_size = 160 * codec_divider;
+		rtpSession.payloadType(codec.getInfo().rtpPayloadCode);
+
+		this.do_sync = true;
+	}
+
+	/** Sets the synchronization adjustment time (in milliseconds). */
+	public void setSyncAdj(int millisecs) {
+		sync_adj = millisecs;
+	}
+
+	/** Whether is running */
+	public boolean isRunning() {
+		return running;
+	}
+
+	public boolean mute() {
+		return muted = !muted;
+	}
+
+	public static int delay = 0;
+
+	/** Stops running */
+	public void halt() {
+		running = false;
+	}
+
+	Random random;
+	double smin = 200,s;
+	int nearend;
+
+	void calc(short[] lin,int off,int len) {
+		int i,j;
+		double sm = 30000,r;
+
+		for (i = 0; i < len; i += 5) {
+			j = lin[i+off];
+			s = 0.03*Math.abs(j) + 0.97*s;
+			if (s < sm) sm = s;
+			if (s > smin) nearend = 3000/5;
+			else if (nearend > 0) nearend--;
+		}
+		for (i = 0; i < len; i++) {
+			j = lin[i+off];
+			if (j > 6550)
+				lin[i+off] = 6550*5;
+			else if (j < -6550)
+				lin[i+off] = -6550*5;
+			else
+				lin[i+off] = (short)(j*5);
+		}
+		r = (double)len/100000;
+		smin = sm*r + smin*(1-r);
+	}
+
+	void noise(short[] lin,int off,int len,double power) {
+		int i,r = (int)(power*2);
+		short ran;
+
+		if (r == 0) r = 1;
+		for (i = 0; i < len; i += 4) {
+			ran = (short)(random.nextInt(r*2)-r);
+			lin[i+off] = ran;
+			lin[i+off+1] = ran;
+			lin[i+off+2] = ran;
+			lin[i+off+3] = ran;
+		}
+	}
+
+	public static int m;
+
+	/** Runs it in a new Thread. */
+	public void run() {
+		if (rtpSession == null)
+			return;
+		byte[] buffer = new byte[codec_frame_size + 12];
+		DatagramPacket packet = new DatagramPacket(buffer, codec_frame_size + 12);
+		RtpPkt pkt = new RtpPkt();
+		pkt.setRawPkt(buffer);
+		pkt.setPayloadType(codec.getInfo().rtpPayloadCode);
+		int seqn = 0;
+		long time = 0;
+		double p = 0;
+		running = true;
+		m = 1;
+
+		if (DEBUG)
+			println("Reading blocks of " + buffer.length + " bytes");
+
+		android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
+
+		Codec.Context codecCtx = codec.initEncoder();
+
+		AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, sampling_rate, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, 
+				AudioRecord.getMinBufferSize(sampling_rate, 
+						AudioFormat.CHANNEL_CONFIGURATION_MONO, 
+						AudioFormat.ENCODING_PCM_16BIT)*2);
+		record.startRecording();
+		short[] lin = new short[frame_size*11];
+		int num,ring = 0;
+		random = new Random();
+		while (running) {
+			num = record.read(lin,(ring+delay)%(frame_size*11),frame_size);
+			if (RtpStreamReceiver.speakermode == AudioManager.MODE_NORMAL) {
+				calc(lin,(ring+delay)%(frame_size*11),num);
+				if (RtpStreamReceiver.nearend != 0)
+					noise(lin,(ring+delay)%(frame_size*11),num,p);
+				else if (nearend == 0)
+					p = 0.9*p + 0.1*s;
+			}
+			codec.encode(codecCtx, lin, ring%(frame_size*11), frame_size, buffer, 12);
+			ring += frame_size;
+			rtpSession.sendData(packet, pkt);
+			if (m == 2) {
+				rtpSession.sendData(packet, pkt);
+				println("retransmit");
+			}
+			seqn++;
+			time += num;
+		}
+		record.stop();
+		rtpSession = null;
+		codec.cleanEncoder(codecCtx);
+		if (DEBUG)
+			println("rtp sender terminated");
+	}
+
+	/** Debug output */
+	private static void println(String str) {
+		android.util.Log.d("DEBUG","RtpStreamSender: " + str);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/Codec.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,19 @@
+package org.sipdroid.media.codecs;
+
+public abstract class Codec {
+	
+	public abstract class Context {
+	};
+	
+	public abstract Context  initEncoder();
+	public abstract Context  initDecoder();
+	public abstract void     cleanEncoder(Context ctx);
+	public abstract void  	 cleanDecoder(Context ctx);
+	
+
+	public abstract int encode(Context ctx, short[] insample, int inoffset, int size, byte[] outdata, int outoffset);
+	public abstract int decode(Context ctx, byte[] indata, int inoffset, int size, short[] outsample, int outoffset);
+	
+	public abstract CodecInfo getInfo();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/CodecInfo.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,43 @@
+package org.sipdroid.media.codecs;
+
+/**
+ * @author vadim
+ *
+ */
+public class CodecInfo {
+	/**
+	 * String to show in config dialog
+	 */
+	public String displayName;
+	/**
+	 * codec spec string to use in SDP
+	 */
+	public String rtpPayloadName;
+	/**
+	 * prefered RTP payload code
+	 */
+	public int    rtpPayloadCode;
+	/**
+	 * sampling rate for this codec
+	 */
+	public int	  samplingRate;
+	/**
+	 * divider for sampling rate to use when computing rtp timestamp 
+	 */
+	public int    rtpSampleDivider;
+	/**
+	 * minimum frameSize in milliseconds
+	 */
+	public int    minFrameTimeMsecs;
+	/**
+	 * codec description to display in configuration dialog
+	 */
+	public String description;
+	
+	/**
+	 * codec frame size
+	 */
+	public int    codecFrameSize;
+	
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/CodecManager.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,46 @@
+/**
+ * 
+ */
+package org.sipdroid.media.codecs;
+
+import java.util.LinkedList;
+
+/**
+ * @author vadim
+ *
+ */
+public class CodecManager {
+	
+	public static void load() {
+		GSM.load();
+		G711.load();
+		G722.load();
+	}
+	
+	public static LinkedList<Codec>  audioCodecs = new LinkedList<Codec>();
+	
+	public static Codec  getCodecByDisplayName(String cn) {
+		
+		for (Codec c : audioCodecs) {
+			if (c.getInfo().displayName.equals(cn))
+				return c;
+		}
+		
+		return null;
+	}
+
+	public static Codec  getCodecByRtpName(String cn) {
+		
+		for (Codec c : audioCodecs) {
+			if (c.getInfo().rtpPayloadName.equals(cn))
+				return c;
+		}
+		
+		return null;
+	}
+	
+	
+	public static void registerAudioCodec(Codec c) {
+		audioCodecs.addLast(c);	
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/G711.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,393 @@
+package org.sipdroid.media.codecs;
+
+/**
+ * G.711 codec. This class provides methods for u-law, A-law and linear PCM
+ * conversions.
+ */
+public class G711 extends Codec {
+	/*
+	 * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische
+	 * Universitaet Berlin.  See the accompanying file "COPYRIGHT" for
+	 * details.  THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
+	 */
+	public static final CodecInfo mCodecInfo = new CodecInfo();
+	
+	static {
+		mCodecInfo.displayName = "aLaw";		
+		mCodecInfo.rtpPayloadName = "PCMA";
+		mCodecInfo.description = "G711 aLaw codec";
+		mCodecInfo.rtpPayloadCode = 8;
+		mCodecInfo.samplingRate = 8000;
+		mCodecInfo.rtpSampleDivider = 1;
+		mCodecInfo.minFrameTimeMsecs = 20;
+		mCodecInfo.codecFrameSize = 160;
+		CodecManager.registerAudioCodec(new G711());
+	}
+	
+	private static final int[] _a2s = {
+
+	 60032, 60288, 59520, 59776, 61056, 61312, 60544, 60800,
+	 57984, 58240, 57472, 57728, 59008, 59264, 58496, 58752,
+	 62784, 62912, 62528, 62656, 63296, 63424, 63040, 63168,
+	 61760, 61888, 61504, 61632, 62272, 62400, 62016, 62144,
+	 43520, 44544, 41472, 42496, 47616, 48640, 45568, 46592,
+	 35328, 36352, 33280, 34304, 39424, 40448, 37376, 38400,
+	 54528, 55040, 53504, 54016, 56576, 57088, 55552, 56064,
+	 50432, 50944, 49408, 49920, 52480, 52992, 51456, 51968,
+	 65192, 65208, 65160, 65176, 65256, 65272, 65224, 65240,
+	 65064, 65080, 65032, 65048, 65128, 65144, 65096, 65112,
+	 65448, 65464, 65416, 65432, 65512, 65528, 65480, 65496,
+	 65320, 65336, 65288, 65304, 65384, 65400, 65352, 65368,
+	 64160, 64224, 64032, 64096, 64416, 64480, 64288, 64352,
+	 63648, 63712, 63520, 63584, 63904, 63968, 63776, 63840,
+	 64848, 64880, 64784, 64816, 64976, 65008, 64912, 64944,
+	 64592, 64624, 64528, 64560, 64720, 64752, 64656, 64688,
+	  5504,  5248,  6016,  5760,  4480,  4224,  4992,  4736,
+	  7552,  7296,  8064,  7808,  6528,  6272,  7040,  6784,
+	  2752,  2624,  3008,  2880,  2240,  2112,  2496,  2368,
+	  3776,  3648,  4032,  3904,  3264,  3136,  3520,  3392,
+	 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944,
+	 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136,
+	 11008, 10496, 12032, 11520,  8960,  8448,  9984,  9472,
+	 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568,
+	   344,   328,   376,   360,   280,   264,   312,   296,
+	   472,   456,   504,   488,   408,   392,   440,   424,
+	    88,    72,   120,   104,    24,     8,    56,    40,
+	   216,   200,   248,   232,   152,   136,   184,   168,
+	  1376,  1312,  1504,  1440,  1120,  1056,  1248,  1184,
+	  1888,  1824,  2016,  1952,  1632,  1568,  1760,  1696,
+	   688,   656,   752,   720,   560,   528,   624,   592,
+	   944,   912,  1008,   976,   816,   784,   880,   848
+
+	};
+
+	private static final int[] _s2a = {
+
+		213,212,215,214,209,208,211,210,221,220,223,222,217,216,219,218,
+		197,196,199,198,193,192,195,194,205,204,207,206,201,200,203,202,
+		245,245,244,244,247,247,246,246,241,241,240,240,243,243,242,242,
+		253,253,252,252,255,255,254,254,249,249,248,248,251,251,250,250,
+		229,229,229,229,228,228,228,228,231,231,231,231,230,230,230,230,
+		225,225,225,225,224,224,224,224,227,227,227,227,226,226,226,226,
+		237,237,237,237,236,236,236,236,239,239,239,239,238,238,238,238,
+		233,233,233,233,232,232,232,232,235,235,235,235,234,234,234,234,
+		149,149,149,149,149,149,149,149,148,148,148,148,148,148,148,148,
+		151,151,151,151,151,151,151,151,150,150,150,150,150,150,150,150,
+		145,145,145,145,145,145,145,145,144,144,144,144,144,144,144,144,
+		147,147,147,147,147,147,147,147,146,146,146,146,146,146,146,146,
+		157,157,157,157,157,157,157,157,156,156,156,156,156,156,156,156,
+		159,159,159,159,159,159,159,159,158,158,158,158,158,158,158,158,
+		153,153,153,153,153,153,153,153,152,152,152,152,152,152,152,152,
+		155,155,155,155,155,155,155,155,154,154,154,154,154,154,154,154,
+		133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
+		132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
+		135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
+		134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,
+		129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
+		128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
+		131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
+		130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,
+		141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,
+		140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,
+		143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+		142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
+		137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
+		136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,
+		139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
+		138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
+		181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
+		181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,
+		180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
+		180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
+		183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,
+		183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,
+		182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+		182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,
+		177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
+		177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,
+		176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
+		176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,
+		179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,
+		179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,
+		178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
+		178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,
+		189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
+		189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,
+		188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
+		188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,
+		191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,
+		191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,
+		190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,
+		190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,
+		185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
+		185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,
+		184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
+		184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,
+		187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,
+		187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,
+		186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,
+		186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,
+		165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
+		165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
+		165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
+		165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,
+		164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
+		164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
+		164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
+		164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,
+		167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
+		167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
+		167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
+		167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,
+		166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
+		166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
+		166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
+		166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,
+		161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
+		161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
+		161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
+		161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,
+		160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
+		160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
+		160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
+		160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
+		163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+		163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+		163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+		163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,
+		162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
+		162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
+		162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
+		162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,
+		173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+		173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+		173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+		173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,
+		172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+		172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+		172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+		172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,
+		175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
+		175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
+		175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
+		175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,
+		174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+		174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+		174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+		174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,
+		169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
+		169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
+		169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
+		169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,
+		168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
+		168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
+		168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
+		168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,
+		171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
+		171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
+		171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
+		171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,
+		170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+		170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+		170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+		170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,
+		 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+		 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+		 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+		 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
+		 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+		 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+		 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+		 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
+		 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+		 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+		 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+		 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+		 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+		 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+		 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+		 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+		 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+		 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+		 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+		 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+		 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+		 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+		 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+		 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+		 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+		 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+		 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+		 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+		 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+		 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+		 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+		 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+		 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+		 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+		 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+		 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+		 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+		 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+		 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+		 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+		 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+		 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+		 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+		 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+		 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+		 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+		 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+		 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+		 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+		 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+		 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+		 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
+		 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+		 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+		 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+		 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
+		 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+		 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+		 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+		 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+		 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+		 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+		 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+		 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+		 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+		 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+		 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+		 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+		 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+		 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+		 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+		 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+		 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+		 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+		 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+		 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+		 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+		 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+		 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+		 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+		 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+		 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+		 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+		 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+		 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+		 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
+		 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+		 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+		 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+		 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+		 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+		 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+		 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+		 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
+		 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+		 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+		 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+		 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+		  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  8,
+		  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,  9,
+		 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+		 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+		 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+		 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+		  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,
+		  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,
+		  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+		  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+		  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,
+		  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,
+		 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+		 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25,
+		 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31,
+		 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29,
+		 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
+		 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
+		 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+		 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21,
+		106,106,106,106,107,107,107,107,104,104,104,104,105,105,105,105,
+		110,110,110,110,111,111,111,111,108,108,108,108,109,109,109,109,
+		 98, 98, 98, 98, 99, 99, 99, 99, 96, 96, 96, 96, 97, 97, 97, 97,
+		102,102,102,102,103,103,103,103,100,100,100,100,101,101,101,101,
+		122,122,123,123,120,120,121,121,126,126,127,127,124,124,125,125,
+		114,114,115,115,112,112,113,113,118,118,119,119,116,116,117,117,
+		 74, 75, 72, 73, 78, 79, 76, 77, 66, 67, 64, 65, 70, 71, 68, 69,
+		 90, 91, 88, 89, 94, 95, 92, 93, 82, 83, 80, 81, 86, 87, 84, 85
+	};
+	
+	
+	public class G711Context extends Context {
+		public final short[] a2s = new short[256];
+		public final byte[] s2a = new byte[65536];
+	}
+	
+	public void init(G711Context ctx) {
+ 		int i;
+		for (i = 0; i < 256; i++)
+			ctx.a2s[i] = (short)_a2s[i];
+		for (i = 0; i < 65536; i++)
+			ctx.s2a[i] = (byte)_s2a[i >> 4];
+	}
+
+	private void alaw2linear(G711Context ctx, byte alaw[], int inoffset, int size, short lin[], int outoffset) {
+		int i;
+		for (i = 0; i < size; i++)
+			lin[i + outoffset] = ctx.a2s[alaw[i + inoffset] & 0xff];
+	}
+	
+	private void linear2alaw(G711Context ctx, short lin[], int inoffset, byte alaw[], int outoffset, int size) {
+		int i;
+		for (i = 0; i < size; i++)
+			alaw[i + outoffset] = ctx.s2a[lin[i + inoffset] & 0xffff];
+	}
+	
+	@Override
+	public Context initDecoder() {
+		G711Context ctx = new G711Context();
+		init(ctx);
+		return ctx;
+	}
+
+	@Override
+	public Context initEncoder() {
+		G711Context ctx = new G711Context();
+		init(ctx);
+		return ctx;
+	}
+
+	@Override
+	public void cleanDecoder(Context ctx) {
+	}
+
+	@Override
+	public void cleanEncoder(Context ctx) {
+	}
+
+	@Override
+	public int decode(Context ctx, byte[] indata, int inoffset, int size,
+			short[] outsample, int outoffset) {
+		alaw2linear((G711Context) ctx, indata, inoffset, size, outsample, outoffset);
+		return size;
+	}
+
+	@Override
+	public int encode(Context ctx, short[] insample, int inoffset, int size,
+			byte[] outdata, int outoffset) {
+		linear2alaw((G711Context) ctx, insample, inoffset, outdata, outoffset, size);
+		return 0;
+	}
+
+	@Override
+	public CodecInfo getInfo() {		
+		return mCodecInfo;
+	}
+	
+	static public void load(){
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/G722.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,68 @@
+package org.sipdroid.media.codecs;
+
+public class G722 extends Codec {
+
+	public static final CodecInfo mCodecInfo = new CodecInfo();
+
+	static {
+		System.loadLibrary("g722");
+		mCodecInfo.displayName = "G722";
+		mCodecInfo.rtpPayloadName = "G722";
+		mCodecInfo.description = "G722 16kHz codec";
+		mCodecInfo.rtpPayloadCode = 9;
+		mCodecInfo.samplingRate = 16000;
+		mCodecInfo.rtpSampleDivider = 2;
+		mCodecInfo.minFrameTimeMsecs = 20;
+		mCodecInfo.codecFrameSize = 160;
+		CodecManager.registerAudioCodec(new G722());
+	}
+
+	public class G722Context extends Context {
+		public long ctx;
+	}
+
+	@Override
+	public Context initDecoder() {
+		G722Context decoderCtx = new G722Context();
+		decoderCtx.ctx = G722JNI.decodeInit(decoderCtx.ctx, mCodecInfo.codecFrameSize, 0);
+		return decoderCtx;
+	}
+
+	@Override
+	public Context initEncoder() {
+		G722Context encoderCtx = new G722Context();
+		encoderCtx.ctx = G722JNI.encodeInit(encoderCtx.ctx, mCodecInfo.codecFrameSize, 0);
+		return encoderCtx;
+	}
+
+	@Override
+	public void cleanDecoder(Context ctx) {
+		G722JNI.decodeRelease(((G722Context)ctx).ctx);
+	}
+
+	@Override
+	public void cleanEncoder(Context ctx) {
+		G722JNI.encodeRelease(((G722Context)ctx).ctx);
+	}
+
+	@Override
+	public int decode(Context ctx, byte[] indata, int inoffset, int size,
+			short[] outsample, int outoffset) {
+		return G722JNI.decode(((G722Context)ctx).ctx, indata, inoffset, outsample, outoffset, size);
+	}
+
+	@Override
+	public int encode(Context ctx, short[] insample, int inoffset, int size,
+			byte[] outdata, int outoffset) {
+		G722JNI.encode(((G722Context)ctx).ctx, insample, inoffset, outdata, outoffset, size);
+		return size;
+	}
+
+	@Override
+	public CodecInfo getInfo() {
+		return mCodecInfo;
+	}
+
+	static public void load(){
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/G722JNI.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,10 @@
+package org.sipdroid.media.codecs;
+
+public class G722JNI {
+	public static native long encodeInit(long g722State, int rate, int options);
+	public static native int encodeRelease(long g722State);
+	public static native int encode(long g722State, short[] signal, long srcPos, byte[] g722Byte, long destPos, int len);
+	public static native long decodeInit(long g722State, int rate, int options);
+	public static native int decodeRelease(long g722State);
+	public static native int decode(long g722State, byte[] g722Byte, long srcPos, short[] signal, long destPos, int len);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/GSM.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,68 @@
+package org.sipdroid.media.codecs;
+
+public class GSM extends Codec {
+
+	public static final CodecInfo mCodecInfo = new CodecInfo();
+
+	static {
+		System.loadLibrary("gsm");
+		mCodecInfo.displayName = "GSM";
+		mCodecInfo.rtpPayloadName = "GSM";
+		mCodecInfo.description = "GSM Full Rate codec";
+		mCodecInfo.rtpPayloadCode = 3;
+		mCodecInfo.samplingRate = 8000;
+		mCodecInfo.rtpSampleDivider = 1;
+		mCodecInfo.minFrameTimeMsecs = 20;
+		mCodecInfo.codecFrameSize = 33;
+		CodecManager.registerAudioCodec(new GSM());
+	}
+
+	public class GSMContext extends Context {
+		public long ctx;
+	}
+
+	@Override
+	public Context initDecoder() {
+		GSMContext decoderCtx = new GSMContext();
+		decoderCtx.ctx = GSMJNI.create();
+		return decoderCtx;
+	}
+
+	@Override
+	public Context initEncoder() {
+		GSMContext encoderCtx = new GSMContext();
+		encoderCtx.ctx = GSMJNI.create();
+		return encoderCtx;
+	}
+
+	@Override
+	public void cleanDecoder(Context ctx) {
+		GSMJNI.destroy(((GSMContext)ctx).ctx);
+	}
+
+	@Override
+	public void cleanEncoder(Context ctx) {
+		GSMJNI.destroy(((GSMContext)ctx).ctx);
+	}
+
+	@Override
+	public int decode(Context ctx, byte[] indata, int inoffset, int size,
+			short[] outsample, int outoffset) {
+		return GSMJNI.decode(((GSMContext)ctx).ctx, indata, inoffset, outsample, outoffset);
+	}
+
+	@Override
+	public int encode(Context ctx, short[] insample, int inoffset, int size,
+			byte[] outdata, int outoffset) {
+		GSMJNI.encode(((GSMContext)ctx).ctx, insample, inoffset, outdata, outoffset);
+		return size;
+	}
+
+	@Override
+	public CodecInfo getInfo() {
+		return mCodecInfo;
+	}
+
+	static public void load(){
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/codecs/GSMJNI.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,8 @@
+package org.sipdroid.media.codecs;
+
+public class GSMJNI {
+	public static native long create();
+	public static native void destroy(long gsm);
+	public static native int decode(long gsm, byte[] gsmByte, long srcPos, short[] signal, long destPos);
+	public static native void encode(long gsm, short[] signal, long srcPos, byte[] gsmByte, long destPos);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/SipdroidSocket.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ * 
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ * 
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package org.sipdroid.net;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.SocketOptions;
+import java.net.UnknownHostException;
+
+import org.sipdroid.net.impl.OSNetworkSystem;
+import org.sipdroid.net.impl.PlainDatagramSocketImpl;
+
+public class SipdroidSocket extends DatagramSocket {
+
+	PlainDatagramSocketImpl impl;
+	public static boolean loaded = false;
+	
+	public SipdroidSocket(int port) throws SocketException, UnknownHostException {
+		super(!loaded?port:0);
+		if (loaded) {
+			impl = new PlainDatagramSocketImpl();
+			impl.create();
+			impl.bind(port,InetAddress.getByName("0"));
+			android.util.Log.d("TEST","name : " + InetAddress.getByName("0"));
+		}
+	}
+	
+	public void close() {
+		super.close();
+		if (loaded) impl.close();
+	}
+	
+	public void setSoTimeout(int val) throws SocketException {
+		if (loaded) impl.setOption(SocketOptions.SO_TIMEOUT, val);
+		else super.setSoTimeout(val);
+	}
+	
+	public void receive(DatagramPacket pack) throws IOException {
+		if (loaded) impl.receive(pack);
+		else super.receive(pack);
+	}
+	
+	public void send(DatagramPacket pack) throws IOException {
+		if (loaded) impl.send(pack);
+		else super.send(pack);
+	}
+	
+	public boolean isConnected() {
+		if (loaded) return true;
+		else return super.isConnected();
+	}
+	
+	public void disconnect() {
+		if (!loaded) super.disconnect();
+	}
+	
+	public void connect(InetAddress addr,int port) {
+		if (!loaded) super.connect(addr,port);
+	}
+
+	static {
+		        System.loadLibrary("OSNetworkSystem");
+		        OSNetworkSystem.getOSNetworkSystem().oneTimeInitialization(true);
+		        SipdroidSocket.loaded = true;
+		        android.util.Log.d("OSNetworkSystem", "LOADED");
+			
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/impl/OSNetworkSystem.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,748 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ * 
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ * 
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+// BEGIN android-note
+// address length was changed from long to int for performance reasons.
+// END android-note
+
+package org.sipdroid.net.impl;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.SocketException;
+import java.net.SocketImpl;
+import java.net.UnknownHostException;
+import java.nio.channels.Channel;
+// BEGIN android-removed
+// import java.nio.channels.SelectableChannel;
+// END android-removed
+/*
+ * 
+ * This Class is used for native code wrap, the implement class of
+ * INetworkSystem.
+ * 
+ */
+public final class OSNetworkSystem {
+
+    // ----------------------------------------------------
+    // Class Variables
+    // ----------------------------------------------------
+
+    private static final int ERRORCODE_SOCKET_TIMEOUT = -209;
+
+    private static OSNetworkSystem ref = new OSNetworkSystem();
+    
+    private static final int INETADDR_REACHABLE = 0;
+    
+    private static boolean isNetworkInited = false;
+    
+    // ----------------------------------------------------
+    // Class Constructor
+    // ----------------------------------------------------
+
+    // can not be instantiated.
+    private OSNetworkSystem() {
+        super();
+    }
+
+    /*
+     * @return a static ref of this class
+     */
+    public static OSNetworkSystem getOSNetworkSystem() {
+        return ref;
+    }
+
+    // Useing when cache set/get is OK
+    // public static native void oneTimeInitializationDatagram(
+    // boolean jcl_IPv6_support);
+    //
+    // public static native void oneTimeInitializationSocket(
+    // boolean jcl_IPv6_support);
+
+    // --------------------------------------------------
+    // java codes that wrap native codes
+    // --------------------------------------------------
+
+    public void createSocket(FileDescriptor fd, boolean preferIPv4Stack)
+            throws IOException {
+        createSocketImpl(fd, preferIPv4Stack);
+    }
+
+    public void createDatagramSocket(FileDescriptor fd, boolean preferIPv4Stack)
+            throws SocketException {
+        createDatagramSocketImpl(fd, preferIPv4Stack);
+    }
+
+    public int read(FileDescriptor aFD, byte[] data, int offset, int count,
+            int timeout) throws IOException {
+        return readSocketImpl(aFD, data, offset, count, timeout);
+    }
+    
+    public int readDirect(FileDescriptor aFD, int address, int offset, int count,
+            int timeout) throws IOException {
+        return readSocketDirectImpl(aFD, address, offset, count, timeout);
+    }
+
+    public int write(FileDescriptor aFD, byte[] data, int offset, int count)
+            throws IOException {
+        return writeSocketImpl(aFD, data, offset, count);
+    }
+    
+    public int writeDirect(FileDescriptor aFD, int address, int offset,
+            int count) throws IOException {
+        return writeSocketDirectImpl(aFD, address, offset, count);
+    }
+
+    public void setNonBlocking(FileDescriptor aFD, boolean block)
+            throws IOException {
+        setNonBlockingImpl(aFD, block);
+    }
+
+    public void connectDatagram(FileDescriptor aFD, int port, int trafficClass,
+            InetAddress inetAddress) throws SocketException {
+        connectDatagramImpl2(aFD, port, trafficClass, inetAddress);
+    }
+
+    public int connect(FileDescriptor aFD, int trafficClass,
+            InetAddress inetAddress, int port)  throws IOException{
+        return connectSocketImpl(aFD, trafficClass, inetAddress, port);
+    }
+
+    // BEGIN android-changed
+    public int connectWithTimeout(FileDescriptor aFD, int timeout,
+            int trafficClass, InetAddress inetAddress, int port, int step,
+            byte[] context)  throws IOException{
+        return connectWithTimeoutSocketImpl(aFD, timeout, trafficClass,
+                inetAddress, port, step, context);
+    }
+    // END android-changed
+
+    public void connectStreamWithTimeoutSocket(FileDescriptor aFD, int aport,
+            int timeout, int trafficClass, InetAddress inetAddress)
+            throws IOException {
+        connectStreamWithTimeoutSocketImpl(aFD, aport, timeout, trafficClass,
+                inetAddress);
+    }
+
+    public void bind(FileDescriptor aFD, int port, InetAddress inetAddress)
+            throws SocketException {
+        socketBindImpl(aFD, port, inetAddress);
+    }
+
+    public boolean bind2(FileDescriptor aFD, int port, boolean bindToDevice,
+            InetAddress inetAddress) throws SocketException {
+        return socketBindImpl2(aFD, port, bindToDevice, inetAddress);
+    }
+
+    public void accept(FileDescriptor fdServer, SocketImpl newSocket,
+            FileDescriptor fdnewSocket, int timeout) throws IOException {
+        acceptSocketImpl(fdServer, newSocket, fdnewSocket, timeout);
+    }
+
+    public int sendDatagram(FileDescriptor fd, byte[] data, int offset,
+            int length, int port, boolean bindToDevice, int trafficClass,
+            InetAddress inetAddress) throws IOException {
+        return sendDatagramImpl(fd, data, offset, length, port, bindToDevice,
+                trafficClass, inetAddress);
+    }
+    
+    public int sendDatagramDirect(FileDescriptor fd, int address, int offset,
+            int length, int port, boolean bindToDevice, int trafficClass,
+            InetAddress inetAddress) throws IOException {
+        return sendDatagramDirectImpl(fd, address, offset, length, port, bindToDevice,
+                trafficClass, inetAddress);
+    }
+
+    public int sendDatagram2(FileDescriptor fd, byte[] data, int offset,
+            int length, int port, InetAddress inetAddress) throws IOException {
+        return sendDatagramImpl2(fd, data, offset, length, port, inetAddress);
+    }
+
+    public int receiveDatagram(FileDescriptor aFD, DatagramPacket packet,
+            byte[] data, int offset, int length, int receiveTimeout,
+            boolean peek) throws IOException {
+        return receiveDatagramImpl(aFD, packet, data, offset, length,
+                receiveTimeout, peek);
+    }
+    
+    public int receiveDatagramDirect(FileDescriptor aFD, DatagramPacket packet,
+            int address, int offset, int length, int receiveTimeout,
+            boolean peek) throws IOException {
+        return receiveDatagramDirectImpl(aFD, packet, address, offset, length,
+                receiveTimeout, peek);
+    }
+
+    public int recvConnectedDatagram(FileDescriptor aFD, DatagramPacket packet,
+            byte[] data, int offset, int length, int receiveTimeout,
+            boolean peek) throws IOException {
+        return recvConnectedDatagramImpl(aFD, packet, data, offset, length,
+                receiveTimeout, peek);
+    }
+    
+    public int recvConnectedDatagramDirect(FileDescriptor aFD, DatagramPacket packet, int address,
+             int offset, int length, int receiveTimeout, boolean peek)
+            throws IOException {
+        return recvConnectedDatagramDirectImpl(aFD, packet, address, offset, length, receiveTimeout, peek);
+    }
+
+    public int peekDatagram(FileDescriptor aFD, InetAddress sender,
+            int receiveTimeout) throws IOException {
+        return peekDatagramImpl(aFD, sender, receiveTimeout);
+    }
+
+    public int sendConnectedDatagram(FileDescriptor fd, byte[] data,
+            int offset, int length, boolean bindToDevice) throws IOException {
+        return sendConnectedDatagramImpl(fd, data, offset, length, bindToDevice);
+    }
+    
+    public int sendConnectedDatagramDirect(FileDescriptor fd, int address,
+            int offset, int length, boolean bindToDevice) throws IOException {
+        return sendConnectedDatagramDirectImpl(fd, address, offset, length, bindToDevice);
+    }
+
+    public void disconnectDatagram(FileDescriptor aFD) throws SocketException {
+        disconnectDatagramImpl(aFD);
+    }
+
+    public void createMulticastSocket(FileDescriptor aFD,
+            boolean preferIPv4Stack) throws SocketException {
+        createMulticastSocketImpl(aFD, preferIPv4Stack);
+    }
+
+    public void createServerStreamSocket(FileDescriptor aFD,
+            boolean preferIPv4Stack) throws SocketException {
+        createServerStreamSocketImpl(aFD, preferIPv4Stack);
+    }
+
+    public int receiveStream(FileDescriptor aFD, byte[] data, int offset,
+            int count, int timeout) throws IOException {
+        return receiveStreamImpl(aFD, data, offset, count, timeout);
+    }
+
+    public int sendStream(FileDescriptor fd, byte[] data, int offset, int count)
+            throws IOException {
+        return sendStreamImpl(fd, data, offset, count);
+    }
+
+    public void shutdownInput(FileDescriptor descriptor) throws IOException {
+        shutdownInputImpl(descriptor);
+    }
+
+    public void shutdownOutput(FileDescriptor descriptor) throws IOException {
+        shutdownOutputImpl(descriptor);
+    }
+
+    public boolean supportsUrgentData(FileDescriptor fd) {
+        return supportsUrgentDataImpl(fd);
+    }
+
+    public void sendUrgentData(FileDescriptor fd, byte value) {
+        sendUrgentDataImpl(fd, value);
+    }
+
+    public int availableStream(FileDescriptor aFD) throws SocketException {
+        return availableStreamImpl(aFD);
+    }
+
+    // BEGIN android-removed
+    // public void acceptStreamSocket(FileDescriptor fdServer,
+    //         SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
+    //         throws IOException {
+    //     acceptStreamSocketImpl(fdServer, newSocket, fdnewSocket, timeout);
+    // }
+    // 
+    // public void createStreamSocket(FileDescriptor aFD, boolean preferIPv4Stack)
+    //         throws SocketException {
+    //     createStreamSocketImpl(aFD, preferIPv4Stack);
+    // }
+    // END android-removed
+
+    public void listenStreamSocket(FileDescriptor aFD, int backlog)
+            throws SocketException {
+        listenStreamSocketImpl(aFD, backlog);
+    }
+    
+    // BEGIN android-removed
+    // public boolean isReachableByICMP(final InetAddress dest,
+    //         InetAddress source, final int ttl, final int timeout) {
+    //     return INETADDR_REACHABLE == isReachableByICMPImpl(dest, source, ttl,
+    //             timeout);
+    // }
+    // END android-removed
+
+    /*
+     * 
+     * @param 
+     *      readChannels all channels interested in read and accept 
+     * @param
+     *      writeChannels all channels interested in write and connect 
+     * @param timeout
+     *      timeout in millis @return a set of channels that are ready for operation
+     * @throws 
+     *      SocketException @return int array, each int approve one of the     * channel if OK
+     */
+
+    public int[] select(FileDescriptor[] readFDs,
+            FileDescriptor[] writeFDs, long timeout)
+            throws SocketException {
+        int countRead = readFDs.length;
+        int countWrite = writeFDs.length;
+        int result = 0;
+        if (0 == countRead + countWrite) {
+            return (new int[0]);
+        }
+        int[] flags = new int[countRead + countWrite];
+
+        // handle timeout in native
+        result = selectImpl(readFDs, writeFDs, countRead, countWrite, flags,
+                timeout);
+
+        if (0 <= result) {
+            return flags;
+        }
+        if (ERRORCODE_SOCKET_TIMEOUT == result) {
+            return new int[0];
+        }
+        throw new SocketException();
+
+    }
+
+    public InetAddress getSocketLocalAddress(FileDescriptor aFD,
+            boolean preferIPv6Addresses) {
+        return getSocketLocalAddressImpl(aFD, preferIPv6Addresses);
+    }
+
+    /*
+     * Query the IP stack for the local port to which this socket is bound.
+     * 
+     * @param aFD the socket descriptor @param preferIPv6Addresses address
+     * preference for nodes that support both IPv4 and IPv6 @return int the
+     * local port to which the socket is bound
+     */
+    public int getSocketLocalPort(FileDescriptor aFD,
+            boolean preferIPv6Addresses) {
+        return getSocketLocalPortImpl(aFD, preferIPv6Addresses);
+    }
+
+    /*
+     * Query the IP stack for the nominated socket option.
+     * 
+     * @param aFD the socket descriptor @param opt the socket option type
+     * @return the nominated socket option value
+     * 
+     * @throws SocketException if the option is invalid
+     */
+    public Object getSocketOption(FileDescriptor aFD, int opt)
+            throws SocketException {
+        return getSocketOptionImpl(aFD, opt);
+    }
+
+    /*
+     * Set the nominated socket option in the IP stack.
+     * 
+     * @param aFD the socket descriptor @param opt the option selector @param
+     * optVal the nominated option value
+     * 
+     * @throws SocketException if the option is invalid or cannot be set
+     */
+    public void setSocketOption(FileDescriptor aFD, int opt, Object optVal)
+            throws SocketException {
+        setSocketOptionImpl(aFD, opt, optVal);
+    }
+
+    public int getSocketFlags() {
+        return getSocketFlagsImpl();
+    }
+
+    /*
+     * Close the socket in the IP stack.
+     * 
+     * @param aFD the socket descriptor
+     */
+    public void socketClose(FileDescriptor aFD) throws IOException {
+        socketCloseImpl(aFD);
+    }
+
+    public InetAddress getHostByAddr(byte[] addr) throws UnknownHostException {
+        return getHostByAddrImpl(addr);
+    }
+
+    public InetAddress getHostByName(String addr, boolean preferIPv6Addresses)
+            throws UnknownHostException {
+        return getHostByNameImpl(addr, preferIPv6Addresses);
+    }
+
+    public void setInetAddress(InetAddress sender, byte[] address) {
+        setInetAddressImpl(sender, address);
+    }
+
+    // ---------------------------------------------------
+    // Native Codes
+    // ---------------------------------------------------
+
+    static native void createSocketImpl(FileDescriptor fd,
+            boolean preferIPv4Stack);
+
+    /*
+     * Allocate a datagram socket in the IP stack. The socket is associated with
+     * the <code>aFD</code>.
+     * 
+     * @param aFD the FileDescriptor to associate with the socket @param
+     * preferIPv4Stack IP stack preference if underlying platform is V4/V6
+     * @exception SocketException upon an allocation error
+     */
+    static native void createDatagramSocketImpl(FileDescriptor aFD,
+            boolean preferIPv4Stack) throws SocketException;
+
+    static native int readSocketImpl(FileDescriptor aFD, byte[] data,
+            int offset, int count, int timeout) throws IOException;
+    
+    static native int readSocketDirectImpl(FileDescriptor aFD, int address,
+            int offset, int count, int timeout) throws IOException;
+
+    static native int writeSocketImpl(FileDescriptor fd, byte[] data,
+            int offset, int count) throws IOException;
+    
+    static native int writeSocketDirectImpl(FileDescriptor fd, int address,
+            int offset, int count) throws IOException;
+
+    static native void setNonBlockingImpl(FileDescriptor aFD,
+            boolean block);
+
+    static native int connectSocketImpl(FileDescriptor aFD,
+            int trafficClass, InetAddress inetAddress, int port);
+
+    // BEGIN android-changed
+    static native int connectWithTimeoutSocketImpl(
+            FileDescriptor aFD, int timeout, int trafficClass,
+            InetAddress hostname, int port, int step, byte[] context);
+    // END android-changed
+
+    static native void connectStreamWithTimeoutSocketImpl(FileDescriptor aFD,
+            int aport, int timeout, int trafficClass, InetAddress inetAddress)
+            throws IOException;
+
+    static native void socketBindImpl(FileDescriptor aFD, int port,
+            InetAddress inetAddress) throws SocketException;
+
+    static native void listenStreamSocketImpl(FileDescriptor aFD, int backlog)
+            throws SocketException;
+
+    static native int availableStreamImpl(FileDescriptor aFD)
+            throws SocketException;
+
+    static native void acceptSocketImpl(FileDescriptor fdServer,
+            SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
+            throws IOException;
+
+    static native boolean supportsUrgentDataImpl(FileDescriptor fd);
+
+    static native void sendUrgentDataImpl(FileDescriptor fd, byte value);
+
+    /*
+     * Connect the socket to a port and address
+     * 
+     * @param aFD the FileDescriptor to associate with the socket @param port
+     * the port to connect to @param trafficClass the traffic Class to be used
+     * then the connection is made @param inetAddress address to connect to.
+     * 
+     * @exception SocketException if the connect fails
+     */
+    static native void connectDatagramImpl2(FileDescriptor aFD,
+            int port, int trafficClass, InetAddress inetAddress)
+            throws SocketException;
+
+    /*
+     * Disconnect the socket to a port and address
+     * 
+     * @param aFD the FileDescriptor to associate with the socket
+     * 
+     * @exception SocketException if the disconnect fails
+     */
+    static native void disconnectDatagramImpl(FileDescriptor aFD)
+            throws SocketException;
+
+    /*
+     * Allocate a datagram socket in the IP stack. The socket is associated with
+     * the <code>aFD</code>.
+     * 
+     * @param aFD the FileDescriptor to associate with the socket @param
+     * preferIPv4Stack IP stack preference if underlying platform is V4/V6
+     * @exception SocketException upon an allocation error
+     */
+
+    /*
+     * Bind the socket to the port/localhost in the IP stack.
+     * 
+     * @param aFD the socket descriptor @param port the option selector @param
+     * bindToDevice bind the socket to the specified interface @param
+     * inetAddress address to connect to. @return if bind successful @exception
+     * SocketException thrown if bind operation fails
+     */
+    static native boolean socketBindImpl2(FileDescriptor aFD,
+            int port, boolean bindToDevice, InetAddress inetAddress)
+            throws SocketException;
+
+    /*
+     * Peek on the socket, update <code>sender</code> address and answer the
+     * sender port.
+     * 
+     * @param aFD the socket FileDescriptor @param sender an InetAddress, to be
+     * updated with the sender's address @param receiveTimeout the maximum
+     * length of time the socket should block, reading @return int the sender
+     * port
+     * 
+     * @exception IOException upon an read error or timeout
+     */
+    static native int peekDatagramImpl(FileDescriptor aFD,
+            InetAddress sender, int receiveTimeout) throws IOException;
+
+    /*
+     * Recieve data on the socket into the specified buffer. The packet fields
+     * <code>data</code> & <code>length</code> are passed in addition to
+     * <code>packet</code> to eliminate the JNI field access calls.
+     * 
+     * @param aFD the socket FileDescriptor @param packet the DatagramPacket to
+     * receive into @param data the data buffer of the packet @param offset the
+     * offset in the data buffer @param length the length of the data buffer in
+     * the packet @param receiveTimeout the maximum length of time the socket
+     * should block, reading @param peek indicates to peek at the data @return
+     * number of data received @exception IOException upon an read error or
+     * timeout
+     */
+    static native int receiveDatagramImpl(FileDescriptor aFD,
+            DatagramPacket packet, byte[] data, int offset, int length,
+            int receiveTimeout, boolean peek) throws IOException;
+    
+    static native int receiveDatagramDirectImpl(FileDescriptor aFD,
+            DatagramPacket packet, int address, int offset, int length,
+            int receiveTimeout, boolean peek) throws IOException;
+
+    /*
+     * Recieve data on the connected socket into the specified buffer. The
+     * packet fields <code>data</code> & <code>length</code> are passed in
+     * addition to <code>packet</code> to eliminate the JNI field access
+     * calls.
+     * 
+     * @param aFD the socket FileDescriptor @param packet the DatagramPacket to
+     * receive into @param data the data buffer of the packet @param offset the
+     * offset in the data buffer @param length the length of the data buffer in
+     * the packet @param receiveTimeout the maximum length of time the socket
+     * should block, reading @param peek indicates to peek at the data @return
+     * number of data received @exception IOException upon an read error or
+     * timeout
+     */
+    static native int recvConnectedDatagramImpl(FileDescriptor aFD,
+            DatagramPacket packet, byte[] data, int offset, int length,
+            int receiveTimeout, boolean peek) throws IOException;
+    
+    static native int recvConnectedDatagramDirectImpl(FileDescriptor aFD,
+            DatagramPacket packet, int address, int offset, int length,
+            int receiveTimeout, boolean peek) throws IOException;
+
+    /*
+     * Send the <code>data</code> to the nominated target <code>address</code>
+     * and <code>port</code>. These values are derived from the
+     * DatagramPacket to reduce the field calls within JNI.
+     * 
+     * @param fd the socket FileDescriptor @param data the data buffer of the
+     * packet @param offset the offset in the data buffer @param length the
+     * length of the data buffer in the packet @param port the target host port
+     * @param bindToDevice if bind to device @param trafficClass the traffic
+     * class to be used when the datagram is sent @param inetAddress address to
+     * connect to. @return number of data send
+     * 
+     * @exception IOException upon an read error or timeout
+     */
+    static native int sendDatagramImpl(FileDescriptor fd,
+            byte[] data, int offset, int length, int port,
+            boolean bindToDevice, int trafficClass, InetAddress inetAddress)
+            throws IOException;
+    
+    static native int sendDatagramDirectImpl(FileDescriptor fd,
+            int address, int offset, int length, int port,
+            boolean bindToDevice, int trafficClass, InetAddress inetAddress)
+            throws IOException;
+
+    /*
+     * Send the <code>data</code> to the address and port to which the was
+     * connnected and <code>port</code>.
+     * 
+     * @param fd the socket FileDescriptor @param data the data buffer of the
+     * packet @param offset the offset in the data buffer @param length the
+     * length of the data buffer in the packet @param bindToDevice not used,
+     * current kept in case needed as was the case for sendDatagramImpl @return
+     * number of data send @exception IOException upon an read error or timeout
+     */
+    static native int sendConnectedDatagramImpl(FileDescriptor fd,
+            byte[] data, int offset, int length, boolean bindToDevice)
+            throws IOException;
+    
+    static native int sendConnectedDatagramDirectImpl(FileDescriptor fd,
+            int address, int offset, int length, boolean bindToDevice)
+            throws IOException;
+
+    /*
+     * Answer the result of attempting to create a server stream socket in the
+     * IP stack. Any special options required for server sockets will be set by
+     * this method.
+     * 
+     * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4
+     * @exception SocketException if an error occurs while creating the socket
+     */
+    static native void createServerStreamSocketImpl(FileDescriptor aFD,
+            boolean preferIPv4Stack) throws SocketException;
+
+    /*
+     * Answer the result of attempting to create a multicast socket in the IP
+     * stack. Any special options required for server sockets will be set by
+     * this method.
+     * 
+     * @param aFD the socket FileDescriptor @param preferIPv4Stack if use IPV4
+     * @exception SocketException if an error occurs while creating the socket
+     */
+    static native void createMulticastSocketImpl(FileDescriptor aFD,
+            boolean preferIPv4Stack) throws SocketException;
+
+    /*
+     * Recieve at most <code>count</code> bytes into the buffer <code>data</code>
+     * at the <code>offset</code> on the socket.
+     * 
+     * @param aFD the socket FileDescriptor @param data the receive buffer
+     * @param offset the offset into the buffer @param count the max number of
+     * bytes to receive @param timeout the max time the read operation should
+     * block waiting for data @return int the actual number of bytes read
+     * @throws IOException @exception SocketException if an error occurs while
+     * reading
+     */
+    static native int receiveStreamImpl(FileDescriptor aFD, byte[] data,
+            int offset, int count, int timeout) throws IOException;
+
+    /*
+     * Send <code>count</code> bytes from the buffer <code>data</code> at
+     * the <code>offset</code>, on the socket.
+     * 
+     * @param fd
+     * 
+     * @param data the send buffer @param offset the offset into the buffer
+     * @param count the number of bytes to receive @return int the actual number
+     * of bytes sent @throws IOException @exception SocketException if an error
+     * occurs while writing
+     */
+    static native int sendStreamImpl(FileDescriptor fd, byte[] data,
+            int offset, int count) throws IOException;
+
+    private native void shutdownInputImpl(FileDescriptor descriptor)
+            throws IOException;
+
+    private native void shutdownOutputImpl(FileDescriptor descriptor)
+            throws IOException;
+
+    // BEGIN android-removed
+    // static native void acceptStreamSocketImpl(FileDescriptor fdServer,
+    //         SocketImpl newSocket, FileDescriptor fdnewSocket, int timeout)
+    //         throws IOException;
+    // 
+    // static native void createStreamSocketImpl(FileDescriptor aFD,
+    //         boolean preferIPv4Stack) throws SocketException;
+    // END android-removed
+
+    static native int sendDatagramImpl2(FileDescriptor fd, byte[] data,
+            int offset, int length, int port, InetAddress inetAddress)
+            throws IOException;
+
+    static native int selectImpl(FileDescriptor[] readfd,
+            FileDescriptor[] writefd, int cread, int cwirte, int[] flags,
+            long timeout);
+
+    static native InetAddress getSocketLocalAddressImpl(FileDescriptor aFD,
+            boolean preferIPv6Addresses);
+
+    /*
+     * Query the IP stack for the local port to which this socket is bound.
+     * 
+     * @param aFD the socket descriptor @param preferIPv6Addresses address
+     * preference for nodes that support both IPv4 and IPv6 @return int the
+     * local port to which the socket is bound
+     */
+    static native int getSocketLocalPortImpl(FileDescriptor aFD,
+            boolean preferIPv6Addresses);
+
+    /*
+     * Query the IP stack for the nominated socket option.
+     * 
+     * @param aFD the socket descriptor @param opt the socket option type
+     * @return the nominated socket option value
+     * 
+     * @throws SocketException if the option is invalid
+     */
+    static native Object getSocketOptionImpl(FileDescriptor aFD, int opt)
+            throws SocketException;
+
+    /*
+     * Set the nominated socket option in the IP stack.
+     * 
+     * @param aFD the socket descriptor @param opt the option selector @param
+     * optVal the nominated option value
+     * 
+     * @throws SocketException if the option is invalid or cannot be set
+     */
+    static native void setSocketOptionImpl(FileDescriptor aFD, int opt,
+            Object optVal) throws SocketException;
+
+    static native int getSocketFlagsImpl();
+
+    /*
+     * Close the socket in the IP stack.
+     * 
+     * @param aFD the socket descriptor
+     */
+    static native void socketCloseImpl(FileDescriptor aFD);
+
+    static native InetAddress getHostByAddrImpl(byte[] addr)
+            throws UnknownHostException;
+
+    static native InetAddress getHostByNameImpl(String addr,
+            boolean preferIPv6Addresses) throws UnknownHostException;
+
+    native void setInetAddressImpl(InetAddress sender, byte[] address);
+
+    // BEGIN android-removed
+    // native int isReachableByICMPImpl(InetAddress addr, InetAddress local,
+    //         int ttl, int timeout);
+    // END android-removed
+    
+    native Channel inheritedChannelImpl();
+
+    public Channel inheritedChannel() {
+        return inheritedChannelImpl();
+    }
+    
+    public void oneTimeInitialization(boolean jcl_supports_ipv6){
+        if (!isNetworkInited){
+            oneTimeInitializationImpl(jcl_supports_ipv6);
+            isNetworkInited = true;
+        } 
+    }
+    
+    native void oneTimeInitializationImpl (boolean jcl_supports_ipv6);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2009 The Sipdroid Open Source Project
+ * 
+ * This file is part of Sipdroid (http://www.sipdroid.org)
+ * 
+ * Sipdroid is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This source code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this source code; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package org.sipdroid.net.impl;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocketImpl;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.net.SocketOptions;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+import java.security.AccessController;
+
+/**
+ * The default, concrete instance of datagram sockets. This class does not
+ * support security checks. Alternative types of DatagramSocketImpl's may be
+ * used by setting the <code>impl.prefix</code> system property.
+ */
+public class PlainDatagramSocketImpl extends DatagramSocketImpl {
+
+    static final int MULTICAST_IF = 1;
+
+    static final int MULTICAST_TTL = 2;
+
+    static final int TCP_NODELAY = 4;
+
+    static final int FLAG_SHUTDOWN = 8;
+
+    private final static int SO_BROADCAST = 32;
+
+    final static int IP_MULTICAST_ADD = 19;
+
+    final static int IP_MULTICAST_DROP = 20;
+
+    final static int IP_MULTICAST_TTL = 17;
+
+    /**
+     * for datagram and multicast sockets we have to set REUSEADDR and REUSEPORT
+     * when REUSEADDR is set for other types of sockets we need to just set
+     * REUSEADDR therefore we have this other option which sets both if
+     * supported by the platform. this cannot be in SOCKET_OPTIONS because since
+     * it is a public interface it ends up being public even if it is not
+     * declared public
+     */
+    static final int REUSEADDR_AND_REUSEPORT = 10001;
+
+    private boolean bindToDevice;
+
+    private byte[] ipaddress = { 0, 0, 0, 0 };
+
+    private int ttl = 1;
+
+    private OSNetworkSystem netImpl = OSNetworkSystem.getOSNetworkSystem();
+
+    private volatile boolean isNativeConnected = false;
+
+    public int receiveTimeout;
+
+    public boolean streaming = true;
+
+    public boolean shutdownInput;
+
+    /**
+     * used to keep address to which the socket was connected to at the native
+     * level
+     */
+    private InetAddress connectedAddress;
+
+    private int connectedPort = -1;
+
+    /**
+     * used to store the trafficClass value which is simply returned as the
+     * value that was set. We also need it to pass it to methods that specify an
+     * address packets are going to be sent to
+     */
+    private int trafficClass;
+
+    public PlainDatagramSocketImpl(FileDescriptor fd, int localPort) {
+        super();
+        this.fd = fd;
+        this.localPort = localPort;
+    }
+
+    public PlainDatagramSocketImpl() {
+        super();
+        fd = new FileDescriptor();
+    }
+
+    @Override
+    public void bind(int port, InetAddress addr) throws SocketException {
+        String prop = null; //AccessController.doPrivileged(new PriviAction<String>("bindToDevice")); //$NON-NLS-1$
+        boolean useBindToDevice = prop != null && prop.toLowerCase().equals("true"); //$NON-NLS-1$
+        bindToDevice = netImpl.bind2(fd, port, useBindToDevice, addr);
+        if (0 != port) {
+            localPort = port;
+        } else {
+//            localPort = netImpl.getSocketLocalPort(fd, NetUtil.preferIPv6Addresses());
+        }
+
+        try {
+            // Ignore failures
+            setOption(SO_BROADCAST, Boolean.TRUE);
+        } catch (IOException e) {
+        }
+    }
+
+    @Override
+    public void close() {
+        synchronized (fd) {
+            if (fd.valid()) {
+                try {
+                    netImpl.socketClose(fd);
+                } catch (IOException e) {
+                }
+                fd = new FileDescriptor();
+            }
+        }
+    }
+
+    @Override
+    public void create() throws SocketException {
+        netImpl.createDatagramSocket(fd, false); //NetUtil.preferIPv4Stack());
+    }
+
+    @Override
+    protected void finalize() {
+        close();
+    }
+
+    @Override
+    public Object getOption(int optID) throws SocketException {
+        if (optID == SocketOptions.SO_TIMEOUT) {
+            return Integer.valueOf(receiveTimeout);
+        } else if (optID == SocketOptions.IP_TOS) {
+            return Integer.valueOf(trafficClass);
+        } else {
+            // Call the native first so there will be
+            // an exception if the socket if closed.
+            Object result = netImpl.getSocketOption(fd, optID);
+            if (optID == SocketOptions.IP_MULTICAST_IF
+                    && (netImpl.getSocketFlags() & MULTICAST_IF) != 0) {
+                try {
+                    return InetAddress.getByAddress(ipaddress);
+                } catch (UnknownHostException e) {
+                    return null;
+                }
+            }
+            return result;
+        }
+    }
+
+    @Override
+    public int getTimeToLive() throws IOException {
+        // Call the native first so there will be an exception if the socket if
+        // closed.
+        int result = (((Byte) getOption(IP_MULTICAST_TTL)).byteValue()) & 0xFF;
+        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
+            return ttl;
+        }
+        return result;
+    }
+
+    @Override
+    public byte getTTL() throws IOException {
+        // Call the native first so there will be an exception if the socket if
+        // closed.
+        byte result = ((Byte) getOption(IP_MULTICAST_TTL)).byteValue();
+        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
+            return (byte) ttl;
+        }
+        return result;
+    }
+
+    @Override
+    public void join(InetAddress addr) throws IOException {
+//        setOption(IP_MULTICAST_ADD, new GenericIPMreq(addr));
+    }
+
+    @Override
+    public void joinGroup(SocketAddress addr, NetworkInterface netInterface) throws IOException {
+        if (addr instanceof InetSocketAddress) {
+            InetAddress groupAddr = ((InetSocketAddress) addr).getAddress();
+//            setOption(IP_MULTICAST_ADD, new GenericIPMreq(groupAddr, netInterface));
+        }
+    }
+
+    @Override
+    public void leave(InetAddress addr) throws IOException {
+//        setOption(IP_MULTICAST_DROP, new GenericIPMreq(addr));
+    }
+
+    @Override
+    public void leaveGroup(SocketAddress addr, NetworkInterface netInterface)
+            throws IOException {
+        if (addr instanceof InetSocketAddress) {
+            InetAddress groupAddr = ((InetSocketAddress) addr).getAddress();
+//            setOption(IP_MULTICAST_DROP, new GenericIPMreq(groupAddr, netInterface));
+        }
+    }
+
+    @Override
+    protected int peek(InetAddress sender) throws IOException {
+        if (isNativeConnected) {
+            /*
+             * in this case we know the port and address from which the data
+             * must have be been received as the socket is connected. However,
+             * we still need to do the receive in order to know that there was
+             * data received. We use a short buffer as we don't actually need
+             * the packet, only the knowledge that it is there
+             */
+            byte[] storageArray = new byte[10];
+            DatagramPacket pack = new DatagramPacket(storageArray, storageArray.length);
+            netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+                    .getLength(), receiveTimeout, true); // peek
+            // to set the sender ,we now use a native function
+            // sender.ipaddress = connectedAddress.getAddress();
+            netImpl.setInetAddress(sender, connectedAddress.getAddress());
+            return connectedPort;
+        }
+        return netImpl.peekDatagram(fd, sender, receiveTimeout);
+    }
+
+    @Override
+    public void receive(DatagramPacket pack) throws java.io.IOException {
+        try {
+            if (isNativeConnected) {
+                // do not peek
+                netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+                        .getLength(), receiveTimeout, false);
+                updatePacketRecvAddress(pack);
+            } else {
+                // receiveDatagramImpl2
+                netImpl.receiveDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+                        .getLength(), receiveTimeout, false);
+            }
+        } catch (InterruptedIOException e) {
+            throw new SocketTimeoutException(e.getMessage());
+        }
+    }
+
+    @Override
+    public void send(DatagramPacket packet) throws IOException {
+
+        if (isNativeConnected) {
+            netImpl.sendConnectedDatagram(fd, packet.getData(), packet.getOffset(), packet
+                    .getLength(), bindToDevice);
+        } else {
+            // sendDatagramImpl2
+            netImpl.sendDatagram(fd, packet.getData(), packet.getOffset(), packet.getLength(),
+                    packet.getPort(), bindToDevice, trafficClass, packet.getAddress());
+        }
+    }
+
+    /**
+     * Set the nominated socket option. As the timeouts are not set as options
+     * in the IP stack, the value is stored in an instance field.
+     * 
+     * @throws SocketException thrown if the option value is unsupported or
+     *         invalid
+     */
+    @Override
+    public void setOption(int optID, Object val) throws SocketException {
+        /*
+         * for datagram sockets on some platforms we have to set both the
+         * REUSEADDR AND REUSEPORT so for REUSEADDR set this option option which
+         * tells the VM to set the two values as appropriate for the platform
+         */
+        if (optID == SocketOptions.SO_REUSEADDR) {
+            optID = REUSEADDR_AND_REUSEPORT;
+        }
+
+        if (optID == SocketOptions.SO_TIMEOUT) {
+            receiveTimeout = ((Integer) val).intValue();
+        } else {
+            int flags = netImpl.getSocketFlags();
+            try {
+                netImpl.setSocketOption(fd, optID | (flags << 16), val);
+            } catch (SocketException e) {
+                // we don't throw an exception for IP_TOS even if the platform
+                // won't let us set the requested value
+                if (optID != SocketOptions.IP_TOS) {
+                    throw e;
+                }
+            }
+            if (optID == SocketOptions.IP_MULTICAST_IF && (flags & MULTICAST_IF) != 0) {
+                InetAddress inet = (InetAddress) val;
+//                if (NetUtil.bytesToInt(inet.getAddress(), 0) == 0 || inet.isLoopbackAddress()) {
+//                    ipaddress = ((InetAddress) val).getAddress();
+//                } else 
+                {
+                    InetAddress local = null;
+                    try {
+                        local = InetAddress.getLocalHost();
+                    } catch (UnknownHostException e) {
+                        throw new SocketException("getLocalHost(): " + e.toString());
+                    }
+                    if (inet.equals(local)) {
+                        ipaddress = ((InetAddress) val).getAddress();
+                    } else {
+                        throw new SocketException(val + " != getLocalHost(): " + local);
+                    }
+                }
+            }
+            /*
+             * save this value as it is actually used differently for IPv4 and
+             * IPv6 so we cannot get the value using the getOption. The option
+             * is actually only set for IPv4 and a masked version of the value
+             * will be set as only a subset of the values are allowed on the
+             * socket. Therefore we need to retain it to return the value that
+             * was set. We also need the value to be passed into a number of
+             * natives so that it can be used properly with IPv6
+             */
+            if (optID == SocketOptions.IP_TOS) {
+                trafficClass = ((Integer) val).intValue();
+            }
+        }
+    }
+
+    @Override
+    public void setTimeToLive(int ttl) throws java.io.IOException {
+        setOption(IP_MULTICAST_TTL, Byte.valueOf((byte) (ttl & 0xFF)));
+        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
+            this.ttl = ttl;
+        }
+    }
+
+    @Override
+    public void setTTL(byte ttl) throws java.io.IOException {
+        setOption(IP_MULTICAST_TTL, Byte.valueOf(ttl));
+        if ((netImpl.getSocketFlags() & MULTICAST_TTL) != 0) {
+            this.ttl = ttl;
+        }
+    }
+
+    @Override
+    public void connect(InetAddress inetAddr, int port) throws SocketException {
+
+        // connectDatagram impl2
+        netImpl.connectDatagram(fd, port, trafficClass, inetAddr);
+
+        // if we get here then we are connected at the native level
+        try {
+            connectedAddress = InetAddress.getByAddress(inetAddr.getAddress());
+        } catch (UnknownHostException e) {
+            // this is never expected to happen as we should not have gotten
+            // here if the address is not resolvable
+            throw new SocketException("K0317 "+inetAddr.getHostName()); //$NON-NLS-1$
+        }
+        connectedPort = port;
+        isNativeConnected = true;
+    }
+
+    @Override
+    public void disconnect() {
+        try {
+            netImpl.disconnectDatagram(fd);
+        } catch (Exception e) {
+            // there is currently no way to return an error so just eat any
+            // exception
+        }
+        connectedPort = -1;
+        connectedAddress = null;
+        isNativeConnected = false;
+    }
+
+    @Override
+    public int peekData(DatagramPacket pack) throws IOException {
+        try {
+            if (isNativeConnected) {
+                netImpl.recvConnectedDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+                        .getLength(), receiveTimeout, true); // peek
+                updatePacketRecvAddress(pack);
+            } else {
+                // receiveDatagram 2
+                netImpl.receiveDatagram(fd, pack, pack.getData(), pack.getOffset(), pack
+                        .getLength(), receiveTimeout, true); // peek
+            }
+        } catch (InterruptedIOException e) {
+            throw new SocketTimeoutException(e.toString());
+        }
+        return pack.getPort();
+    }
+
+    /**
+     * Set the received address and port in the packet. We do this when the
+     * Datagram socket is connected at the native level and the
+     * recvConnnectedDatagramImpl does not update the packet with address from
+     * which the packet was received
+     * 
+     * @param packet
+     *            the packet to be updated
+     */
+    private void updatePacketRecvAddress(DatagramPacket packet) {
+        packet.setAddress(connectedAddress);
+        packet.setPort(connectedPort);
+    }
+    
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/DataFramePool.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,44 @@
+package org.sipdroid.net.tools;
+
+import jlibrtp.DataFrame;
+
+public class DataFramePool extends ObjectPool {
+
+	private static DataFramePool instance = null;
+	public static DataFramePool getInstance() {
+		if(instance == null) {
+			instance = new DataFramePool(20);
+		}
+		return instance;
+	}
+	
+	public static void removeInstance() {
+		instance = null;
+	}
+	
+	protected DataFramePool(int nbObject) {
+		super(nbObject);
+		for(int i = 0; i < nbObject; ++i) {
+			checkIn(create());
+		}
+	}
+	
+	@Override
+	Object create() {
+		return new DataFrame();
+	}
+
+	@Override
+	boolean validate(Object o) {
+		return true;
+	}
+	
+	public DataFrame borrowFrame() {
+		return (DataFrame) super.checkOut();
+	}
+	
+	public void returnFrame(DataFrame o) {
+		o.release();
+		super.checkIn(o);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/DatagramPool.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,45 @@
+package org.sipdroid.net.tools;
+
+import java.net.DatagramPacket;
+
+public class DatagramPool extends ObjectPool {
+
+	private static DatagramPool instance = null;
+	public static DatagramPool getInstance() {
+		if(instance == null) {
+			instance = new DatagramPool(20);
+		}
+		return instance;
+	}
+	
+	public static void removeInstance() {
+		instance = null;
+	}
+
+	protected DatagramPool(int nbDatagram) {
+		super(nbDatagram);
+		for(int i = 0; i < nbDatagram; ++i) {
+			checkIn(create());
+		}
+	}
+
+	@Override
+	Object create() {
+		byte[] rawPkt = new byte[1500];
+		DatagramPacket packet = new DatagramPacket(rawPkt, rawPkt.length);
+		return packet;
+	}
+
+	@Override
+	boolean validate(Object o) {		
+		return true;
+	}
+
+	public DatagramPacket borrowPacket() {
+		return (DatagramPacket) super.checkOut();
+	}
+
+	public void returnPacket(DatagramPacket packet) {
+		super.checkIn(packet);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/GenericPool.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,31 @@
+package org.sipdroid.net.tools;
+
+public class GenericPool<E> extends ObjectPool<Object> {
+
+	public GenericPool(int size) {
+		super(size);
+		for(int i = 0; i < size; ++i) {
+			checkIn(create());
+		}
+	}
+
+	@Override
+	protected E create() {
+		return (E)new Object();
+	}
+
+	@Override
+	protected boolean validate(Object o) {
+		// TODO Auto-generated method stub
+		return false;
+	}
+
+	public E borrowItem() {
+		return (E) super.checkOut();
+	}
+	
+	public void returnItem(E o) {
+		super.checkIn(o);
+	}
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/ObjectPool.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,37 @@
+package org.sipdroid.net.tools;
+
+import java.util.ArrayList;
+
+public abstract class ObjectPool<E> {  
+	private ArrayList<Object> locked, unlocked;
+
+	ObjectPool(int size){
+		locked = new ArrayList<Object>(size);         
+		unlocked = new ArrayList<Object>(size);
+	}
+
+	public int getPoolSize() {
+		return locked.size() + unlocked.size();
+	}
+
+	abstract Object create();
+	abstract boolean validate( Object o );
+	synchronized Object checkOut(){     
+		if(unlocked.size() > 0){
+			Object cur = unlocked.get(0);
+			unlocked.remove(cur);
+			locked.add(cur);           
+			return(cur);
+		}      
+		// no objects available, create a new one
+		Object o = create();
+		locked.add(o);
+		return(o);
+	}
+
+	synchronized void checkIn( Object o ) {
+		locked.remove( o );
+		unlocked.add(o);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/PktBufNodePool.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,44 @@
+package org.sipdroid.net.tools;
+
+import jlibrtp.PktBufNode;
+
+public class PktBufNodePool extends ObjectPool {
+
+	private static PktBufNodePool instance = null;
+	public static PktBufNodePool getInstance() {
+		if(instance == null) {
+			instance = new PktBufNodePool(20);
+		}
+		return instance;
+	}
+	
+	public static void removeInstance() {
+		instance = null;
+	}
+	
+	protected PktBufNodePool(int nbObject) {
+		super(nbObject);
+		for(int i = 0; i < nbObject; ++i) {
+			checkIn(create());
+		}
+	}
+	
+	@Override
+	Object create() {
+		return new PktBufNode();
+	}
+
+	@Override
+	boolean validate(Object o) {
+		return true;
+	}
+	
+	public PktBufNode borrowBufNode() {
+		return (PktBufNode) super.checkOut();
+	}
+	
+	public void returnBufNode(PktBufNode o) {
+		super.checkIn(o);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/tools/RtpPktPool.java	Sat Jan 23 00:51:15 2010 +0100
@@ -0,0 +1,44 @@
+package org.sipdroid.net.tools;
+
+import jlibrtp.RtpPkt;
+
+public class RtpPktPool extends ObjectPool {
+
+	private static RtpPktPool instance = null;
+	public static RtpPktPool getInstance() {
+		if(instance == null) {
+			instance = new RtpPktPool(20);
+		}
+		return instance;
+	}
+	
+	public static void removeInstance() {
+		instance = null;
+	}
+	
+	protected RtpPktPool(int nbObject) {
+		super(nbObject);
+		for(int i = 0; i < nbObject; ++i) {
+			checkIn(create());
+		}
+	}
+	
+	@Override
+	Object create() {
+		return new RtpPkt();
+	}
+
+	@Override
+	boolean validate(Object o) {
+		return true;
+	}
+
+	public RtpPkt borrowPkt() {
+		return (RtpPkt) super.checkOut();
+	}
+	
+	public void returnPkt(RtpPkt o) {
+		super.checkIn(o);
+	}
+	
+}