tmpContactList = mRoster.getContactList();
@@ -817,6 +824,7 @@
}
mXmppFacade = null;
mRoster = null;
+ mJingle = null;
mListContact.clear();
mListGroup.clear();
mContactOnGroup.clear();
diff -r 9fb797159236 -r 532fdf132146 src/com/beem/project/beem/utils/Random.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/com/beem/project/beem/utils/Random.java Sun Feb 14 17:25:38 2010 +0100
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
+ *
+ * This file is part of MjSip (http://www.mjsip.org)
+ *
+ * MjSip 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * MjSip 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 MjSip; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author(s):
+ * Luca Veltri (luca.veltri@unipr.it)
+ */
+
+package com.beem.project.beem.utils;
+
+/**
+ * Class Random collects some static methods for generating random numbers and
+ * other stuff.
+ */
+public class Random {
+ /** The random seed */
+ static final long seed = System.currentTimeMillis();
+ // static final long seed=0;
+
+ static java.util.Random rand = new java.util.Random(seed);
+
+ // static java.util.Random rand=new java.util.Random();
+
+ /** Returns a random integer between 0 and n-1 */
+ /*
+ * static public int nextInt(int n) { seed=(seed*37)%987654321; return
+ * (int)(seed%n); }
+ */
+
+ /** Returns true or false respectively with probability p/100 and (1-p/100) */
+ /*
+ * static boolean percent(int p) { return integer(100)> 4];
+ }
+
+ public static void alaw2linear(byte alaw[],short lin[],int frames) {
+ int i;
+ for (i = 0; i < frames; i++)
+ lin[i] = a2s[alaw[i+12] & 0xff];
+ }
+
+ public static void linear2alaw(short lin[],int offset,byte alaw[],int frames) {
+ int i;
+ for (i = 0; i < frames; i++)
+ alaw[i+12] = s2a[lin[i+offset] & 0xffff];
+ }
+
+ //change g711 ulaw start
+ protected static int alaw2ulaw(int aval)
+ { aval&=0xff;
+ return ((aval & 0x80)!=0)? (0xFF^_a2u[aval^0xD5]) : (0x7F^_a2u[aval^0x55]);
+ }
+
+ protected static int ulaw2alaw(int uval)
+ { uval&=0xff;
+ return ((uval&0x80)!=0)? (0xD5^(_u2a[0xFF^uval]-1)) : (0x55^(_u2a[0x7F^uval]-1));
+ }
+
+ public static void ulaw2linear(byte ulaw[],short lin[],int frames) {
+ int i;
+ for (i = 0; i < frames; i++)
+ lin[i] = a2s[ulaw2alaw(ulaw[i+12] & 0xff)];
+ }
+ public static void linear2ulaw(short lin[],int offset,byte ulaw[],int frames) {
+ int i;
+ for (i = 0; i < frames; i++)
+ ulaw[i+12] = (byte)alaw2ulaw(s2a[lin[i+offset] & 0xffff]);
+ }
+ //change end
+}
diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/media/RtpStreamReceiver.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/RtpStreamReceiver.java Sun Feb 14 17:25:38 2010 +0100
@@ -0,0 +1,474 @@
+/*
+ * 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.IOException;
+import java.net.SocketException;
+
+import com.beem.project.beem.jingle.JingleService;
+import com.beem.project.beem.ui.Call;
+import org.sipdroid.net.RtpPacket;
+import org.sipdroid.net.RtpSocket;
+import org.sipdroid.net.SipdroidSocket;
+import org.sipdroid.pjlib.Codec;
+
+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.os.PowerManager;
+import android.os.RemoteException;
+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 {
+
+ /** Whether working in debug mode. */
+ public static boolean DEBUG = true;
+
+ /** Payload type */
+ int p_type;
+
+ /** 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 */
+ private RtpSocket rtp_socket = null;
+
+ /** Whether it is running */
+ private boolean running;
+ private AudioManager am;
+ private ContentResolver cr;
+ public static int speakermode;
+ private JingleService mJingle;
+
+ /**
+ * Constructs a RtpStreamReceiver.
+ *
+ * @param output_stream
+ * the stream sink
+ * @param socket
+ * the local receiver SipdroidSocket
+ */
+ public RtpStreamReceiver(SipdroidSocket socket, int payload_type) {
+ init(socket);
+ p_type = payload_type;
+ }
+
+ /** Inits the RtpStreamReceiver */
+ private void init(SipdroidSocket socket) {
+ if (socket != null)
+ rtp_socket = new RtpSocket(socket);
+ }
+
+ /** Whether is running */
+ public boolean isRunning() {
+ return running;
+ }
+
+ /** Stops running */
+ public void halt() {
+ running = false;
+ }
+
+ public int speaker(int mode) {
+ int old = speakermode;
+
+ if (Call.headset > 0 && mode == AudioManager.MODE_NORMAL)
+ return old;
+ saveVolume();
+ setMode(speakermode = mode);
+ restoreVolume();
+ return old;
+ }
+
+ double smin = 200,s;
+ 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);
+ }
+
+ static void setStreamVolume(final int stream,final int vol,final int flags) {
+ (new Thread() {
+ public void run() {
+ AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE);
+ am.setStreamVolume(stream, vol, flags);
+ if (stream == AudioManager.STREAM_MUSIC) restored = true;
+ }
+ }).start();
+ }
+
+ static boolean restored;
+
+ public static float getEarGain() {
+ try {
+ return Float.valueOf(PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString(Call.headset > 0?"heargain":"eargain", "0.25"));
+ } catch (NumberFormatException i) {
+ return (float)0.25;
+ }
+ }
+
+ void restoreVolume() {
+ switch (am.getMode()) {
+ case AudioManager.MODE_IN_CALL:
+ setStreamVolume(AudioManager.STREAM_RING,(int)(
+ am.getStreamMaxVolume(AudioManager.STREAM_RING)*
+ getEarGain()), 0);
+ track.setStereoVolume(AudioTrack.getMaxVolume()*
+ getEarGain()
+ ,AudioTrack.getMaxVolume()*
+ getEarGain());
+ break;
+ case AudioManager.MODE_NORMAL:
+ track.setStereoVolume(AudioTrack.getMaxVolume(),AudioTrack.getMaxVolume());
+ break;
+ }
+ setStreamVolume(AudioManager.STREAM_MUSIC,
+ PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("volume"+speakermode,
+ am.getStreamMaxVolume(AudioManager.STREAM_MUSIC)*
+ (speakermode == AudioManager.MODE_NORMAL?4:3)/4
+ ),0);
+ }
+
+ void saveVolume() {
+ if (restored) {
+ Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit();
+ edit.putInt("volume"+speakermode,am.getStreamVolume(AudioManager.STREAM_MUSIC));
+ edit.commit();
+ }
+ }
+
+ void saveSettings() {
+ if (!PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("oldvalid",false)) {
+ int oldvibrate = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
+ int oldvibrate2 = am.getVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
+ if (!PreferenceManager.getDefaultSharedPreferences(Call.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(Call.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();
+ }
+ }
+
+ public static void setMode(int mode) {
+ Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit();
+ edit.putBoolean("setmode", mode != AudioManager.MODE_NORMAL);
+ edit.commit();
+ AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE);
+ am.setMode(mode);
+ }
+
+ public static void restoreMode() {
+ if (PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("setmode",true)) {
+ setMode(AudioManager.MODE_NORMAL);
+ }
+ }
+
+ public static void restoreSettings() {
+ if (PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("oldvalid",true)) {
+ AudioManager am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE);
+ ContentResolver cr = Call.mContext.getContentResolver();
+ int oldvibrate = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldvibrate",0);
+ int oldvibrate2 = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldvibrate2",0);
+ int oldpolicy = PreferenceManager.getDefaultSharedPreferences(Call.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);
+ setStreamVolume(AudioManager.STREAM_RING, PreferenceManager.getDefaultSharedPreferences(Call.mContext).getInt("oldring",0), 0);
+ Editor edit = PreferenceManager.getDefaultSharedPreferences(Call.mContext).edit();
+ edit.putBoolean("oldvalid", false);
+ edit.commit();
+ PowerManager pm = (PowerManager) Call.mContext.getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK |
+ PowerManager.ACQUIRE_CAUSES_WAKEUP, "Sipdroid.RtpStreamReceiver");
+ wl.acquire(1000);
+ }
+ restoreMode();
+ }
+
+ public static float good, late, lost, loss;
+ public static int timeout;
+
+ void empty() {
+ try {
+ rtp_socket.getDatagramSocket().setSoTimeout(1);
+ for (;;)
+ rtp_socket.receive(rtp_packet);
+ } catch (SocketException e2) {
+ e2.printStackTrace();
+ } catch (IOException e) {
+ }
+ try {
+ rtp_socket.getDatagramSocket().setSoTimeout(1000);
+ } catch (SocketException e2) {
+ e2.printStackTrace();
+ }
+ }
+
+ RtpPacket rtp_packet;
+ AudioTrack track;
+
+ /** Runs it in a new Thread. */
+ public void run() {
+ boolean nodata = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("nodata",false);
+
+ if (rtp_socket == null) {
+ if (DEBUG)
+ println("ERROR: RTP socket is null");
+ return;
+ }
+
+ byte[] buffer = new byte[BUFFER_SIZE+12];
+ byte[] buffer_gsm = new byte[33+12];
+ int i;
+ rtp_packet = new RtpPacket(buffer, 0);
+
+ if (DEBUG)
+ println("Reading blocks of max " + buffer.length + " bytes");
+
+ running = true;
+ speakermode = Call.docked > 0?AudioManager.MODE_NORMAL:AudioManager.MODE_IN_CALL;
+ restored = false;
+
+ android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
+ am = (AudioManager) Call.mContext.getSystemService(Context.AUDIO_SERVICE);
+ cr = Call.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);
+ int oldvol = am.getStreamVolume(AudioManager.STREAM_MUSIC);
+ track = new AudioTrack(AudioManager.STREAM_MUSIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ BUFFER_SIZE*2*2, AudioTrack.MODE_STREAM);
+ short lin[] = new short[BUFFER_SIZE];
+ short lin2[] = new short[BUFFER_SIZE];
+ int user, server, lserver, luser, cnt, todo, headroom, len = 0, seq = 0, cnt2 = 0, m = 1,
+ expseq, getseq, vm = 1, gap, gseq;
+ timeout = 1;
+ boolean islate;
+ user = 0;
+ lserver = 0;
+ luser = -8000;
+ cnt = 0;
+ switch (p_type) {
+ case 3:
+ Codec.init();
+ break;
+ case 0:
+ case 8:
+ G711.init();
+ break;
+ }
+ ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_MUSIC,(int)(ToneGenerator.MAX_VOLUME*2*0.95));
+ track.play();
+ if (Call.headset > 0 && Call.oRingtone != null) {
+ ToneGenerator tg2 = new ToneGenerator(AudioManager.STREAM_RING,(int)(ToneGenerator.MAX_VOLUME*2*0.95));
+ tg2.startTone(ToneGenerator.TONE_SUP_RINGTONE);
+ System.gc();
+ tg2.stopTone();
+ } else
+ System.gc();
+ while (running) {
+ if (Call.call_state == Call.UA_STATE_HOLD) {
+ tg.stopTone();
+ track.pause();
+ while (running && Call.call_state == Call.UA_STATE_HOLD) {
+ try {
+ sleep(1000);
+ } catch (InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ }
+ track.play();
+ System.gc();
+ timeout = 1;
+ seq = 0;
+ }
+ try {
+ rtp_socket.receive(rtp_packet);
+ if (timeout != 0) {
+ tg.stopTone();
+ track.pause();
+ user += track.write(lin2,0,BUFFER_SIZE);
+ user += track.write(lin2,0,BUFFER_SIZE);
+ track.play();
+ cnt += 2*BUFFER_SIZE;
+ empty();
+ }
+ timeout = 0;
+ } catch (IOException e) {
+ if (timeout == 0 && nodata) {
+ tg.startTone(ToneGenerator.TONE_SUP_RINGTONE);
+ }
+ rtp_socket.getDatagramSocket().disconnect();
+ if (++timeout > 22) {
+ try {
+ mJingle.closeCall();
+ } catch (RemoteException e1) {
+ e1.printStackTrace();
+ }
+ break;
+ }
+ }
+ if (running && timeout == 0) {
+ gseq = rtp_packet.getSequenceNumber();
+ if (seq == gseq) {
+ m++;
+ continue;
+ }
+
+ server = track.getPlaybackHeadPosition();
+ headroom = user-server;
+
+ if (headroom > 1500)
+ cnt += len;
+ else
+ cnt = 0;
+
+ if (lserver == server)
+ cnt2++;
+ else
+ cnt2 = 0;
+
+ if (cnt <= 500 || cnt2 >= 2 || headroom - 875 < len) {
+ switch (rtp_packet.getPayloadType()) {
+ case 0:
+ len = rtp_packet.getPayloadLength();
+ G711.ulaw2linear(buffer, lin, len);
+ break;
+ case 8:
+ len = rtp_packet.getPayloadLength();
+ G711.alaw2linear(buffer, lin, len);
+ break;
+ case 3:
+ for (i = 12; i < 45; i++)
+ buffer_gsm[i] = buffer[i];
+ len = Codec.decode(buffer_gsm, lin, 0);
+ break;
+ }
+
+ if (speakermode == AudioManager.MODE_NORMAL)
+ calc(lin,0,len);
+ }
+
+ if (headroom < 250) {
+ todo = 875 - headroom;
+ println("insert "+todo);
+ islate = true;
+ user += track.write(lin2,0,todo);
+ } else
+ islate = false;
+
+ if (cnt > 500 && cnt2 < 2) {
+ todo = headroom - 875;
+ println("cut "+todo);
+ if (todo < len)
+ user += track.write(lin,todo,len-todo);
+ } else
+ user += track.write(lin,0,len);
+
+ seq = gseq;
+
+ if (user >= luser + 8000 && Call.call_state == Call.UA_STATE_INCALL) {
+ if (luser == -8000 || am.getMode() != speakermode) {
+ saveVolume();
+ setMode(speakermode);
+ restoreVolume();
+ }
+ luser = user;
+ }
+ lserver = server;
+ }
+ }
+ track.stop();
+ saveVolume();
+ setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0);
+ restoreSettings();
+ setStreamVolume(AudioManager.STREAM_MUSIC,oldvol,0);
+ tg.stopTone();
+ tg = new ToneGenerator(AudioManager.STREAM_RING,ToneGenerator.MAX_VOLUME/4*3);
+ tg.startTone(ToneGenerator.TONE_PROP_PROMPT);
+ try {
+ sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ tg.stopTone();
+
+ rtp_socket.close();
+ rtp_socket = null;
+
+ if (DEBUG)
+ println("rtp receiver terminated");
+ }
+
+ /** Debug output */
+ private static void println(String str) {
+ System.out.println("RtpStreamReceiver: " + 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;
+ }
+}
diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/media/RtpStreamSender.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/media/RtpStreamSender.java Sun Feb 14 17:25:38 2010 +0100
@@ -0,0 +1,376 @@
+/*
+ * 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.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.util.Random;
+
+
+import org.sipdroid.pjlib.Codec;
+
+import org.sipdroid.media.RtpStreamReceiver;
+import org.sipdroid.net.RtpPacket;
+import org.sipdroid.net.RtpSocket;
+import org.sipdroid.net.SipdroidSocket;
+
+import com.beem.project.beem.ui.Call;
+import com.beem.project.beem.utils.BeemConnectivity;
+
+import android.content.Context;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+
+/**
+ * RtpStreamSender is a generic stream sender. It takes an InputStream and sends
+ * it through RTP.
+ */
+public class RtpStreamSender extends Thread {
+ /** Whether working in debug mode. */
+ public static boolean DEBUG = true;
+
+ /** The RtpSocket */
+ RtpSocket rtp_socket = null;
+
+ /** Payload type */
+ int p_type;
+
+ /** Number of frame per second */
+ long frame_rate;
+
+ /** Number of bytes per frame */
+ int frame_size;
+
+ /**
+ * Whether it works synchronously with a local clock, or it it acts as slave
+ * of the InputStream
+ */
+ boolean do_sync = true;
+
+ /**
+ * Synchronization correction value, in milliseconds. It accellarates the
+ * sending rate respect to the nominal value, in order to compensate program
+ * latencies.
+ */
+ int sync_adj = 0;
+
+ /** Whether it is running */
+ boolean running = false;
+ boolean muted = false;
+
+ /**
+ * Constructs a RtpStreamSender.
+ *
+ * @param input_stream
+ * the stream to be sent
+ * @param do_sync
+ * whether time synchronization must be performed by the
+ * RtpStreamSender, or it is performed by the InputStream (e.g.
+ * the system audio input)
+ * @param payload_type
+ * the payload type
+ * @param frame_rate
+ * the frame rate, i.e. the number of frames that should be sent
+ * per second; it is used to calculate the nominal packet time
+ * and,in case of do_sync==true, the next departure time
+ * @param frame_size
+ * the size of the payload
+ * @param src_socket
+ * the socket used to send the RTP packet
+ * @param dest_addr
+ * the destination address
+ * @param dest_port
+ * the destination port
+ */
+ public RtpStreamSender(boolean do_sync,
+ int payload_type, long frame_rate, int frame_size,
+ SipdroidSocket src_socket, String dest_addr, int dest_port) {
+ init(do_sync, payload_type, frame_rate, frame_size,
+ src_socket, dest_addr, dest_port);
+ }
+
+ /** Inits the RtpStreamSender */
+ private void init(boolean do_sync,
+ int payload_type, long frame_rate, int frame_size,
+ SipdroidSocket src_socket, String dest_addr,
+ int dest_port) {
+ this.p_type = payload_type;
+ this.frame_rate = frame_rate;
+ this.frame_size = frame_size;
+ this.do_sync = do_sync;
+ try {
+ rtp_socket = new RtpSocket(src_socket, InetAddress
+ .getByName(dest_addr), dest_port);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /** 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 calc1(short[] lin,int off,int len) {
+ int i,j;
+
+ for (i = 0; i < len; i++) {
+ j = lin[i+off];
+ lin[i+off] = (short)(j>>1);
+ }
+ }
+
+ void calc5(short[] lin,int off,int len) {
+ int i,j;
+
+ for (i = 0; i < len; i++) {
+ j = lin[i+off];
+ if (j > 16350)
+ lin[i+off] = 16350<<1;
+ else if (j < -16350)
+ lin[i+off] = -16350<<1;
+ else
+ lin[i+off] = (short)(j<<1);
+ }
+ }
+
+ void calc10(short[] lin,int off,int len) {
+ int i,j;
+
+ for (i = 0; i < len; i++) {
+ j = lin[i+off];
+ if (j > 8150)
+ lin[i+off] = 8150<<2;
+ else if (j < -8150)
+ lin[i+off] = -8150<<2;
+ else
+ lin[i+off] = (short)(j<<2);
+ }
+ }
+
+ 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 float getMicGain() {
+ if (Call.headset > 0)
+ return Float.valueOf(PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString("hmicgain", "1.0"));
+ return Float.valueOf(PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString("micgain", "0.25"));
+ }
+
+ /** Runs it in a new Thread. */
+ public void run() {
+ if (rtp_socket == null)
+ return;
+ byte[] buffer = new byte[frame_size + 12];
+ RtpPacket rtp_packet = new RtpPacket(buffer, 0);
+ rtp_packet.setPayloadType(p_type);
+ int seqn = 0;
+ long time = 0;
+ double p = 0;
+ TelephonyManager tm = (TelephonyManager) Call.mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ boolean improve = PreferenceManager.getDefaultSharedPreferences(Call.mContext).getBoolean("improve",false);
+ boolean useGSM = !PreferenceManager.getDefaultSharedPreferences(Call.mContext).getString("compression","edge").equals("never");
+ int micgain = (int)(getMicGain()*10);
+ running = true;
+
+ if (DEBUG)
+ println("Reading blocks of " + buffer.length + " bytes");
+
+ android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
+ AudioRecord record = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,
+ AudioRecord.getMinBufferSize(8000,
+ AudioFormat.CHANNEL_CONFIGURATION_MONO,
+ AudioFormat.ENCODING_PCM_16BIT)*3/2);
+ short[] lin = new short[frame_size*11];
+ int num,ring = 0;
+ random = new Random();
+ InputStream alerting = null;
+ try {
+ alerting = Call.mContext.getAssets().open("alerting");
+ } catch (IOException e2) {
+ e2.printStackTrace();
+ }
+ switch (p_type) {
+ case 3:
+ Codec.init();
+ break;
+ case 0:
+ case 8:
+ G711.init();
+ break;
+ }
+ record.startRecording();
+ while (running) {
+ if (muted || Call.call_state == Call.UA_STATE_HOLD) {
+ record.stop();
+ while (running && (muted || Call.call_state == Call.UA_STATE_HOLD)) {
+ try {
+ sleep(1000);
+ } catch (InterruptedException e1) {
+ e1.printStackTrace();
+ }
+ }
+ record.startRecording();
+ }
+ 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 (RtpStreamReceiver.nearend == 0)
+ p = 0.9*p + 0.1*s;
+ } else switch (micgain) {
+ case 1:
+ calc1(lin,(ring+delay)%(frame_size*11),num);
+ break;
+ case 5:
+ calc5(lin,(ring+delay)%(frame_size*11),num);
+ break;
+ case 10:
+ calc10(lin,(ring+delay)%(frame_size*11),num);
+ break;
+ }
+ if (Call.call_state != Call.UA_STATE_INCALL && alerting != null) {
+ try {
+ if (alerting.available() < num)
+ alerting.reset();
+ alerting.read(buffer,12,num);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ switch (p_type) {// have to add ulaw case?
+ case 3:
+ G711.alaw2linear(buffer, lin, num);
+ num = Codec.encode(lin, 0, buffer, num);
+ break;
+ case 0:
+ G711.alaw2linear(buffer, lin, num);
+ G711.linear2ulaw(lin, 0, buffer, num);
+ break;
+ }
+ } else {
+ switch (p_type) {
+ case 3:
+ num = Codec.encode(lin, ring%(frame_size*11), buffer, num);
+ break;
+ case 0:
+ G711.linear2ulaw(lin, ring%(frame_size*11), buffer, num);
+ break;
+ case 8:
+ G711.linear2alaw(lin, ring%(frame_size*11), buffer, num);
+ break;
+ }
+ }
+ ring += frame_size;
+ rtp_packet.setSequenceNumber(seqn++);
+ rtp_packet.setTimestamp(time);
+ rtp_packet.setPayloadLength(num);
+ try {
+ rtp_socket.send(rtp_packet);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ time += frame_size;
+ /*if (useGSM && p_type == 8 && !BeemConnectivity.isWifi(Call.mContext) && tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_EDGE) {
+ rtp_packet.setPayloadType(p_type = 3);
+ if (frame_size == 1024) {
+ frame_size = 960;
+ ring = 0;
+ }
+ }*/
+ }
+ record.stop();
+
+ rtp_socket.close();
+ rtp_socket = null;
+
+ if (DEBUG)
+ println("rtp sender terminated");
+ }
+
+ /** Debug output */
+ private static void println(String str) {
+ System.out.println("RtpStreamSender: " + str);
+ }
+
+}
\ No newline at end of file
diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/RtpPacket.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/RtpPacket.java Sun Feb 14 17:25:38 2010 +0100
@@ -0,0 +1,318 @@
+/*
+ * 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.net;
+
+import com.beem.project.beem.utils.Random;
+
+/**
+ * RtpPacket implements a RTP packet.
+ */
+public class RtpPacket {
+ /* RTP packet buffer containing both the RTP header and payload */
+ byte[] packet;
+
+ /* RTP packet length */
+ int packet_len;
+
+ /* RTP header length */
+ // int header_len;
+ /** Gets the RTP packet */
+ public byte[] getPacket() {
+ return packet;
+ }
+
+ /** Gets the RTP packet length */
+ public int getLength() {
+ return packet_len;
+ }
+
+ /** Gets the RTP header length */
+ public int getHeaderLength() {
+ if (packet_len >= 12)
+ return 12 + 4 * getCscrCount();
+ else
+ return packet_len; // broken packet
+ }
+
+ /** Gets the RTP header length */
+ public int getPayloadLength() {
+ if (packet_len >= 12)
+ return packet_len - getHeaderLength();
+ else
+ return 0; // broken packet
+ }
+
+ /** Sets the RTP payload length */
+ public void setPayloadLength(int len) {
+ packet_len = getHeaderLength() + len;
+ }
+
+ // version (V): 2 bits
+ // padding (P): 1 bit
+ // extension (X): 1 bit
+ // CSRC count (CC): 4 bits
+ // marker (M): 1 bit
+ // payload type (PT): 7 bits
+ // sequence number: 16 bits
+ // timestamp: 32 bits
+ // SSRC: 32 bits
+ // CSRC list: 0 to 15 items, 32 bits each
+
+ /** Gets the version (V) */
+ public int getVersion() {
+ if (packet_len >= 12)
+ return (packet[0] >> 6 & 0x03);
+ else
+ return 0; // broken packet
+ }
+
+ /** Sets the version (V) */
+ public void setVersion(int v) {
+ if (packet_len >= 12)
+ packet[0] = (byte) ((packet[0] & 0x3F) | ((v & 0x03) << 6));
+ }
+
+ /** Whether has padding (P) */
+ public boolean hasPadding() {
+ if (packet_len >= 12)
+ return getBit(packet[0], 5);
+ else
+ return false; // broken packet
+ }
+
+ /** Set padding (P) */
+ public void setPadding(boolean p) {
+ if (packet_len >= 12)
+ packet[0] = setBit(p, packet[0], 5);
+ }
+
+ /** Whether has extension (X) */
+ public boolean hasExtension() {
+ if (packet_len >= 12)
+ return getBit(packet[0], 4);
+ else
+ return false; // broken packet
+ }
+
+ /** Set extension (X) */
+ public void setExtension(boolean x) {
+ if (packet_len >= 12)
+ packet[0] = setBit(x, packet[0], 4);
+ }
+
+ /** Gets the CSCR count (CC) */
+ public int getCscrCount() {
+ if (packet_len >= 12)
+ return (packet[0] & 0x0F);
+ else
+ return 0; // broken packet
+ }
+
+ /** Whether has marker (M) */
+ public boolean hasMarker() {
+ if (packet_len >= 12)
+ return getBit(packet[1], 7);
+ else
+ return false; // broken packet
+ }
+
+ /** Set marker (M) */
+ public void setMarker(boolean m) {
+ if (packet_len >= 12)
+ packet[1] = setBit(m, packet[1], 7);
+ }
+
+ /** Gets the payload type (PT) */
+ public int getPayloadType() {
+ if (packet_len >= 12)
+ return (packet[1] & 0x7F);
+ else
+ return -1; // broken packet
+ }
+
+ /** Sets the payload type (PT) */
+ public void setPayloadType(int pt) {
+ if (packet_len >= 12)
+ packet[1] = (byte) ((packet[1] & 0x80) | (pt & 0x7F));
+ }
+
+ /** Gets the sequence number */
+ public int getSequenceNumber() {
+ if (packet_len >= 12)
+ return getInt(packet, 2, 4);
+ else
+ return 0; // broken packet
+ }
+
+ /** Sets the sequence number */
+ public void setSequenceNumber(int sn) {
+ if (packet_len >= 12)
+ setInt(sn, packet, 2, 4);
+ }
+
+ /** Gets the timestamp */
+ public long getTimestamp() {
+ if (packet_len >= 12)
+ return getLong(packet, 4, 8);
+ else
+ return 0; // broken packet
+ }
+
+ /** Sets the timestamp */
+ public void setTimestamp(long timestamp) {
+ if (packet_len >= 12)
+ setLong(timestamp, packet, 4, 8);
+ }
+
+ /** Gets the SSCR */
+ public long getSscr() {
+ if (packet_len >= 12)
+ return getLong(packet, 8, 12);
+ else
+ return 0; // broken packet
+ }
+
+ /** Sets the SSCR */
+ public void setSscr(long ssrc) {
+ if (packet_len >= 12)
+ setLong(ssrc, packet, 8, 12);
+ }
+
+ /** Gets the CSCR list */
+ public long[] getCscrList() {
+ int cc = getCscrCount();
+ long[] cscr = new long[cc];
+ for (int i = 0; i < cc; i++)
+ cscr[i] = getLong(packet, 12 + 4 * i, 16 + 4 * i);
+ return cscr;
+ }
+
+ /** Sets the CSCR list */
+ public void setCscrList(long[] cscr) {
+ if (packet_len >= 12) {
+ int cc = cscr.length;
+ if (cc > 15)
+ cc = 15;
+ packet[0] = (byte) (((packet[0] >> 4) << 4) + cc);
+ cscr = new long[cc];
+ for (int i = 0; i < cc; i++)
+ setLong(cscr[i], packet, 12 + 4 * i, 16 + 4 * i);
+ // header_len=12+4*cc;
+ }
+ }
+
+ /** Sets the payload */
+ public void setPayload(byte[] payload, int len) {
+ if (packet_len >= 12) {
+ int header_len = getHeaderLength();
+ for (int i = 0; i < len; i++)
+ packet[header_len + i] = payload[i];
+ packet_len = header_len + len;
+ }
+ }
+
+ /** Gets the payload */
+ public byte[] getPayload() {
+ int header_len = getHeaderLength();
+ int len = packet_len - header_len;
+ byte[] payload = new byte[len];
+ for (int i = 0; i < len; i++)
+ payload[i] = packet[header_len + i];
+ return payload;
+ }
+
+ /** Creates a new RTP packet */
+ public RtpPacket(byte[] buffer, int packet_length) {
+ packet = buffer;
+ packet_len = packet_length;
+ if (packet_len < 12)
+ packet_len = 12;
+ init(0x0F);
+ }
+
+ /** init the RTP packet header (only PT) */
+ public void init(int ptype) {
+ init(ptype, Random.nextLong());
+ }
+
+ /** init the RTP packet header (PT and SSCR) */
+ public void init(int ptype, long sscr) {
+ init(ptype, Random.nextInt(), Random.nextLong(), sscr);
+ }
+
+ /** init the RTP packet header (PT, SQN, TimeStamp, SSCR) */
+ public void init(int ptype, int seqn, long timestamp, long sscr) {
+ setVersion(2);
+ setPayloadType(ptype);
+ setSequenceNumber(seqn);
+ setTimestamp(timestamp);
+ setSscr(sscr);
+ }
+
+ // *********************** Private and Static ***********************
+
+ /** Gets int value */
+ private static int getInt(byte b) {
+ return ((int) b + 256) % 256;
+ }
+
+ /** Gets long value */
+ private static long getLong(byte[] data, int begin, int end) {
+ long n = 0;
+ for (; begin < end; begin++) {
+ n <<= 8;
+ n += data[begin];
+ }
+ return n;
+ }
+
+ /** Sets long value */
+ private static void setLong(long n, byte[] data, int begin, int end) {
+ for (end--; end >= begin; end--) {
+ data[end] = (byte) (n % 256);
+ n >>= 8;
+ }
+ }
+
+ /** Gets Int value */
+ private static int getInt(byte[] data, int begin, int end) {
+ return (int) getLong(data, begin, end);
+ }
+
+ /** Sets Int value */
+ private static void setInt(int n, byte[] data, int begin, int end) {
+ setLong(n, data, begin, end);
+ }
+
+ /** Gets bit value */
+ private static boolean getBit(byte b, int bit) {
+ return (b >> bit) == 1;
+ }
+
+ /** Sets bit value */
+ private static byte setBit(boolean value, byte b, int bit) {
+ if (value)
+ return (byte) (b | (1 << bit));
+ else
+ return (byte) ((b | (1 << bit)) ^ (1 << bit));
+ }
+}
diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/RtpSocket.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/RtpSocket.java Sun Feb 14 17:25:38 2010 +0100
@@ -0,0 +1,92 @@
+/*
+ * 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.net;
+
+import java.net.InetAddress;
+import java.net.DatagramPacket;
+import java.io.IOException;
+
+
+
+/**
+ * RtpSocket implements a RTP socket for receiving and sending RTP packets.
+ *
+ * RtpSocket is associated to a DatagramSocket that is used to send and/or
+ * receive RtpPackets.
+ */
+public class RtpSocket {
+ /** UDP socket */
+ SipdroidSocket socket;
+ DatagramPacket datagram;
+
+ /** Remote address */
+ InetAddress r_addr;
+
+ /** Remote port */
+ int r_port;
+
+ /** Creates a new RTP socket (only receiver) */
+ public RtpSocket(SipdroidSocket datagram_socket) {
+ socket = datagram_socket;
+ r_addr = null;
+ r_port = 0;
+ datagram = new DatagramPacket(new byte[1],1);
+ }
+
+ /** Creates a new RTP socket (sender and receiver) */
+ public RtpSocket(SipdroidSocket datagram_socket,
+ InetAddress remote_address, int remote_port) {
+ socket = datagram_socket;
+ r_addr = remote_address;
+ r_port = remote_port;
+ datagram = new DatagramPacket(new byte[1],1);
+ }
+
+ /** Returns the RTP SipdroidSocket */
+ public SipdroidSocket getDatagramSocket() {
+ return socket;
+ }
+
+ /** Receives a RTP packet from this socket */
+ public void receive(RtpPacket rtpp) throws IOException {
+ datagram.setData(rtpp.packet);
+ datagram.setLength(rtpp.packet.length);
+ socket.receive(datagram);
+ if (!socket.isConnected())
+ socket.connect(datagram.getAddress(),datagram.getPort());
+ rtpp.packet_len = datagram.getLength();
+ }
+
+ /** Sends a RTP packet from this socket */
+ public void send(RtpPacket rtpp) throws IOException {
+ datagram.setData(rtpp.packet);
+ datagram.setLength(rtpp.packet_len);
+ datagram.setAddress(r_addr);
+ datagram.setPort(r_port);
+ socket.send(datagram);
+ }
+
+ /** Closes this socket */
+ public void close() { // socket.close();
+ }
+
+}
diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/SipdroidSocket.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/SipdroidSocket.java Sun Feb 14 17:25:38 2010 +0100
@@ -0,0 +1,90 @@
+/*
+ * 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"));
+ }
+ }
+
+ 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 {
+ try {
+ System.loadLibrary("OSNetworkSystem");
+ OSNetworkSystem.getOSNetworkSystem().oneTimeInitialization(true);
+ SipdroidSocket.loaded = true;
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}
diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/impl/OSNetworkSystem.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/impl/OSNetworkSystem.java Sun Feb 14 17:25:38 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 aFD
.
+ *
+ * @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 aFD
.
+ *
+ * @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 sender
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
+ * data
& length
are passed in addition to
+ * packet
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 data
& length
are passed in
+ * addition to packet
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 data
to the nominated target address
+ * and port
. 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 data
to the address and port to which the was
+ * connnected and port
.
+ *
+ * @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 count
bytes into the buffer data
+ * at the offset
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 count
bytes from the buffer data
at
+ * the offset
, 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
diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/net/impl/PlainDatagramSocketImpl.java Sun Feb 14 17:25:38 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 impl.prefix
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;
+
+ 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("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
diff -r 9fb797159236 -r 532fdf132146 src/org/sipdroid/pjlib/Codec.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/org/sipdroid/pjlib/Codec.java Sun Feb 14 17:25:38 2010 +0100
@@ -0,0 +1,44 @@
+/*
+ * 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.pjlib;
+
+import java.lang.String;
+
+public class Codec {
+ public static native int open(String codec_id);
+ public static native int decode(byte alaw[], short lin[], int frames);
+ public static native int encode(short lin[], int offset, byte alaw[], int frames);
+ public static native int close();
+
+ public static void init() {
+ }
+
+ public static boolean loaded;
+
+ static {
+ try {
+ System.loadLibrary("pjlib_linker_jni");
+ open("gsm");
+ loaded = true;
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+}