SipSessionGroup.java revision 3d7606aa607b24817e37c264f2141ed7b2d50be0
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; 222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.header.WWWAuthenticate; 2395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yehimport gov.nist.javax.sip.message.SIPMessage; 242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipSession; 262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipSessionListener; 272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SessionDescription; 28903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyanimport android.net.sip.SipErrorCode; 292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SipProfile; 302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SipSessionAdapter; 312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SipSessionState; 322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.text.TextUtils; 332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.util.Log; 342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.io.IOException; 3695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yehimport java.io.UnsupportedEncodingException; 372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.net.DatagramSocket; 38903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyanimport java.net.UnknownHostException; 392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.text.ParseException; 402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Collection; 412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.EventObject; 422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.HashMap; 432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Map; 442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Properties; 452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.TooManyListenersException; 462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ClientTransaction; 482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.Dialog; 492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.DialogTerminatedEvent; 502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.IOExceptionEvent; 512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.InvalidArgumentException; 522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ListeningPoint; 532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.RequestEvent; 542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ResponseEvent; 552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ServerTransaction; 562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipException; 572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipFactory; 582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipListener; 592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipProvider; 602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.SipStack; 612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.TimeoutEvent; 622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.Transaction; 632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.TransactionState; 642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.TransactionTerminatedEvent; 65903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyanimport javax.sip.TransactionUnavailableException; 662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.address.Address; 672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.address.SipURI; 682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.CSeqHeader; 692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.ExpiresHeader; 702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.FromHeader; 712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.MinExpiresHeader; 722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.header.ViaHeader; 732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.message.Message; 742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.message.Request; 752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.message.Response; 762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang/** 782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Manages {@link ISipSession}'s for a SIP account. 792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangclass SipSessionGroup implements SipListener { 812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final String TAG = "SipSession"; 822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final String ANONYMOUS = "anonymous"; 83903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private static final String SERVER_ERROR_PREFIX = "Response: "; 842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final int EXPIRY_TIME = 3600; 852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject DEREGISTER = new EventObject("Deregister"); 872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject END_CALL = new EventObject("End call"); 882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject HOLD_CALL = new EventObject("Hold call"); 892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject CONTINUE_CALL 902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang = new EventObject("Continue call"); 912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private final SipProfile mLocalProfile; 932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private final String mPassword; 942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipStack mSipStack; 962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipHelper mSipHelper; 972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String mLastNonce; 982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int mRPort; 992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // session that processes INVITE requests 1012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipSessionImpl mCallReceiverSession; 1022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String mLocalIp; 1032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // call-id-to-SipSession map 1052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Map<String, SipSessionImpl> mSessionMap = 1062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang new HashMap<String, SipSessionImpl>(); 1072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 1092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @param myself the local profile with password crossed out 1102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @param password the password of the profile 1112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @throws IOException if cannot assign requested address 1122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 1132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionGroup(String localIp, SipProfile myself, String password) 1142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException, IOException { 1152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalProfile = myself; 1162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPassword = password; 1172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(localIp); 1182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang void reset(String localIp) throws SipException, IOException { 1212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalIp = localIp; 1222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (localIp == null) return; 1232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProfile myself = mLocalProfile; 1252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipFactory sipFactory = SipFactory.getInstance(); 1262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Properties properties = new Properties(); 1272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang properties.setProperty("javax.sip.STACK_NAME", getStackName()); 1282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String outboundProxy = myself.getProxyAddress(); 1292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (!TextUtils.isEmpty(outboundProxy)) { 1305de1d36dd0415c4cf9afdf093a4915951ef6c770Chung-yih Wang Log.v(TAG, "outboundProxy is " + outboundProxy); 1312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang properties.setProperty("javax.sip.OUTBOUND_PROXY", outboundProxy 1322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + ":" + myself.getPort() + "/" + myself.getProtocol()); 1332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipStack stack = mSipStack = sipFactory.createSipStack(properties); 1352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 1372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProvider provider = stack.createSipProvider( 1382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang stack.createListeningPoint(localIp, allocateLocalPort(), 1392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang myself.getProtocol())); 1402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang provider.addSipListener(this); 1412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper = new SipHelper(stack, provider); 1422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (InvalidArgumentException e) { 1432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new IOException(e.getMessage()); 1442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (TooManyListenersException e) { 1452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // must never happen 1462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("SipSessionGroup constructor", e); 1472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " start stack for " + myself.getUriString()); 1492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang stack.start(); 1502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLastNonce = null; 1522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = null; 1532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.clear(); 1542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getLocalProfile() { 1572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile; 1582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getLocalProfileUri() { 1612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getUriString(); 1622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String getStackName() { 1652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return "stack" + System.currentTimeMillis(); 1662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void close() { 1692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " close stack for " + mLocalProfile.getUriString()); 1702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.clear(); 1712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang closeToNotReceiveCalls(); 1722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mSipStack != null) { 1732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipStack.stop(); 1742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipStack = null; 1752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper = null; 1762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized boolean isClosed() { 1802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (mSipStack == null); 1812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // For internal use, require listener not to block in callbacks. 1842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void openToReceiveCalls(ISipSessionListener listener) { 1852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mCallReceiverSession == null) { 1862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = new SipSessionCallReceiverImpl(listener); 1872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 1882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession.setListener(listener); 1892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void closeToNotReceiveCalls() { 1932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = null; 1942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public ISipSession createSession(ISipSessionListener listener) { 1972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (isClosed() ? null : new SipSessionImpl(listener)); 1982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static int allocateLocalPort() throws SipException { 2012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 2022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang DatagramSocket s = new DatagramSocket(); 2032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int localPort = s.getLocalPort(); 2042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang s.close(); 2052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return localPort; 2062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (IOException e) { 2072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("allocateLocalPort()", e); 2082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized SipSessionImpl getSipSession(EventObject event) { 2122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = SipHelper.getCallId(event); 2132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " sesssion key from event: " + key); 2142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " active sessions:"); 2152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang for (String k : mSessionMap.keySet()) { 2162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " ..... '" + k + "': " + mSessionMap.get(k)); 2172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl session = mSessionMap.get(key); 2192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((session != null) ? session : mCallReceiverSession); 2202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void addSipSession(SipSessionImpl newSession) { 2232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang removeSipSession(newSession); 2242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = newSession.getCallId(); 2252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " +++++ add a session with key: '" + key + "'"); 2262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.put(key, newSession); 2272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang for (String k : mSessionMap.keySet()) { 2282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " ..... " + k + ": " + mSessionMap.get(k)); 2292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void removeSipSession(SipSessionImpl session) { 2332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (session == mCallReceiverSession) return; 2342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = session.getCallId(); 2352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl s = mSessionMap.remove(key); 2362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // sanity check 2372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if ((s != null) && (s != session)) { 2382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.w(TAG, "session " + session + " is not associated with key '" 2392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + key + "'"); 2402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.put(key, s); 2412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang for (Map.Entry<String, SipSessionImpl> entry 2422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : mSessionMap.entrySet()) { 2432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (entry.getValue() == s) { 2442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang key = entry.getKey(); 2452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.remove(key); 2462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " remove session " + session + " with key '" + key + "'"); 2502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang for (String k : mSessionMap.keySet()) { 2522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " ..... " + k + ": " + mSessionMap.get(k)); 2532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processRequest(RequestEvent event) { 2572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processResponse(ResponseEvent event) { 2612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processIOException(IOExceptionEvent event) { 2652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processTimeout(TimeoutEvent event) { 2692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processTransactionTerminated(TransactionTerminatedEvent event) { 2732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processDialogTerminated(DialogTerminatedEvent event) { 2772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void process(EventObject event) { 2812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl session = getSipSession(event); 2822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 2832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if ((session != null) && session.process(event)) { 2842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " ~~~~~ new state: " + session.mState); 2852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 2862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, "event not processed: " + event); 2872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 289903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Log.w(TAG, "event process error: " + event, e); 2902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang session.onError(e); 2912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 29495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh private String extractContent(Message message) { 29595b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh // Currently we do not support secure MIME bodies. 29695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh byte[] bytes = message.getRawContent(); 29795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh if (bytes != null) { 29895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh try { 29995b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh if (message instanceof SIPMessage) { 30095b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return ((SIPMessage) message).getMessageContent(); 30195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } else { 30295b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return new String(bytes, "UTF-8"); 30395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 30495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } catch (UnsupportedEncodingException e) { 30595b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 30695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 30795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return null; 30895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 30995b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh 3102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class SipSessionCallReceiverImpl extends SipSessionImpl { 3112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionCallReceiverImpl(ISipSessionListener listener) { 3122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(listener); 3132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean process(EventObject evt) throws SipException { 3162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " ~~~~~ " + this + ": " + mState + ": processing " 3172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + log(evt)); 3182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.INVITE, evt)) { 3192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent event = (RequestEvent) evt; 3202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl newSession = new SipSessionImpl(mProxy); 3212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mServerTransaction = mSipHelper.sendRinging(event, 3222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag()); 3232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mDialog = newSession.mServerTransaction.getDialog(); 3242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mInviteReceived = event; 3252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerProfile = createPeerProfile(event.getRequest()); 3262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mState = SipSessionState.INCOMING_CALL; 3272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerSessionDescription = 32895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh extractContent(event.getRequest()); 3292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(newSession); 3302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRinging(newSession, newSession.mPeerProfile, 3312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerSessionDescription); 3322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 3332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 3342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 3352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang class SipSessionImpl extends ISipSession.Stub { 3402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProfile mPeerProfile; 3412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 3422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionState mState = SipSessionState.READY_TO_CALL; 3432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent mInviteReceived; 3442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Dialog mDialog; 3452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ServerTransaction mServerTransaction; 3462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ClientTransaction mClientTransaction; 34795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh String mPeerSessionDescription; 3482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang boolean mInCall; 3492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang boolean mReRegisterFlag = false; 3502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionImpl(ISipSessionListener listener) { 3522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang setListener(listener); 3532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl duplicate() { 3562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new SipSessionImpl(mProxy.getListener()); 3572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void reset() { 3602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInCall = false; 3612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang removeSipSession(this); 3622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPeerProfile = null; 3632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.READY_TO_CALL; 3642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInviteReceived = null; 3652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = null; 3662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = null; 3672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = null; 3682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPeerSessionDescription = null; 3692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean isInCall() { 3722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mInCall; 3732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getLocalIp() { 3762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalIp; 3772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getLocalProfile() { 3802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile; 3812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getPeerProfile() { 3842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mPeerProfile; 3852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getCallId() { 3882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return SipHelper.getCallId(getTransaction()); 3892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Transaction getTransaction() { 3922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mClientTransaction != null) return mClientTransaction; 3932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mServerTransaction != null) return mServerTransaction; 3942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return null; 3952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getState() { 3982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mState.toString(); 3992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void setListener(ISipSessionListener listener) { 4022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.setListener((listener instanceof SipSessionListenerProxy) 4032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ? ((SipSessionListenerProxy) listener).getListener() 4042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : listener); 4052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 407dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan // process the command in a new thread 408dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan private void doCommandAsync(final EventObject command) { 409dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan new Thread(new Runnable() { 410dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan public void run() { 411dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan try { 412dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan processCommand(command); 413dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } catch (SipException e) { 414903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Log.w(TAG, "command error: " + command, e); 4153d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(e); 416dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 417dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 418dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan }).start(); 419dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 420dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan 4212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void makeCall(SipProfile peerProfile, 42295b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh String sessionDescription) { 423dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync( 424dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan new MakeCallCommand(peerProfile, sessionDescription)); 4252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 42795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh public void answerCall(String sessionDescription) { 4282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 4292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processCommand( 4302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang new MakeCallCommand(mPeerProfile, sessionDescription)); 4312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (SipException e) { 4322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onError(e); 4332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void endCall() { 437dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(END_CALL); 4382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 44095b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh public void changeCall(String sessionDescription) { 441dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync( 442dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan new MakeCallCommand(mPeerProfile, sessionDescription)); 4432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void register(int duration) { 446dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(new RegisterCommand(duration)); 4472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void unregister() { 450dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(DEREGISTER); 4512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean isReRegisterRequired() { 4542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mReRegisterFlag; 4552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void clearReRegisterRequired() { 4582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mReRegisterFlag = false; 4592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void sendKeepAlive() { 4622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.PINGING; 4632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 4642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processCommand(new OptionsCommand()); 4652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang while (SipSessionState.PINGING.equals(mState)) { 4662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Thread.sleep(1000); 4672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (SipException e) { 4692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "sendKeepAlive failed", e); 4702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (InterruptedException e) { 4712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "sendKeepAlive interrupted", e); 4722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processCommand(EventObject command) throws SipException { 4762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (!process(command)) { 4773d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.IN_PROGRESS, 4783d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan "cannot initiate a new transaction to execute: " 4793d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan + command); 4802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang protected String generateTag() { 4842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // 32-bit randomness 4852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return String.valueOf((long) (Math.random() * 0x100000000L)); 4862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String toString() { 4892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 4902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String s = super.toString(); 4912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return s.substring(s.indexOf("@")) + ":" + mState; 4922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 4932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return super.toString(); 4942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean process(EventObject evt) throws SipException { 4982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " ~~~~~ " + this + ": " + mState + ": processing " 4992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + log(evt)); 5002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipSessionGroup.this) { 5012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isClosed()) return false; 5022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Dialog dialog = null; 5042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof RequestEvent) { 5052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang dialog = ((RequestEvent) evt).getDialog(); 5062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 5072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang dialog = ((ResponseEvent) evt).getDialog(); 5082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (dialog != null) mDialog = dialog; 5102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang boolean processed; 5122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (mState) { 5142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case REGISTERING: 5152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case DEREGISTERING: 5162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = registeringToReady(evt); 5172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 5182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case PINGING: 5192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = keepAliveProcess(evt); 5202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 5212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case READY_TO_CALL: 5222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = readyForCall(evt); 5232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 5242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case INCOMING_CALL: 5252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = incomingCall(evt); 5262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 5272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case INCOMING_CALL_ANSWERING: 5282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = incomingCallToInCall(evt); 5292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 5302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case OUTGOING_CALL: 5312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case OUTGOING_CALL_RING_BACK: 5322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = outgoingCall(evt); 5332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 5342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case OUTGOING_CALL_CANCELING: 5352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = outgoingCallToReady(evt); 5362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 5372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case IN_CALL: 5382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = inCall(evt); 5392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 5402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 5412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = false; 5422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (processed || processExceptions(evt)); 5442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean processExceptions(EventObject evt) throws SipException { 5482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.BYE, evt)) { 5492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // terminate the call whenever a BYE is received 5502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 5512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 5522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 5532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 5542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, 5552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); 5562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 5572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof TransactionTerminatedEvent) { 5582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof TimeoutEvent) { 5592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processTimeout((TimeoutEvent) evt); 5602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 5613d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan processTransactionTerminated( 5623d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan (TransactionTerminatedEvent) evt); 5632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 5652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof DialogTerminatedEvent) { 5662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processDialogTerminated((DialogTerminatedEvent) evt); 5672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 5682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 5702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processDialogTerminated(DialogTerminatedEvent event) { 5732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mDialog == event.getDialog()) { 5742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onError(new SipException("dialog terminated")); 5752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 5762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, "not the current dialog; current=" + mDialog 5772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + ", terminated=" + event.getDialog()); 5782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5813d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void processTransactionTerminated( 5823d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan TransactionTerminatedEvent event) { 5833d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan switch (mState) { 5843d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case IN_CALL: 5853d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case READY_TO_CALL: 5863d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, "Transaction terminated; do nothing"); 5873d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 5883d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 5893d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, "Transaction terminated early: " + this); 5903d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.TRANSACTION_TERMINTED, 5913d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan "transaction terminated"); 5923d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 5933d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 5943d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 5952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processTimeout(TimeoutEvent event) { 5962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, "processing Timeout..." + event); 5972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Transaction current = event.isServerTransaction() 5982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ? mServerTransaction 5992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : mClientTransaction; 6002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Transaction target = event.isServerTransaction() 6012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ? event.getServerTransaction() 6022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : event.getClientTransaction(); 6032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if ((current != target) && (mState != SipSessionState.PINGING)) { 6052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, "not the current transaction; current=" + current 6062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + ", timed out=" + target); 6072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return; 6082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (mState) { 6103d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case REGISTERING: 6113d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case DEREGISTERING: 6123d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 6133d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistrationTimeout(this); 6143d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 6153d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case INCOMING_CALL: 6163d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case INCOMING_CALL_ANSWERING: 6173d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case OUTGOING_CALL: 6183d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case OUTGOING_CALL_CANCELING: 6193d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.TIME_OUT, event.toString()); 6203d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 6213d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case PINGING: 6223d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 6233d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mReRegisterFlag = true; 6243d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mState = SipSessionState.READY_TO_CALL; 6253d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 6262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6273d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 6283d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, " do nothing"); 6293d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 6302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int getExpiryTime(Response response) { 6342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int expires = EXPIRY_TIME; 6352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ExpiresHeader expiresHeader = (ExpiresHeader) 6362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang response.getHeader(ExpiresHeader.NAME); 6372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expiresHeader != null) expires = expiresHeader.getExpires(); 6382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang expiresHeader = (ExpiresHeader) 6392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang response.getHeader(MinExpiresHeader.NAME); 6402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expiresHeader != null) { 6412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang expires = Math.max(expires, expiresHeader.getExpires()); 6422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expires; 6442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean keepAliveProcess(EventObject evt) throws SipException { 6472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof OptionsCommand) { 6482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendKeepAlive(mLocalProfile, 6492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag()); 6502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 6512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 6522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 6532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 6542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return parseOptionsResult(evt); 6552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 6572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean parseOptionsResult(EventObject evt) { 6602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.OPTIONS, evt)) { 6612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 6622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int rPort = getRPortFromResponse(event.getResponse()); 6632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (rPort != -1) { 6642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mRPort == 0) mRPort = rPort; 6652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mRPort != rPort) { 6662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mReRegisterFlag = true; 6672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.w(TAG, String.format("rport is changed: %d <> %d", 6682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRPort, rPort)); 6692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRPort = rPort; 6702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 6712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.w(TAG, "rport is the same: " + rPort); 6722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 6742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.w(TAG, "peer did not respect our rport request"); 6752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6763d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 6772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 6782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 6802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int getRPortFromResponse(Response response) { 6832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ViaHeader viaHeader = (ViaHeader)(response.getHeader( 6842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SIPHeaderNames.VIA)); 6852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (viaHeader == null) ? -1 : viaHeader.getRPort(); 6862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean registeringToReady(EventObject evt) 6892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 6902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.REGISTER, evt)) { 6912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 6922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 6932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 6952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (statusCode) { 6962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.OK: 6972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionState state = mState; 6982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onRegistrationDone((state == SipSessionState.REGISTERING) 6992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ? getExpiryTime(((ResponseEvent) evt).getResponse()) 7002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : -1); 7012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLastNonce = null; 7022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRPort = 0; 7032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.UNAUTHORIZED: 7052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.PROXY_AUTHENTICATION_REQUIRED: 706903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (!handleAuthentication(event)) { 7072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.v(TAG, "Incorrect username/password"); 708903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan onRegistrationFailed(SipErrorCode.INVALID_CREDENTIALS, 709903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan "incorrect username or password"); 7102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 7132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 500) { 7143d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(response); 7152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 7202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 722903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private boolean handleAuthentication(ResponseEvent event) 723903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan throws SipException { 724903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Response response = event.getResponse(); 725903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan String nonce = getNonceFromResponse(response); 726903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (((nonce != null) && nonce.equals(mLastNonce)) || 727903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan (nonce == mLastNonce)) { 728903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return false; 729903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 730903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mClientTransaction = mSipHelper.handleChallenge( 731903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan event, getAccountManager()); 732903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 733903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mLastNonce = nonce; 734903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return true; 735903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 736903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 737903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 7382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private AccountManager getAccountManager() { 7392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new AccountManager() { 7402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public UserCredentials getCredentials(ClientTransaction 7412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang challengedTransaction, String realm) { 7422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new UserCredentials() { 7432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getUserName() { 7442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getUserName(); 7452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getPassword() { 7482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mPassword; 7492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getSipDomain() { 7522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getSipDomain(); 7532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang }; 7552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang }; 7572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String getNonceFromResponse(Response response) { 7602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang WWWAuthenticate authHeader = (WWWAuthenticate)(response.getHeader( 7612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SIPHeaderNames.WWW_AUTHENTICATE)); 7622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (authHeader == null) ? null : authHeader.getNonce(); 7632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean readyForCall(EventObject evt) throws SipException { 7662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect MakeCallCommand, RegisterCommand, DEREGISTER 7672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof MakeCallCommand) { 7682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang MakeCallCommand cmd = (MakeCallCommand) evt; 7692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPeerProfile = cmd.getPeerProfile(); 7702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendInvite(mLocalProfile, 77195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerProfile, cmd.getSessionDescription(), 77295b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh generateTag()); 7732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 7742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 7752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.OUTGOING_CALL; 7762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onCalling(this); 7772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof RegisterCommand) { 7792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int duration = ((RegisterCommand) evt).getDuration(); 7802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 7812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag(), duration); 7822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 7832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 7842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.REGISTERING; 7852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistering(this); 7862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (DEREGISTER == evt) { 7882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 7892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag(), 0); 7902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 7912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 7922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.DEREGISTERING; 7932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistering(this); 7942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 7972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean incomingCall(EventObject evt) throws SipException { 8002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect MakeCallCommand(answering) , END_CALL cmd , Cancel 8012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof MakeCallCommand) { 8022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // answer call 8032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = mSipHelper.sendInviteOk(mInviteReceived, 8042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalProfile, 8052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ((MakeCallCommand) evt).getSessionDescription(), 8062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction); 8072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.INCOMING_CALL_ANSWERING; 8082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (END_CALL == evt) { 8102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteBusyHere(mInviteReceived, 8112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction); 8122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 8132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 8152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent event = (RequestEvent) evt; 8162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse(event, Response.OK); 8172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteRequestTerminated( 8182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInviteReceived.getRequest(), mServerTransaction); 8192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 8202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 8232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean incomingCallToInCall(EventObject evt) 8262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 8272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect ACK, CANCEL request 8282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.ACK, evt)) { 8292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang establishCall(); 8302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 8322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // http://tools.ietf.org/html/rfc3261#section-9.2 8332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // Final response has been sent; do nothing here. 8342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 8372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean outgoingCall(EventObject evt) throws SipException { 8402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.INVITE, evt)) { 8412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 8422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 8432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 8452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (statusCode) { 8462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.RINGING: 8472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mState == SipSessionState.OUTGOING_CALL) { 8482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.OUTGOING_CALL_RING_BACK; 8492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRingingBack(this); 8502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.OK: 8532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteAck(event, mDialog); 85495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerSessionDescription = extractContent(response); 8552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang establishCall(); 8562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.PROXY_AUTHENTICATION_REQUIRED: 858903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (handleAuthentication(event)) { 859903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan addSipSession(this); 860903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 861903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan endCallOnError(SipErrorCode.INVALID_CREDENTIALS, 862903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan "incorrect username or password"); 863903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 8642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.REQUEST_PENDING: 8662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: 8672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-14.1; re-schedule invite 8682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 8702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 400) { 8712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // error: an ack is sent automatically by the stack 872903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan onError(response); 8732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (statusCode >= 300) { 8752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: handle 3xx (redirect) 8762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 8772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 8812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (END_CALL == evt) { 8822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // RFC says that UA should not send out cancel when no 8832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // response comes back yet. We are cheating for not checking 8842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // response. 8852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendCancel(mClientTransaction); 8862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.OUTGOING_CALL_CANCELING; 8872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 8902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean outgoingCallToReady(EventObject evt) 8932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 8942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 8952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 8962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 8972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 8982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.CANCEL, evt)) { 8992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode == Response.OK) { 9002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // do nothing; wait for REQUEST_TERMINATED 9012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (expectResponse(Request.INVITE, evt)) { 9042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode == Response.OK) { 9052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang outgoingCall(evt); // abort Cancel 9062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 9092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 9102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 400) { 9133d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(response); 9142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof TransactionTerminatedEvent) { 9172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-14.1: 9182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // if re-invite gets timed out, terminate the dialog; but 9192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // re-invite is not reliable, just let it go and pretend 9202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // nothing happened. 9212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onError(new SipException("timed out")); 9222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 9242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean inCall(EventObject evt) throws SipException { 9272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect END_CALL cmd, BYE request, hold call (MakeCallCommand) 9282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // OK retransmission is handled in SipStack 9292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (END_CALL == evt) { 9302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-15.1.1 9312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendBye(mDialog); 9322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 9332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.INVITE, evt)) { 9352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // got Re-INVITE 9362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent event = mInviteReceived = (RequestEvent) evt; 9372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.INCOMING_CALL; 93895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerSessionDescription = extractContent(event.getRequest()); 9392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = null; 9402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription); 9412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.BYE, evt)) { 9432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 9442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 9452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof MakeCallCommand) { 9472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // to change call 9482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendReinvite(mDialog, 9492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ((MakeCallCommand) evt).getSessionDescription()); 9502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.OUTGOING_CALL; 9512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 9542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 956903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private String createErrorMessage(Response response) { 957903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return String.format(SERVER_ERROR_PREFIX + "%s (%d)", 958903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan response.getReasonPhrase(), response.getStatusCode()); 959903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 960903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 9612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void establishCall() { 9622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mState = SipSessionState.IN_CALL; 9632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInCall = true; 9642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onCallEstablished(this, mPeerSessionDescription); 9652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void fallbackToPreviousInCall(Throwable exception) { 968903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception = getRootCause(exception); 9693d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan fallbackToPreviousInCall(getErrorCode(exception), 970903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception.toString()); 9712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9733d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void fallbackToPreviousInCall(SipErrorCode errorCode, 9743d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan String message) { 9753d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mState = SipSessionState.IN_CALL; 9763d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onCallChangeFailed(this, errorCode.toString(), message); 9773d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 9783d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 9792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void endCallNormally() { 9802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(); 9812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onCallEnded(this); 9822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 984903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private void endCallOnError(SipErrorCode errorCode, String message) { 9852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(); 986903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mProxy.onError(this, errorCode.toString(), message); 987903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 988903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 989903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private void endCallOnBusy() { 990903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan reset(); 991903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mProxy.onCallBusy(this); 9922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9943d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void onError(SipErrorCode errorCode, String message) { 9953d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan switch (mState) { 9963d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case REGISTERING: 9973d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan case DEREGISTERING: 9983d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(errorCode, message); 9993d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 10003d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 10013d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan if (mInCall) { 10023d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan fallbackToPreviousInCall(errorCode, message); 10033d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } else { 10043d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan endCallOnError(errorCode, message); 10053d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 10062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10093d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 10103d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void onError(Throwable exception) { 10113d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan exception = getRootCause(exception); 10123d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(getErrorCode(exception), exception.toString()); 10133d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 10143d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 1015903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private void onError(Response response) { 10163d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan int statusCode = response.getStatusCode(); 10173d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan if (!mInCall && ((statusCode == Response.TEMPORARILY_UNAVAILABLE) 10183d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan || (statusCode == Response.BUSY_HERE))) { 10193d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan endCallOnBusy(); 1020903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 10213d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(getErrorCode(statusCode), createErrorMessage(response)); 1022903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1023903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1024903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 1025903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private SipErrorCode getErrorCode(int responseStatusCode) { 1026903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan switch (responseStatusCode) { 1027903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.NOT_FOUND: 1028903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.ADDRESS_INCOMPLETE: 1029903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.INVALID_REMOTE_URI; 1030903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.REQUEST_TIMEOUT: 1031903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.TIME_OUT; 1032903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan default: 1033903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (responseStatusCode < 500) { 1034903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 1035903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 1036903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.SERVER_ERROR; 1037903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1038903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1039903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1040903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 1041903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private Throwable getRootCause(Throwable exception) { 1042903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Throwable cause = exception.getCause(); 1043903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan while (cause != null) { 1044903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception = cause; 1045903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan cause = exception.getCause(); 1046903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1047903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return exception; 1048903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1049903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 1050903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private SipErrorCode getErrorCode(Throwable exception) { 1051903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan String message = exception.getMessage(); 1052903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (exception instanceof UnknownHostException) { 1053903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.INVALID_REMOTE_URI; 1054903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else if (exception instanceof IOException) { 1055903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.SOCKET_ERROR; 1056903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else if (message.startsWith(SERVER_ERROR_PREFIX)) { 1057903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.SERVER_ERROR; 1058903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 1059903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 1060903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1061903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1062903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 10632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void onRegistrationDone(int duration) { 10643d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 10652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistrationDone(this, duration); 10662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1068903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private void onRegistrationFailed(SipErrorCode errorCode, 1069903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan String message) { 10703d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 1071903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mProxy.onRegistrationFailed(this, errorCode.toString(), message); 1072903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1073903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 10742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void onRegistrationFailed(Throwable exception) { 10753d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 1076903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception = getRootCause(exception); 1077903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan onRegistrationFailed(getErrorCode(exception), 1078903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception.toString()); 10792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10803d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 10813d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void onRegistrationFailed(Response response) { 10823d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 10833d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan int statusCode = response.getStatusCode(); 10843d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(getErrorCode(statusCode), 10853d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan createErrorMessage(response)); 10863d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 10872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 10902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a request event matching the specified 10912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * method; false otherwise 10922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 10932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean isRequestEvent(String method, EventObject event) { 10942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 10952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (event instanceof RequestEvent) { 10962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent requestEvent = (RequestEvent) event; 10972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return method.equals(requestEvent.getRequest().getMethod()); 10982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 11002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 11022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static String getCseqMethod(Message message) { 11052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((CSeqHeader) message.getHeader(CSeqHeader.NAME)).getMethod(); 11062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 11092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a response event and the CSeqHeader method 11102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * match the given arguments; false otherwise 11112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 11122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean expectResponse( 11132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String expectedMethod, EventObject evt) { 11142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 11152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 11162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 11172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 11182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 11202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 11232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a response event and the response code and 11242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * CSeqHeader method match the given arguments; false otherwise 11252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 11262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean expectResponse( 11272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int responseCode, String expectedMethod, EventObject evt) { 11282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 11292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 11302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 11312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (response.getStatusCode() == responseCode) { 11322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 11332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 11362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static SipProfile createPeerProfile(Request request) 11392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 11402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 11412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang FromHeader fromHeader = 11422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang (FromHeader) request.getHeader(FromHeader.NAME); 11432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Address address = fromHeader.getAddress(); 11442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipURI uri = (SipURI) address.getURI(); 11452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String username = uri.getUser(); 11462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (username == null) username = ANONYMOUS; 11472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new SipProfile.Builder(username, uri.getHost()) 11482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang .setPort(uri.getPort()) 11492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang .setDisplayName(address.getDisplayName()) 11502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang .build(); 11512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (InvalidArgumentException e) { 11522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("createPeerProfile()", e); 11532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (ParseException e) { 11542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("createPeerProfile()", e); 11552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static String log(EventObject evt) { 11592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof RequestEvent) { 11602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((RequestEvent) evt).getRequest().toString(); 11612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 11622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((ResponseEvent) evt).getResponse().toString(); 11632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 11642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return evt.toString(); 11652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class OptionsCommand extends EventObject { 11692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public OptionsCommand() { 11702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(SipSessionGroup.this); 11712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class RegisterCommand extends EventObject { 11752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int mDuration; 11762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public RegisterCommand(int duration) { 11782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(SipSessionGroup.this); 11792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDuration = duration; 11802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public int getDuration() { 11832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mDuration; 11842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class MakeCallCommand extends EventObject { 118895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh private String mSessionDescription; 11892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public MakeCallCommand(SipProfile peerProfile, 119195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh String sessionDescription) { 11922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(peerProfile); 11932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionDescription = sessionDescription; 11942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getPeerProfile() { 11972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (SipProfile) getSource(); 11982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 120095b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh public String getSessionDescription() { 12012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mSessionDescription; 12022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang} 1206