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.ProxyAuthenticate; 22f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo syncimport gov.nist.javax.sip.header.ReferTo; 23f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo syncimport gov.nist.javax.sip.header.SIPHeaderNames; 24f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo syncimport gov.nist.javax.sip.header.StatusLine; 259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport gov.nist.javax.sip.header.WWWAuthenticate; 2622ecc3df834674605daf86f7edf20169b6ca800brepo syncimport gov.nist.javax.sip.header.extensions.ReferredByHeader; 2722ecc3df834674605daf86f7edf20169b6ca800brepo syncimport gov.nist.javax.sip.header.extensions.ReplacesHeader; 289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport gov.nist.javax.sip.message.SIPMessage; 29f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo syncimport gov.nist.javax.sip.message.SIPResponse; 309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSession; 329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.ISipSessionListener; 339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipErrorCode; 349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipProfile; 359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.net.sip.SipSession; 368a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyanimport android.net.sip.SipSessionAdapter; 379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport android.text.TextUtils; 389329db04f13480ccdff013dcc00cdb96f12a921cWink Savilleimport android.telephony.Rlog; 399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.IOException; 419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.io.UnsupportedEncodingException; 429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.DatagramSocket; 431b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yehimport java.net.InetAddress; 449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.net.UnknownHostException; 459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.text.ParseException; 469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.EventObject; 479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.HashMap; 489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Map; 499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport java.util.Properties; 509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.ClientTransaction; 529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.Dialog; 539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.DialogTerminatedEvent; 549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.IOExceptionEvent; 55e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyanimport javax.sip.ObjectInUseException; 569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.RequestEvent; 579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.ResponseEvent; 589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.ServerTransaction; 599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipException; 609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipFactory; 619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipListener; 629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipProvider; 639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.SipStack; 649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.TimeoutEvent; 659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.Transaction; 669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.TransactionTerminatedEvent; 679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.address.Address; 689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.address.SipURI; 699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.CSeqHeader; 705e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yehimport javax.sip.header.ContactHeader; 719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.ExpiresHeader; 729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.FromHeader; 73f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo syncimport javax.sip.header.HeaderAddress; 749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.MinExpiresHeader; 75f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo syncimport javax.sip.header.ReferToHeader; 769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.header.ViaHeader; 779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.message.Message; 789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.message.Request; 799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanimport javax.sip.message.Response; 809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 81f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync 829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan/** 839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * Manages {@link ISipSession}'s for a SIP account. 849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyanclass SipSessionGroup implements SipListener { 869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String TAG = "SipSession"; 879329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final boolean DBG = false; 889329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final boolean DBG_PING = false; 899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final String ANONYMOUS = "anonymous"; 90b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang // Limit the size of thread pool to 1 for the order issue when the phone is 91b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang // waken up from sleep and there are many packets to be processed in the SIP 92b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang // stack. Note: The default thread pool size in NIST SIP stack is -1 which is 93b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang // unlimited. 94b891d6f795fd5ba90455f8071b03404ff0a5b1aaChung-yih Wang private static final String THREAD_POOL_SIZE = "1"; 959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int EXPIRY_TIME = 3600; // in seconds 969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final int CANCEL_CALL_TIMER = 3; // in seconds 97ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan private static final int END_CALL_TIMER = 3; // in seconds 9837f93394fe5c7cfede3a780214fa99a9e2a69133Chia-chi Yeh private static final int KEEPALIVE_TIMEOUT = 5; // in seconds 990f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan private static final int INCALL_KEEPALIVE_INTERVAL = 10; // in seconds 100acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan private static final long WAKE_LOCK_HOLDING_TIME = 500; // in milliseconds 1019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final EventObject DEREGISTER = new EventObject("Deregister"); 1039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static final EventObject END_CALL = new EventObject("End call"); 1049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private final SipProfile mLocalProfile; 1069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private final String mPassword; 1079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipStack mSipStack; 1099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipHelper mSipHelper; 1109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // session that processes INVITE requests 1129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private SipSessionImpl mCallReceiverSession; 1139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mLocalIp; 1149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1158a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private SipWakeupTimer mWakeupTimer; 116acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan private SipWakeLock mWakeLock; 117acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan 1189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // call-id-to-SipSession map 1199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Map<String, SipSessionImpl> mSessionMap = 1209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new HashMap<String, SipSessionImpl>(); 1219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1223efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan // external address observed from any response 1233efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan private String mExternalIp; 1243efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan private int mExternalPort; 1253efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan 1269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 1271b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh * @param profile the local profile with password crossed out 1289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @param password the password of the profile 1299329db04f13480ccdff013dcc00cdb96f12a921cWink Saville * @throws SipException if cannot assign requested address 1309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 1311b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh public SipSessionGroup(SipProfile profile, String password, 1321b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh SipWakeupTimer timer, SipWakeLock wakeLock) throws SipException { 1331b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh mLocalProfile = profile; 1349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPassword = password; 1358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mWakeupTimer = timer; 136acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan mWakeLock = wakeLock; 1371b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh reset(); 1389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 1399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // TODO: remove this method once SipWakeupTimer can better handle variety 1418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // of timeout values 1428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan void setWakeupTimer(SipWakeupTimer timer) { 1438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mWakeupTimer = timer; 1448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 1458a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 1461b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh synchronized void reset() throws SipException { 1479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Properties properties = new Properties(); 1481b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh 1491b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh String protocol = mLocalProfile.getProtocol(); 1501b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh int port = mLocalProfile.getPort(); 1511b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh String server = mLocalProfile.getProxyAddress(); 1521b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh 1531b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh if (!TextUtils.isEmpty(server)) { 1541b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh properties.setProperty("javax.sip.OUTBOUND_PROXY", 1551b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh server + ':' + port + '/' + protocol); 1561b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } else { 1571b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh server = mLocalProfile.getSipDomain(); 1581b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } 1591b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh if (server.startsWith("[") && server.endsWith("]")) { 1601b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh server = server.substring(1, server.length() - 1); 1611b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } 1621b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh 1631b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh String local = null; 1641b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh try { 1651b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh for (InetAddress remote : InetAddress.getAllByName(server)) { 1661b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh DatagramSocket socket = new DatagramSocket(); 1671b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh socket.connect(remote, port); 1681b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh if (socket.isConnected()) { 1691b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh local = socket.getLocalAddress().getHostAddress(); 1701b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh port = socket.getLocalPort(); 1711b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh socket.close(); 1721b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh break; 1731b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } 1741b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh socket.close(); 1751b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } 1761b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } catch (Exception e) { 1771b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh // ignore. 1781b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } 1791b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh if (local == null) { 1801b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh // We are unable to reach the server. Just bail out. 1811b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh return; 1821b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } 1831b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh 1841b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh close(); 1851b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh mLocalIp = local; 1861b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh 1879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan properties.setProperty("javax.sip.STACK_NAME", getStackName()); 1887f5530b2b6b0183208a3280600de5e74fc1c672cChung-yih Wang properties.setProperty( 1897f5530b2b6b0183208a3280600de5e74fc1c672cChung-yih Wang "gov.nist.javax.sip.THREAD_POOL_SIZE", THREAD_POOL_SIZE); 1901b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh mSipStack = SipFactory.getInstance().createSipStack(properties); 1919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 1921b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh SipProvider provider = mSipStack.createSipProvider( 1931b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh mSipStack.createListeningPoint(local, port, protocol)); 1949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan provider.addSipListener(this); 1951b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh mSipHelper = new SipHelper(mSipStack, provider); 1961b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } catch (SipException e) { 1971b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh throw e; 1981b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh } catch (Exception e) { 1991b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh throw new SipException("failed to initialize SIP stack", e); 2009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2013efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan 2029329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("reset: start stack for " + mLocalProfile.getUriString()); 2031b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh mSipStack.start(); 2049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized void onConnectivityChanged() { 20727820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan SipSessionImpl[] ss = mSessionMap.values().toArray( 20827820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan new SipSessionImpl[mSessionMap.size()]); 20927820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan // Iterate on the copied array instead of directly on mSessionMap to 21027820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan // avoid ConcurrentModificationException being thrown when 21127820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan // SipSessionImpl removes itself from mSessionMap in onError() in the 21227820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan // following loop. 21327820a94e73622f647daf8678180abc541d3a092Hung-ying Tyan for (SipSessionImpl s : ss) { 2149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan s.onError(SipErrorCode.DATA_CONNECTION_LOST, 2159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan "data connection lost"); 2169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2193efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan synchronized void resetExternalAddress() { 2209329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) { 2219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("resetExternalAddress: " + mSipStack); 22285caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh } 2233efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan mExternalIp = null; 2243efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan mExternalPort = 0; 2253efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan } 2263efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan 2279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getLocalProfile() { 2289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile; 2299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getLocalProfileUri() { 2329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile.getUriString(); 2339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getStackName() { 2369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return "stack" + System.currentTimeMillis(); 2379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void close() { 2409329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("close: " + mLocalProfile.getUriString()); 2410d603e36cb0d81f55bb90fc37784da3221f13920Hung-ying Tyan onConnectivityChanged(); 2429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.clear(); 2439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan closeToNotReceiveCalls(); 2449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mSipStack != null) { 2459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipStack.stop(); 2469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipStack = null; 2479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper = null; 2489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2491b5111f16c1401437d577dfd547af10aa691d44fChia-chi Yeh resetExternalAddress(); 2509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized boolean isClosed() { 2539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (mSipStack == null); 2549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // For internal use, require listener not to block in callbacks. 2579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void openToReceiveCalls(ISipSessionListener listener) { 2589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mCallReceiverSession == null) { 2599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallReceiverSession = new SipSessionCallReceiverImpl(listener); 2609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 2619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallReceiverSession.setListener(listener); 2629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public synchronized void closeToNotReceiveCalls() { 2669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mCallReceiverSession = null; 2679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public ISipSession createSession(ISipSessionListener listener) { 2709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (isClosed() ? null : new SipSessionImpl(listener)); 2719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 273ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan synchronized boolean containsSession(String callId) { 274ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return mSessionMap.containsKey(callId); 275ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 276ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 2779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized SipSessionImpl getSipSession(EventObject event) { 2789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = SipHelper.getCallId(event); 2799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl session = mSessionMap.get(key); 2809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((session != null) && isLoggable(session)) { 2819329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("getSipSession: event=" + key); 2829329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("getSipSession: active sessions:"); 2839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (String k : mSessionMap.keySet()) { 2849329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("getSipSession: ..." + k + ": " + mSessionMap.get(k)); 2859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((session != null) ? session : mCallReceiverSession); 2889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 2909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void addSipSession(SipSessionImpl newSession) { 2919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan removeSipSession(newSession); 2929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = newSession.getCallId(); 2939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.put(key, newSession); 2949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isLoggable(newSession)) { 2959329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("addSipSession: key='" + key + "'"); 2969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (String k : mSessionMap.keySet()) { 2979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("addSipSession: " + k + ": " + mSessionMap.get(k)); 2989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 2999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void removeSipSession(SipSessionImpl session) { 3039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (session == mCallReceiverSession) return; 3049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String key = session.getCallId(); 3059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl s = mSessionMap.remove(key); 3069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // sanity check 3079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((s != null) && (s != session)) { 3089329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("removeSession: " + session + " is not associated with key '" 3099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + key + "'"); 3109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.put(key, s); 3119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (Map.Entry<String, SipSessionImpl> entry 3129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : mSessionMap.entrySet()) { 3139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (entry.getValue() == s) { 3149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan key = entry.getKey(); 3159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionMap.remove(key); 3169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((s != null) && isLoggable(s)) { 3219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("removeSession: " + session + " @key '" + key + "'"); 3229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan for (String k : mSessionMap.keySet()) { 3239329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("removeSession: " + k + ": " + mSessionMap.get(k)); 3249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3289329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 329acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan public void processRequest(final RequestEvent event) { 330acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan if (isRequestEvent(Request.INVITE, event)) { 3319329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("processRequest: mWakeLock.acquire got INVITE, thread:" 332acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan + Thread.currentThread()); 333acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan // Acquire a wake lock and keep it for WAKE_LOCK_HOLDING_TIME; 334acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan // should be large enough to bring up the app. 335acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan mWakeLock.acquire(WAKE_LOCK_HOLDING_TIME); 336acedadc1967457ac2f8981c67f884fd8c0ee853cHung-ying Tyan } 3379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3409329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 3419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processResponse(ResponseEvent event) { 3429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 3469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processIOException(IOExceptionEvent event) { 3479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3509329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 3519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processTimeout(TimeoutEvent event) { 3529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3559329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 3569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processTransactionTerminated(TransactionTerminatedEvent event) { 3579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 3619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void processDialogTerminated(DialogTerminatedEvent event) { 3629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan process(event); 3639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void process(EventObject event) { 3669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl session = getSipSession(event); 3679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean isLoggable = isLoggable(session, event); 3699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean processed = (session != null) && session.process(event); 3709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isLoggable && processed) { 3719329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("process: event new state after: " 3729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipSession.State.toString(session.mState)); 3739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable e) { 3759329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("process: error event=" + event, getRootCause(e)); 3769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan session.onError(e); 3779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String extractContent(Message message) { 3819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // Currently we do not support secure MIME bodies. 3829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan byte[] bytes = message.getRawContent(); 3839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (bytes != null) { 3849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 3859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (message instanceof SIPMessage) { 3869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((SIPMessage) message).getMessageContent(); 3879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 3889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new String(bytes, "UTF-8"); 3899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (UnsupportedEncodingException e) { 3919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 3949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 3959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 3963efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan private void extractExternalAddress(ResponseEvent evt) { 3973efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan Response response = evt.getResponse(); 3983efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan ViaHeader viaHeader = (ViaHeader)(response.getHeader( 3993efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan SIPHeaderNames.VIA)); 4003efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan if (viaHeader == null) return; 4013efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan int rport = viaHeader.getRPort(); 4023efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan String externalIp = viaHeader.getReceived(); 4033efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan if ((rport > 0) && (externalIp != null)) { 4043efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan mExternalIp = externalIp; 4053efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan mExternalPort = rport; 4069329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) { 4079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("extractExternalAddress: external addr " + externalIp + ":" + rport 40885caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh + " on " + mSipStack); 40985caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh } 41085caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh } 41185caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh } 41285caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh 41385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh private Throwable getRootCause(Throwable exception) { 41485caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh Throwable cause = exception.getCause(); 41585caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh while (cause != null) { 41685caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh exception = cause; 41785caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh cause = exception.getCause(); 4183efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan } 41985caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh return exception; 4203efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan } 4213efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan 422f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync private SipSessionImpl createNewSession(RequestEvent event, 423f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync ISipSessionListener listener, ServerTransaction transaction, 424f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync int newState) throws SipException { 425f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync SipSessionImpl newSession = new SipSessionImpl(listener); 426f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mServerTransaction = transaction; 427f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mState = newState; 428f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mDialog = newSession.mServerTransaction.getDialog(); 429f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mInviteReceived = event; 430f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mPeerProfile = createPeerProfile((HeaderAddress) 431f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync event.getRequest().getHeader(FromHeader.NAME)); 432f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mPeerSessionDescription = 433f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync extractContent(event.getRequest()); 434f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync return newSession; 435f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 436f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync 4379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class SipSessionCallReceiverImpl extends SipSessionImpl { 4389329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final String SSCRI_TAG = "SipSessionCallReceiverImpl"; 4399329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final boolean SSCRI_DBG = true; 4409329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 4419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipSessionCallReceiverImpl(ISipSessionListener listener) { 4429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(listener); 4439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 4449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 44522ecc3df834674605daf86f7edf20169b6ca800brepo sync private int processInviteWithReplaces(RequestEvent event, 44622ecc3df834674605daf86f7edf20169b6ca800brepo sync ReplacesHeader replaces) { 44722ecc3df834674605daf86f7edf20169b6ca800brepo sync String callId = replaces.getCallId(); 44822ecc3df834674605daf86f7edf20169b6ca800brepo sync SipSessionImpl session = mSessionMap.get(callId); 44922ecc3df834674605daf86f7edf20169b6ca800brepo sync if (session == null) { 45022ecc3df834674605daf86f7edf20169b6ca800brepo sync return Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST; 45122ecc3df834674605daf86f7edf20169b6ca800brepo sync } 45222ecc3df834674605daf86f7edf20169b6ca800brepo sync 45322ecc3df834674605daf86f7edf20169b6ca800brepo sync Dialog dialog = session.mDialog; 45422ecc3df834674605daf86f7edf20169b6ca800brepo sync if (dialog == null) return Response.DECLINE; 45522ecc3df834674605daf86f7edf20169b6ca800brepo sync 45622ecc3df834674605daf86f7edf20169b6ca800brepo sync if (!dialog.getLocalTag().equals(replaces.getToTag()) || 45722ecc3df834674605daf86f7edf20169b6ca800brepo sync !dialog.getRemoteTag().equals(replaces.getFromTag())) { 45822ecc3df834674605daf86f7edf20169b6ca800brepo sync // No match is found, returns 481. 45922ecc3df834674605daf86f7edf20169b6ca800brepo sync return Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST; 46022ecc3df834674605daf86f7edf20169b6ca800brepo sync } 46122ecc3df834674605daf86f7edf20169b6ca800brepo sync 46222ecc3df834674605daf86f7edf20169b6ca800brepo sync ReferredByHeader referredBy = (ReferredByHeader) event.getRequest() 46322ecc3df834674605daf86f7edf20169b6ca800brepo sync .getHeader(ReferredByHeader.NAME); 46422ecc3df834674605daf86f7edf20169b6ca800brepo sync if ((referredBy == null) || 46522ecc3df834674605daf86f7edf20169b6ca800brepo sync !dialog.getRemoteParty().equals(referredBy.getAddress())) { 46622ecc3df834674605daf86f7edf20169b6ca800brepo sync return Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST; 46722ecc3df834674605daf86f7edf20169b6ca800brepo sync } 46822ecc3df834674605daf86f7edf20169b6ca800brepo sync return Response.OK; 46922ecc3df834674605daf86f7edf20169b6ca800brepo sync } 47022ecc3df834674605daf86f7edf20169b6ca800brepo sync 47122ecc3df834674605daf86f7edf20169b6ca800brepo sync private void processNewInviteRequest(RequestEvent event) 47222ecc3df834674605daf86f7edf20169b6ca800brepo sync throws SipException { 47322ecc3df834674605daf86f7edf20169b6ca800brepo sync ReplacesHeader replaces = (ReplacesHeader) event.getRequest() 47422ecc3df834674605daf86f7edf20169b6ca800brepo sync .getHeader(ReplacesHeader.NAME); 47522ecc3df834674605daf86f7edf20169b6ca800brepo sync SipSessionImpl newSession = null; 47622ecc3df834674605daf86f7edf20169b6ca800brepo sync if (replaces != null) { 47722ecc3df834674605daf86f7edf20169b6ca800brepo sync int response = processInviteWithReplaces(event, replaces); 4789329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSCRI_DBG) { 4799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("processNewInviteRequest: " + replaces 48022ecc3df834674605daf86f7edf20169b6ca800brepo sync + " response=" + response); 48122ecc3df834674605daf86f7edf20169b6ca800brepo sync } 48222ecc3df834674605daf86f7edf20169b6ca800brepo sync if (response == Response.OK) { 48322ecc3df834674605daf86f7edf20169b6ca800brepo sync SipSessionImpl replacedSession = 48422ecc3df834674605daf86f7edf20169b6ca800brepo sync mSessionMap.get(replaces.getCallId()); 48522ecc3df834674605daf86f7edf20169b6ca800brepo sync // got INVITE w/ replaces request. 48622ecc3df834674605daf86f7edf20169b6ca800brepo sync newSession = createNewSession(event, 48722ecc3df834674605daf86f7edf20169b6ca800brepo sync replacedSession.mProxy.getListener(), 488f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mSipHelper.getServerTransaction(event), 489f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync SipSession.State.INCOMING_CALL); 49022ecc3df834674605daf86f7edf20169b6ca800brepo sync newSession.mProxy.onCallTransferring(newSession, 49122ecc3df834674605daf86f7edf20169b6ca800brepo sync newSession.mPeerSessionDescription); 49222ecc3df834674605daf86f7edf20169b6ca800brepo sync } else { 49322ecc3df834674605daf86f7edf20169b6ca800brepo sync mSipHelper.sendResponse(event, response); 49422ecc3df834674605daf86f7edf20169b6ca800brepo sync } 49522ecc3df834674605daf86f7edf20169b6ca800brepo sync } else { 49622ecc3df834674605daf86f7edf20169b6ca800brepo sync // New Incoming call. 49722ecc3df834674605daf86f7edf20169b6ca800brepo sync newSession = createNewSession(event, mProxy, 498f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mSipHelper.sendRinging(event, generateTag()), 499f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync SipSession.State.INCOMING_CALL); 50022ecc3df834674605daf86f7edf20169b6ca800brepo sync mProxy.onRinging(newSession, newSession.mPeerProfile, 50122ecc3df834674605daf86f7edf20169b6ca800brepo sync newSession.mPeerSessionDescription); 50222ecc3df834674605daf86f7edf20169b6ca800brepo sync } 50322ecc3df834674605daf86f7edf20169b6ca800brepo sync if (newSession != null) addSipSession(newSession); 50422ecc3df834674605daf86f7edf20169b6ca800brepo sync } 50522ecc3df834674605daf86f7edf20169b6ca800brepo sync 5069329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 5079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean process(EventObject evt) throws SipException { 5089329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (isLoggable(this, evt)) log("process: " + this + ": " 5099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipSession.State.toString(mState) + ": processing " 5109329db04f13480ccdff013dcc00cdb96f12a921cWink Saville + logEvt(evt)); 5119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isRequestEvent(Request.INVITE, evt)) { 51222ecc3df834674605daf86f7edf20169b6ca800brepo sync processNewInviteRequest((RequestEvent) evt); 5139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 5149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.OPTIONS, evt)) { 5159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 5169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 5179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 5189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 5199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 5229329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void log(String s) { 5239329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.d(SSCRI_TAG, s); 5249329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 5259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan static interface KeepAliveProcessCallback { 5288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan /** Invoked when the response of keeping alive comes back. */ 5298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan void onResponse(boolean portChanged); 5308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan void onError(int errorCode, String description); 5318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 5328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 5339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan class SipSessionImpl extends ISipSession.Stub { 5349329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final String SSI_TAG = "SipSessionImpl"; 5359329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final boolean SSI_DBG = true; 5369329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 5379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipProfile mPeerProfile; 5389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 5399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int mState = SipSession.State.READY_TO_CALL; 5409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan RequestEvent mInviteReceived; 5419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Dialog mDialog; 5429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ServerTransaction mServerTransaction; 5439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ClientTransaction mClientTransaction; 5449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String mPeerSessionDescription; 5459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean mInCall; 5468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan SessionTimer mSessionTimer; 547fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan int mAuthenticationRetryCount; 548fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan 5499329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private SipKeepAlive mSipKeepAlive; 5509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5519329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private SipSessionImpl mSipSessionImpl; 5520f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan 553f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync // the following three members are used for handling refer request. 554f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync SipSessionImpl mReferSession; 555f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync ReferredByHeader mReferredBy; 556f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync String mReplaces; 557f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync 5589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // lightweight timer 5599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan class SessionTimer { 5609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean mRunning = true; 5619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan void start(final int timeout) { 5639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new Thread(new Runnable() { 5649329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 5659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 5669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan sleep(timeout); 5679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mRunning) timeout(); 5689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }, "SipSessionTimerThread").start(); 5709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized void cancel() { 5739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mRunning = false; 5749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan this.notify(); 5759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void timeout() { 5789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipSessionGroup.this) { 5799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.TIME_OUT, "Session timed out!"); 5809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private synchronized void sleep(int timeout) { 5849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 5859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan this.wait(timeout * 1000); 5869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (InterruptedException e) { 5879329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("session timer interrupted!", e); 5889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipSessionImpl(ISipSessionListener listener) { 5939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan setListener(listener); 5949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 5969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipSessionImpl duplicate() { 5979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new SipSessionImpl(mProxy.getListener()); 5989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 5999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void reset() { 6019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mInCall = false; 6029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan removeSipSession(this); 6039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerProfile = null; 6049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.READY_TO_CALL; 6059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mInviteReceived = null; 606e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan mPeerSessionDescription = null; 607fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan mAuthenticationRetryCount = 0; 608f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mReferSession = null; 609f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mReferredBy = null; 610f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mReplaces = null; 611e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan 612e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan if (mDialog != null) mDialog.delete(); 6139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = null; 614e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan 615e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan try { 616e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan if (mServerTransaction != null) mServerTransaction.terminate(); 617e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan } catch (ObjectInUseException e) { 618e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan // ignored 619e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan } 6209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction = null; 621e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan 622e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan try { 623e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan if (mClientTransaction != null) mClientTransaction.terminate(); 624e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan } catch (ObjectInUseException e) { 625e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan // ignored 626e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan } 6279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = null; 6289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelSessionTimer(); 6300f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan 6319329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (mSipSessionImpl != null) { 6329329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipSessionImpl.stopKeepAliveProcess(); 6339329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipSessionImpl = null; 6340f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan } 6359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6379329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean isInCall() { 6399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mInCall; 6409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6429329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getLocalIp() { 6449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalIp; 6459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6479329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getLocalProfile() { 6499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile; 6509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6529329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getPeerProfile() { 6549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mPeerProfile; 6559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6579329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getCallId() { 6599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipHelper.getCallId(getTransaction()); 6609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private Transaction getTransaction() { 6639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mClientTransaction != null) return mClientTransaction; 6649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mServerTransaction != null) return mServerTransaction; 6659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return null; 6669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public int getState() { 6709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mState; 6719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6739329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void setListener(ISipSessionListener listener) { 6759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.setListener((listener instanceof SipSessionListenerProxy) 6769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? ((SipSessionListenerProxy) listener).getListener() 6779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : listener); 6789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // process the command in a new thread 6819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void doCommandAsync(final EventObject command) { 6829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan new Thread(new Runnable() { 6839329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void run() { 6859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 6869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processCommand(command); 687e26eb3274a65c41a6a30bdace1818c5629cca1c8Hung-ying Tyan } catch (Throwable e) { 6889329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("command error: " + command + ": " 6898a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + mLocalProfile.getUriString(), 6908a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan getRootCause(e)); 6919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(e); 6929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }, "SipSessionAsyncCmdThread").start(); 6959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 6969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 6979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 6989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void makeCall(SipProfile peerProfile, String sessionDescription, 6999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int timeout) { 7009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription, 7019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan timeout)); 7029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7049329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 7059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void answerCall(String sessionDescription, int timeout) { 706d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan synchronized (SipSessionGroup.this) { 707d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan if (mPeerProfile == null) return; 708aef08f1dd08902d0260dec34b2feede626d1bdc6repo sync doCommandAsync(new MakeCallCommand(mPeerProfile, 709aef08f1dd08902d0260dec34b2feede626d1bdc6repo sync sessionDescription, timeout)); 7109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7139329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 7149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void endCall() { 7159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan doCommandAsync(END_CALL); 7169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7189329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 7199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void changeCall(String sessionDescription, int timeout) { 720d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan synchronized (SipSessionGroup.this) { 721d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan if (mPeerProfile == null) return; 722d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan doCommandAsync(new MakeCallCommand(mPeerProfile, 723d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan sessionDescription, timeout)); 724d47a47a131a8e7f80b934aec4cc7a10fd9fe1094Hung-ying Tyan } 7259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7279329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 7289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void register(int duration) { 7299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan doCommandAsync(new RegisterCommand(duration)); 7309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7329329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 7339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public void unregister() { 7349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan doCommandAsync(DEREGISTER); 7359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void processCommand(EventObject command) throws SipException { 7389329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (isLoggable(command)) log("process cmd: " + command); 7399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!process(command)) { 7409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.IN_PROGRESS, 7419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan "cannot initiate a new transaction to execute: " 7429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + command); 7439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan protected String generateTag() { 7479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // 32-bit randomness 7489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return String.valueOf((long) (Math.random() * 0x100000000L)); 7499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7519329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 7529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String toString() { 7539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 7549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String s = super.toString(); 7559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return s.substring(s.indexOf("@")) + ":" 7569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipSession.State.toString(mState); 7579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable e) { 7589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return super.toString(); 7599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public boolean process(EventObject evt) throws SipException { 7639329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (isLoggable(this, evt)) log(" ~~~~~ " + this + ": " 7649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + SipSession.State.toString(mState) + ": processing " 7659329db04f13480ccdff013dcc00cdb96f12a921cWink Saville + logEvt(evt)); 7669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan synchronized (SipSessionGroup.this) { 7679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isClosed()) return false; 7689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7699329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (mSipKeepAlive != null) { 7708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // event consumed by keepalive process 7719329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (mSipKeepAlive.process(evt)) return true; 7728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 7738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 7749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Dialog dialog = null; 7759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof RequestEvent) { 7769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan dialog = ((RequestEvent) evt).getDialog(); 7779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof ResponseEvent) { 7789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan dialog = ((ResponseEvent) evt).getDialog(); 7793efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan extractExternalAddress((ResponseEvent) evt); 7809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 7819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (dialog != null) mDialog = dialog; 7829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan boolean processed; 7849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 7859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (mState) { 7869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.REGISTERING: 7879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.DEREGISTERING: 7889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = registeringToReady(evt); 7899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.READY_TO_CALL: 7919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = readyForCall(evt); 7929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.INCOMING_CALL: 7949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = incomingCall(evt); 7959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.INCOMING_CALL_ANSWERING: 7979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = incomingCallToInCall(evt); 7989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 7999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL: 8009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL_RING_BACK: 8019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = outgoingCall(evt); 8029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 8039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL_CANCELING: 8049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = outgoingCallToReady(evt); 8059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 8069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.IN_CALL: 8079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = inCall(evt); 8089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 809ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan case SipSession.State.ENDING_CALL: 810ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan processed = endingCall(evt); 811ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan break; 8129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 8139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processed = false; 8149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (processed || processExceptions(evt)); 8169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean processExceptions(EventObject evt) throws SipException { 8209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isRequestEvent(Request.BYE, evt)) { 8219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // terminate the call whenever a BYE is received 8229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 8239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 8249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.CANCEL, evt)) { 8269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, 8279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); 8289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof TransactionTerminatedEvent) { 8309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isCurrentTransaction((TransactionTerminatedEvent) evt)) { 8319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof TimeoutEvent) { 8329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processTimeout((TimeoutEvent) evt); 8339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 8349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processTransactionTerminated( 8359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan (TransactionTerminatedEvent) evt); 8369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.OPTIONS, evt)) { 8409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 8419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof DialogTerminatedEvent) { 8439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan processDialogTerminated((DialogTerminatedEvent) evt); 8449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 8479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void processDialogTerminated(DialogTerminatedEvent event) { 8509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mDialog == event.getDialog()) { 8519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(new SipException("dialog terminated")); 8529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 8539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) log("not the current dialog; current=" + mDialog 8549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + ", terminated=" + event.getDialog()); 8559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean isCurrentTransaction(TransactionTerminatedEvent event) { 8599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Transaction current = event.isServerTransaction() 8609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? mServerTransaction 8619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : mClientTransaction; 8629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Transaction target = event.isServerTransaction() 8639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? event.getServerTransaction() 8649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : event.getClientTransaction(); 8659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if ((current != target) && (mState != SipSession.State.PINGING)) { 8679329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) log("not the current transaction; current=" 8689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan + toString(current) + ", target=" + toString(target)); 8699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 8709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (current != null) { 8719329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) log("transaction terminated: " + toString(current)); 8729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 8749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // no transaction; shouldn't be here; ignored 8759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 8769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String toString(Transaction transaction) { 8809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (transaction == null) return "null"; 8819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Request request = transaction.getRequest(); 8829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Dialog dialog = transaction.getDialog(); 8839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan CSeqHeader cseq = (CSeqHeader) request.getHeader(CSeqHeader.NAME); 8849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return String.format("req=%s,%s,s=%s,ds=%s,", request.getMethod(), 8859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cseq.getSeqNumber(), transaction.getState(), 8869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((dialog == null) ? "-" : dialog.getState())); 8879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 8889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 8899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void processTransactionTerminated( 8909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan TransactionTerminatedEvent event) { 8919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (mState) { 8929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.IN_CALL: 8939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.READY_TO_CALL: 8949329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) log("Transaction terminated; do nothing"); 8959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 8969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 8979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) log("Transaction terminated early: " + this); 8989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.TRANSACTION_TERMINTED, 8999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan "transaction terminated"); 9009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void processTimeout(TimeoutEvent event) { 9049329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) log("processing Timeout..."); 9059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (mState) { 9069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.REGISTERING: 9079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.DEREGISTERING: 9089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 9099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationTimeout(this); 9109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 9119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.INCOMING_CALL: 9129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.INCOMING_CALL_ANSWERING: 9139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL: 9149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.OUTGOING_CALL_CANCELING: 9159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(SipErrorCode.TIME_OUT, event.toString()); 9169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 9179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 9199329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) log(" do nothing"); 9209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 9219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int getExpiryTime(Response response) { 9255e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh int time = -1; 9265e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh ContactHeader contact = (ContactHeader) response.getHeader(ContactHeader.NAME); 9275e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh if (contact != null) { 9285e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh time = contact.getExpires(); 9299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9305e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh ExpiresHeader expires = (ExpiresHeader) response.getHeader(ExpiresHeader.NAME); 9315e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh if (expires != null && (time < 0 || time > expires.getExpires())) { 9325e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh time = expires.getExpires(); 9335e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh } 934a3d53b09556994c514640e69d84f40c655347692Chia-chi Yeh if (time <= 0) { 935a3d53b09556994c514640e69d84f40c655347692Chia-chi Yeh time = EXPIRY_TIME; 936a3d53b09556994c514640e69d84f40c655347692Chia-chi Yeh } 9375e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh expires = (ExpiresHeader) response.getHeader(MinExpiresHeader.NAME); 9385e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh if (expires != null && time < expires.getExpires()) { 9395e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh time = expires.getExpires(); 9405e75bad33a53a468440871e4dbf83d05e6642de4Chia-chi Yeh } 9419329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) { 9429329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("Expiry time = " + time); 94385caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh } 944a3d53b09556994c514640e69d84f40c655347692Chia-chi Yeh return time; 9459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean registeringToReady(EventObject evt) 9489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 9499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expectResponse(Request.REGISTER, evt)) { 9509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 9519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 9529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 9549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (statusCode) { 9559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.OK: 9569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int state = mState; 9579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationDone((state == SipSession.State.REGISTERING) 9589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ? getExpiryTime(((ResponseEvent) evt).getResponse()) 9599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan : -1); 9609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.UNAUTHORIZED: 9629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.PROXY_AUTHENTICATION_REQUIRED: 963fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan handleAuthentication(event); 9649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 9669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (statusCode >= 500) { 9679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationFailed(response); 9689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 9699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 9739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 9749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 9759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean handleAuthentication(ResponseEvent event) 9769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 9779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 9789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String nonce = getNonceFromResponse(response); 979fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan if (nonce == null) { 980fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan onError(SipErrorCode.SERVER_ERROR, 981fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan "server does not provide challenge"); 9829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 983fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan } else if (mAuthenticationRetryCount < 2) { 9849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.handleChallenge( 9859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan event, getAccountManager()); 9869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 987fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan mAuthenticationRetryCount++; 988fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan if (isLoggable(this, event)) { 9899329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SSI_DBG) log(" authentication retry count=" 990fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan + mAuthenticationRetryCount); 991fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan } 9929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 993fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan } else { 994a0b7374a8afc7fb1db2eebb32ecba0f10db083cdHung-ying Tyan if (crossDomainAuthenticationRequired(response)) { 995a0b7374a8afc7fb1db2eebb32ecba0f10db083cdHung-ying Tyan onError(SipErrorCode.CROSS_DOMAIN_AUTHENTICATION, 996a0b7374a8afc7fb1db2eebb32ecba0f10db083cdHung-ying Tyan getRealmFromResponse(response)); 997a0b7374a8afc7fb1db2eebb32ecba0f10db083cdHung-ying Tyan } else { 998a0b7374a8afc7fb1db2eebb32ecba0f10db083cdHung-ying Tyan onError(SipErrorCode.INVALID_CREDENTIALS, 999a0b7374a8afc7fb1db2eebb32ecba0f10db083cdHung-ying Tyan "incorrect username or password"); 1000a0b7374a8afc7fb1db2eebb32ecba0f10db083cdHung-ying Tyan } 1001fcc474636f42243cfce960158373b9c49636a556Hung-ying Tyan return false; 10029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean crossDomainAuthenticationRequired(Response response) { 10069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String realm = getRealmFromResponse(response); 10079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (realm == null) realm = ""; 10089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return !mLocalProfile.getSipDomain().trim().equals(realm.trim()); 10099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private AccountManager getAccountManager() { 10129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new AccountManager() { 10139329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 10149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public UserCredentials getCredentials(ClientTransaction 10159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan challengedTransaction, String realm) { 10169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return new UserCredentials() { 10179329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 10189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getUserName() { 10191b666e24bacbe3695ca5fe2f996c177c3f10d5f0Chung-yih Wang String username = mLocalProfile.getAuthUserName(); 10201b666e24bacbe3695ca5fe2f996c177c3f10d5f0Chung-yih Wang return (!TextUtils.isEmpty(username) ? username : 10211b666e24bacbe3695ca5fe2f996c177c3f10d5f0Chung-yih Wang mLocalProfile.getUserName()); 10229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10249329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 10259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getPassword() { 10269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mPassword; 10279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10299329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 10309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getSipDomain() { 10319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mLocalProfile.getSipDomain(); 10329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }; 10349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan }; 10369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getRealmFromResponse(Response response) { 10399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader( 10409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.WWW_AUTHENTICATE); 10419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (wwwAuth != null) return wwwAuth.getRealm(); 10429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( 10439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.PROXY_AUTHENTICATE); 10449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (proxyAuth == null) ? null : proxyAuth.getRealm(); 10459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 10479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String getNonceFromResponse(Response response) { 10489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader( 10499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.WWW_AUTHENTICATE); 10509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (wwwAuth != null) return wwwAuth.getNonce(); 10519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( 10529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SIPHeaderNames.PROXY_AUTHENTICATE); 10539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (proxyAuth == null) ? null : proxyAuth.getNonce(); 10549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1056f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync private String getResponseString(int statusCode) { 1057f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync StatusLine statusLine = new StatusLine(); 1058f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync statusLine.setStatusCode(statusCode); 1059f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync statusLine.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode)); 1060f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync return statusLine.encode(); 1061f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 1062f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync 10639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean readyForCall(EventObject evt) throws SipException { 10649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // expect MakeCallCommand, RegisterCommand, DEREGISTER 10659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof MakeCallCommand) { 1066d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.OUTGOING_CALL; 10679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan MakeCallCommand cmd = (MakeCallCommand) evt; 10689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerProfile = cmd.getPeerProfile(); 1069f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync if (mReferSession != null) { 1070f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mSipHelper.sendReferNotify(mReferSession.mDialog, 1071f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync getResponseString(Response.TRYING)); 1072f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 1073f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mClientTransaction = mSipHelper.sendInvite( 1074f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mLocalProfile, mPeerProfile, cmd.getSessionDescription(), 1075f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync generateTag(), mReferredBy, mReplaces); 10769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 10779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 10789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan startSessionTimer(cmd.getTimeout()); 1079e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan mProxy.onCalling(this); 10809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof RegisterCommand) { 1082d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.REGISTERING; 10839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int duration = ((RegisterCommand) evt).getDuration(); 10849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 10859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan generateTag(), duration); 10869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 10879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 10889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(this); 10899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (DEREGISTER == evt) { 1091d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.DEREGISTERING; 10929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 10939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan generateTag(), 0); 10949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 10959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 10969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistering(this); 10979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 10989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 10999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 11009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean incomingCall(EventObject evt) throws SipException { 11039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // expect MakeCallCommand(answering) , END_CALL cmd , Cancel 11049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof MakeCallCommand) { 11059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // answer call 1106d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.INCOMING_CALL_ANSWERING; 11079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction = mSipHelper.sendInviteOk(mInviteReceived, 11089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mLocalProfile, 11099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((MakeCallCommand) evt).getSessionDescription(), 11103efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan mServerTransaction, 11113efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan mExternalIp, mExternalPort); 11129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan startSessionTimer(((MakeCallCommand) evt).getTimeout()); 11139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (END_CALL == evt) { 11159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendInviteBusyHere(mInviteReceived, 11169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction); 11179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 11189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.CANCEL, evt)) { 11209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan RequestEvent event = (RequestEvent) evt; 11219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse(event, Response.OK); 11229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendInviteRequestTerminated( 11239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mInviteReceived.getRequest(), mServerTransaction); 11249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 11259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 11289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11309329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private boolean incomingCallToInCall(EventObject evt) { 11319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // expect ACK, CANCEL request 11329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (isRequestEvent(Request.ACK, evt)) { 1133bb18b405c539e483cce67ae207bd7e6263c0d071repo sync String sdp = extractContent(((RequestEvent) evt).getRequest()); 1134bb18b405c539e483cce67ae207bd7e6263c0d071repo sync if (sdp != null) mPeerSessionDescription = sdp; 1135bb18b405c539e483cce67ae207bd7e6263c0d071repo sync if (mPeerSessionDescription == null) { 1136bb18b405c539e483cce67ae207bd7e6263c0d071repo sync onError(SipErrorCode.CLIENT_ERROR, "peer sdp is empty"); 1137bb18b405c539e483cce67ae207bd7e6263c0d071repo sync } else { 1138bb18b405c539e483cce67ae207bd7e6263c0d071repo sync establishCall(false); 1139bb18b405c539e483cce67ae207bd7e6263c0d071repo sync } 11409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.CANCEL, evt)) { 11429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // http://tools.ietf.org/html/rfc3261#section-9.2 11439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // Final response has been sent; do nothing here. 11449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 11479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean outgoingCall(EventObject evt) throws SipException { 11509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expectResponse(Request.INVITE, evt)) { 11519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 11529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 11539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 11549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 11559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (statusCode) { 11569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.RINGING: 11576ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan case Response.CALL_IS_BEING_FORWARDED: 11586ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan case Response.QUEUED: 11596ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan case Response.SESSION_PROGRESS: 11606ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan // feedback any provisional responses (except TRYING) as 11616ca8ec4793540c6c0ad83574aa52e316a8ed17b4Hung-ying Tyan // ring back for better UX 11629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (mState == SipSession.State.OUTGOING_CALL) { 11639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.OUTGOING_CALL_RING_BACK; 11649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelSessionTimer(); 1165e8782e2fdfd256296a0d1fd2a1c3f98d58103eaaHung-ying Tyan mProxy.onRingingBack(this); 11669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.OK: 1169f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync if (mReferSession != null) { 1170f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mSipHelper.sendReferNotify(mReferSession.mDialog, 1171f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync getResponseString(Response.OK)); 1172f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync // since we don't need to remember the session anymore. 1173f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mReferSession = null; 1174f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 11759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendInviteAck(event, mDialog); 11769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerSessionDescription = extractContent(response); 11770f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan establishCall(true); 11789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.UNAUTHORIZED: 11809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.PROXY_AUTHENTICATION_REQUIRED: 1181a0b7374a8afc7fb1db2eebb32ecba0f10db083cdHung-ying Tyan if (handleAuthentication(event)) { 11829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan addSipSession(this); 11839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 11849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.REQUEST_PENDING: 11869329db04f13480ccdff013dcc00cdb96f12a921cWink Saville // TODO: rfc3261#section-14.1; re-schedule invite 11879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 1189f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync if (mReferSession != null) { 1190f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mSipHelper.sendReferNotify(mReferSession.mDialog, 1191f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync getResponseString(Response.SERVICE_UNAVAILABLE)); 1192f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 11939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (statusCode >= 400) { 11949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // error: an ack is sent automatically by the stack 11959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(response); 11969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 11979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (statusCode >= 300) { 11989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // TODO: handle 3xx (redirect) 11999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 12019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 12049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (END_CALL == evt) { 12059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // RFC says that UA should not send out cancel when no 12069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // response comes back yet. We are cheating for not checking 12079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // response. 12089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.OUTGOING_CALL_CANCELING; 1209d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mSipHelper.sendCancel(mClientTransaction); 12109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan startSessionTimer(CANCEL_CALL_TIMER); 12119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 1212ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } else if (isRequestEvent(Request.INVITE, evt)) { 1213ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan // Call self? Send BUSY HERE so server may redirect the call to 1214ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan // voice mailbox. 1215ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan RequestEvent event = (RequestEvent) evt; 1216ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan mSipHelper.sendInviteBusyHere(event, 1217ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan event.getServerTransaction()); 1218ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return true; 12199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 12219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean outgoingCallToReady(EventObject evt) 12249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 12259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof ResponseEvent) { 12269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 12279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 12289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 12299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (expectResponse(Request.CANCEL, evt)) { 12309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (statusCode == Response.OK) { 12319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // do nothing; wait for REQUEST_TERMINATED 12329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 12339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (expectResponse(Request.INVITE, evt)) { 12359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (statusCode) { 12369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.OK: 12379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan outgoingCall(evt); // abort Cancel 12389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 12399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.REQUEST_TERMINATED: 12409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 12419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 12429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 12449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 12459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 12479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (statusCode >= 400) { 12489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(response); 12499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 12509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof TransactionTerminatedEvent) { 12529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // rfc3261#section-14.1: 12539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // if re-invite gets timed out, terminate the dialog; but 12549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // re-invite is not reliable, just let it go and pretend 12559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // nothing happened. 12569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(new SipException("timed out")); 12579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 12599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 12609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1261f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync private boolean processReferRequest(RequestEvent event) 1262f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync throws SipException { 1263f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync try { 1264f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync ReferToHeader referto = (ReferToHeader) event.getRequest() 1265f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync .getHeader(ReferTo.NAME); 1266f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync Address address = referto.getAddress(); 1267f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync SipURI uri = (SipURI) address.getURI(); 1268f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync String replacesHeader = uri.getHeader(ReplacesHeader.NAME); 1269f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync String username = uri.getUser(); 1270f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync if (username == null) { 1271f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mSipHelper.sendResponse(event, Response.BAD_REQUEST); 1272f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync return false; 1273f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 1274f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync // send notify accepted 1275f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mSipHelper.sendResponse(event, Response.ACCEPTED); 1276f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync SipSessionImpl newSession = createNewSession(event, 1277f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync this.mProxy.getListener(), 1278f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync mSipHelper.getServerTransaction(event), 1279f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync SipSession.State.READY_TO_CALL); 1280f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mReferSession = this; 1281f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mReferredBy = (ReferredByHeader) event.getRequest() 1282f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync .getHeader(ReferredByHeader.NAME); 1283f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mReplaces = replacesHeader; 1284f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mPeerProfile = createPeerProfile(referto); 1285f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.mProxy.onCallTransferring(newSession, 1286f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync null); 1287f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync return true; 1288f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } catch (IllegalArgumentException e) { 1289f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync throw new SipException("createPeerProfile()", e); 1290f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 1291f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 1292f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync 12939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private boolean inCall(EventObject evt) throws SipException { 12949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // expect END_CALL cmd, BYE request, hold call (MakeCallCommand) 12959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // OK retransmission is handled in SipStack 12969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (END_CALL == evt) { 12979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // rfc3261#section-15.1.1 1298ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan mState = SipSession.State.ENDING_CALL; 12999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendBye(mDialog); 1300ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan mProxy.onCallEnded(this); 1301ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan startSessionTimer(END_CALL_TIMER); 13029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 13039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.INVITE, evt)) { 13049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // got Re-INVITE 13059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.INCOMING_CALL; 1306d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan RequestEvent event = mInviteReceived = (RequestEvent) evt; 13079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mPeerSessionDescription = extractContent(event.getRequest()); 13089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mServerTransaction = null; 13099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription); 13109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 13119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (isRequestEvent(Request.BYE, evt)) { 13129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 13139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallNormally(); 13149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 1315f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } else if (isRequestEvent(Request.REFER, evt)) { 1316f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync return processReferRequest((RequestEvent) evt); 13179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof MakeCallCommand) { 13189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // to change call 1319d8d3b15f408314ac88201eee3e401a35556ba669Hung-ying Tyan mState = SipSession.State.OUTGOING_CALL; 13209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mClientTransaction = mSipHelper.sendReinvite(mDialog, 13219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ((MakeCallCommand) evt).getSessionDescription()); 13229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan startSessionTimer(((MakeCallCommand) evt).getTimeout()); 13239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return true; 1324f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } else if (evt instanceof ResponseEvent) { 1325f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync if (expectResponse(Request.NOTIFY, evt)) return true; 13269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 13289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1330ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan private boolean endingCall(EventObject evt) throws SipException { 1331ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan if (expectResponse(Request.BYE, evt)) { 1332ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 1333ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan Response response = event.getResponse(); 1334ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan 1335ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan int statusCode = response.getStatusCode(); 1336ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan switch (statusCode) { 1337ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan case Response.UNAUTHORIZED: 1338ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan case Response.PROXY_AUTHENTICATION_REQUIRED: 1339ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan if (handleAuthentication(event)) { 1340ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan return true; 1341ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan } else { 1342ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan // can't authenticate; pass through to end session 1343ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan } 1344ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan } 1345ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan cancelSessionTimer(); 1346ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan reset(); 1347ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan return true; 1348ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan } 1349ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan return false; 1350ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan } 1351ceb525d85512bde884b0f01a3aa93f2943dcf5f3Hung-ying Tyan 13529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan // timeout in seconds 13539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void startSessionTimer(int timeout) { 13549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (timeout > 0) { 13558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSessionTimer = new SessionTimer(); 13568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSessionTimer.start(timeout); 13579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void cancelSessionTimer() { 13618a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mSessionTimer != null) { 13628a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSessionTimer.cancel(); 13638a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mSessionTimer = null; 13649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String createErrorMessage(Response response) { 13683b9456929376a047ef38b5ddb27fed9b11664306Hung-ying Tyan return String.format("%s (%d)", response.getReasonPhrase(), 13693b9456929376a047ef38b5ddb27fed9b11664306Hung-ying Tyan response.getStatusCode()); 13709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13720f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan private void enableKeepAlive() { 13739329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (mSipSessionImpl != null) { 13749329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipSessionImpl.stopKeepAliveProcess(); 13750f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan } else { 13769329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipSessionImpl = duplicate(); 13770f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan } 13780f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan try { 13799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipSessionImpl.startKeepAliveProcess( 13800f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan INCALL_KEEPALIVE_INTERVAL, mPeerProfile, null); 13810f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan } catch (SipException e) { 13829329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("keepalive cannot be enabled; ignored", e); 13839329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipSessionImpl.stopKeepAliveProcess(); 13840f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan } 13850f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan } 13860f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan 13870f8ceff66069c98480481241ba9d70dc34448188Hung-ying Tyan private void establishCall(boolean enableKeepAlive) { 13889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mState = SipSession.State.IN_CALL; 13899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelSessionTimer(); 1390108e51ec4c06c75db2a11d1417f1bc8c0545ea8bHung-ying Tyan if (!mInCall && enableKeepAlive) enableKeepAlive(); 1391108e51ec4c06c75db2a11d1417f1bc8c0545ea8bHung-ying Tyan mInCall = true; 13929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onCallEstablished(this, mPeerSessionDescription); 13939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 13959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void endCallNormally() { 13969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 13979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onCallEnded(this); 13989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 13999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void endCallOnError(int errorCode, String message) { 14019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 14029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onError(this, errorCode, message); 14039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14059c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void endCallOnBusy() { 14069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 14079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onCallBusy(this); 14089c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onError(int errorCode, String message) { 14119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan cancelSessionTimer(); 14129c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (mState) { 14139c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.REGISTERING: 14149c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.DEREGISTERING: 14159c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationFailed(errorCode, message); 14169c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan break; 14179c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 1418bddf530f0bbd2917d98c3fd0f11920c2b2473154Hung-ying Tyan endCallOnError(errorCode, message); 14199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onError(Throwable exception) { 14249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan exception = getRootCause(exception); 14259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(getErrorCode(exception), exception.toString()); 14269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onError(Response response) { 14299c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 14309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!mInCall && (statusCode == Response.BUSY_HERE)) { 14319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan endCallOnBusy(); 14329c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 14339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onError(getErrorCode(statusCode), createErrorMessage(response)); 14349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14359c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14369c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14379c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int getErrorCode(int responseStatusCode) { 14389c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (responseStatusCode) { 14399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.TEMPORARILY_UNAVAILABLE: 14409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.FORBIDDEN: 14419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.GONE: 14429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.NOT_FOUND: 14439c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.NOT_ACCEPTABLE: 14449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.NOT_ACCEPTABLE_HERE: 14459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.PEER_NOT_REACHABLE; 14469c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.REQUEST_URI_TOO_LONG: 14489c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.ADDRESS_INCOMPLETE: 14499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.AMBIGUOUS: 14509c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.INVALID_REMOTE_URI; 14519c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14529c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case Response.REQUEST_TIMEOUT: 14539c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.TIME_OUT; 14549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan default: 14569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (responseStatusCode < 500) { 14579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 14589c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 14599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.SERVER_ERROR; 14609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int getErrorCode(Throwable exception) { 14659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String message = exception.getMessage(); 14669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (exception instanceof UnknownHostException) { 1467e26eb3274a65c41a6a30bdace1818c5629cca1c8Hung-ying Tyan return SipErrorCode.SERVER_UNREACHABLE; 14689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (exception instanceof IOException) { 14699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.SOCKET_ERROR; 14709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 14719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 14729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onRegistrationDone(int duration) { 14769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 14779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationDone(this, duration); 14789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onRegistrationFailed(int errorCode, String message) { 14819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan reset(); 14829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mProxy.onRegistrationFailed(this, errorCode, message); 14839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 14859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private void onRegistrationFailed(Response response) { 14869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan int statusCode = response.getStatusCode(); 14879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan onRegistrationFailed(getErrorCode(statusCode), 14889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan createErrorMessage(response)); 14899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 14908a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 14918a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // Notes: SipSessionListener will be replaced by the keepalive process 14928a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // @param interval in seconds 14938a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void startKeepAliveProcess(int interval, 14948a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan KeepAliveProcessCallback callback) throws SipException { 14958a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipSessionGroup.this) { 14968a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan startKeepAliveProcess(interval, mLocalProfile, callback); 14978a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 14988a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 14998a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15008a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // Notes: SipSessionListener will be replaced by the keepalive process 15018a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // @param interval in seconds 15028a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void startKeepAliveProcess(int interval, SipProfile peerProfile, 15038a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan KeepAliveProcessCallback callback) throws SipException { 15048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipSessionGroup.this) { 15059329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (mSipKeepAlive != null) { 15068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan throw new SipException("Cannot create more than one " 15078a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + "keepalive process in a SipSession"); 15088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mPeerProfile = peerProfile; 15109329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipKeepAlive = new SipKeepAlive(); 15119329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mProxy.setListener(mSipKeepAlive); 15129329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipKeepAlive.start(interval, callback); 15138a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15158a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15168a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void stopKeepAliveProcess() { 15178a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipSessionGroup.this) { 15189329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (mSipKeepAlive != null) { 15199329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipKeepAlive.stop(); 15209329db04f13480ccdff013dcc00cdb96f12a921cWink Saville mSipKeepAlive = null; 15218a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15259329db04f13480ccdff013dcc00cdb96f12a921cWink Saville class SipKeepAlive extends SipSessionAdapter implements Runnable { 15269329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final String SKA_TAG = "SipKeepAlive"; 15279329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final boolean SKA_DBG = true; 15289329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 15298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private boolean mRunning = false; 15308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private KeepAliveProcessCallback mCallback; 15318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private boolean mPortChanged = false; 15338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private int mRPort = 0; 153444ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan private int mInterval; // just for debugging 15358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15368a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // @param interval in seconds 15378a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan void start(int interval, KeepAliveProcessCallback callback) { 15388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mRunning) return; 15398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mRunning = true; 154044ccfb03bb349a90546ddb3dc0063cbf4aaddaf1Hung-ying Tyan mInterval = interval; 15418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mCallback = new KeepAliveProcessCallbackProxy(callback); 15428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mWakeupTimer.set(interval * 1000, this); 15439329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SKA_DBG) { 15449329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("start keepalive:" 15458a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + mLocalProfile.getUriString()); 15468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15488a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // No need to run the first time in a separate thread for now 15498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan run(); 15508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15518a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15528a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // return true if the event is consumed 15539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville boolean process(EventObject evt) { 15548a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mRunning && (mState == SipSession.State.PINGING)) { 15558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (evt instanceof ResponseEvent) { 15568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (parseOptionsResult(evt)) { 15578a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mPortChanged) { 15583efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan resetExternalAddress(); 15598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan stop(); 15608a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } else { 15618a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan cancelSessionTimer(); 15628a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan removeSipSession(SipSessionImpl.this); 15638a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15648a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mCallback.onResponse(mPortChanged); 15658a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return true; 15668a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15678a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15688a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return false; 15708a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15718a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15728a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipSessionAdapter 15738a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // To react to the session timeout event and network error. 15748a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 15758a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onError(ISipSession session, int errorCode, String message) { 15768a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan stop(); 15778a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mCallback.onError(errorCode, message); 15788a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15798a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15808a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // SipWakeupTimer timeout handler 15818a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // To send out keepalive message. 15828a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan @Override 15838a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void run() { 15848a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipSessionGroup.this) { 15858a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (!mRunning) return; 15868a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 15879329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG_PING) { 15883efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan String peerUri = (mPeerProfile == null) 15893efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan ? "null" 15903efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan : mPeerProfile.getUriString(); 15919329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("keepalive: " + mLocalProfile.getUriString() 15923efff6c5840a99faadc3ee6197940c3290f65a62Hung-ying Tyan + " --> " + peerUri + ", interval=" + mInterval); 15938a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 15948a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan try { 15958a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan sendKeepAlive(); 15968a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } catch (Throwable t) { 15979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SKA_DBG) { 15989329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("keepalive error: " 159985caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh + mLocalProfile.getUriString(), getRootCause(t)); 160085caf063c027ba0d1defeaff8850e12b6428c4f7Chia-chi Yeh } 16018a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // It's possible that the keepalive process is being stopped 16028a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // during session.sendKeepAlive() so need to check mRunning 16038a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // again here. 16048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mRunning) SipSessionImpl.this.onError(t); 16058a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16078a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 16098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan void stop() { 16108a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipSessionGroup.this) { 16119329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SKA_DBG) { 16129329db04f13480ccdff013dcc00cdb96f12a921cWink Saville log("stop keepalive:" + mLocalProfile.getUriString() 16138a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan + ",RPort=" + mRPort); 16148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16158a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mRunning = false; 16168a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mWakeupTimer.cancel(this); 16178a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan reset(); 16188a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16198a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16208a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 16219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void sendKeepAlive() throws SipException { 16228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan synchronized (SipSessionGroup.this) { 16238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mState = SipSession.State.PINGING; 16248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mClientTransaction = mSipHelper.sendOptions( 16258a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mLocalProfile, mPeerProfile, generateTag()); 16268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 16278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan addSipSession(SipSessionImpl.this); 16288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 16298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan startSessionTimer(KEEPALIVE_TIMEOUT); 16308a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // when timed out, onError() will be called with SipErrorCode.TIME_OUT 16318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 16348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private boolean parseOptionsResult(EventObject evt) { 16358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (expectResponse(Request.OPTIONS, evt)) { 16368a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 16378a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan int rPort = getRPortFromResponse(event.getResponse()); 16388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (rPort != -1) { 16398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mRPort == 0) mRPort = rPort; 16408a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mRPort != rPort) { 16418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mPortChanged = true; 16429329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SKA_DBG) log(String.format( 16438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan "rport is changed: %d <> %d", mRPort, rPort)); 16448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mRPort = rPort; 16458a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } else { 16469329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SKA_DBG) log("rport is the same: " + rPort); 16478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16488a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } else { 16499329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (SKA_DBG) log("peer did not respond rport"); 16508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16518a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return true; 16528a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16538a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return false; 16548a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16558a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 16568a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private int getRPortFromResponse(Response response) { 16578a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan ViaHeader viaHeader = (ViaHeader)(response.getHeader( 16588a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan SIPHeaderNames.VIA)); 16598a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan return (viaHeader == null) ? -1 : viaHeader.getRPort(); 16608a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16619329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 16629329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void log(String s) { 16639329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.d(SKA_TAG, s); 16649329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 16659329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 16669329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 16679329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void log(String s) { 16689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.d(SSI_TAG, s); 16698a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 16709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 16719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 16729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 16739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @return true if the event is a request event matching the specified 16749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * method; false otherwise 16759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 16769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean isRequestEvent(String method, EventObject event) { 16779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 16789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (event instanceof RequestEvent) { 16799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan RequestEvent requestEvent = (RequestEvent) event; 16809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return method.equals(requestEvent.getRequest().getMethod()); 16819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 16829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (Throwable e) { 16839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 16849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 16859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 16869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 16879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static String getCseqMethod(Message message) { 16889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((CSeqHeader) message.getHeader(CSeqHeader.NAME)).getMethod(); 16899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 16909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 16919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan /** 16929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * @return true if the event is a response event and the CSeqHeader method 16939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan * match the given arguments; false otherwise 16949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan */ 16959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean expectResponse( 16969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String expectedMethod, EventObject evt) { 16979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof ResponseEvent) { 16989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan ResponseEvent event = (ResponseEvent) evt; 16999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = event.getResponse(); 17009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 17019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 17039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17049c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1705f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync private static SipProfile createPeerProfile(HeaderAddress header) 17069c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throws SipException { 17079c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan try { 1708f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync Address address = header.getAddress(); 17099c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan SipURI uri = (SipURI) address.getURI(); 17109c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String username = uri.getUser(); 17119c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (username == null) username = ANONYMOUS; 1712007493a9f98959c350c3787230df9afa346ee938Hung-ying Tyan int port = uri.getPort(); 1713007493a9f98959c350c3787230df9afa346ee938Hung-ying Tyan SipProfile.Builder builder = 1714007493a9f98959c350c3787230df9afa346ee938Hung-ying Tyan new SipProfile.Builder(username, uri.getHost()) 1715007493a9f98959c350c3787230df9afa346ee938Hung-ying Tyan .setDisplayName(address.getDisplayName()); 1716007493a9f98959c350c3787230df9afa346ee938Hung-ying Tyan if (port > 0) builder.setPort(port); 1717007493a9f98959c350c3787230df9afa346ee938Hung-ying Tyan return builder.build(); 17189c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (IllegalArgumentException e) { 17199c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new SipException("createPeerProfile()", e); 17209c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } catch (ParseException e) { 17219c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan throw new SipException("createPeerProfile()", e); 17229c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17239c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17249c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17259c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean isLoggable(SipSessionImpl s) { 17269c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (s != null) { 17279c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan switch (s.mState) { 17289c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan case SipSession.State.PINGING: 17299329db04f13480ccdff013dcc00cdb96f12a921cWink Saville return DBG_PING; 17309c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17319c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17329329db04f13480ccdff013dcc00cdb96f12a921cWink Saville return DBG; 17339c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17349c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 1735ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan private static boolean isLoggable(EventObject evt) { 1736ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan return isLoggable(null, evt); 1737ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan } 1738ed3c0fbbd5457f43ff72cec31b8ab0bb3f7a0047Hung-ying Tyan 17399c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private static boolean isLoggable(SipSessionImpl s, EventObject evt) { 17409c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (!isLoggable(s)) return false; 17419c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt == null) return false; 17429c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (evt instanceof ResponseEvent) { 17449c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan Response response = ((ResponseEvent) evt).getResponse(); 17459c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (Request.OPTIONS.equals(response.getHeader(CSeqHeader.NAME))) { 17469329db04f13480ccdff013dcc00cdb96f12a921cWink Saville return DBG_PING; 17479c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17489329db04f13480ccdff013dcc00cdb96f12a921cWink Saville return DBG; 17499c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof RequestEvent) { 17508a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (isRequestEvent(Request.OPTIONS, evt)) { 17519329db04f13480ccdff013dcc00cdb96f12a921cWink Saville return DBG_PING; 17528a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 17539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville return DBG; 17549c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17559c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return false; 17569c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17579c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17589329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static String logEvt(EventObject evt) { 17599c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan if (evt instanceof RequestEvent) { 17609c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((RequestEvent) evt).getRequest().toString(); 17619c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else if (evt instanceof ResponseEvent) { 17629c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return ((ResponseEvent) evt).getResponse().toString(); 17639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } else { 17649c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return evt.toString(); 17659c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17669c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17679c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17689c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class RegisterCommand extends EventObject { 17699c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mDuration; 17709c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17719c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public RegisterCommand(int duration) { 17729c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(SipSessionGroup.this); 17739c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mDuration = duration; 17749c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17759c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17769c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public int getDuration() { 17779c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mDuration; 17789c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17799c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17809c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17819c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private class MakeCallCommand extends EventObject { 17829c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private String mSessionDescription; 17839c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan private int mTimeout; // in seconds 17849c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17859c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public MakeCallCommand(SipProfile peerProfile, 17869c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan String sessionDescription, int timeout) { 17879c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan super(peerProfile); 17889c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mSessionDescription = sessionDescription; 17899c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan mTimeout = timeout; 17909c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17919c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17929c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public SipProfile getPeerProfile() { 17939c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return (SipProfile) getSource(); 17949c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17959c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 17969c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public String getSessionDescription() { 17979c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mSessionDescription; 17989c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 17999c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan 18009c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan public int getTimeout() { 18019c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan return mTimeout; 18029c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 18039c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan } 18048a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 18058a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan /** Class to help safely run KeepAliveProcessCallback in a different thread. */ 18068a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan static class KeepAliveProcessCallbackProxy implements KeepAliveProcessCallback { 18079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final String KAPCP_TAG = "KeepAliveProcessCallbackProxy"; 18088a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private KeepAliveProcessCallback mCallback; 18098a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 18108a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan KeepAliveProcessCallbackProxy(KeepAliveProcessCallback callback) { 18118a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mCallback = callback; 18128a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18138a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 18148a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan private void proxy(Runnable runnable) { 18158a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // One thread for each calling back. 18168a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // Note: Guarantee ordering if the issue becomes important. Currently, 18178a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan // the chance of handling two callback events at a time is none. 18188a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan new Thread(runnable, "SIP-KeepAliveProcessCallbackThread").start(); 18198a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18208a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 18219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 18228a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onResponse(final boolean portChanged) { 18238a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mCallback == null) return; 18248a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan proxy(new Runnable() { 18259329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 18268a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void run() { 18278a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan try { 18288a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mCallback.onResponse(portChanged); 18298a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } catch (Throwable t) { 18309329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onResponse", t); 18318a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18328a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18338a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan }); 18348a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18358a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan 18369329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 18378a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void onError(final int errorCode, final String description) { 18388a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan if (mCallback == null) return; 18398a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan proxy(new Runnable() { 18409329db04f13480ccdff013dcc00cdb96f12a921cWink Saville @Override 18418a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan public void run() { 18428a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan try { 18438a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan mCallback.onError(errorCode, description); 18448a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } catch (Throwable t) { 18459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onError", t); 18468a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18478a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18488a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan }); 18498a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18509329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 18519329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void loge(String s, Throwable t) { 18529329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.e(KAPCP_TAG, s, t); 18539329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 18549329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 18559329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 18569329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void log(String s) { 18579329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.d(TAG, s); 18589329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 18599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 18609329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void loge(String s, Throwable t) { 18619329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.e(TAG, s, t); 18628a044dee1690c3dc7b5f467461ce4fa65c565a66Hung-ying Tyan } 18639c1fbe7bca34ac7463079926a401a3ce42717460Hung-ying Tyan} 1864