SipSessionGroup.java revision 6057cd00d95c756b78f22c67279cb982bc0674ef
12d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang/* 22d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Copyright (C) 2010 The Android Open Source Project 32d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 42d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License"); 52d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * you may not use this file except in compliance with the License. 62d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * You may obtain a copy of the License at 72d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 82d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * http://www.apache.org/licenses/LICENSE-2.0 92d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Unless required by applicable law or agreed to in writing, software 112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS, 122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * See the License for the specific language governing permissions and 142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * limitations under the License. 152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangpackage com.android.server.sip; 182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.clientauthutils.AccountManager; 202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.clientauthutils.UserCredentials; 212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.header.SIPHeaderNames; 227d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wangimport gov.nist.javax.sip.header.ProxyAuthenticate; 232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.header.WWWAuthenticate; 2495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yehimport gov.nist.javax.sip.message.SIPMessage; 252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipSession; 272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipSessionListener; 28903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyanimport android.net.sip.SipErrorCode; 292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SipProfile; 3084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyanimport android.net.sip.SipSession; 312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.text.TextUtils; 322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.util.Log; 332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.io.IOException; 3595b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yehimport java.io.UnsupportedEncodingException; 362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.net.DatagramSocket; 37903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyanimport java.net.UnknownHostException; 382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.text.ParseException; 392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Collection; 402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.EventObject; 412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.HashMap; 422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Map; 432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Properties; 442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.TooManyListenersException; 452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ClientTransaction; 472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.Dialog; 482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.DialogTerminatedEvent; 492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.IOExceptionEvent; 502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.InvalidArgumentException; 512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ListeningPoint; 522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.RequestEvent; 532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ResponseEvent; 542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ServerTransaction; 552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipException; 562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipFactory; 572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipListener; 582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipProvider; 592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipStack; 602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.TimeoutEvent; 612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.Transaction; 622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.TransactionState; 632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.TransactionTerminatedEvent; 64903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyanimport javax.sip.TransactionUnavailableException; 652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.address.Address; 662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.address.SipURI; 672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.CSeqHeader; 682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.ExpiresHeader; 692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.FromHeader; 702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.MinExpiresHeader; 712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.ViaHeader; 722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.message.Message; 732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.message.Request; 742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.message.Response; 752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang/** 772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Manages {@link ISipSession}'s for a SIP account. 782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangclass SipSessionGroup implements SipListener { 802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final String TAG = "SipSession"; 81c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan private static final boolean DEBUG = true; 82c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan private static final boolean DEBUG_PING = DEBUG && false; 832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final String ANONYMOUS = "anonymous"; 849352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private static final int EXPIRY_TIME = 3600; // in seconds 85194bbcce9ba15634500f542b9ea017b2cf154b45Hung-ying Tyan private static final int CANCEL_CALL_TIMER = 3; // in seconds 862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject DEREGISTER = new EventObject("Deregister"); 882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject END_CALL = new EventObject("End call"); 892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject HOLD_CALL = new EventObject("Hold call"); 902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject CONTINUE_CALL 912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang = new EventObject("Continue call"); 922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private final SipProfile mLocalProfile; 942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private final String mPassword; 952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipStack mSipStack; 972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipHelper mSipHelper; 982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String mLastNonce; 992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int mRPort; 1002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // session that processes INVITE requests 1022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipSessionImpl mCallReceiverSession; 1032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String mLocalIp; 1042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // call-id-to-SipSession map 1062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Map<String, SipSessionImpl> mSessionMap = 1072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang new HashMap<String, SipSessionImpl>(); 1082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 1102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @param myself the local profile with password crossed out 1112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @param password the password of the profile 1122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @throws IOException if cannot assign requested address 1132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 1142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionGroup(String localIp, SipProfile myself, String password) 1152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException, IOException { 1162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalProfile = myself; 1172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPassword = password; 1182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(localIp); 1192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan synchronized void reset(String localIp) throws SipException, IOException { 1222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalIp = localIp; 1232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (localIp == null) return; 1242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProfile myself = mLocalProfile; 1262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipFactory sipFactory = SipFactory.getInstance(); 1272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Properties properties = new Properties(); 1282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang properties.setProperty("javax.sip.STACK_NAME", getStackName()); 1292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String outboundProxy = myself.getProxyAddress(); 1302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (!TextUtils.isEmpty(outboundProxy)) { 1315de1d36dd0415c4cf9afdf093a4915951ef6c770Chung-yih Wang Log.v(TAG, "outboundProxy is " + outboundProxy); 1322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang properties.setProperty("javax.sip.OUTBOUND_PROXY", outboundProxy 1332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + ":" + myself.getPort() + "/" + myself.getProtocol()); 1342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipStack stack = mSipStack = sipFactory.createSipStack(properties); 1362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 1382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProvider provider = stack.createSipProvider( 1392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang stack.createListeningPoint(localIp, allocateLocalPort(), 1402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang myself.getProtocol())); 1412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang provider.addSipListener(this); 1422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper = new SipHelper(stack, provider); 1432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (InvalidArgumentException e) { 1442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new IOException(e.getMessage()); 1452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (TooManyListenersException e) { 1462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // must never happen 1472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("SipSessionGroup constructor", e); 1482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " start stack for " + myself.getUriString()); 1502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang stack.start(); 1512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLastNonce = null; 1532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = null; 1542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.clear(); 1552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 157d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan synchronized void onConnectivityChanged() { 158d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan for (SipSessionImpl s : mSessionMap.values()) { 159d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan s.onError(SipErrorCode.DATA_CONNECTION_LOST, 160d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan "data connection lost"); 161d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan } 162d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan } 163d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan 1642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getLocalProfile() { 1652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile; 1662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getLocalProfileUri() { 1692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getUriString(); 1702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String getStackName() { 1732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return "stack" + System.currentTimeMillis(); 1742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void close() { 1772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " close stack for " + mLocalProfile.getUriString()); 1782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.clear(); 1792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang closeToNotReceiveCalls(); 1802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mSipStack != null) { 1812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipStack.stop(); 1822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipStack = null; 1832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper = null; 1842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized boolean isClosed() { 1882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (mSipStack == null); 1892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // For internal use, require listener not to block in callbacks. 1922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void openToReceiveCalls(ISipSessionListener listener) { 1932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mCallReceiverSession == null) { 1942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = new SipSessionCallReceiverImpl(listener); 1952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 1962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession.setListener(listener); 1972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void closeToNotReceiveCalls() { 2012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = null; 2022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public ISipSession createSession(ISipSessionListener listener) { 2052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (isClosed() ? null : new SipSessionImpl(listener)); 2062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static int allocateLocalPort() throws SipException { 2092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 2102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang DatagramSocket s = new DatagramSocket(); 2112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int localPort = s.getLocalPort(); 2122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang s.close(); 2132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return localPort; 2142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (IOException e) { 2152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("allocateLocalPort()", e); 2162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized SipSessionImpl getSipSession(EventObject event) { 2202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = SipHelper.getCallId(event); 2212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl session = mSessionMap.get(key); 222c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if ((session != null) && isLoggable(session)) { 223c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, "session key from event: " + key); 224c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, "active sessions:"); 225c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan for (String k : mSessionMap.keySet()) { 226c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, " ..." + k + ": " + mSessionMap.get(k)); 227c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 228c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 2292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((session != null) ? session : mCallReceiverSession); 2302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void addSipSession(SipSessionImpl newSession) { 2332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang removeSipSession(newSession); 2342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = newSession.getCallId(); 2352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.put(key, newSession); 236c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (isLoggable(newSession)) { 237c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, "+++ add a session with key: '" + key + "'"); 238c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan for (String k : mSessionMap.keySet()) { 239c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, " " + k + ": " + mSessionMap.get(k)); 240c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 2412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void removeSipSession(SipSessionImpl session) { 2452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (session == mCallReceiverSession) return; 2462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = session.getCallId(); 2472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl s = mSessionMap.remove(key); 2482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // sanity check 2492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if ((s != null) && (s != session)) { 2502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.w(TAG, "session " + session + " is not associated with key '" 2512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + key + "'"); 2522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.put(key, s); 2532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang for (Map.Entry<String, SipSessionImpl> entry 2542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : mSessionMap.entrySet()) { 2552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (entry.getValue() == s) { 2562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang key = entry.getKey(); 2572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.remove(key); 2582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 262c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if ((s != null) && isLoggable(s)) { 263c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, "remove session " + session + " @key '" + key + "'"); 264c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan for (String k : mSessionMap.keySet()) { 265c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, " " + k + ": " + mSessionMap.get(k)); 266c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 2672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processRequest(RequestEvent event) { 2712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processResponse(ResponseEvent event) { 2752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processIOException(IOExceptionEvent event) { 2792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processTimeout(TimeoutEvent event) { 2832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processTransactionTerminated(TransactionTerminatedEvent event) { 2872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processDialogTerminated(DialogTerminatedEvent event) { 2912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void process(EventObject event) { 2952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl session = getSipSession(event); 2962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 297c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan boolean isLoggable = isLoggable(session, event); 298c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan boolean processed = (session != null) && session.process(event); 299c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (isLoggable && processed) { 30097963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan Log.d(TAG, "new state after: " 30184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan + SipSession.State.toString(session.mState)); 3022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 304903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Log.w(TAG, "event process error: " + event, e); 3052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang session.onError(e); 3062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 30995b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh private String extractContent(Message message) { 31095b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh // Currently we do not support secure MIME bodies. 31195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh byte[] bytes = message.getRawContent(); 31295b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh if (bytes != null) { 31395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh try { 31495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh if (message instanceof SIPMessage) { 31595b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return ((SIPMessage) message).getMessageContent(); 31695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } else { 31795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return new String(bytes, "UTF-8"); 31895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 31995b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } catch (UnsupportedEncodingException e) { 32095b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 32195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 32295b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return null; 32395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 32495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh 3252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class SipSessionCallReceiverImpl extends SipSessionImpl { 3262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionCallReceiverImpl(ISipSessionListener listener) { 3272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(listener); 3282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean process(EventObject evt) throws SipException { 331c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " 33284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan + SipSession.State.toString(mState) + ": processing " 33397963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan + log(evt)); 3342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.INVITE, evt)) { 3352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent event = (RequestEvent) evt; 3362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl newSession = new SipSessionImpl(mProxy); 3372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mServerTransaction = mSipHelper.sendRinging(event, 3382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag()); 3392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mDialog = newSession.mServerTransaction.getDialog(); 3402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mInviteReceived = event; 3412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerProfile = createPeerProfile(event.getRequest()); 34284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan newSession.mState = SipSession.State.INCOMING_CALL; 3432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerSessionDescription = 34495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh extractContent(event.getRequest()); 3452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(newSession); 3462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRinging(newSession, newSession.mPeerProfile, 3472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerSessionDescription); 3482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 3490b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang } else if (isRequestEvent(Request.OPTIONS, evt)) { 3500b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 3510b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang return true; 3522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 3532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 3542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang class SipSessionImpl extends ISipSession.Stub { 3592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProfile mPeerProfile; 3602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 36184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan int mState = SipSession.State.READY_TO_CALL; 3622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent mInviteReceived; 3632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Dialog mDialog; 3642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ServerTransaction mServerTransaction; 3652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ClientTransaction mClientTransaction; 36695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh String mPeerSessionDescription; 3672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang boolean mInCall; 3682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang boolean mReRegisterFlag = false; 3699352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan SessionTimer mTimer; 3709352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 3719352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan // lightweight timer 3729352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan class SessionTimer { 3739352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private boolean mRunning = true; 3749352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 3759352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan void start(final int timeout) { 3769352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan new Thread(new Runnable() { 3779352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void run() { 3789352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan sleep(timeout); 3799352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan if (mRunning) timeout(); 3809352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 38184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan }, "SipSessionTimerThread").start(); 3829352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 3839352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 3849352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan synchronized void cancel() { 3859352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mRunning = false; 3869352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan this.notify(); 3879352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 3889352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 3899352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private void timeout() { 3909352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan synchronized (SipSessionGroup.this) { 3919352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan onError(SipErrorCode.TIME_OUT, "Session timed out!"); 3929352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 3939352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 3949352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 3959352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private synchronized void sleep(int timeout) { 3969352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan try { 3979352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan this.wait(timeout * 1000); 3989352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } catch (InterruptedException e) { 3999352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan Log.e(TAG, "session timer interrupted!"); 4009352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4019352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4029352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionImpl(ISipSessionListener listener) { 4052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang setListener(listener); 4062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl duplicate() { 4092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new SipSessionImpl(mProxy.getListener()); 4102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void reset() { 4132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInCall = false; 4142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang removeSipSession(this); 4152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPeerProfile = null; 41684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.READY_TO_CALL; 4172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInviteReceived = null; 4182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = null; 4192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = null; 4202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = null; 4212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPeerSessionDescription = null; 4229352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 4239352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan cancelSessionTimer(); 4242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean isInCall() { 4272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mInCall; 4282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getLocalIp() { 4312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalIp; 4322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getLocalProfile() { 4352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile; 4362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getPeerProfile() { 4392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mPeerProfile; 4402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getCallId() { 4432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return SipHelper.getCallId(getTransaction()); 4442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Transaction getTransaction() { 4472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mClientTransaction != null) return mClientTransaction; 4482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mServerTransaction != null) return mServerTransaction; 4492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return null; 4502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 45297963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan public int getState() { 45397963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan return mState; 4542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void setListener(ISipSessionListener listener) { 4572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.setListener((listener instanceof SipSessionListenerProxy) 4582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ? ((SipSessionListenerProxy) listener).getListener() 4592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : listener); 4602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 462dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan // process the command in a new thread 463dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan private void doCommandAsync(final EventObject command) { 464dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan new Thread(new Runnable() { 465dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan public void run() { 466dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan try { 467dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan processCommand(command); 468dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } catch (SipException e) { 469903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Log.w(TAG, "command error: " + command, e); 4703d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(e); 471dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 472dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 47384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan }, "SipSessionAsyncCmdThread").start(); 474dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 475dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan 4769352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void makeCall(SipProfile peerProfile, String sessionDescription, 4779352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan int timeout) { 4789352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription, 4799352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan timeout)); 4802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4829352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void answerCall(String sessionDescription, int timeout) { 4832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 4849352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan processCommand(new MakeCallCommand(mPeerProfile, 4859352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan sessionDescription, timeout)); 4862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (SipException e) { 4872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onError(e); 4882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void endCall() { 492dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(END_CALL); 4932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4959352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void changeCall(String sessionDescription, int timeout) { 4969352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription, 4979352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan timeout)); 4989352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4999352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 5009352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void changeCallWithTimeout( 5019352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan String sessionDescription, int timeout) { 5029352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription, 5039352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan timeout)); 5042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void register(int duration) { 507dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(new RegisterCommand(duration)); 5082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void unregister() { 511dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(DEREGISTER); 5122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean isReRegisterRequired() { 5152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mReRegisterFlag; 5162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void clearReRegisterRequired() { 5192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mReRegisterFlag = false; 5202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void sendKeepAlive() { 52384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.PINGING; 5242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 5252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processCommand(new OptionsCommand()); 52684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan while (SipSession.State.PINGING == mState) { 5272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Thread.sleep(1000); 5282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (SipException e) { 5302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "sendKeepAlive failed", e); 5312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (InterruptedException e) { 5322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "sendKeepAlive interrupted", e); 5332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processCommand(EventObject command) throws SipException { 5372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (!process(command)) { 5383d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.IN_PROGRESS, 5393d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan "cannot initiate a new transaction to execute: " 5403d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan + command); 5412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang protected String generateTag() { 5452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // 32-bit randomness 5462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return String.valueOf((long) (Math.random() * 0x100000000L)); 5472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String toString() { 5502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 5512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String s = super.toString(); 55297963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan return s.substring(s.indexOf("@")) + ":" 55384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan + SipSession.State.toString(mState); 5542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 5552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return super.toString(); 5562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean process(EventObject evt) throws SipException { 560c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " 56184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan + SipSession.State.toString(mState) + ": processing " 56297963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan + log(evt)); 5632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipSessionGroup.this) { 5642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isClosed()) return false; 5652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Dialog dialog = null; 5672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof RequestEvent) { 5682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang dialog = ((RequestEvent) evt).getDialog(); 5692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 5702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang dialog = ((ResponseEvent) evt).getDialog(); 5712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (dialog != null) mDialog = dialog; 5732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang boolean processed; 5752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (mState) { 57784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.REGISTERING: 57884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.DEREGISTERING: 5792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = registeringToReady(evt); 5802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 58184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.PINGING: 5822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = keepAliveProcess(evt); 5832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 58484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.READY_TO_CALL: 5852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = readyForCall(evt); 5862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 58784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.INCOMING_CALL: 5882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = incomingCall(evt); 5892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 59084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.INCOMING_CALL_ANSWERING: 5912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = incomingCallToInCall(evt); 5922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 59384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL: 59484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL_RING_BACK: 5952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = outgoingCall(evt); 5962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 59784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL_CANCELING: 5982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = outgoingCallToReady(evt); 5992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 60084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.IN_CALL: 6012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = inCall(evt); 6022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 6032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 6042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = false; 6052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (processed || processExceptions(evt)); 6072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean processExceptions(EventObject evt) throws SipException { 6112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.BYE, evt)) { 6122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // terminate the call whenever a BYE is received 6132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 6142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 6152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 6162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 6172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, 6182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); 6192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 6202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof TransactionTerminatedEvent) { 621025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if (isCurrentTransaction((TransactionTerminatedEvent) evt)) { 622025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if (evt instanceof TimeoutEvent) { 623025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan processTimeout((TimeoutEvent) evt); 624025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } else { 625025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan processTransactionTerminated( 626025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan (TransactionTerminatedEvent) evt); 627025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 628025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return true; 6292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6300b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang } else if (isRequestEvent(Request.OPTIONS, evt)) { 6310b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 6320b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang return true; 6332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof DialogTerminatedEvent) { 6342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processDialogTerminated((DialogTerminatedEvent) evt); 6352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 6362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 6382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processDialogTerminated(DialogTerminatedEvent event) { 6412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mDialog == event.getDialog()) { 6422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onError(new SipException("dialog terminated")); 6432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 6442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, "not the current dialog; current=" + mDialog 6452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + ", terminated=" + event.getDialog()); 6462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 649025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan private boolean isCurrentTransaction(TransactionTerminatedEvent event) { 650025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Transaction current = event.isServerTransaction() 651025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan ? mServerTransaction 652025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan : mClientTransaction; 653025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Transaction target = event.isServerTransaction() 654025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan ? event.getServerTransaction() 655025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan : event.getClientTransaction(); 656025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan 657025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if ((current != target) && (mState != SipSession.State.PINGING)) { 658025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Log.d(TAG, "not the current transaction; current=" 659025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan + toString(current) + ", target=" + toString(target)); 660025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return false; 661025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } else if (current != null) { 662025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Log.d(TAG, "transaction terminated: " + toString(current)); 663025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return true; 664fccd5bc78f94b7dcfbcf78ddca83719c9cd1a74fHung-ying Tyan } else { 665fccd5bc78f94b7dcfbcf78ddca83719c9cd1a74fHung-ying Tyan // no transaction; shouldn't be here; ignored 666fccd5bc78f94b7dcfbcf78ddca83719c9cd1a74fHung-ying Tyan return true; 667025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 668025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 669025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan 670025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan private String toString(Transaction transaction) { 671025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if (transaction == null) return "null"; 672025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Request request = transaction.getRequest(); 673025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Dialog dialog = transaction.getDialog(); 674025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan CSeqHeader cseq = (CSeqHeader) request.getHeader(CSeqHeader.NAME); 675025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return String.format("req=%s,%s,s=%s,ds=%s,", request.getMethod(), 676025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan cseq.getSeqNumber(), transaction.getState(), 677025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan ((dialog == null) ? "-" : dialog.getState())); 678025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 679025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan 6803d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void processTransactionTerminated( 6813d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan TransactionTerminatedEvent event) { 6823d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan switch (mState) { 68384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.IN_CALL: 68484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.READY_TO_CALL: 6853d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, "Transaction terminated; do nothing"); 6863d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 6873d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 6883d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, "Transaction terminated early: " + this); 6893d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.TRANSACTION_TERMINTED, 6903d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan "transaction terminated"); 6913d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 6923d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 6933d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 6942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processTimeout(TimeoutEvent event) { 695025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Log.d(TAG, "processing Timeout..."); 6962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (mState) { 69784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.REGISTERING: 69884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.DEREGISTERING: 6993d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 7003d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistrationTimeout(this); 7013d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 70284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.INCOMING_CALL: 70384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.INCOMING_CALL_ANSWERING: 70484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL: 70584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL_CANCELING: 7063d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.TIME_OUT, event.toString()); 7073d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 70884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.PINGING: 7093d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 7103d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mReRegisterFlag = true; 71184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.READY_TO_CALL; 7123d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 7132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7143d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 7153d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, " do nothing"); 7163d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 7172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int getExpiryTime(Response response) { 7212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int expires = EXPIRY_TIME; 7222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ExpiresHeader expiresHeader = (ExpiresHeader) 7232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang response.getHeader(ExpiresHeader.NAME); 7242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expiresHeader != null) expires = expiresHeader.getExpires(); 7252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang expiresHeader = (ExpiresHeader) 7262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang response.getHeader(MinExpiresHeader.NAME); 7272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expiresHeader != null) { 7282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang expires = Math.max(expires, expiresHeader.getExpires()); 7292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expires; 7312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean keepAliveProcess(EventObject evt) throws SipException { 7342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof OptionsCommand) { 7352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendKeepAlive(mLocalProfile, 7362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag()); 7372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 7382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 7392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 7412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return parseOptionsResult(evt); 7422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 7442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean parseOptionsResult(EventObject evt) { 7472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.OPTIONS, evt)) { 7482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 7492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int rPort = getRPortFromResponse(event.getResponse()); 7502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (rPort != -1) { 7512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mRPort == 0) mRPort = rPort; 7522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mRPort != rPort) { 7532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mReRegisterFlag = true; 754c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.w(TAG, String.format( 755c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan "rport is changed: %d <> %d", mRPort, rPort)); 7562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRPort = rPort; 7572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 758c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG_PING) Log.w(TAG, "rport is the same: " + rPort); 7592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 761c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.w(TAG, "peer did not respond rport"); 7622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7633d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 7642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 7672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int getRPortFromResponse(Response response) { 7702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ViaHeader viaHeader = (ViaHeader)(response.getHeader( 7712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SIPHeaderNames.VIA)); 7722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (viaHeader == null) ? -1 : viaHeader.getRPort(); 7732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean registeringToReady(EventObject evt) 7762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 7772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.REGISTER, evt)) { 7782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 7792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 7802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 7822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (statusCode) { 7832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.OK: 78497963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan int state = mState; 78584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan onRegistrationDone((state == SipSession.State.REGISTERING) 7862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ? getExpiryTime(((ResponseEvent) evt).getResponse()) 7872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : -1); 7882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLastNonce = null; 7892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRPort = 0; 7902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.UNAUTHORIZED: 7922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.PROXY_AUTHENTICATION_REQUIRED: 793903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (!handleAuthentication(event)) { 79488203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan if (mLastNonce == null) { 79588203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan onRegistrationFailed(SipErrorCode.SERVER_ERROR, 79688203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan "server does not provide challenge"); 79788203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan } else { 79888203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan Log.v(TAG, "Incorrect username/password"); 79988203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan onRegistrationFailed( 80088203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan SipErrorCode.INVALID_CREDENTIALS, 80188203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan "incorrect username or password"); 80288203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan } 8032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 8062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 500) { 8073d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(response); 8082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 8132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 815903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private boolean handleAuthentication(ResponseEvent event) 816903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan throws SipException { 817903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Response response = event.getResponse(); 818903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan String nonce = getNonceFromResponse(response); 819903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (((nonce != null) && nonce.equals(mLastNonce)) || 8207d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang (nonce == null)) { 8217d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang mLastNonce = nonce; 822903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return false; 823903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 824903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mClientTransaction = mSipHelper.handleChallenge( 825903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan event, getAccountManager()); 826903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 827903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mLastNonce = nonce; 828903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return true; 829903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 830903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 831903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 83200a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan private boolean crossDomainAuthenticationRequired(Response response) { 83300a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan String realm = getRealmFromResponse(response); 83400a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan if (realm == null) realm = ""; 83500a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan return !mLocalProfile.getSipDomain().trim().equals(realm.trim()); 83600a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan } 83700a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan 8382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private AccountManager getAccountManager() { 8392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new AccountManager() { 8402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public UserCredentials getCredentials(ClientTransaction 8412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang challengedTransaction, String realm) { 8422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new UserCredentials() { 8432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getUserName() { 8442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getUserName(); 8452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getPassword() { 8482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mPassword; 8492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getSipDomain() { 8522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getSipDomain(); 8532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang }; 8552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang }; 8572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 85900a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan private String getRealmFromResponse(Response response) { 86000a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader( 86100a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan SIPHeaderNames.WWW_AUTHENTICATE); 86200a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan if (wwwAuth != null) return wwwAuth.getRealm(); 86300a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( 86400a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan SIPHeaderNames.PROXY_AUTHENTICATE); 86500a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan return (proxyAuth == null) ? null : proxyAuth.getRealm(); 86600a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan } 86700a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan 8682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String getNonceFromResponse(Response response) { 8697d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader( 8707d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang SIPHeaderNames.WWW_AUTHENTICATE); 8717d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang if (wwwAuth != null) return wwwAuth.getNonce(); 8727d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( 8737d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang SIPHeaderNames.PROXY_AUTHENTICATE); 8747d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang return (proxyAuth == null) ? null : proxyAuth.getNonce(); 8752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean readyForCall(EventObject evt) throws SipException { 8782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect MakeCallCommand, RegisterCommand, DEREGISTER 8792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof MakeCallCommand) { 8802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang MakeCallCommand cmd = (MakeCallCommand) evt; 8812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPeerProfile = cmd.getPeerProfile(); 8822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendInvite(mLocalProfile, 88395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerProfile, cmd.getSessionDescription(), 88495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh generateTag()); 8852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 8862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 88784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.OUTGOING_CALL; 8882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onCalling(this); 8899352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan startSessionTimer(cmd.getTimeout()); 8902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof RegisterCommand) { 8922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int duration = ((RegisterCommand) evt).getDuration(); 8932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 8942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag(), duration); 8952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 8962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 89784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.REGISTERING; 8982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistering(this); 8992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (DEREGISTER == evt) { 9012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 9022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag(), 0); 9032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 9042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 90584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.DEREGISTERING; 9062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistering(this); 9072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 9102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean incomingCall(EventObject evt) throws SipException { 9132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect MakeCallCommand(answering) , END_CALL cmd , Cancel 9142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof MakeCallCommand) { 9152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // answer call 9162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = mSipHelper.sendInviteOk(mInviteReceived, 9172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalProfile, 9182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ((MakeCallCommand) evt).getSessionDescription(), 9192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction); 92084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.INCOMING_CALL_ANSWERING; 9219352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan startSessionTimer(((MakeCallCommand) evt).getTimeout()); 9222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (END_CALL == evt) { 9242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteBusyHere(mInviteReceived, 9252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction); 9262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 9272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 9292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent event = (RequestEvent) evt; 9302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse(event, Response.OK); 9312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteRequestTerminated( 9322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInviteReceived.getRequest(), mServerTransaction); 9332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 9342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 9372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean incomingCallToInCall(EventObject evt) 9402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 9412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect ACK, CANCEL request 9422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.ACK, evt)) { 9432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang establishCall(); 9442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 9462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // http://tools.ietf.org/html/rfc3261#section-9.2 9472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // Final response has been sent; do nothing here. 9482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 9512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean outgoingCall(EventObject evt) throws SipException { 9542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.INVITE, evt)) { 9552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 9562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 9572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 9592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (statusCode) { 9602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.RINGING: 9616057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan case Response.CALL_IS_BEING_FORWARDED: 9626057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan case Response.QUEUED: 9636057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan case Response.SESSION_PROGRESS: 9646057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan // feedback any provisional responses (except TRYING) as 9656057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan // ring back for better UX 96684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan if (mState == SipSession.State.OUTGOING_CALL) { 96784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.OUTGOING_CALL_RING_BACK; 9682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRingingBack(this); 9699352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan cancelSessionTimer(); 9702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.OK: 9732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteAck(event, mDialog); 97495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerSessionDescription = extractContent(response); 9752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang establishCall(); 9762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9770e0633828928481658c0e09e5893f6214b57ba38Chung-yih Wang case Response.UNAUTHORIZED: 9782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.PROXY_AUTHENTICATION_REQUIRED: 97900a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan if (crossDomainAuthenticationRequired(response)) { 98000a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan onError(SipErrorCode.CROSS_DOMAIN_AUTHENTICATION, 98100a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan getRealmFromResponse(response)); 98200a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan } else if (handleAuthentication(event)) { 983903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan addSipSession(this); 98488203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan } else if (mLastNonce == null) { 9859352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan onError(SipErrorCode.SERVER_ERROR, 98688203cb111cd9605edcdedb402f8f2a96f8f01e1Hung-ying Tyan "server does not provide challenge"); 987903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 9889352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan onError(SipErrorCode.INVALID_CREDENTIALS, 989903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan "incorrect username or password"); 990903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 9912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.REQUEST_PENDING: 9932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: 9942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-14.1; re-schedule invite 9952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 9972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 400) { 9982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // error: an ack is sent automatically by the stack 999903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan onError(response); 10002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (statusCode >= 300) { 10022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: handle 3xx (redirect) 10032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 10042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (END_CALL == evt) { 10092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // RFC says that UA should not send out cancel when no 10102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // response comes back yet. We are cheating for not checking 10112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // response. 10122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendCancel(mClientTransaction); 101384a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.OUTGOING_CALL_CANCELING; 10149352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan startSessionTimer(CANCEL_CALL_TIMER); 10152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean outgoingCallToReady(EventObject evt) 10212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 10222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 10232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 10242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 10252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 10262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.CANCEL, evt)) { 1027025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if (statusCode == Response.OK) { 1028025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan // do nothing; wait for REQUEST_TERMINATED 1029025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return true; 1030025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 1031025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } else if (expectResponse(Request.INVITE, evt)) { 10329352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan switch (statusCode) { 10339352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan case Response.OK: 1034025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan outgoingCall(evt); // abort Cancel 10359352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan return true; 10369352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan case Response.REQUEST_TERMINATED: 10379352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan endCallNormally(); 10389352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan return true; 10392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 10412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 400) { 10453d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(response); 10462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof TransactionTerminatedEvent) { 10492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-14.1: 10502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // if re-invite gets timed out, terminate the dialog; but 10512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // re-invite is not reliable, just let it go and pretend 10522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // nothing happened. 10532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onError(new SipException("timed out")); 10542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean inCall(EventObject evt) throws SipException { 10592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect END_CALL cmd, BYE request, hold call (MakeCallCommand) 10602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // OK retransmission is handled in SipStack 10612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (END_CALL == evt) { 10622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-15.1.1 10632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendBye(mDialog); 10642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 10652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.INVITE, evt)) { 10672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // got Re-INVITE 10682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent event = mInviteReceived = (RequestEvent) evt; 106984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.INCOMING_CALL; 107095b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerSessionDescription = extractContent(event.getRequest()); 10712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = null; 10722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription); 10732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.BYE, evt)) { 10752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 10762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 10772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof MakeCallCommand) { 10792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // to change call 10802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendReinvite(mDialog, 10812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ((MakeCallCommand) evt).getSessionDescription()); 108284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.OUTGOING_CALL; 10839352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan startSessionTimer(((MakeCallCommand) evt).getTimeout()); 10842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10899352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan // timeout in seconds 10909352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private void startSessionTimer(int timeout) { 10919352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan if (timeout > 0) { 10929352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimer = new SessionTimer(); 10939352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimer.start(timeout); 10949352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 10959352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 10969352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 10979352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private void cancelSessionTimer() { 10989352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan if (mTimer != null) { 10999352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimer.cancel(); 11009352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimer = null; 11019352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 11029352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 11039352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 1104903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private String createErrorMessage(Response response) { 1105624d5b4e8c20516516d0bff74479b9f5abdfe61cHung-ying Tyan return String.format("%s (%d)", response.getReasonPhrase(), 1106624d5b4e8c20516516d0bff74479b9f5abdfe61cHung-ying Tyan response.getStatusCode()); 1107903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1108903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 11092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void establishCall() { 111084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.IN_CALL; 11112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInCall = true; 11129352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan cancelSessionTimer(); 11132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onCallEstablished(this, mPeerSessionDescription); 11142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 111697963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private void fallbackToPreviousInCall(int errorCode, String message) { 111784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.IN_CALL; 111897963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan mProxy.onCallChangeFailed(this, errorCode, message); 11193d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 11203d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 11212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void endCallNormally() { 11222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(); 11232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onCallEnded(this); 11242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 112697963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private void endCallOnError(int errorCode, String message) { 11272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(); 112897963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan mProxy.onError(this, errorCode, message); 1129903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1130903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 1131903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private void endCallOnBusy() { 1132903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan reset(); 1133903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mProxy.onCallBusy(this); 11342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 113697963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private void onError(int errorCode, String message) { 11379352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan cancelSessionTimer(); 11383d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan switch (mState) { 113984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.REGISTERING: 114084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.DEREGISTERING: 11413d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(errorCode, message); 11423d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 11433d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 1144d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan if ((errorCode != SipErrorCode.DATA_CONNECTION_LOST) 1145d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan && mInCall) { 11463d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan fallbackToPreviousInCall(errorCode, message); 11473d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } else { 11483d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan endCallOnError(errorCode, message); 11493d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 11502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11533d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 11543d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void onError(Throwable exception) { 11553d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan exception = getRootCause(exception); 11563d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(getErrorCode(exception), exception.toString()); 11573d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 11583d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 1159903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private void onError(Response response) { 11603d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan int statusCode = response.getStatusCode(); 1161ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan if (!mInCall && (statusCode == Response.BUSY_HERE)) { 11623d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan endCallOnBusy(); 1163903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 11643d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(getErrorCode(statusCode), createErrorMessage(response)); 1165903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1166903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1167903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 116897963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private int getErrorCode(int responseStatusCode) { 1169903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan switch (responseStatusCode) { 1170ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.TEMPORARILY_UNAVAILABLE: 1171ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.FORBIDDEN: 1172ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.GONE: 1173903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.NOT_FOUND: 1174ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.NOT_ACCEPTABLE: 1175ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.NOT_ACCEPTABLE_HERE: 1176ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan return SipErrorCode.PEER_NOT_REACHABLE; 1177ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan 1178ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.REQUEST_URI_TOO_LONG: 1179903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.ADDRESS_INCOMPLETE: 1180ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.AMBIGUOUS: 1181903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.INVALID_REMOTE_URI; 1182ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan 1183903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.REQUEST_TIMEOUT: 1184903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.TIME_OUT; 1185ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan 1186903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan default: 1187903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (responseStatusCode < 500) { 1188903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 1189903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 1190903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.SERVER_ERROR; 1191903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1192903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1193903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1194903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 1195903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private Throwable getRootCause(Throwable exception) { 1196903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Throwable cause = exception.getCause(); 1197903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan while (cause != null) { 1198903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception = cause; 1199903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan cause = exception.getCause(); 1200903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1201903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return exception; 1202903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1203903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 120497963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private int getErrorCode(Throwable exception) { 1205903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan String message = exception.getMessage(); 1206903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (exception instanceof UnknownHostException) { 1207903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.INVALID_REMOTE_URI; 1208903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else if (exception instanceof IOException) { 1209903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.SOCKET_ERROR; 1210903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 1211903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 1212903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1213903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1214903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 12152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void onRegistrationDone(int duration) { 12163d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 12172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistrationDone(this, duration); 12182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 122097963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private void onRegistrationFailed(int errorCode, String message) { 12213d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 122297963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan mProxy.onRegistrationFailed(this, errorCode, message); 1223903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1224903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 12252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void onRegistrationFailed(Throwable exception) { 12263d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 1227903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception = getRootCause(exception); 1228903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan onRegistrationFailed(getErrorCode(exception), 1229903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception.toString()); 12302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12313d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 12323d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void onRegistrationFailed(Response response) { 12333d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 12343d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan int statusCode = response.getStatusCode(); 12353d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(getErrorCode(statusCode), 12363d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan createErrorMessage(response)); 12373d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 12382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 12412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a request event matching the specified 12422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * method; false otherwise 12432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 12442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean isRequestEvent(String method, EventObject event) { 12452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 12462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (event instanceof RequestEvent) { 12472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent requestEvent = (RequestEvent) event; 12482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return method.equals(requestEvent.getRequest().getMethod()); 12492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 12512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 12532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static String getCseqMethod(Message message) { 12562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((CSeqHeader) message.getHeader(CSeqHeader.NAME)).getMethod(); 12572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 12602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a response event and the CSeqHeader method 12612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * match the given arguments; false otherwise 12622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 12632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean expectResponse( 12642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String expectedMethod, EventObject evt) { 12652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 12662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 12672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 12682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 12692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 12712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 12742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a response event and the response code and 12752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * CSeqHeader method match the given arguments; false otherwise 12762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 12772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean expectResponse( 12782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int responseCode, String expectedMethod, EventObject evt) { 12792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 12802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 12812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 12822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (response.getStatusCode() == responseCode) { 12832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 12842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 12872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static SipProfile createPeerProfile(Request request) 12902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 12912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 12922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang FromHeader fromHeader = 12932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang (FromHeader) request.getHeader(FromHeader.NAME); 12942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Address address = fromHeader.getAddress(); 12952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipURI uri = (SipURI) address.getURI(); 12962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String username = uri.getUser(); 12972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (username == null) username = ANONYMOUS; 12982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new SipProfile.Builder(username, uri.getHost()) 12992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang .setPort(uri.getPort()) 13002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang .setDisplayName(address.getDisplayName()) 13012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang .build(); 130299bf4e45c4566172189735b34b368b76660ca57aHung-ying Tyan } catch (IllegalArgumentException e) { 13032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("createPeerProfile()", e); 13042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (ParseException e) { 13052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("createPeerProfile()", e); 13062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1309c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan private static boolean isLoggable(SipSessionImpl s) { 1310c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (s != null) { 1311c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan switch (s.mState) { 131284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.PINGING: 1313c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG_PING; 1314c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1315c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1316c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG; 1317c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1318c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan 1319c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan private static boolean isLoggable(SipSessionImpl s, EventObject evt) { 1320c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (!isLoggable(s)) return false; 1321c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (evt == null) return false; 1322c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan 1323c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (evt instanceof OptionsCommand) { 1324c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG_PING; 1325c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } else if (evt instanceof ResponseEvent) { 1326c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Response response = ((ResponseEvent) evt).getResponse(); 1327c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (Request.OPTIONS.equals(response.getHeader(CSeqHeader.NAME))) { 1328c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG_PING; 1329c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1330c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG; 1331c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } else if (evt instanceof RequestEvent) { 1332c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG; 1333c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1334c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return false; 1335c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1336c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan 13372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static String log(EventObject evt) { 13382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof RequestEvent) { 13392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((RequestEvent) evt).getRequest().toString(); 13402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 13412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((ResponseEvent) evt).getResponse().toString(); 13422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 13432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return evt.toString(); 13442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class OptionsCommand extends EventObject { 13482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public OptionsCommand() { 13492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(SipSessionGroup.this); 13502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class RegisterCommand extends EventObject { 13542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int mDuration; 13552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public RegisterCommand(int duration) { 13572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(SipSessionGroup.this); 13582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDuration = duration; 13592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public int getDuration() { 13622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mDuration; 13632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class MakeCallCommand extends EventObject { 136795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh private String mSessionDescription; 13689352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private int mTimeout; // in seconds 13692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public MakeCallCommand(SipProfile peerProfile, 137195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh String sessionDescription) { 13729352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan this(peerProfile, sessionDescription, -1); 13739352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 13749352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 13759352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public MakeCallCommand(SipProfile peerProfile, 13769352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan String sessionDescription, int timeout) { 13772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(peerProfile); 13782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionDescription = sessionDescription; 13799352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimeout = timeout; 13802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getPeerProfile() { 13832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (SipProfile) getSource(); 13842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 138695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh public String getSessionDescription() { 13872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mSessionDescription; 13882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13909352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public int getTimeout() { 13919352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan return mTimeout; 13929352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 13939352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 13942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang} 1395