SipSessionGroup.java revision d47a47a131a8e7f80b934aec4cc7a10fd9fe1094
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 gov.nist.javax.sip.clientauthutils.AccountManager; 209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport gov.nist.javax.sip.clientauthutils.UserCredentials; 219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport gov.nist.javax.sip.header.SIPHeaderNames; 229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport gov.nist.javax.sip.header.ProxyAuthenticate; 239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport gov.nist.javax.sip.header.WWWAuthenticate; 249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport gov.nist.javax.sip.message.SIPMessage; 259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSession; 279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSessionListener; 289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipErrorCode; 299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipProfile; 309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSession; 319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.text.TextUtils; 329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.util.Log; 339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.IOException; 359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.UnsupportedEncodingException; 369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.DatagramSocket; 379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.UnknownHostException; 389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.text.ParseException; 399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Collection; 409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.EventObject; 419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.HashMap; 429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Map; 439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Properties; 449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.TooManyListenersException; 459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.ClientTransaction; 479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.Dialog; 489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.DialogTerminatedEvent; 499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.IOExceptionEvent; 509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.InvalidArgumentException; 519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.ListeningPoint; 52e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyanimport javax.sip.ObjectInUseException; 539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.RequestEvent; 549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.ResponseEvent; 559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.ServerTransaction; 569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException; 579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipFactory; 589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipListener; 599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipProvider; 609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipStack; 619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.TimeoutEvent; 629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.Transaction; 639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.TransactionState; 649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.TransactionTerminatedEvent; 659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.TransactionUnavailableException; 669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.address.Address; 679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.address.SipURI; 689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.CSeqHeader; 699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.ExpiresHeader; 709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.FromHeader; 719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.MinExpiresHeader; 729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.ViaHeader; 739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.message.Message; 749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.message.Request; 759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.message.Response; 769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/** 789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Manages {@link ISipSession}'s for a SIP account. 799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanclass SipSessionGroup implements SipListener { 819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TAG = "SipSession"; 829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final boolean DEBUG = true; 839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final boolean DEBUG_PING = DEBUG && false; 849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String ANONYMOUS = "anonymous"; 85b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang // Limit the size of thread pool to 1 for the order issue when the phone is 86b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang // waken up from sleep and there are many packets to be processed in the SIP 87b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang // stack. Note: The default thread pool size in NIST SIP stack is -1 which is 88b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang // unlimited. 89b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang private static final String THREAD_POOL_SIZE = "1"; 909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int EXPIRY_TIME = 3600; // in seconds 919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int CANCEL_CALL_TIMER = 3; // in seconds 92acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan private static final long WAKE_LOCK_HOLDING_TIME = 500; // in milliseconds 939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final EventObject DEREGISTER = new EventObject("Deregister"); 959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final EventObject END_CALL = new EventObject("End call"); 969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final EventObject HOLD_CALL = new EventObject("Hold call"); 979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final EventObject CONTINUE_CALL 989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan = new EventObject("Continue call"); 999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private final SipProfile mLocalProfile; 1019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private final String mPassword; 1029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipStack mSipStack; 1049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipHelper mSipHelper; 1059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // session that processes INVITE requests 1079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionImpl mCallReceiverSession; 1089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mLocalIp; 1099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 110acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan private SipWakeLock mWakeLock; 111acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan 1129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // call-id-to-SipSession map 1139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, SipSessionImpl> mSessionMap = 1149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, SipSessionImpl>(); 1159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 1179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param myself the local profile with password crossed out 1189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param password the password of the profile 1199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @throws IOException if cannot assign requested address 1209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 121acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan public SipSessionGroup(String localIp, SipProfile myself, String password, 122acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan SipWakeLock wakeLock) throws SipException, IOException { 1239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalProfile = myself; 1249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPassword = password; 125acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan mWakeLock = wakeLock; 1269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(localIp); 1279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized void reset(String localIp) throws SipException, IOException { 1309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalIp = localIp; 1319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (localIp == null) return; 1329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile myself = mLocalProfile; 1349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipFactory sipFactory = SipFactory.getInstance(); 1359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Properties properties = new Properties(); 1369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan properties.setProperty("javax.sip.STACK_NAME", getStackName()); 1377f5530b2b6b0183208a3280600de5e74fc1c672cChung-yih Wang properties.setProperty( 1387f5530b2b6b0183208a3280600de5e74fc1c672cChung-yih Wang "gov.nist.javax.sip.THREAD_POOL_SIZE", THREAD_POOL_SIZE); 1399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String outboundProxy = myself.getProxyAddress(); 1409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!TextUtils.isEmpty(outboundProxy)) { 1419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.v(TAG, "outboundProxy is " + outboundProxy); 1429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan properties.setProperty("javax.sip.OUTBOUND_PROXY", outboundProxy 1439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ":" + myself.getPort() + "/" + myself.getProtocol()); 1449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipStack stack = mSipStack = sipFactory.createSipStack(properties); 1469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 1489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProvider provider = stack.createSipProvider( 1499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan stack.createListeningPoint(localIp, allocateLocalPort(), 1509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan myself.getProtocol())); 1519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan provider.addSipListener(this); 1529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper = new SipHelper(stack, provider); 1539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (InvalidArgumentException e) { 1549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new IOException(e.getMessage()); 1559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (TooManyListenersException e) { 1569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // must never happen 1579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new SipException("SipSessionGroup constructor", e); 1589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " start stack for " + myself.getUriString()); 1609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan stack.start(); 1619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallReceiverSession = null; 1639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.clear(); 1649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized void onConnectivityChanged() { 16727820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan SipSessionImpl[] ss = mSessionMap.values().toArray( 16827820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan new SipSessionImpl[mSessionMap.size()]); 16927820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan // Iterate on the copied array instead of directly on mSessionMap to 17027820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan // avoid ConcurrentModificationException being thrown when 17127820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan // SipSessionImpl removes itself from mSessionMap in onError() in the 17227820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan // following loop. 17327820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan for (SipSessionImpl s : ss) { 1749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s.onError(SipErrorCode.DATA_CONNECTION_LOST, 1759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan "data connection lost"); 1769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getLocalProfile() { 1809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile; 1819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getLocalProfileUri() { 1849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile.getUriString(); 1859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getStackName() { 1889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return "stack" + System.currentTimeMillis(); 1899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void close() { 1929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " close stack for " + mLocalProfile.getUriString()); 1930d603e36cb0d81f55bb90fc37784da3221f13920Hung-ying Tyan onConnectivityChanged(); 1949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.clear(); 1959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan closeToNotReceiveCalls(); 1969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mSipStack != null) { 1979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipStack.stop(); 1989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipStack = null; 1999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper = null; 2009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isClosed() { 2049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (mSipStack == null); 2059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // For internal use, require listener not to block in callbacks. 2089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void openToReceiveCalls(ISipSessionListener listener) { 2099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mCallReceiverSession == null) { 2109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallReceiverSession = new SipSessionCallReceiverImpl(listener); 2119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 2129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallReceiverSession.setListener(listener); 2139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void closeToNotReceiveCalls() { 2179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallReceiverSession = null; 2189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public ISipSession createSession(ISipSessionListener listener) { 2219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (isClosed() ? null : new SipSessionImpl(listener)); 2229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static int allocateLocalPort() throws SipException { 2259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 2269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan DatagramSocket s = new DatagramSocket(); 2279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int localPort = s.getLocalPort(); 2289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s.close(); 2299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return localPort; 2309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IOException e) { 2319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new SipException("allocateLocalPort()", e); 2329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 235ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan synchronized boolean containsSession(String callId) { 236ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return mSessionMap.containsKey(callId); 237ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 238ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 2399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized SipSessionImpl getSipSession(EventObject event) { 2409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = SipHelper.getCallId(event); 2419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl session = mSessionMap.get(key); 2429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((session != null) && isLoggable(session)) { 2439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "session key from event: " + key); 2449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "active sessions:"); 2459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (String k : mSessionMap.keySet()) { 2469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " ..." + k + ": " + mSessionMap.get(k)); 2479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((session != null) ? session : mCallReceiverSession); 2509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void addSipSession(SipSessionImpl newSession) { 2539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan removeSipSession(newSession); 2549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = newSession.getCallId(); 2559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.put(key, newSession); 2569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isLoggable(newSession)) { 2579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "+++ add a session with key: '" + key + "'"); 2589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (String k : mSessionMap.keySet()) { 2599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " " + k + ": " + mSessionMap.get(k)); 2609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void removeSipSession(SipSessionImpl session) { 2659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (session == mCallReceiverSession) return; 2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = session.getCallId(); 2679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl s = mSessionMap.remove(key); 2689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // sanity check 2699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((s != null) && (s != session)) { 2709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "session " + session + " is not associated with key '" 2719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + key + "'"); 2729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.put(key, s); 2739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (Map.Entry<String, SipSessionImpl> entry 2749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : mSessionMap.entrySet()) { 2759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (entry.getValue() == s) { 2769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan key = entry.getKey(); 2779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.remove(key); 2789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((s != null) && isLoggable(s)) { 2839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "remove session " + session + " @key '" + key + "'"); 2849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (String k : mSessionMap.keySet()) { 2859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " " + k + ": " + mSessionMap.get(k)); 2869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 290acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan public void processRequest(final RequestEvent event) { 291acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan if (isRequestEvent(Request.INVITE, event)) { 292acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan if (DEBUG) Log.d(TAG, "<<<<< got INVITE, thread:" 293acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan + Thread.currentThread()); 294acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan // Acquire a wake lock and keep it for WAKE_LOCK_HOLDING_TIME; 295acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan // should be large enough to bring up the app. 296acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan mWakeLock.acquire(WAKE_LOCK_HOLDING_TIME); 297acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan } 2989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 2999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processResponse(ResponseEvent event) { 3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processIOException(IOExceptionEvent event) { 3069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processTimeout(TimeoutEvent event) { 3109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processTransactionTerminated(TransactionTerminatedEvent event) { 3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processDialogTerminated(DialogTerminatedEvent event) { 3189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void process(EventObject event) { 3229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl session = getSipSession(event); 3239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean isLoggable = isLoggable(session, event); 3259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean processed = (session != null) && session.process(event); 3269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isLoggable && processed) { 3279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "new state after: " 3289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipSession.State.toString(session.mState)); 3299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable e) { 3319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "event process error: " + event, e); 3329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan session.onError(e); 3339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String extractContent(Message message) { 3379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // Currently we do not support secure MIME bodies. 3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan byte[] bytes = message.getRawContent(); 3399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (bytes != null) { 3409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (message instanceof SIPMessage) { 3429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((SIPMessage) message).getMessageContent(); 3439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 3449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new String(bytes, "UTF-8"); 3459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (UnsupportedEncodingException e) { 3479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 3509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class SipSessionCallReceiverImpl extends SipSessionImpl { 3539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipSessionCallReceiverImpl(ISipSessionListener listener) { 3549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(listener); 3559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean process(EventObject evt) throws SipException { 3589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " 3599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipSession.State.toString(mState) + ": processing " 3609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + log(evt)); 3619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isRequestEvent(Request.INVITE, evt)) { 3629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan RequestEvent event = (RequestEvent) evt; 3639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl newSession = new SipSessionImpl(mProxy); 364d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan newSession.mState = SipSession.State.INCOMING_CALL; 3659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan newSession.mServerTransaction = mSipHelper.sendRinging(event, 3669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan generateTag()); 3679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan newSession.mDialog = newSession.mServerTransaction.getDialog(); 3689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan newSession.mInviteReceived = event; 3699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan newSession.mPeerProfile = createPeerProfile(event.getRequest()); 3709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan newSession.mPeerSessionDescription = 3719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan extractContent(event.getRequest()); 3729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(newSession); 3739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRinging(newSession, newSession.mPeerProfile, 3749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan newSession.mPeerSessionDescription); 3759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 3769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.OPTIONS, evt)) { 3779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 3789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 3799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 3809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 3819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan class SipSessionImpl extends ISipSession.Stub { 3869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile mPeerProfile; 3879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 3889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int mState = SipSession.State.READY_TO_CALL; 3899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan RequestEvent mInviteReceived; 3909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Dialog mDialog; 3919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ServerTransaction mServerTransaction; 3929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ClientTransaction mClientTransaction; 3939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String mPeerSessionDescription; 3949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean mInCall; 3959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SessionTimer mTimer; 396fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan int mAuthenticationRetryCount; 397fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan 398fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan // for registration 399fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan boolean mReRegisterFlag = false; 400fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan int mRPort; 4019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // lightweight timer 4039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan class SessionTimer { 4049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mRunning = true; 4059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan void start(final int timeout) { 4079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new Thread(new Runnable() { 4089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 4099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan sleep(timeout); 4109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mRunning) timeout(); 4119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }, "SipSessionTimerThread").start(); 4139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized void cancel() { 4169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRunning = false; 4179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan this.notify(); 4189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void timeout() { 4219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipSessionGroup.this) { 4229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.TIME_OUT, "Session timed out!"); 4239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void sleep(int timeout) { 4279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 4289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan this.wait(timeout * 1000); 4299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (InterruptedException e) { 4309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "session timer interrupted!"); 4319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipSessionImpl(ISipSessionListener listener) { 4369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan setListener(listener); 4379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl duplicate() { 4409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new SipSessionImpl(mProxy.getListener()); 4419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void reset() { 4449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mInCall = false; 4459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan removeSipSession(this); 4469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerProfile = null; 4479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.READY_TO_CALL; 4489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mInviteReceived = null; 449e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan mPeerSessionDescription = null; 450fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan mRPort = 0; 451fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan mAuthenticationRetryCount = 0; 452e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan 453e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan if (mDialog != null) mDialog.delete(); 4549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = null; 455e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan 456e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan try { 457e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan if (mServerTransaction != null) mServerTransaction.terminate(); 458e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan } catch (ObjectInUseException e) { 459e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan // ignored 460e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan } 4619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction = null; 462e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan 463e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan try { 464e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan if (mClientTransaction != null) mClientTransaction.terminate(); 465e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan } catch (ObjectInUseException e) { 466e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan // ignored 467e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan } 4689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = null; 4699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelSessionTimer(); 4719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isInCall() { 4749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mInCall; 4759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getLocalIp() { 4789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalIp; 4799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getLocalProfile() { 4829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile; 4839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getPeerProfile() { 4869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mPeerProfile; 4879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getCallId() { 4909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipHelper.getCallId(getTransaction()); 4919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Transaction getTransaction() { 4949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mClientTransaction != null) return mClientTransaction; 4959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mServerTransaction != null) return mServerTransaction; 4969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 4979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 4999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public int getState() { 5009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mState; 5019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 5049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.setListener((listener instanceof SipSessionListenerProxy) 5059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? ((SipSessionListenerProxy) listener).getListener() 5069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : listener); 5079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // process the command in a new thread 5109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void doCommandAsync(final EventObject command) { 5119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new Thread(new Runnable() { 5129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 5139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processCommand(command); 515e26eb3274a65c41a6a30bdace1818c5629cca1c8Hung-ying Tyan } catch (Throwable e) { 5169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.w(TAG, "command error: " + command, e); 5179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(e); 5189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }, "SipSessionAsyncCmdThread").start(); 5219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void makeCall(SipProfile peerProfile, String sessionDescription, 5249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int timeout) { 5259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription, 5269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan timeout)); 5279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void answerCall(String sessionDescription, int timeout) { 530d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan synchronized (SipSessionGroup.this) { 531d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan if (mPeerProfile == null) return; 532d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan try { 533d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan processCommand(new MakeCallCommand(mPeerProfile, 534d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan sessionDescription, timeout)); 535d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan } catch (SipException e) { 536d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan onError(e); 537d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan } 5389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void endCall() { 5429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan doCommandAsync(END_CALL); 5439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void changeCall(String sessionDescription, int timeout) { 546d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan synchronized (SipSessionGroup.this) { 547d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan if (mPeerProfile == null) return; 548d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan doCommandAsync(new MakeCallCommand(mPeerProfile, 549d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan sessionDescription, timeout)); 550d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan } 5519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void register(int duration) { 5549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan doCommandAsync(new RegisterCommand(duration)); 5559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void unregister() { 5589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan doCommandAsync(DEREGISTER); 5599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isReRegisterRequired() { 5629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mReRegisterFlag; 5639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void clearReRegisterRequired() { 5669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mReRegisterFlag = false; 5679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void sendKeepAlive() { 5709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.PINGING; 5719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processCommand(new OptionsCommand()); 573257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan for (int i = 0; i < 15; i++) { 574257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (SipSession.State.PINGING != mState) break; 575257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan Thread.sleep(200); 576257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan } 577257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (SipSession.State.PINGING == mState) { 578257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan // FIXME: what to do if server doesn't respond 579257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan reset(); 580257c7e2b4193bff3793fcedd8b34b7fec2b1019bHung-ying Tyan if (DEBUG) Log.w(TAG, "no response from ping"); 5819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (SipException e) { 5839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "sendKeepAlive failed", e); 5849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (InterruptedException e) { 5859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.e(TAG, "sendKeepAlive interrupted", e); 5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void processCommand(EventObject command) throws SipException { 590ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan if (isLoggable(command)) Log.d(TAG, "process cmd: " + command); 5919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!process(command)) { 5929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.IN_PROGRESS, 5939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan "cannot initiate a new transaction to execute: " 5949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + command); 5959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan protected String generateTag() { 5999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // 32-bit randomness 6009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return String.valueOf((long) (Math.random() * 0x100000000L)); 6019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String toString() { 6049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 6059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String s = super.toString(); 6069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s.substring(s.indexOf("@")) + ":" 6079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipSession.State.toString(mState); 6089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable e) { 6099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return super.toString(); 6109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean process(EventObject evt) throws SipException { 6149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " 6159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipSession.State.toString(mState) + ": processing " 6169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + log(evt)); 6179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipSessionGroup.this) { 6189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isClosed()) return false; 6199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Dialog dialog = null; 6219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof RequestEvent) { 6229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan dialog = ((RequestEvent) evt).getDialog(); 6239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof ResponseEvent) { 6249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan dialog = ((ResponseEvent) evt).getDialog(); 6259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (dialog != null) mDialog = dialog; 6279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean processed; 6299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (mState) { 6319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.REGISTERING: 6329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.DEREGISTERING: 6339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = registeringToReady(evt); 6349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 6359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.PINGING: 6369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = keepAliveProcess(evt); 6379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 6389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.READY_TO_CALL: 6399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = readyForCall(evt); 6409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 6419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.INCOMING_CALL: 6429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = incomingCall(evt); 6439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 6449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.INCOMING_CALL_ANSWERING: 6459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = incomingCallToInCall(evt); 6469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 6479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL: 6489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL_RING_BACK: 6499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = outgoingCall(evt); 6509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 6519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL_CANCELING: 6529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = outgoingCallToReady(evt); 6539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 6549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.IN_CALL: 6559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = inCall(evt); 6569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 6579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 6589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = false; 6599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (processed || processExceptions(evt)); 6619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean processExceptions(EventObject evt) throws SipException { 6659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isRequestEvent(Request.BYE, evt)) { 6669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // terminate the call whenever a BYE is received 6679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 6689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 6699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 6709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.CANCEL, evt)) { 6719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, 6729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); 6739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 6749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof TransactionTerminatedEvent) { 6759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isCurrentTransaction((TransactionTerminatedEvent) evt)) { 6769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof TimeoutEvent) { 6779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processTimeout((TimeoutEvent) evt); 6789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 6799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processTransactionTerminated( 6809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (TransactionTerminatedEvent) evt); 6819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 6839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.OPTIONS, evt)) { 6859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 6869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 6879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof DialogTerminatedEvent) { 6889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processDialogTerminated((DialogTerminatedEvent) evt); 6899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 6909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 6929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void processDialogTerminated(DialogTerminatedEvent event) { 6959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mDialog == event.getDialog()) { 6969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(new SipException("dialog terminated")); 6979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 6989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "not the current dialog; current=" + mDialog 6999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ", terminated=" + event.getDialog()); 7009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean isCurrentTransaction(TransactionTerminatedEvent event) { 7049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Transaction current = event.isServerTransaction() 7059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? mServerTransaction 7069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : mClientTransaction; 7079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Transaction target = event.isServerTransaction() 7089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? event.getServerTransaction() 7099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : event.getClientTransaction(); 7109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((current != target) && (mState != SipSession.State.PINGING)) { 7129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "not the current transaction; current=" 7139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + toString(current) + ", target=" + toString(target)); 7149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 7159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (current != null) { 7169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "transaction terminated: " + toString(current)); 7179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 7189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 7199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // no transaction; shouldn't be here; ignored 7209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 7219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String toString(Transaction transaction) { 7259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (transaction == null) return "null"; 7269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Request request = transaction.getRequest(); 7279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Dialog dialog = transaction.getDialog(); 7289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan CSeqHeader cseq = (CSeqHeader) request.getHeader(CSeqHeader.NAME); 7299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return String.format("req=%s,%s,s=%s,ds=%s,", request.getMethod(), 7309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cseq.getSeqNumber(), transaction.getState(), 7319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((dialog == null) ? "-" : dialog.getState())); 7329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void processTransactionTerminated( 7359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan TransactionTerminatedEvent event) { 7369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (mState) { 7379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.IN_CALL: 7389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.READY_TO_CALL: 7399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "Transaction terminated; do nothing"); 7409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 7429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "Transaction terminated early: " + this); 7439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.TRANSACTION_TERMINTED, 7449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan "transaction terminated"); 7459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void processTimeout(TimeoutEvent event) { 7499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, "processing Timeout..."); 7509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (mState) { 7519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.REGISTERING: 7529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.DEREGISTERING: 7539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 7549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(this); 7559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.INCOMING_CALL: 7579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.INCOMING_CALL_ANSWERING: 7589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL: 7599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL_CANCELING: 7609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.TIME_OUT, event.toString()); 7619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.PINGING: 7639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 7649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mReRegisterFlag = true; 7659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 7689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Log.d(TAG, " do nothing"); 7699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int getExpiryTime(Response response) { 7749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int expires = EXPIRY_TIME; 7759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ExpiresHeader expiresHeader = (ExpiresHeader) 7769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan response.getHeader(ExpiresHeader.NAME); 7779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expiresHeader != null) expires = expiresHeader.getExpires(); 7789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan expiresHeader = (ExpiresHeader) 7799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan response.getHeader(MinExpiresHeader.NAME); 7809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expiresHeader != null) { 7819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan expires = Math.max(expires, expiresHeader.getExpires()); 7829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return expires; 7849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean keepAliveProcess(EventObject evt) throws SipException { 7879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof OptionsCommand) { 7889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.sendKeepAlive(mLocalProfile, 7899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan generateTag()); 7909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 7919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 7929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 7939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof ResponseEvent) { 7949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return parseOptionsResult(evt); 7959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 7979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean parseOptionsResult(EventObject evt) { 8009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expectResponse(Request.OPTIONS, evt)) { 8019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 8029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int rPort = getRPortFromResponse(event.getResponse()); 8039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (rPort != -1) { 8049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mRPort == 0) mRPort = rPort; 8059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mRPort != rPort) { 8069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mReRegisterFlag = true; 8079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.w(TAG, String.format( 8089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan "rport is changed: %d <> %d", mRPort, rPort)); 8099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRPort = rPort; 8109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 8119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG_PING) Log.w(TAG, "rport is the same: " + rPort); 8129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 8149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (DEBUG) Log.w(TAG, "peer did not respond rport"); 8159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 8179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 8209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int getRPortFromResponse(Response response) { 8239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ViaHeader viaHeader = (ViaHeader)(response.getHeader( 8249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.VIA)); 8259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (viaHeader == null) ? -1 : viaHeader.getRPort(); 8269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean registeringToReady(EventObject evt) 8299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 8309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expectResponse(Request.REGISTER, evt)) { 8319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 8329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 8339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 8359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (statusCode) { 8369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.OK: 8379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int state = mState; 8389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationDone((state == SipSession.State.REGISTERING) 8399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? getExpiryTime(((ResponseEvent) evt).getResponse()) 8409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : -1); 8419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.UNAUTHORIZED: 8439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.PROXY_AUTHENTICATION_REQUIRED: 844fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan handleAuthentication(event); 8459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 8479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (statusCode >= 500) { 8489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationFailed(response); 8499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 8549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean handleAuthentication(ResponseEvent event) 8579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 8589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 8599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String nonce = getNonceFromResponse(response); 860fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan if (nonce == null) { 861fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan onError(SipErrorCode.SERVER_ERROR, 862fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan "server does not provide challenge"); 8639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 864fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan } else if (mAuthenticationRetryCount < 2) { 8659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.handleChallenge( 8669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event, getAccountManager()); 8679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 868fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan mAuthenticationRetryCount++; 869fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan if (isLoggable(this, event)) { 870fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan Log.d(TAG, " authentication retry count=" 871fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan + mAuthenticationRetryCount); 872fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan } 8739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 874fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan } else { 875fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan onError(SipErrorCode.INVALID_CREDENTIALS, 876fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan "incorrect username or password"); 877fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan return false; 8789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean crossDomainAuthenticationRequired(Response response) { 8829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String realm = getRealmFromResponse(response); 8839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (realm == null) realm = ""; 8849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return !mLocalProfile.getSipDomain().trim().equals(realm.trim()); 8859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private AccountManager getAccountManager() { 8889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new AccountManager() { 8899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public UserCredentials getCredentials(ClientTransaction 8909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan challengedTransaction, String realm) { 8919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new UserCredentials() { 8929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getUserName() { 8939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile.getUserName(); 8949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getPassword() { 8979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mPassword; 8989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getSipDomain() { 9019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile.getSipDomain(); 9029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }; 9049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }; 9069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getRealmFromResponse(Response response) { 9099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader( 9109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.WWW_AUTHENTICATE); 9119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (wwwAuth != null) return wwwAuth.getRealm(); 9129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( 9139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.PROXY_AUTHENTICATE); 9149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (proxyAuth == null) ? null : proxyAuth.getRealm(); 9159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getNonceFromResponse(Response response) { 9189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader( 9199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.WWW_AUTHENTICATE); 9209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (wwwAuth != null) return wwwAuth.getNonce(); 9219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( 9229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.PROXY_AUTHENTICATE); 9239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (proxyAuth == null) ? null : proxyAuth.getNonce(); 9249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean readyForCall(EventObject evt) throws SipException { 9279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // expect MakeCallCommand, RegisterCommand, DEREGISTER 9289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof MakeCallCommand) { 929d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.OUTGOING_CALL; 9309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MakeCallCommand cmd = (MakeCallCommand) evt; 9319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerProfile = cmd.getPeerProfile(); 9329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.sendInvite(mLocalProfile, 9339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerProfile, cmd.getSessionDescription(), 9349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan generateTag()); 9359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 9369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 9379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan startSessionTimer(cmd.getTimeout()); 938e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan mProxy.onCalling(this); 9399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof RegisterCommand) { 941d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.REGISTERING; 9429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = ((RegisterCommand) evt).getDuration(); 9439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 9449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan generateTag(), duration); 9459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 9469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 9479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(this); 9489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (DEREGISTER == evt) { 950d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.DEREGISTERING; 9519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 9529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan generateTag(), 0); 9539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 9549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 9559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(this); 9569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 9599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean incomingCall(EventObject evt) throws SipException { 9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // expect MakeCallCommand(answering) , END_CALL cmd , Cancel 9639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof MakeCallCommand) { 9649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // answer call 965d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.INCOMING_CALL_ANSWERING; 9669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction = mSipHelper.sendInviteOk(mInviteReceived, 9679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalProfile, 9689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((MakeCallCommand) evt).getSessionDescription(), 9699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction); 9709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan startSessionTimer(((MakeCallCommand) evt).getTimeout()); 9719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (END_CALL == evt) { 9739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendInviteBusyHere(mInviteReceived, 9749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction); 9759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 9769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.CANCEL, evt)) { 9789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan RequestEvent event = (RequestEvent) evt; 9799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse(event, Response.OK); 9809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendInviteRequestTerminated( 9819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mInviteReceived.getRequest(), mServerTransaction); 9829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 9839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 9869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean incomingCallToInCall(EventObject evt) 9899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 9909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // expect ACK, CANCEL request 9919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isRequestEvent(Request.ACK, evt)) { 9929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan establishCall(); 9939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.CANCEL, evt)) { 9959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // http://tools.ietf.org/html/rfc3261#section-9.2 9969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // Final response has been sent; do nothing here. 9979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 10009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean outgoingCall(EventObject evt) throws SipException { 10039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expectResponse(Request.INVITE, evt)) { 10049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 10059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 10069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 10089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (statusCode) { 10099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.RINGING: 10106ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan case Response.CALL_IS_BEING_FORWARDED: 10116ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan case Response.QUEUED: 10126ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan case Response.SESSION_PROGRESS: 10136ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan // feedback any provisional responses (except TRYING) as 10146ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan // ring back for better UX 10159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mState == SipSession.State.OUTGOING_CALL) { 10169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.OUTGOING_CALL_RING_BACK; 10179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelSessionTimer(); 1018e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan mProxy.onRingingBack(this); 10199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.OK: 10229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendInviteAck(event, mDialog); 10239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerSessionDescription = extractContent(response); 10249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan establishCall(); 10259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.UNAUTHORIZED: 10279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.PROXY_AUTHENTICATION_REQUIRED: 10289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (crossDomainAuthenticationRequired(response)) { 10299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.CROSS_DOMAIN_AUTHENTICATION, 10309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan getRealmFromResponse(response)); 10319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (handleAuthentication(event)) { 10329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 10339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.REQUEST_PENDING: 10369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: 10379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // rfc3261#section-14.1; re-schedule invite 10389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 10409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (statusCode >= 400) { 10419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // error: an ack is sent automatically by the stack 10429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(response); 10439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (statusCode >= 300) { 10459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: handle 3xx (redirect) 10469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (END_CALL == evt) { 10529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // RFC says that UA should not send out cancel when no 10539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // response comes back yet. We are cheating for not checking 10549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // response. 10559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.OUTGOING_CALL_CANCELING; 1056d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mSipHelper.sendCancel(mClientTransaction); 10579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan startSessionTimer(CANCEL_CALL_TIMER); 10589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 1059ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } else if (isRequestEvent(Request.INVITE, evt)) { 1060ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan // Call self? Send BUSY HERE so server may redirect the call to 1061ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan // voice mailbox. 1062ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan RequestEvent event = (RequestEvent) evt; 1063ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan mSipHelper.sendInviteBusyHere(event, 1064ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan event.getServerTransaction()); 1065ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return true; 10669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 10689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean outgoingCallToReady(EventObject evt) 10719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 10729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof ResponseEvent) { 10739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 10749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 10759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 10769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expectResponse(Request.CANCEL, evt)) { 10779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (statusCode == Response.OK) { 10789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // do nothing; wait for REQUEST_TERMINATED 10799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (expectResponse(Request.INVITE, evt)) { 10829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (statusCode) { 10839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.OK: 10849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan outgoingCall(evt); // abort Cancel 10859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.REQUEST_TERMINATED: 10879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 10889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 10919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 10929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (statusCode >= 400) { 10959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(response); 10969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof TransactionTerminatedEvent) { 10999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // rfc3261#section-14.1: 11009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // if re-invite gets timed out, terminate the dialog; but 11019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // re-invite is not reliable, just let it go and pretend 11029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // nothing happened. 11039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(new SipException("timed out")); 11049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 11069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean inCall(EventObject evt) throws SipException { 11099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // expect END_CALL cmd, BYE request, hold call (MakeCallCommand) 11109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // OK retransmission is handled in SipStack 11119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (END_CALL == evt) { 11129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // rfc3261#section-15.1.1 11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendBye(mDialog); 11149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 11159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.INVITE, evt)) { 11179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // got Re-INVITE 11189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.INCOMING_CALL; 1119d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan RequestEvent event = mInviteReceived = (RequestEvent) evt; 11209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerSessionDescription = extractContent(event.getRequest()); 11219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction = null; 11229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription); 11239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.BYE, evt)) { 11259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 11269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 11279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof MakeCallCommand) { 11299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // to change call 1130d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.OUTGOING_CALL; 11319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.sendReinvite(mDialog, 11329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((MakeCallCommand) evt).getSessionDescription()); 11339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan startSessionTimer(((MakeCallCommand) evt).getTimeout()); 11349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 11379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // timeout in seconds 11409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void startSessionTimer(int timeout) { 11419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (timeout > 0) { 11429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer = new SessionTimer(); 11439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.start(timeout); 11449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void cancelSessionTimer() { 11489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mTimer != null) { 11499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer.cancel(); 11509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimer = null; 11519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String createErrorMessage(Response response) { 11553b9456929376a047ef38b5ddb27fed9b11664306Hung-ying Tyan return String.format("%s (%d)", response.getReasonPhrase(), 11563b9456929376a047ef38b5ddb27fed9b11664306Hung-ying Tyan response.getStatusCode()); 11579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void establishCall() { 11609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.IN_CALL; 11619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mInCall = true; 11629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelSessionTimer(); 11639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onCallEstablished(this, mPeerSessionDescription); 11649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void endCallNormally() { 11679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 11689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onCallEnded(this); 11699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void endCallOnError(int errorCode, String message) { 11729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 11739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onError(this, errorCode, message); 11749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void endCallOnBusy() { 11779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 11789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onCallBusy(this); 11799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onError(int errorCode, String message) { 11829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelSessionTimer(); 11839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (mState) { 11849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.REGISTERING: 11859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.DEREGISTERING: 11869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationFailed(errorCode, message); 11879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 11889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 1189bddf530f0bbd2917d98c3fd0f11920c2b2473154Hung-ying Tyan endCallOnError(errorCode, message); 11909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onError(Throwable exception) { 11959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan exception = getRootCause(exception); 11969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(getErrorCode(exception), exception.toString()); 11979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onError(Response response) { 12009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 12019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mInCall && (statusCode == Response.BUSY_HERE)) { 12029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallOnBusy(); 12039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(getErrorCode(statusCode), createErrorMessage(response)); 12059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int getErrorCode(int responseStatusCode) { 12099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (responseStatusCode) { 12109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.TEMPORARILY_UNAVAILABLE: 12119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.FORBIDDEN: 12129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.GONE: 12139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.NOT_FOUND: 12149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.NOT_ACCEPTABLE: 12159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.NOT_ACCEPTABLE_HERE: 12169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.PEER_NOT_REACHABLE; 12179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.REQUEST_URI_TOO_LONG: 12199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.ADDRESS_INCOMPLETE: 12209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.AMBIGUOUS: 12219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.INVALID_REMOTE_URI; 12229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.REQUEST_TIMEOUT: 12249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.TIME_OUT; 12259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 12279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (responseStatusCode < 500) { 12289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 12299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.SERVER_ERROR; 12319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Throwable getRootCause(Throwable exception) { 12369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Throwable cause = exception.getCause(); 12379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan while (cause != null) { 12389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan exception = cause; 12399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cause = exception.getCause(); 12409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return exception; 12429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int getErrorCode(Throwable exception) { 12459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message = exception.getMessage(); 12469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (exception instanceof UnknownHostException) { 1247e26eb3274a65c41a6a30bdace1818c5629cca1c8Hung-ying Tyan return SipErrorCode.SERVER_UNREACHABLE; 12489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (exception instanceof IOException) { 12499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.SOCKET_ERROR; 12509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 12529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onRegistrationDone(int duration) { 12569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 12579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(this, duration); 12589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onRegistrationFailed(int errorCode, String message) { 12619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 12629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationFailed(this, errorCode, message); 12639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onRegistrationFailed(Throwable exception) { 12669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan exception = getRootCause(exception); 12679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationFailed(getErrorCode(exception), 12689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan exception.toString()); 12699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onRegistrationFailed(Response response) { 12729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 12739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationFailed(getErrorCode(statusCode), 12749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan createErrorMessage(response)); 12759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 12799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @return true if the event is a request event matching the specified 12809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * method; false otherwise 12819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 12829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean isRequestEvent(String method, EventObject event) { 12839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 12849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (event instanceof RequestEvent) { 12859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan RequestEvent requestEvent = (RequestEvent) event; 12869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return method.equals(requestEvent.getRequest().getMethod()); 12879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable e) { 12899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 12919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static String getCseqMethod(Message message) { 12949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((CSeqHeader) message.getHeader(CSeqHeader.NAME)).getMethod(); 12959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 12989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @return true if the event is a response event and the CSeqHeader method 12999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * match the given arguments; false otherwise 13009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 13019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean expectResponse( 13029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String expectedMethod, EventObject evt) { 13039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof ResponseEvent) { 13049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 13059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 13069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 13079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 13099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 13129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @return true if the event is a response event and the response code and 13139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * CSeqHeader method match the given arguments; false otherwise 13149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 13159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean expectResponse( 13169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int responseCode, String expectedMethod, EventObject evt) { 13179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof ResponseEvent) { 13189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 13199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 13209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (response.getStatusCode() == responseCode) { 13219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 13229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 13259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static SipProfile createPeerProfile(Request request) 13289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 13299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 13309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan FromHeader fromHeader = 13319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (FromHeader) request.getHeader(FromHeader.NAME); 13329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Address address = fromHeader.getAddress(); 13339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipURI uri = (SipURI) address.getURI(); 13349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String username = uri.getUser(); 13359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (username == null) username = ANONYMOUS; 13369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new SipProfile.Builder(username, uri.getHost()) 13379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan .setPort(uri.getPort()) 13389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan .setDisplayName(address.getDisplayName()) 13399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan .build(); 13409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IllegalArgumentException e) { 13419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new SipException("createPeerProfile()", e); 13429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (ParseException e) { 13439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new SipException("createPeerProfile()", e); 13449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean isLoggable(SipSessionImpl s) { 13489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (s != null) { 13499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (s.mState) { 13509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.PINGING: 13519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return DEBUG_PING; 13529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return DEBUG; 13559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1357ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan private static boolean isLoggable(EventObject evt) { 1358ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return isLoggable(null, evt); 1359ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 1360ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 13619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean isLoggable(SipSessionImpl s, EventObject evt) { 13629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!isLoggable(s)) return false; 13639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt == null) return false; 13649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof OptionsCommand) { 13669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return DEBUG_PING; 13679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof ResponseEvent) { 13689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = ((ResponseEvent) evt).getResponse(); 13699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (Request.OPTIONS.equals(response.getHeader(CSeqHeader.NAME))) { 13709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return DEBUG_PING; 13719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return DEBUG; 13739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof RequestEvent) { 13749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return DEBUG; 13759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 13779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static String log(EventObject evt) { 13809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof RequestEvent) { 13819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((RequestEvent) evt).getRequest().toString(); 13829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof ResponseEvent) { 13839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((ResponseEvent) evt).getResponse().toString(); 13849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 13859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return evt.toString(); 13869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class OptionsCommand extends EventObject { 13909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public OptionsCommand() { 13919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(SipSessionGroup.this); 13929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class RegisterCommand extends EventObject { 13969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mDuration; 13979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public RegisterCommand(int duration) { 13999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(SipSessionGroup.this); 14009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDuration = duration; 14019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public int getDuration() { 14049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mDuration; 14059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class MakeCallCommand extends EventObject { 14099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mSessionDescription; 14109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mTimeout; // in seconds 14119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public MakeCallCommand(SipProfile peerProfile, 14139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String sessionDescription) { 14149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan this(peerProfile, sessionDescription, -1); 14159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public MakeCallCommand(SipProfile peerProfile, 14189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String sessionDescription, int timeout) { 14199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(peerProfile); 14209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionDescription = sessionDescription; 14219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimeout = timeout; 14229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getPeerProfile() { 14259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (SipProfile) getSource(); 14269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getSessionDescription() { 14299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSessionDescription; 14309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public int getTimeout() { 14339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mTimeout; 14349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan} 1437