SipService.java revision 7d803d942453ed2139bb590aba4c4fe025529a8f
19c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/* 29c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Copyright (C) 2010, The Android Open Source Project 39c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 49c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Licensed under the Apache License, Version 2.0 (the "License"); 59c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * you may not use this file except in compliance with the License. 69c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * You may obtain a copy of the License at 79c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 89c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * http://www.apache.org/licenses/LICENSE-2.0 99c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * 109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Unless required by applicable law or agreed to in writing, software 119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * distributed under the License is distributed on an "AS IS" BASIS, 129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * See the License for the specific language governing permissions and 149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * limitations under the License. 159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpackage com.android.server.sip; 189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.app.AlarmManager; 209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.app.PendingIntent; 219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.BroadcastReceiver; 229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Context; 239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.Intent; 249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.content.IntentFilter; 259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.ConnectivityManager; 269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.NetworkInfo; 279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipService; 289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSession; 299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSessionListener; 309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipErrorCode; 319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipManager; 329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipProfile; 339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSession; 349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSessionAdapter; 359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.wifi.WifiManager; 369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Binder; 379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Bundle; 389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Handler; 399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.HandlerThread; 409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Looper; 419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.Message; 42257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyanimport android.os.PowerManager; 43a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport android.os.Process; 449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.RemoteException; 459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.ServiceManager; 469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.os.SystemClock; 479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.text.TextUtils; 489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.util.Log; 499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.IOException; 519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.DatagramSocket; 529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.InetAddress; 539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.UnknownHostException; 54a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyanimport java.util.ArrayList; 559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Collection; 569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Comparator; 579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.HashMap; 589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Iterator; 599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Map; 609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Timer; 619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TimerTask; 629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TreeSet; 634cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyanimport java.util.concurrent.Executor; 649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException; 659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/** 679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @hide 689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanpublic final class SipService extends ISipService.Stub { 70acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan static final String TAG = "SipService"; 7185caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh static final boolean DEBUG = false; 729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int EXPIRY_TIME = 3600; 739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int SHORT_EXPIRY_TIME = 10; 749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int MIN_EXPIRY_TIME = 60; 758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private static final int DEFAULT_KEEPALIVE_INTERVAL = 10; // in seconds 76cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan private static final int DEFAULT_MAX_KEEPALIVE_INTERVAL = 120; // in seconds 779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Context mContext; 799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mLocalIp; 807d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh private int mNetworkType = -1; 814cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private SipWakeupTimer mTimer; 829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private WifiManager.WifiLock mWifiLock; 8379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh private boolean mSipOnWifiOnly; 84987b505b1c190ff0e5a05d2cc20c9b08d2b99b18Hung-ying Tyan 85469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private IntervalMeasurementProcess mIntervalMeasurementProcess; 869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 874cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private MyExecutor mExecutor = new MyExecutor(); 889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // SipProfile URI --> group 909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, SipSessionGroupExt> mSipGroups = 919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, SipSessionGroupExt>(); 929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // session ID --> session 949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, ISipSession> mPendingSessions = 959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, ISipSession>(); 969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private ConnectivityReceiver mConnectivityReceiver; 98acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan private SipWakeLock mMyWakeLock; 99469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private int mKeepAliveInterval; 100cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan private int mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL; 1019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 1039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Starts the SIP service. Do nothing if the SIP API is not supported on the 1049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * device. 1059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 1069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public static void start(Context context) { 1079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (SipManager.isApiSupported(context)) { 1089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ServiceManager.addService("sip", new SipService(context)); 10922523a59d879cf47f1e9c202d001d569fad4f69eHung-ying Tyan context.sendBroadcast(new Intent(SipManager.ACTION_SIP_SERVICE_UP)); 110dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan if (DEBUG) Log.d(TAG, "SIP service started"); 1119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipService(Context context) { 1159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " service started!"); 1169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext = context; 1179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mConnectivityReceiver = new ConnectivityReceiver(); 11879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh 11979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mWifiLock = ((WifiManager) 12079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh context.getSystemService(Context.WIFI_SERVICE)) 12179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh .createWifiLock(WifiManager.WIFI_MODE_FULL, TAG); 12279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mWifiLock.setReferenceCounted(false); 12379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mSipOnWifiOnly = SipManager.isSipWifiOnly(context); 12479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh 125acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan mMyWakeLock = new SipWakeLock((PowerManager) 126257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan context.getSystemService(Context.POWER_SERVICE)); 1279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1284cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan mTimer = new SipWakeupTimer(context, mExecutor); 129dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan } 130dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan 1319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized SipProfile[] getListOfProfiles() { 1328127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1338127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 134a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan boolean isCallerRadio = isCallerRadio(); 135a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan ArrayList<SipProfile> profiles = new ArrayList<SipProfile>(); 1369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 137a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerRadio || isCallerCreator(group)) { 138a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan profiles.add(group.getLocalProfile()); 139a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 1409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 141a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return profiles.toArray(new SipProfile[profiles.size()]); 1429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 144dc7545495e1ef8bad32cd78775f4dc072015eea0Hung-ying Tyan public synchronized void open(SipProfile localProfile) { 1458127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1468127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 1479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 1489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 1499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan createGroup(localProfile); 1509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 1519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "openToMakeCalls()", e); 1529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: how to send the exception back 1539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void open3(SipProfile localProfile, 157845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 158845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan ISipSessionListener listener) { 1598127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1608127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 1619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 162845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan if (incomingCallPendingIntent == null) { 163845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan Log.w(TAG, "incomingCallPendingIntent cannot be null; " 164845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + "the profile is not opened"); 165a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 1669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "open3: " + localProfile.getUriString() + ": " 168845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + incomingCallPendingIntent + ": " + listener); 1699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 1709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = createGroup(localProfile, 171845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan incomingCallPendingIntent, listener); 1729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localProfile.getAutoRegistration()) { 1739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.openToReceiveCalls(); 1747d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh updateWakeLocks(); 1759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 1779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "openToReceiveCalls()", e); 1789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: how to send the exception back 1799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 182a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerCreator(SipSessionGroupExt group) { 183a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipProfile profile = group.getLocalProfile(); 184a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (profile.getCallingUid() == Binder.getCallingUid()); 185a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 186a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 187a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerCreatorOrRadio(SipSessionGroupExt group) { 188a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (isCallerRadio() || isCallerCreator(group)); 189a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 190a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 191a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan private boolean isCallerRadio() { 192a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return (Binder.getCallingUid() == Process.PHONE_UID); 193a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 194a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 1959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void close(String localProfileUri) { 1968127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 1978127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 198a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 199a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return; 200a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (!isCallerCreatorOrRadio(group)) { 2016d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can close this profile"); 202a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return; 2039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 204a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan 205a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group = mSipGroups.remove(localProfileUri); 206a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan notifyProfileRemoved(group.getLocalProfile()); 207a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group.close(); 208257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 2097d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh updateWakeLocks(); 2109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isOpened(String localProfileUri) { 2138127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2148127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 216a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return false; 217a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 218617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan return true; 219a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2206d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can query on the profile"); 221a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return false; 222a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isRegistered(String localProfileUri) { 2268127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2278127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 229a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return false; 230a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreatorOrRadio(group)) { 231a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return group.isRegistered(); 232a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2336d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator or radio can query on the profile"); 234a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan return false; 235a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void setRegistrationListener(String localProfileUri, 2399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) { 2408127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2418127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(localProfileUri); 243a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (group == null) return; 244a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (isCallerCreator(group)) { 245a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan group.setListener(listener); 246a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else { 2476d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.w(TAG, "only creator can set listener on the profile"); 248a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 2499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized ISipSession createSession(SipProfile localProfile, 2529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) { 2538127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2548127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan localProfile.setCallingUid(Binder.getCallingUid()); 2567d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mNetworkType == -1) return null; 2579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 2589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = createGroup(localProfile); 2599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group.createSession(listener); 2609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 2616d9d99615a30de0675271553552c3c7b49311354Joe Onorato if (DEBUG) Log.d(TAG, "createSession()", e); 2629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 2639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized ISipSession getPendingSession(String callId) { 2678127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan mContext.enforceCallingOrSelfPermission( 2688127b35b75c13f853dc8eb2fed8bba4bf99e3eedHung-ying Tyan android.Manifest.permission.USE_SIP, null); 2699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (callId == null) return null; 2709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mPendingSessions.get(callId); 2719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String determineLocalIp() { 2749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 2759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan DatagramSocket s = new DatagramSocket(); 2769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s.connect(InetAddress.getByName("192.168.1.1"), 80); 2779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s.getLocalAddress().getHostAddress(); 2789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 2796d9d99615a30de0675271553552c3c7b49311354Joe Onorato if (DEBUG) Log.d(TAG, "determineLocalIp()", e); 2809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // dont do anything; there should be a connectivity change going 2819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 2829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroupExt createGroup(SipProfile localProfile) 2869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 2879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = localProfile.getUriString(); 2889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(key); 2899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group == null) { 2909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group = new SipSessionGroupExt(localProfile, null, null); 2919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroups.put(key, group); 2929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan notifyProfileAdded(localProfile); 293a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } else if (!isCallerCreator(group)) { 294a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan throw new SipException("only creator can access the profile"); 2959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group; 2979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroupExt createGroup(SipProfile localProfile, 300845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 301845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan ISipSessionListener listener) throws SipException { 3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = localProfile.getUriString(); 3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionGroupExt group = mSipGroups.get(key); 3049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (group != null) { 305a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan if (!isCallerCreator(group)) { 306a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan throw new SipException("only creator can access the profile"); 307a072a6e3aa75c9bd038406a5067156463b58551bHung-ying Tyan } 308845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan group.setIncomingCallPendingIntent(incomingCallPendingIntent); 3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.setListener(listener); 3109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 3119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group = new SipSessionGroupExt(localProfile, 312845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan incomingCallPendingIntent, listener); 3139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroups.put(key, group); 3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan notifyProfileAdded(localProfile); 3159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return group; 3179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void notifyProfileAdded(SipProfile localProfile) { 3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile added: " + localProfile); 3219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_ADD_PHONE); 3229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 3247d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mSipGroups.size() == 1) { 3257d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh registerReceivers(); 3267d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh } 3279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void notifyProfileRemoved(SipProfile localProfile) { 3309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "notify: profile removed: " + localProfile); 3319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = new Intent(SipManager.ACTION_SIP_REMOVE_PHONE); 3329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan intent.putExtra(SipManager.EXTRA_LOCAL_URI, localProfile.getUriString()); 3339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.sendBroadcast(intent); 3347d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mSipGroups.size() == 0) { 3357d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh unregisterReceivers(); 3369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 339469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private void stopPortMappingMeasurement() { 340469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang if (mIntervalMeasurementProcess != null) { 341469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang mIntervalMeasurementProcess.stop(); 342469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang mIntervalMeasurementProcess = null; 343469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 344469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 345469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 3468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private void startPortMappingLifetimeMeasurement( 3478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan SipProfile localProfile) { 348cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan startPortMappingLifetimeMeasurement(localProfile, 349cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan DEFAULT_MAX_KEEPALIVE_INTERVAL); 35044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan } 35144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan 35244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private void startPortMappingLifetimeMeasurement( 35344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan SipProfile localProfile, int maxInterval) { 3548a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if ((mIntervalMeasurementProcess == null) 3558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan && (mKeepAliveInterval == -1) 3568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan && isBehindNAT(mLocalIp)) { 3578a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.d(TAG, "start NAT port mapping timeout measurement on " 3588a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + localProfile.getUriString()); 3598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 360cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan int minInterval = mLastGoodKeepAliveInterval; 361cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan if (minInterval >= maxInterval) { 362cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // If mLastGoodKeepAliveInterval also does not work, reset it 363cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // to the default min 364cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan minInterval = mLastGoodKeepAliveInterval 365cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan = DEFAULT_KEEPALIVE_INTERVAL; 366cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan Log.d(TAG, " reset min interval to " + minInterval); 367cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan } 368cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mIntervalMeasurementProcess = new IntervalMeasurementProcess( 369cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan localProfile, minInterval, maxInterval); 3708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mIntervalMeasurementProcess.start(); 3718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 372469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 373469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 37444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private void restartPortMappingLifetimeMeasurement( 37544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan SipProfile localProfile, int maxInterval) { 37644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan stopPortMappingMeasurement(); 37744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan mKeepAliveInterval = -1; 37844ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan startPortMappingLifetimeMeasurement(localProfile, maxInterval); 37944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan } 38044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan 3819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void addPendingSession(ISipSession session) { 3829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3833f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan cleanUpPendingSessions(); 3849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPendingSessions.put(session.getCallId(), session); 3853f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan if (DEBUG) Log.d(TAG, "#pending sess=" + mPendingSessions.size()); 3869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (RemoteException e) { 3879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // should not happen with a local call 3889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "addPendingSession()", e); 3899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3923f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan private void cleanUpPendingSessions() throws RemoteException { 3933f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan Map.Entry<String, ISipSession>[] entries = 3943f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan mPendingSessions.entrySet().toArray( 3953f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan new Map.Entry[mPendingSessions.size()]); 3963f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan for (Map.Entry<String, ISipSession> entry : entries) { 3973f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan if (entry.getValue().getState() != SipSession.State.INCOMING_CALL) { 3983f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan mPendingSessions.remove(entry.getKey()); 3993f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 4003f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 4013f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan } 4023f4d44657ccad3ed02ed0e1354387b14b07dc011Hung-ying Tyan 403ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan private synchronized boolean callingSelf(SipSessionGroupExt ringingGroup, 404ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan SipSessionGroup.SipSessionImpl ringingSession) { 405ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan String callId = ringingSession.getCallId(); 406ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 407ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if ((group != ringingGroup) && group.containsSession(callId)) { 408ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if (DEBUG) Log.d(TAG, "call self: " 409ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan + ringingSession.getLocalProfile().getUriString() 410ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan + " -> " + group.getLocalProfile().getUriString()); 411ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return true; 412ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 413ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 414ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return false; 415ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 416ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 4178a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private synchronized void onKeepAliveIntervalChanged() { 4188a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan for (SipSessionGroupExt group : mSipGroups.values()) { 4198a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan group.onKeepAliveIntervalChanged(); 4208a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 4218a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 4228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 4238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private int getKeepAliveInterval() { 4248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return (mKeepAliveInterval < 0) 425cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan ? mLastGoodKeepAliveInterval 4268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan : mKeepAliveInterval; 4278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 4288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 4298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private boolean isBehindNAT(String address) { 4308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan try { 4318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan byte[] d = InetAddress.getByName(address).getAddress(); 4328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if ((d[0] == 10) || 4338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 172) && 4348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan ((0x000000F0 & ((int)d[1])) == 16)) || 4358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan (((0x000000FF & ((int)d[0])) == 192) && 4368a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan ((0x000000FF & ((int)d[1])) == 168))) { 4378a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return true; 4388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 4398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } catch (UnknownHostException e) { 4408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.e(TAG, "isBehindAT()" + address, e); 4418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 4428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return false; 4438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 444ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 4459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class SipSessionGroupExt extends SipSessionAdapter { 4469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup mSipGroup; 447845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan private PendingIntent mIncomingCallPendingIntent; 448617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan private boolean mOpenedToReceiveCalls; 4499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private AutoRegistrationProcess mAutoRegistration = 4519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new AutoRegistrationProcess(); 4529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipSessionGroupExt(SipProfile localProfile, 454845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan PendingIntent incomingCallPendingIntent, 4559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ISipSessionListener listener) throws SipException { 4569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String password = localProfile.getPassword(); 4579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile p = duplicate(localProfile); 4589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup = createSipSessionGroup(mLocalIp, p, password); 459845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent = incomingCallPendingIntent; 4609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.setListener(listener); 4619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getLocalProfile() { 4649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.getLocalProfile(); 4659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 467ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan public boolean containsSession(String callId) { 468ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return mSipGroup.containsSession(callId); 469ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 470ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 4718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onKeepAliveIntervalChanged() { 4728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mAutoRegistration.onKeepAliveIntervalChanged(); 4738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 4748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 4758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // TODO: remove this method once SipWakeupTimer can better handle variety 4768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // of timeout values 4778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan void setWakeupTimer(SipWakeupTimer timer) { 4788a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSipGroup.setWakeupTimer(timer); 4798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 4808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 4819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network connectivity is tricky because network can be disconnected 4829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // at any instant so need to deal with exceptions carefully even when 4839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // you think you are connected 4849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup createSipSessionGroup(String localIp, 4859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile localProfile, String password) throws SipException { 4869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 487acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan return new SipSessionGroup(localIp, localProfile, password, 4888a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mTimer, mMyWakeLock); 4899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 4909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network disconnected 4919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "createSipSessionGroup(): network disconnected?"); 4929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp != null) { 4939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return createSipSessionGroup(null, localProfile, password); 4949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 4959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // recursive 4966d9d99615a30de0675271553552c3c7b49311354Joe Onorato Log.wtf(TAG, "impossible! recursive!"); 4979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("createSipSessionGroup"); 4989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipProfile duplicate(SipProfile p) { 5039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new SipProfile.Builder(p).setPassword("*").build(); 5059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Exception e) { 5069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "duplicate()", e); 5079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("duplicate profile", e); 5089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 5129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.setListener(listener); 5139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 515845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan public void setIncomingCallPendingIntent(PendingIntent pIntent) { 516845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent = pIntent; 5179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void openToReceiveCalls() throws SipException { 520617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan mOpenedToReceiveCalls = true; 5217d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mNetworkType != -1) { 5229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.openToReceiveCalls(this); 5239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.start(mSipGroup); 5249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " openToReceiveCalls: " + getUri() + ": " 526845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + mIncomingCallPendingIntent); 5279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onConnectivityChanged(boolean connected) 5309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 5319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.onConnectivityChanged(); 5329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (connected) { 5339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan resetGroup(mLocalIp); 534617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan if (mOpenedToReceiveCalls) openToReceiveCalls(); 5359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 536617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan // close mSipGroup but remember mOpenedToReceiveCalls 5379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " close auto reg temporarily: " 538845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + getUri() + ": " + mIncomingCallPendingIntent); 5399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.close(); 5409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.stop(); 5419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void resetGroup(String localIp) throws SipException { 5459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.reset(localIp); 5479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 5489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // network disconnected 5499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "resetGroup(): network disconnected?"); 5509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp != null) { 5519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan resetGroup(null); // reset w/o local IP 5529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 5539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // recursive 5549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.wtf(TAG, "impossible!"); 5559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new RuntimeException("resetGroup"); 5569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void close() { 561617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan mOpenedToReceiveCalls = false; 5629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipGroup.close(); 5639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mAutoRegistration.stop(); 5649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " close: " + getUri() + ": " 565845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + mIncomingCallPendingIntent); 5669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public ISipSession createSession(ISipSessionListener listener) { 5699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.createSession(listener); 5709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 573845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan public void onRinging(ISipSession s, SipProfile caller, 5749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String sessionDescription) { 57585caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh if (DEBUG) Log.d(TAG, "<<<<< onRinging()"); 576845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan SipSessionGroup.SipSessionImpl session = 577845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan (SipSessionGroup.SipSessionImpl) s; 5789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 5799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 580ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if (!isRegistered() || callingSelf(this, session)) { 5819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan session.endCall(); 5829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return; 5839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // send out incoming call broadcast 5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addPendingSession(session); 5879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Intent intent = SipManager.createIncomingCallBroadcast( 588845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan session.getCallId(), sessionDescription); 5899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, " ringing~~ " + getUri() + ": " 5909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + caller.getUri() + ": " + session.getCallId() 591845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan + " " + mIncomingCallPendingIntent); 592845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan mIncomingCallPendingIntent.send(mContext, 593845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan SipManager.INCOMING_CALL_RESULT_CODE, intent); 594845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan } catch (PendingIntent.CanceledException e) { 595845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan Log.w(TAG, "pendingIntent is canceled, drop incoming call"); 596845f7332f04864c5483b3e63da5db076fc7a888aHung-ying Tyan session.endCall(); 5979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 6029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onError(ISipSession session, int errorCode, 6039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message) { 6049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "sip session error: " 6059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 6069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 608617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan public boolean isOpenedToReceiveCalls() { 609617479363dcafe01bfa1fa025e1d9d122864a0ceHung-ying Tyan return mOpenedToReceiveCalls; 6109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isRegistered() { 6139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mAutoRegistration.isRegistered(); 6149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getUri() { 6179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSipGroup.getLocalProfileUri(); 6189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6217d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private class IntervalMeasurementProcess implements Runnable, 6228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan SipSessionGroup.KeepAliveProcessCallback { 6238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private static final String TAG = "SipKeepAliveInterval"; 6247d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private static final int MIN_INTERVAL = 5; // in seconds 6258a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private static final int PASS_THRESHOLD = 10; 62644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private static final int MAX_RETRY_COUNT = 5; 6277d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds 62837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh private SipProfile mLocalProfile; 629469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private SipSessionGroupExt mGroup; 630469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang private SipSessionGroup.SipSessionImpl mSession; 631cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan private int mMinInterval; 63244ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private int mMaxInterval; 63344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private int mInterval; 63437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh private int mPassCount; 63544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan 636cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan public IntervalMeasurementProcess(SipProfile localProfile, 637cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan int minInterval, int maxInterval) { 638cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mMaxInterval = maxInterval; 639cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mMinInterval = minInterval; 64037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mLocalProfile = localProfile; 641469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 642469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 643469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang public void start() { 6448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipService.this) { 64537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh if (mSession != null) { 64637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh return; 6477d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 64837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 64937f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mInterval = (mMaxInterval + mMinInterval) / 2; 65037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mPassCount = 0; 65137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 65237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh // Don't start measurement if the interval is too small 65337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh if (mInterval < DEFAULT_KEEPALIVE_INTERVAL || checkTermination()) { 65437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh Log.w(TAG, "measurement aborted; interval=[" + 65537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mMinInterval + "," + mMaxInterval + "]"); 65637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh return; 65737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh } 65837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 6598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan try { 66037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh Log.d(TAG, "start measurement w interval=" + mInterval); 66137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 66237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup = new SipSessionGroupExt(mLocalProfile, null, null); 66337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh // TODO: remove this line once SipWakeupTimer can better handle 66437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh // variety of timeout values 66537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor)); 66637f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh 66737f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mSession = (SipSessionGroup.SipSessionImpl) 66837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup.createSession(null); 6698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSession.startKeepAliveProcess(mInterval, this); 67037f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh } catch (Throwable t) { 67137f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh onError(SipErrorCode.CLIENT_ERROR, t.toString()); 6728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 6738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 674469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 675469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 676469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang public void stop() { 6778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipService.this) { 6787d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mSession != null) { 6797d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mSession.stopKeepAliveProcess(); 6807d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mSession = null; 6817d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 68237f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh if (mGroup != null) { 68337f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup.close(); 68437f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh mGroup = null; 68537f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh } 6867d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mTimer.cancel(this); 687469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 688469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 689469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 6908a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private void restart() { 691469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang synchronized (SipService.this) { 6927d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan // Return immediately if the measurement process is stopped 6937d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mSession == null) return; 6947d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 6957d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.d(TAG, "restart measurement w interval=" + mInterval); 696469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang try { 6978a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSession.stopKeepAliveProcess(); 6987d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mPassCount = 0; 6998a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSession.startKeepAliveProcess(mInterval, this); 7008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } catch (SipException e) { 7018a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.e(TAG, "restart()", e); 702469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 703469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 704469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 705469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang 706cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan private boolean checkTermination() { 707cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan return ((mMaxInterval - mMinInterval) < MIN_INTERVAL); 708cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan } 709cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan 7108a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 7118a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 7128a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onResponse(boolean portChanged) { 7139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 7148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (!portChanged) { 71544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan if (++mPassCount != PASS_THRESHOLD) return; 7168a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // update the interval, since the current interval is good to 7178a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // keep the port mapping. 718cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan if (mKeepAliveInterval > 0) { 719cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan mLastGoodKeepAliveInterval = mKeepAliveInterval; 720cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan } 7218a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mKeepAliveInterval = mMinInterval = mInterval; 7228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) { 7238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.d(TAG, "measured good keepalive interval: " 7248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + mKeepAliveInterval); 725257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 7268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan onKeepAliveIntervalChanged(); 7278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } else { 7288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // Since the rport is changed, shorten the interval. 7298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mMaxInterval = mInterval; 7308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 731cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan if (checkTermination()) { 7328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // update mKeepAliveInterval and stop measurement. 7338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan stop(); 734cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // If all the measurements failed, we still set it to 735cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // mMinInterval; If mMinInterval still doesn't work, a new 736cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // measurement with min interval=DEFAULT_KEEPALIVE_INTERVAL 737cd9cb0845a0ad468bbbadadc133bc7a406e40b4aHung-ying Tyan // will be conducted. 7388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mKeepAliveInterval = mMinInterval; 7398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) { 7408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.d(TAG, "measured keepalive interval: " 7418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + mKeepAliveInterval); 742469491e7807a46f31681d21c0ddae215f7891094Chung-yih Wang } 7438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } else { 7448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // calculate the new interval and continue. 7458a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mInterval = (mMaxInterval + mMinInterval) / 2; 7468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) { 7478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.d(TAG, "current interval: " + mKeepAliveInterval 7488a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + ", test new interval: " + mInterval); 7498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 7508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan restart(); 7519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 7568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 7578a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onError(int errorCode, String description) { 7587d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.w(TAG, "interval measurement error: " + description); 7597d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan restartLater(); 7607d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 7617d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 7627d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan // timeout handler 7637d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan @Override 7647d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan public void run() { 7657d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mTimer.cancel(this); 7667d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan restart(); 7677d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 7687d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 7697d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private void restartLater() { 7708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipService.this) { 7717d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan int interval = NAT_MEASUREMENT_RETRY_INTERVAL; 7727d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mTimer.cancel(this); 7737d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mTimer.set(interval * 1000, this); 7748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 7759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class AutoRegistrationProcess extends SipSessionAdapter 7798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan implements Runnable, SipSessionGroup.KeepAliveProcessCallback { 7807d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10; 78185caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh private String TAG = "SipAutoReg"; 7827d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 7839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionGroup.SipSessionImpl mSession; 7848a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private SipSessionGroup.SipSessionImpl mKeepAliveSession; 7859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 7869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mBackoff = 1; 7879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mRegistered; 7889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private long mExpiryTime; 7899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mErrorCode; 7909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mErrorMessage; 791d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean mRunning = false; 7929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7937d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private int mKeepAliveSuccessCount = 0; 7947d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 7959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getAction() { 7969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return toString(); 7979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void start(SipSessionGroup group) { 800d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) { 801d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = true; 8029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mBackoff = 1; 8039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession = (SipSessionGroup.SipSessionImpl) 8049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan group.createSession(this); 8059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // return right away if no active network connection. 8069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mSession == null) return; 8079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // start unregistration to clear up old registration at server 8099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: when rfc5626 is deployed, use reg-id and sip.instance 8109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // in registration to avoid adding duplicate entries to server 811257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mSession); 8129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSession.unregister(); 81385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh TAG = "SipAutoReg:" + mSession.getLocalProfile().getUriString(); 8149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8177d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private void startKeepAliveProcess(int interval) { 81885caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh if (DEBUG) Log.d(TAG, "start keepalive w interval=" + interval); 8197d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mKeepAliveSession == null) { 8207d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession = mSession.duplicate(); 8217d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } else { 8227d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession.stopKeepAliveProcess(); 8237d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 8247d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan try { 8257d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession.startKeepAliveProcess(interval, this); 8267d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } catch (SipException e) { 8277d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.e(TAG, "failed to start keepalive w interval=" + interval, 8287d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan e); 8297d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 8307d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 8317d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 8327d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan private void stopKeepAliveProcess() { 8337d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mKeepAliveSession != null) { 8347d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession.stopKeepAliveProcess(); 8357d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSession = null; 8367d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 8377d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount = 0; 8387d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 8397d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan 8408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 8418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 8428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onResponse(boolean portChanged) { 8438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipService.this) { 84444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan if (portChanged) { 8457d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan int interval = getKeepAliveInterval(); 8467d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (mKeepAliveSuccessCount < MIN_KEEPALIVE_SUCCESS_COUNT) { 8477d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan Log.i(TAG, "keepalive doesn't work with interval " 8487d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan + interval + ", past success count=" 8497d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan + mKeepAliveSuccessCount); 8507d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan if (interval > DEFAULT_KEEPALIVE_INTERVAL) { 8517d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan restartPortMappingLifetimeMeasurement( 8527d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mSession.getLocalProfile(), interval); 8537d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount = 0; 8547d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 8557d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } else { 85685caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh if (DEBUG) { 85785caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh Log.i(TAG, "keep keepalive going with interval " 85885caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh + interval + ", past success count=" 85985caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh + mKeepAliveSuccessCount); 86085caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh } 8617d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount /= 2; 8627d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan } 86344ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan } else { 86444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan // Start keep-alive interval measurement on the first 86544ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan // successfully kept-alive SipSessionGroup 86644ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan startPortMappingLifetimeMeasurement( 86744ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan mSession.getLocalProfile()); 8687d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount++; 86944ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan } 8708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 8718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (!mRunning || !portChanged) return; 8729dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan 8739dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan // The keep alive process is stopped when port is changed; 8749dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan // Nullify the session so that the process can be restarted 8759dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan // again when the re-registration is done 8769dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan mKeepAliveSession = null; 8779dbe2c72276b9968593054dcfd39fd5135a574aaHung-ying Tyan 8788a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // Acquire wake lock for the registration process. The 8798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // lock will be released when registration is complete. 8808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mMyWakeLock.acquire(mSession); 8818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSession.register(EXPIRY_TIME); 8828a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 8838a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 8848a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 8858a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionGroup.KeepAliveProcessCallback 8868a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 8878a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onError(int errorCode, String description) { 88885caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh if (DEBUG) { 88985caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh Log.e(TAG, "keepalive error: " + description); 89085caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh } 89144ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan onResponse(true); // re-register immediately 8928a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 8938a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 8949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void stop() { 895d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 896d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRunning = false; 897257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(mSession); 898257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (mSession != null) { 899257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mSession.setListener(null); 9007d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mNetworkType != -1 && mRegistered) mSession.unregister(); 901257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 902d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 9039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 9047d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan stopKeepAliveProcess(); 9059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 906d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mRegistered = false; 907d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan setListener(mProxy.getListener()); 9089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9108a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onKeepAliveIntervalChanged() { 9118a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mKeepAliveSession != null) { 9128a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan int newInterval = getKeepAliveInterval(); 91385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh if (DEBUG) { 9148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan Log.v(TAG, "restart keepalive w interval=" + newInterval); 9158a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 9167d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan mKeepAliveSuccessCount = 0; 9177d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan startKeepAliveProcess(newInterval); 9188a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 9198a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 9208a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 9219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 9229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 9239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.setListener(listener); 9249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 9269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int state = (mSession == null) 9279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? SipSession.State.READY_TO_CALL 9289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : mSession.getState(); 9299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((state == SipSession.State.REGISTERING) 9309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan || (state == SipSession.State.DEREGISTERING)) { 9319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(mSession); 9329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mRegistered) { 9339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = (int) 9349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (mExpiryTime - SystemClock.elapsedRealtime()); 9359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(mSession, duration); 9369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (mErrorCode != SipErrorCode.NO_ERROR) { 9379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mErrorCode == SipErrorCode.TIME_OUT) { 9389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(mSession); 9399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 9409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationFailed(mSession, mErrorCode, 9419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mErrorMessage); 9429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9437d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh } else if (mNetworkType == -1) { 944d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 945d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.DATA_CONNECTION_LOST, 946d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan "no data connection"); 947d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else if (!mRunning) { 948d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 949d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.CLIENT_ERROR, 950d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan "registration not running"); 951d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } else { 952d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(mSession, 953d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan SipErrorCode.IN_PROGRESS, 954d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan String.valueOf(state)); 9559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable t) { 9579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "setListener(): " + t); 9589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isRegistered() { 9639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mRegistered; 9649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 966257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // timeout handler: re-register 9678a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 9689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 969d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan synchronized (SipService.this) { 970d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (!mRunning) return; 971d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 972d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorCode = SipErrorCode.NO_ERROR; 973d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorMessage = null; 9748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (DEBUG) Log.d(TAG, "registering"); 9757d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mNetworkType != -1) { 976257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(mSession); 977257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mSession.register(EXPIRY_TIME); 978257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 9799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void restart(int duration) { 98385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh Log.d(TAG, "Refresh registration " + duration + "s later."); 9849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(this); 9859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.set(duration * 1000, this); 9869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int backoffDuration() { 9899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = SHORT_EXPIRY_TIME * mBackoff; 9909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration > 3600) { 9919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration = 3600; 9929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 9939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mBackoff *= 2; 9949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return duration; 9969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 9999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistering(ISipSession session) { 10009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistering(): " + session); 10019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 1002d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 1003d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 10049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 10059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(session); 10069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1009d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan private boolean notCurrentSession(ISipSession session) { 1010d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (session != mSession) { 1011d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan ((SipSessionGroup.SipSessionImpl) session).setListener(null); 1012257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 1013d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return true; 1014d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 1015d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan return !mRunning; 1016d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan } 1017d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 10189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 10199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationDone(ISipSession session, int duration) { 10209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationDone(): " + session); 10219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 1022d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 10239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(session, duration); 10259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration > 0) { 10279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mExpiryTime = SystemClock.elapsedRealtime() 10289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + (duration * 1000); 10299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mRegistered) { 10319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = true; 10329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // allow some overlap to avoid call drop during renew 10339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration -= MIN_EXPIRY_TIME; 10349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (duration < MIN_EXPIRY_TIME) { 10359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan duration = MIN_EXPIRY_TIME; 10369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan restart(duration); 10389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan SipProfile localProfile = mSession.getLocalProfile(); 10408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if ((mKeepAliveSession == null) && (isBehindNAT(mLocalIp) 10418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan || localProfile.getSendKeepAlive())) { 10427d2904eaae91bd096eccef637dce430a41923424Hung-ying Tyan startKeepAliveProcess(getKeepAliveInterval()); 10439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1045257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 10469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 10489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mExpiryTime = -1L; 10499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "Refresh registration immediately"); 10509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan run(); 10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 10569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationFailed(ISipSession session, int errorCode, 10579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message) { 10589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationFailed(): " + session + ": " 10599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 10609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 1061d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 10629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1063fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan switch (errorCode) { 1064fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan case SipErrorCode.INVALID_CREDENTIALS: 1065fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan case SipErrorCode.SERVER_UNREACHABLE: 1066fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan if (DEBUG) Log.d(TAG, " pause auto-registration"); 1067fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan stop(); 10680b88a073712b1510db7c636f89c4e19f0131449aHung-ying Tyan break; 1069fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan default: 1070fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan restartLater(); 10719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1072d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 1073d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorCode = errorCode; 1074d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mErrorMessage = message; 1075d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mProxy.onRegistrationFailed(session, errorCode, message); 1076257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 10779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void onRegistrationTimeout(ISipSession session) { 10829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.d(TAG, "onRegistrationTimeout(): " + session); 10839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipService.this) { 1084d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan if (notCurrentSession(session)) return; 1085d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan 10869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mErrorCode = SipErrorCode.TIME_OUT; 10879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(session); 1088fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan restartLater(); 1089257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(session); 10909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1093fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan private void restartLater() { 10949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRegistered = false; 10959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan restart(backoffDuration()); 10969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class ConnectivityReceiver extends BroadcastReceiver { 11009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 110179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh public void onReceive(Context context, Intent intent) { 110279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh Bundle bundle = intent.getExtras(); 110379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh if (bundle != null) { 110479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh final NetworkInfo info = (NetworkInfo) 110579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh bundle.get(ConnectivityManager.EXTRA_NETWORK_INFO); 11069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 110779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // Run the handler in MyExecutor to be protected by wake lock 110879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mExecutor.execute(new Runnable() { 110979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh public void run() { 111079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh onConnectivityChanged(info); 11119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 111279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh }); 11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 111579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh } 111679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh 111779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh private void registerReceivers() { 111879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mContext.registerReceiver(mConnectivityReceiver, 111979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); 112079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh if (DEBUG) Log.d(TAG, " +++ register receivers"); 112179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh } 11229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 112379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh private void unregisterReceivers() { 112479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mContext.unregisterReceiver(mConnectivityReceiver); 112579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh if (DEBUG) Log.d(TAG, " --- unregister receivers"); 112679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh 112779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // Reset variables maintained by ConnectivityReceiver. 112879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mWifiLock.release(); 11297d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh mNetworkType = -1; 11307d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh } 11317d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh 11327d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh private void updateWakeLocks() { 11337d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh for (SipSessionGroupExt group : mSipGroups.values()) { 11347d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (group.isOpenedToReceiveCalls()) { 11357d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh // Also grab the WifiLock when we are disconnected, so the 11367d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh // system will keep trying to reconnect. It will be released 11377d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh // when the system eventually connects to something else. 11387d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mNetworkType == ConnectivityManager.TYPE_WIFI || mNetworkType == -1) { 11397d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh mWifiLock.acquire(); 11407d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh } else { 11417d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh mWifiLock.release(); 11427d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh } 11437d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh return; 11447d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh } 11457d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh } 11467d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh mWifiLock.release(); 11477d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh mMyWakeLock.reset(); // in case there's a leak 114879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh } 114979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh 115079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh private synchronized void onConnectivityChanged(NetworkInfo info) { 115179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // We only care about the default network, and getActiveNetworkInfo() 115279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // is the only way to distinguish them. However, as broadcasts are 115379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // delivered asynchronously, we might miss DISCONNECTED events from 115479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // getActiveNetworkInfo(), which is critical to our SIP stack. To 115579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // solve this, if it is a DISCONNECTED event to our current network, 115679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // respect it. Otherwise get a new one from getActiveNetworkInfo(). 11577d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (info == null || info.isConnected() || info.getType() != mNetworkType) { 11589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ConnectivityManager cm = (ConnectivityManager) 11599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 116079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh info = cm.getActiveNetworkInfo(); 11619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 116379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // Some devices limit SIP on Wi-Fi. In this case, if we are not on 116479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // Wi-Fi, treat it as a DISCONNECTED event. 11657d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh int networkType = (info != null && info.isConnected()) ? info.getType() : -1; 11667d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mSipOnWifiOnly && networkType != ConnectivityManager.TYPE_WIFI) { 11677d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh networkType = -1; 11687d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh } 11699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 117079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh // Ignore the event if the current active network is not changed. 11717d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mNetworkType == networkType) { 117279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh return; 117379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh } 117479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh if (DEBUG) { 117579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh Log.d(TAG, "onConnectivityChanged(): " + mNetworkType + 117679d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh " -> " + networkType); 117779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh } 11789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 117979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh try { 11807d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mNetworkType != -1) { 118179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mLocalIp = null; 118279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh stopPortMappingMeasurement(); 118379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh for (SipSessionGroupExt group : mSipGroups.values()) { 118479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh group.onConnectivityChanged(false); 118579d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh } 11869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 118779d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mNetworkType = networkType; 11889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11897d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh if (mNetworkType != -1) { 119079d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mLocalIp = determineLocalIp(); 119179d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mKeepAliveInterval = -1; 119279d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh mLastGoodKeepAliveInterval = DEFAULT_KEEPALIVE_INTERVAL; 119379d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh for (SipSessionGroupExt group : mSipGroups.values()) { 119479d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh group.onConnectivityChanged(true); 11959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11977d803d942453ed2139bb590aba4c4fe025529a8fChia-chi Yeh updateWakeLocks(); 119879d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh } catch (SipException e) { 119979d4e0ecfe1bc8d369ffcdfb01dd1900b3ea10d5Chia-chi Yeh Log.e(TAG, "onConnectivityChanged()", e); 12009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1203257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private static Looper createLooper() { 1204257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan HandlerThread thread = new HandlerThread("SipService.Executor"); 1205257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan thread.start(); 1206257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan return thread.getLooper(); 1207257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1208257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 1209257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Executes immediate tasks in a single thread. 1210257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // Hold/release wake lock for running tasks 12114cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan private class MyExecutor extends Handler implements Executor { 12129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MyExecutor() { 12139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(createLooper()); 12149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12164cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan @Override 12174cbf2d2f94aaa094dda5b93357c93234ebccb120Hung-ying Tyan public void execute(Runnable task) { 1218257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.acquire(task); 12199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Message.obtain(this, 0/* don't care */, task).sendToTarget(); 12209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan @Override 12239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void handleMessage(Message msg) { 12249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (msg.obj instanceof Runnable) { 1225257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan executeInternal((Runnable) msg.obj); 12269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "can't handle msg: " + msg); 12289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1230257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan 1231257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan private void executeInternal(Runnable task) { 1232257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan try { 1233257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan task.run(); 1234257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } catch (Throwable t) { 1235257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan Log.e(TAG, "run task: " + task, t); 1236257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } finally { 1237257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan mMyWakeLock.release(task); 1238257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1239257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 1240257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 12419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan} 1242