--- 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);
+ }
+
+}