SipSessionGroup.java revision a936b256eb1611b5d8b88d0cd61f21225152cc82
12d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang/* 22d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Copyright (C) 2010 The Android Open Source Project 32d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 42d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License"); 52d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * you may not use this file except in compliance with the License. 62d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * You may obtain a copy of the License at 72d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 82d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * http://www.apache.org/licenses/LICENSE-2.0 92d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * 102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * Unless required by applicable law or agreed to in writing, software 112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS, 122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * See the License for the specific language governing permissions and 142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * limitations under the License. 152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangpackage com.android.server.sip; 182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.clientauthutils.AccountManager; 202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.clientauthutils.UserCredentials; 212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.header.SIPHeaderNames; 227d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wangimport gov.nist.javax.sip.header.ProxyAuthenticate; 232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport gov.nist.javax.sip.header.WWWAuthenticate; 2495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yehimport gov.nist.javax.sip.message.SIPMessage; 252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipSession; 272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.ISipSessionListener; 28903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyanimport android.net.sip.SipErrorCode; 292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.net.sip.SipProfile; 3084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyanimport android.net.sip.SipSession; 312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.text.TextUtils; 322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport android.util.Log; 332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.io.IOException; 3595b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yehimport java.io.UnsupportedEncodingException; 362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.net.DatagramSocket; 37903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyanimport java.net.UnknownHostException; 382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.text.ParseException; 392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Collection; 402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.EventObject; 412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.HashMap; 422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Map; 432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.Properties; 442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport java.util.TooManyListenersException; 452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ClientTransaction; 472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.Dialog; 482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.DialogTerminatedEvent; 492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.IOExceptionEvent; 502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.InvalidArgumentException; 512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wangimport javax.sip.ListeningPoint; 529ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyanimport javax.sip.ObjectInUseException; 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"; 82c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan private static final boolean DEBUG = true; 83c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan private static final boolean DEBUG_PING = DEBUG && false; 842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final String ANONYMOUS = "anonymous"; 8566cc5355a137e291cc1e3c5d871e1d9cd35ee0abChung-yih Wang // Limit the size of thread pool to 1 for the order issue when the phone is 8666cc5355a137e291cc1e3c5d871e1d9cd35ee0abChung-yih Wang // waken up from sleep and there are many packets to be processed in the SIP 8766cc5355a137e291cc1e3c5d871e1d9cd35ee0abChung-yih Wang // stack. Note: The default thread pool size in NIST SIP stack is -1 which is 8866cc5355a137e291cc1e3c5d871e1d9cd35ee0abChung-yih Wang // unlimited. 8966cc5355a137e291cc1e3c5d871e1d9cd35ee0abChung-yih Wang private static final String THREAD_POOL_SIZE = "1"; 909352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private static final int EXPIRY_TIME = 3600; // in seconds 91194bbcce9ba15634500f542b9ea017b2cf154b45Hung-ying Tyan private static final int CANCEL_CALL_TIMER = 3; // in seconds 9228f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan private static final long WAKE_LOCK_HOLDING_TIME = 500; // in milliseconds 932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject DEREGISTER = new EventObject("Deregister"); 952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject END_CALL = new EventObject("End call"); 962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject HOLD_CALL = new EventObject("Hold call"); 972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static final EventObject CONTINUE_CALL 982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang = new EventObject("Continue call"); 992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private final SipProfile mLocalProfile; 1012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private final String mPassword; 1022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipStack mSipStack; 1042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipHelper mSipHelper; 1052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // session that processes INVITE requests 1072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private SipSessionImpl mCallReceiverSession; 1082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String mLocalIp; 1092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11028f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan private SipWakeLock mWakeLock; 11128f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan 1122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // call-id-to-SipSession map 1132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Map<String, SipSessionImpl> mSessionMap = 1142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang new HashMap<String, SipSessionImpl>(); 1152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 1172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @param myself the local profile with password crossed out 1182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @param password the password of the profile 1192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @throws IOException if cannot assign requested address 1202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 12128f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan public SipSessionGroup(String localIp, SipProfile myself, String password, 12228f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan SipWakeLock wakeLock) throws SipException, IOException { 1232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalProfile = myself; 1242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPassword = password; 12528f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan mWakeLock = wakeLock; 1262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(localIp); 1272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan synchronized void reset(String localIp) throws SipException, IOException { 1302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalIp = localIp; 1312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (localIp == null) return; 1322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProfile myself = mLocalProfile; 1342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipFactory sipFactory = SipFactory.getInstance(); 1352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Properties properties = new Properties(); 1362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang properties.setProperty("javax.sip.STACK_NAME", getStackName()); 137b4116c09fb9784551911ea0a10b4dd321ff9aa7dChung-yih Wang properties.setProperty( 138b4116c09fb9784551911ea0a10b4dd321ff9aa7dChung-yih Wang "gov.nist.javax.sip.THREAD_POOL_SIZE", THREAD_POOL_SIZE); 1392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String outboundProxy = myself.getProxyAddress(); 1402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (!TextUtils.isEmpty(outboundProxy)) { 1415de1d36dd0415c4cf9afdf093a4915951ef6c770Chung-yih Wang Log.v(TAG, "outboundProxy is " + outboundProxy); 1422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang properties.setProperty("javax.sip.OUTBOUND_PROXY", outboundProxy 1432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + ":" + myself.getPort() + "/" + myself.getProtocol()); 1442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipStack stack = mSipStack = sipFactory.createSipStack(properties); 1462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 1482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProvider provider = stack.createSipProvider( 1492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang stack.createListeningPoint(localIp, allocateLocalPort(), 1502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang myself.getProtocol())); 1512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang provider.addSipListener(this); 1522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper = new SipHelper(stack, provider); 1532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (InvalidArgumentException e) { 1542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new IOException(e.getMessage()); 1552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (TooManyListenersException e) { 1562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // must never happen 1572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("SipSessionGroup constructor", e); 1582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " start stack for " + myself.getUriString()); 1602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang stack.start(); 1612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = null; 1632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.clear(); 1642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 166d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan synchronized void onConnectivityChanged() { 167ebc886c857a702d788c2bdfb9e0b3d20746ad745Hung-ying Tyan SipSessionImpl[] ss = mSessionMap.values().toArray( 168ebc886c857a702d788c2bdfb9e0b3d20746ad745Hung-ying Tyan new SipSessionImpl[mSessionMap.size()]); 169ebc886c857a702d788c2bdfb9e0b3d20746ad745Hung-ying Tyan // Iterate on the copied array instead of directly on mSessionMap to 170ebc886c857a702d788c2bdfb9e0b3d20746ad745Hung-ying Tyan // avoid ConcurrentModificationException being thrown when 171ebc886c857a702d788c2bdfb9e0b3d20746ad745Hung-ying Tyan // SipSessionImpl removes itself from mSessionMap in onError() in the 172ebc886c857a702d788c2bdfb9e0b3d20746ad745Hung-ying Tyan // following loop. 173ebc886c857a702d788c2bdfb9e0b3d20746ad745Hung-ying Tyan for (SipSessionImpl s : ss) { 174d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan s.onError(SipErrorCode.DATA_CONNECTION_LOST, 175d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan "data connection lost"); 176d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan } 177d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan } 178d231aa880ab006d51ffe03454c1fc082f1c97bb8Hung-ying Tyan 1792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getLocalProfile() { 1802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile; 1812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getLocalProfileUri() { 1842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getUriString(); 1852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String getStackName() { 1882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return "stack" + System.currentTimeMillis(); 1892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 1902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void close() { 1922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, " close stack for " + mLocalProfile.getUriString()); 1935d0c5cf2d6c6e82bcdce95d72d9000a934b2f354Hung-ying Tyan onConnectivityChanged(); 1942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.clear(); 1952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang closeToNotReceiveCalls(); 1962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mSipStack != null) { 1972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipStack.stop(); 1982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipStack = null; 1992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper = null; 2002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized boolean isClosed() { 2042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (mSipStack == null); 2052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // For internal use, require listener not to block in callbacks. 2082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void openToReceiveCalls(ISipSessionListener listener) { 2092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mCallReceiverSession == null) { 2102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = new SipSessionCallReceiverImpl(listener); 2112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 2122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession.setListener(listener); 2132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public synchronized void closeToNotReceiveCalls() { 2172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mCallReceiverSession = null; 2182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public ISipSession createSession(ISipSessionListener listener) { 2212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (isClosed() ? null : new SipSessionImpl(listener)); 2222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static int allocateLocalPort() throws SipException { 2252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 2262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang DatagramSocket s = new DatagramSocket(); 2272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int localPort = s.getLocalPort(); 2282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang s.close(); 2292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return localPort; 2302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (IOException e) { 2312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("allocateLocalPort()", e); 2322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2350a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan synchronized boolean containsSession(String callId) { 2360a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan return mSessionMap.containsKey(callId); 2370a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan } 2380a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan 2392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized SipSessionImpl getSipSession(EventObject event) { 2402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = SipHelper.getCallId(event); 2412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl session = mSessionMap.get(key); 242c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if ((session != null) && isLoggable(session)) { 243c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, "session key from event: " + key); 244c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, "active sessions:"); 245c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan for (String k : mSessionMap.keySet()) { 246c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, " ..." + k + ": " + mSessionMap.get(k)); 247c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 248c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 2492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((session != null) ? session : mCallReceiverSession); 2502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void addSipSession(SipSessionImpl newSession) { 2532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang removeSipSession(newSession); 2542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = newSession.getCallId(); 2552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.put(key, newSession); 256c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (isLoggable(newSession)) { 257c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, "+++ add a session with key: '" + key + "'"); 258c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan for (String k : mSessionMap.keySet()) { 259c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, " " + k + ": " + mSessionMap.get(k)); 260c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 2612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 2642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void removeSipSession(SipSessionImpl session) { 2652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (session == mCallReceiverSession) return; 2662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String key = session.getCallId(); 2672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl s = mSessionMap.remove(key); 2682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // sanity check 2692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if ((s != null) && (s != session)) { 2702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.w(TAG, "session " + session + " is not associated with key '" 2712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + key + "'"); 2722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.put(key, s); 2732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang for (Map.Entry<String, SipSessionImpl> entry 2742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : mSessionMap.entrySet()) { 2752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (entry.getValue() == s) { 2762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang key = entry.getKey(); 2772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionMap.remove(key); 2782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 282c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if ((s != null) && isLoggable(s)) { 283c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, "remove session " + session + " @key '" + key + "'"); 284c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan for (String k : mSessionMap.keySet()) { 285c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Log.d(TAG, " " + k + ": " + mSessionMap.get(k)); 286c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 2872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 2892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 29028f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan public void processRequest(final RequestEvent event) { 29128f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan if (isRequestEvent(Request.INVITE, event)) { 29228f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan if (DEBUG) Log.d(TAG, "<<<<< got INVITE, thread:" 29328f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan + Thread.currentThread()); 29428f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan // Acquire a wake lock and keep it for WAKE_LOCK_HOLDING_TIME; 29528f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan // should be large enough to bring up the app. 29628f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan mWakeLock.acquire(WAKE_LOCK_HOLDING_TIME); 29728f63c06894b9ca9252f43bc54a098c0a785d4b4Hung-ying Tyan } 2982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 2992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processResponse(ResponseEvent event) { 3022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 3032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processIOException(IOExceptionEvent event) { 3062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 3072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processTimeout(TimeoutEvent event) { 3102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 3112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processTransactionTerminated(TransactionTerminatedEvent event) { 3142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 3152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void processDialogTerminated(DialogTerminatedEvent event) { 3182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang process(event); 3192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private synchronized void process(EventObject event) { 3222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl session = getSipSession(event); 3232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 324c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan boolean isLoggable = isLoggable(session, event); 325c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan boolean processed = (session != null) && session.process(event); 326c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (isLoggable && processed) { 32797963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan Log.d(TAG, "new state after: " 32884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan + SipSession.State.toString(session.mState)); 3292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 331903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Log.w(TAG, "event process error: " + event, e); 3322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang session.onError(e); 3332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 33695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh private String extractContent(Message message) { 33795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh // Currently we do not support secure MIME bodies. 33895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh byte[] bytes = message.getRawContent(); 33995b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh if (bytes != null) { 34095b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh try { 34195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh if (message instanceof SIPMessage) { 34295b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return ((SIPMessage) message).getMessageContent(); 34395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } else { 34495b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return new String(bytes, "UTF-8"); 34595b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 34695b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } catch (UnsupportedEncodingException e) { 34795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 34895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 34995b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh return null; 35095b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh } 35195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh 3522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class SipSessionCallReceiverImpl extends SipSessionImpl { 3532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionCallReceiverImpl(ISipSessionListener listener) { 3542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(listener); 3552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean process(EventObject evt) throws SipException { 358c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " 35984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan + SipSession.State.toString(mState) + ": processing " 36097963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan + log(evt)); 3612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.INVITE, evt)) { 3622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent event = (RequestEvent) evt; 3632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl newSession = new SipSessionImpl(mProxy); 364fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan newSession.mState = SipSession.State.INCOMING_CALL; 3652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mServerTransaction = mSipHelper.sendRinging(event, 3662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag()); 3672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mDialog = newSession.mServerTransaction.getDialog(); 3682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mInviteReceived = event; 3692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerProfile = createPeerProfile(event.getRequest()); 3702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerSessionDescription = 37195b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh extractContent(event.getRequest()); 3722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(newSession); 3732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRinging(newSession, newSession.mPeerProfile, 3742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang newSession.mPeerSessionDescription); 3752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 3760b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang } else if (isRequestEvent(Request.OPTIONS, evt)) { 3770b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 3780b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang return true; 3792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 3802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 3812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 3842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 3852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang class SipSessionImpl extends ISipSession.Stub { 3862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipProfile mPeerProfile; 3872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionListenerProxy mProxy = new SipSessionListenerProxy(); 38884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan int mState = SipSession.State.READY_TO_CALL; 3892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent mInviteReceived; 3902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Dialog mDialog; 3912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ServerTransaction mServerTransaction; 3922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ClientTransaction mClientTransaction; 39395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh String mPeerSessionDescription; 3942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang boolean mInCall; 3959352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan SessionTimer mTimer; 396ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan int mAuthenticationRetryCount; 397ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan 398ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan // for registration 399ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan boolean mReRegisterFlag = false; 400ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan int mRPort; 4019352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 4029352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan // lightweight timer 4039352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan class SessionTimer { 4049352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private boolean mRunning = true; 4059352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 4069352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan void start(final int timeout) { 4079352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan new Thread(new Runnable() { 4089352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void run() { 4099352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan sleep(timeout); 4109352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan if (mRunning) timeout(); 4119352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 41284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan }, "SipSessionTimerThread").start(); 4139352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4149352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 4159352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan synchronized void cancel() { 4169352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mRunning = false; 4179352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan this.notify(); 4189352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4199352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 4209352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private void timeout() { 4219352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan synchronized (SipSessionGroup.this) { 4229352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan onError(SipErrorCode.TIME_OUT, "Session timed out!"); 4239352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4249352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4259352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 4269352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private synchronized void sleep(int timeout) { 4279352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan try { 4289352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan this.wait(timeout * 1000); 4299352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } catch (InterruptedException e) { 4309352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan Log.e(TAG, "session timer interrupted!"); 4319352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4329352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4339352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 4342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipSessionImpl(ISipSessionListener listener) { 4362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang setListener(listener); 4372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipSessionImpl duplicate() { 4402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new SipSessionImpl(mProxy.getListener()); 4412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void reset() { 4442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInCall = false; 4452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang removeSipSession(this); 4462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPeerProfile = null; 44784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.READY_TO_CALL; 4482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInviteReceived = null; 4499ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan mPeerSessionDescription = null; 450ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan mRPort = 0; 451ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan mAuthenticationRetryCount = 0; 4529ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan 4539ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan if (mDialog != null) mDialog.delete(); 4542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = null; 4559ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan 4569ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan try { 4579ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan if (mServerTransaction != null) mServerTransaction.terminate(); 4589ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan } catch (ObjectInUseException e) { 4599ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan // ignored 4609ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan } 4612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = null; 4629ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan 4639ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan try { 4649ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan if (mClientTransaction != null) mClientTransaction.terminate(); 4659ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan } catch (ObjectInUseException e) { 4669ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan // ignored 4679ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan } 4682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = null; 4699352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 4709352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan cancelSessionTimer(); 4712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean isInCall() { 4742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mInCall; 4752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getLocalIp() { 4782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalIp; 4792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getLocalProfile() { 4822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile; 4832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getPeerProfile() { 4862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mPeerProfile; 4872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getCallId() { 4902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return SipHelper.getCallId(getTransaction()); 4912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 4932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private Transaction getTransaction() { 4942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mClientTransaction != null) return mClientTransaction; 4952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mServerTransaction != null) return mServerTransaction; 4962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return null; 4972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 4982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 49997963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan public int getState() { 50097963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan return mState; 5012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void setListener(ISipSessionListener listener) { 5042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.setListener((listener instanceof SipSessionListenerProxy) 5052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ? ((SipSessionListenerProxy) listener).getListener() 5062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : listener); 5072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 509dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan // process the command in a new thread 510dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan private void doCommandAsync(final EventObject command) { 511dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan new Thread(new Runnable() { 512dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan public void run() { 513dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan try { 514dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan processCommand(command); 515c6548fd9eda7b58f5a2e2a9c01e3c7cafd42fafbHung-ying Tyan } catch (Throwable e) { 516903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Log.w(TAG, "command error: " + command, e); 5173d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(e); 518dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 519dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 52084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan }, "SipSessionAsyncCmdThread").start(); 521dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan } 522dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan 5239352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void makeCall(SipProfile peerProfile, String sessionDescription, 5249352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan int timeout) { 5259352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription, 5269352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan timeout)); 5272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5299352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void answerCall(String sessionDescription, int timeout) { 53006e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan synchronized (SipSessionGroup.this) { 53106e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan if (mPeerProfile == null) return; 53206e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan try { 53306e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan processCommand(new MakeCallCommand(mPeerProfile, 53406e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan sessionDescription, timeout)); 53506e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan } catch (SipException e) { 53606e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan onError(e); 53706e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan } 5382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void endCall() { 542dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(END_CALL); 5432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5459352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public void changeCall(String sessionDescription, int timeout) { 54606e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan synchronized (SipSessionGroup.this) { 54706e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan if (mPeerProfile == null) return; 54806e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan doCommandAsync(new MakeCallCommand(mPeerProfile, 54906e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan sessionDescription, timeout)); 55006e8cdc0f81ead604d5adf9d7b3f982e10226fd2Hung-ying Tyan } 5512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void register(int duration) { 554dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(new RegisterCommand(duration)); 5552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void unregister() { 558dba514c6d8e8263d4b8f31cb2fdebfc1d4f84c35Hung-ying Tyan doCommandAsync(DEREGISTER); 5592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean isReRegisterRequired() { 5622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mReRegisterFlag; 5632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void clearReRegisterRequired() { 5662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mReRegisterFlag = false; 5672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public void sendKeepAlive() { 57084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.PINGING; 5712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 5722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processCommand(new OptionsCommand()); 573bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan for (int i = 0; i < 15; i++) { 574bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan if (SipSession.State.PINGING != mState) break; 575bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan Thread.sleep(200); 576bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan } 577bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan if (SipSession.State.PINGING == mState) { 578bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan // FIXME: what to do if server doesn't respond 579bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan reset(); 580bd57eeafe034cf850225db403700b5dc5db5ebccHung-ying Tyan if (DEBUG) Log.w(TAG, "no response from ping"); 5812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (SipException e) { 5832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "sendKeepAlive failed", e); 5842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (InterruptedException e) { 5852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.e(TAG, "sendKeepAlive interrupted", e); 5862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processCommand(EventObject command) throws SipException { 5900a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan if (isLoggable(command)) Log.d(TAG, "process cmd: " + command); 5912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (!process(command)) { 5923d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.IN_PROGRESS, 5933d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan "cannot initiate a new transaction to execute: " 5943d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan + command); 5952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 5972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 5982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang protected String generateTag() { 5992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // 32-bit randomness 6002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return String.valueOf((long) (Math.random() * 0x100000000L)); 6012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String toString() { 6042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 6052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String s = super.toString(); 60697963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan return s.substring(s.indexOf("@")) + ":" 60784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan + SipSession.State.toString(mState); 6082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 6092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return super.toString(); 6102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public boolean process(EventObject evt) throws SipException { 614c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " 61584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan + SipSession.State.toString(mState) + ": processing " 61697963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan + log(evt)); 6172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang synchronized (SipSessionGroup.this) { 6182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isClosed()) return false; 6192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Dialog dialog = null; 6212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof RequestEvent) { 6222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang dialog = ((RequestEvent) evt).getDialog(); 6232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 6242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang dialog = ((ResponseEvent) evt).getDialog(); 6252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (dialog != null) mDialog = dialog; 6272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang boolean processed; 6292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (mState) { 63184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.REGISTERING: 63284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.DEREGISTERING: 6332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = registeringToReady(evt); 6342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 63584a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.PINGING: 6362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = keepAliveProcess(evt); 6372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 63884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.READY_TO_CALL: 6392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = readyForCall(evt); 6402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 64184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.INCOMING_CALL: 6422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = incomingCall(evt); 6432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 64484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.INCOMING_CALL_ANSWERING: 6452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = incomingCallToInCall(evt); 6462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 64784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL: 64884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL_RING_BACK: 6492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = outgoingCall(evt); 6502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 65184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL_CANCELING: 6522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = outgoingCallToReady(evt); 6532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 65484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.IN_CALL: 6552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = inCall(evt); 6562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang break; 6572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 6582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processed = false; 6592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (processed || processExceptions(evt)); 6612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean processExceptions(EventObject evt) throws SipException { 6652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.BYE, evt)) { 6662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // terminate the call whenever a BYE is received 6672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 6682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 6692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 6702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 6712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, 6722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST); 6732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 6742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof TransactionTerminatedEvent) { 675025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if (isCurrentTransaction((TransactionTerminatedEvent) evt)) { 676025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if (evt instanceof TimeoutEvent) { 677025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan processTimeout((TimeoutEvent) evt); 678025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } else { 679025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan processTransactionTerminated( 680025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan (TransactionTerminatedEvent) evt); 681025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 682025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return true; 6832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6840b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang } else if (isRequestEvent(Request.OPTIONS, evt)) { 6850b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 6860b4d2fb11405e2e785ec30cabe7bb311c654c0d2Chung-yih Wang return true; 6872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof DialogTerminatedEvent) { 6882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang processDialogTerminated((DialogTerminatedEvent) evt); 6892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 6902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 6922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 6932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 6942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processDialogTerminated(DialogTerminatedEvent event) { 6952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mDialog == event.getDialog()) { 6962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onError(new SipException("dialog terminated")); 6972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 6982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Log.d(TAG, "not the current dialog; current=" + mDialog 6992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang + ", terminated=" + event.getDialog()); 7002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 703025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan private boolean isCurrentTransaction(TransactionTerminatedEvent event) { 704025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Transaction current = event.isServerTransaction() 705025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan ? mServerTransaction 706025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan : mClientTransaction; 707025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Transaction target = event.isServerTransaction() 708025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan ? event.getServerTransaction() 709025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan : event.getClientTransaction(); 710025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan 711025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if ((current != target) && (mState != SipSession.State.PINGING)) { 712025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Log.d(TAG, "not the current transaction; current=" 713025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan + toString(current) + ", target=" + toString(target)); 714025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return false; 715025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } else if (current != null) { 716025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Log.d(TAG, "transaction terminated: " + toString(current)); 717025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return true; 718fccd5bc78f94b7dcfbcf78ddca83719c9cd1a74fHung-ying Tyan } else { 719fccd5bc78f94b7dcfbcf78ddca83719c9cd1a74fHung-ying Tyan // no transaction; shouldn't be here; ignored 720fccd5bc78f94b7dcfbcf78ddca83719c9cd1a74fHung-ying Tyan return true; 721025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 722025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 723025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan 724025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan private String toString(Transaction transaction) { 725025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if (transaction == null) return "null"; 726025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Request request = transaction.getRequest(); 727025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Dialog dialog = transaction.getDialog(); 728025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan CSeqHeader cseq = (CSeqHeader) request.getHeader(CSeqHeader.NAME); 729025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return String.format("req=%s,%s,s=%s,ds=%s,", request.getMethod(), 730025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan cseq.getSeqNumber(), transaction.getState(), 731025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan ((dialog == null) ? "-" : dialog.getState())); 732025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 733025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan 7343d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void processTransactionTerminated( 7353d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan TransactionTerminatedEvent event) { 7363d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan switch (mState) { 73784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.IN_CALL: 73884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.READY_TO_CALL: 7393d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, "Transaction terminated; do nothing"); 7403d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 7413d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 7423d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, "Transaction terminated early: " + this); 7433d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.TRANSACTION_TERMINTED, 7443d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan "transaction terminated"); 7453d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 7463d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 7473d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 7482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void processTimeout(TimeoutEvent event) { 749025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan Log.d(TAG, "processing Timeout..."); 7502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (mState) { 75184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.REGISTERING: 75284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.DEREGISTERING: 7533d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 7543d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mProxy.onRegistrationTimeout(this); 7553d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 75684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.INCOMING_CALL: 75784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.INCOMING_CALL_ANSWERING: 75884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL: 75984a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.OUTGOING_CALL_CANCELING: 7603d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(SipErrorCode.TIME_OUT, event.toString()); 7613d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 76284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.PINGING: 7633d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 7643d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan mReRegisterFlag = true; 7653d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 7662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7673d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 7683d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan Log.d(TAG, " do nothing"); 7693d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 7702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int getExpiryTime(Response response) { 7742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int expires = EXPIRY_TIME; 7752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ExpiresHeader expiresHeader = (ExpiresHeader) 7762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang response.getHeader(ExpiresHeader.NAME); 7772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expiresHeader != null) expires = expiresHeader.getExpires(); 7782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang expiresHeader = (ExpiresHeader) 7792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang response.getHeader(MinExpiresHeader.NAME); 7802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expiresHeader != null) { 7812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang expires = Math.max(expires, expiresHeader.getExpires()); 7822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expires; 7842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean keepAliveProcess(EventObject evt) throws SipException { 7872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof OptionsCommand) { 7882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendKeepAlive(mLocalProfile, 7892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag()); 7902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 7912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 7922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 7932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 7942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return parseOptionsResult(evt); 7952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 7972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 7982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 7992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean parseOptionsResult(EventObject evt) { 8002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.OPTIONS, evt)) { 8012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 8022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int rPort = getRPortFromResponse(event.getResponse()); 8032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (rPort != -1) { 8042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mRPort == 0) mRPort = rPort; 8052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (mRPort != rPort) { 8062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mReRegisterFlag = true; 807c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.w(TAG, String.format( 808c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan "rport is changed: %d <> %d", mRPort, rPort)); 8092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mRPort = rPort; 8102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 811c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG_PING) Log.w(TAG, "rport is the same: " + rPort); 8122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 814c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (DEBUG) Log.w(TAG, "peer did not respond rport"); 8152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8163d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 8172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 8202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int getRPortFromResponse(Response response) { 8232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ViaHeader viaHeader = (ViaHeader)(response.getHeader( 8242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SIPHeaderNames.VIA)); 8252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (viaHeader == null) ? -1 : viaHeader.getRPort(); 8262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean registeringToReady(EventObject evt) 8292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 8302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.REGISTER, evt)) { 8312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 8322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 8332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 8342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 8352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (statusCode) { 8362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.OK: 83797963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan int state = mState; 83884a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan onRegistrationDone((state == SipSession.State.REGISTERING) 8392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ? getExpiryTime(((ResponseEvent) evt).getResponse()) 8402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang : -1); 8412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.UNAUTHORIZED: 8432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.PROXY_AUTHENTICATION_REQUIRED: 844ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan handleAuthentication(event); 8452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 8472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 500) { 8483d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(response); 8492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 8502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 8542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 8552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 856903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private boolean handleAuthentication(ResponseEvent event) 857903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan throws SipException { 858903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Response response = event.getResponse(); 859903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan String nonce = getNonceFromResponse(response); 860ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan if (nonce == null) { 861ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan onError(SipErrorCode.SERVER_ERROR, 862ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan "server does not provide challenge"); 863903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return false; 864ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan } else if (mAuthenticationRetryCount < 2) { 865903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mClientTransaction = mSipHelper.handleChallenge( 866903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan event, getAccountManager()); 867903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mDialog = mClientTransaction.getDialog(); 868ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan mAuthenticationRetryCount++; 869ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan if (isLoggable(this, event)) { 870ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan Log.d(TAG, " authentication retry count=" 871ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan + mAuthenticationRetryCount); 872ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan } 873903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return true; 874ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan } else { 875a936b256eb1611b5d8b88d0cd61f21225152cc82Hung-ying Tyan if (crossDomainAuthenticationRequired(response)) { 876a936b256eb1611b5d8b88d0cd61f21225152cc82Hung-ying Tyan onError(SipErrorCode.CROSS_DOMAIN_AUTHENTICATION, 877a936b256eb1611b5d8b88d0cd61f21225152cc82Hung-ying Tyan getRealmFromResponse(response)); 878a936b256eb1611b5d8b88d0cd61f21225152cc82Hung-ying Tyan } else { 879a936b256eb1611b5d8b88d0cd61f21225152cc82Hung-ying Tyan onError(SipErrorCode.INVALID_CREDENTIALS, 880a936b256eb1611b5d8b88d0cd61f21225152cc82Hung-ying Tyan "incorrect username or password"); 881a936b256eb1611b5d8b88d0cd61f21225152cc82Hung-ying Tyan } 882ee8a884f3504c981be8a1d6888b4590a0a394e05Hung-ying Tyan return false; 883903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 884903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 885903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 88600a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan private boolean crossDomainAuthenticationRequired(Response response) { 88700a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan String realm = getRealmFromResponse(response); 88800a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan if (realm == null) realm = ""; 88900a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan return !mLocalProfile.getSipDomain().trim().equals(realm.trim()); 89000a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan } 89100a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan 8922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private AccountManager getAccountManager() { 8932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new AccountManager() { 8942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public UserCredentials getCredentials(ClientTransaction 8952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang challengedTransaction, String realm) { 8962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return new UserCredentials() { 8972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getUserName() { 8982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getUserName(); 8992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getPassword() { 9022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mPassword; 9032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public String getSipDomain() { 9062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mLocalProfile.getSipDomain(); 9072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang }; 9092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang }; 9112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 91300a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan private String getRealmFromResponse(Response response) { 91400a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader( 91500a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan SIPHeaderNames.WWW_AUTHENTICATE); 91600a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan if (wwwAuth != null) return wwwAuth.getRealm(); 91700a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( 91800a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan SIPHeaderNames.PROXY_AUTHENTICATE); 91900a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan return (proxyAuth == null) ? null : proxyAuth.getRealm(); 92000a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan } 92100a22064efef4f574e439079aae2deae1a087a31Hung-ying Tyan 9222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private String getNonceFromResponse(Response response) { 9237d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang WWWAuthenticate wwwAuth = (WWWAuthenticate)response.getHeader( 9247d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang SIPHeaderNames.WWW_AUTHENTICATE); 9257d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang if (wwwAuth != null) return wwwAuth.getNonce(); 9267d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang ProxyAuthenticate proxyAuth = (ProxyAuthenticate)response.getHeader( 9277d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang SIPHeaderNames.PROXY_AUTHENTICATE); 9287d137e40cd36290c6bfb5beaf66f4018ae92c97fChung-yih Wang return (proxyAuth == null) ? null : proxyAuth.getNonce(); 9292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean readyForCall(EventObject evt) throws SipException { 9322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect MakeCallCommand, RegisterCommand, DEREGISTER 9332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof MakeCallCommand) { 934fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mState = SipSession.State.OUTGOING_CALL; 9352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang MakeCallCommand cmd = (MakeCallCommand) evt; 9362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mPeerProfile = cmd.getPeerProfile(); 9372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendInvite(mLocalProfile, 93895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerProfile, cmd.getSessionDescription(), 93995b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh generateTag()); 9402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 9412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 9429352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan startSessionTimer(cmd.getTimeout()); 9439ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan mProxy.onCalling(this); 9442d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof RegisterCommand) { 946fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mState = SipSession.State.REGISTERING; 9472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int duration = ((RegisterCommand) evt).getDuration(); 9482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 9492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag(), duration); 9502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 9512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 9522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistering(this); 9532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (DEREGISTER == evt) { 955fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mState = SipSession.State.DEREGISTERING; 9562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendRegister(mLocalProfile, 9572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang generateTag(), 0); 9582d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDialog = mClientTransaction.getDialog(); 9592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang addSipSession(this); 9602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistering(this); 9612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9622d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 9642d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean incomingCall(EventObject evt) throws SipException { 9672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect MakeCallCommand(answering) , END_CALL cmd , Cancel 9682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof MakeCallCommand) { 9692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // answer call 970fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mState = SipSession.State.INCOMING_CALL_ANSWERING; 9712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = mSipHelper.sendInviteOk(mInviteReceived, 9722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mLocalProfile, 9732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ((MakeCallCommand) evt).getSessionDescription(), 9742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction); 9759352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan startSessionTimer(((MakeCallCommand) evt).getTimeout()); 9762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (END_CALL == evt) { 9782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteBusyHere(mInviteReceived, 9792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction); 9802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 9812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 9832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent event = (RequestEvent) evt; 9842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse(event, Response.OK); 9852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteRequestTerminated( 9862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInviteReceived.getRequest(), mServerTransaction); 9872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 9882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 9912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 9922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 9932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean incomingCallToInCall(EventObject evt) 9942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 9952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect ACK, CANCEL request 9962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (isRequestEvent(Request.ACK, evt)) { 9972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang establishCall(); 9982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 9992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.CANCEL, evt)) { 10002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // http://tools.ietf.org/html/rfc3261#section-9.2 10012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // Final response has been sent; do nothing here. 10022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean outgoingCall(EventObject evt) throws SipException { 10082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.INVITE, evt)) { 10092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 10102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 10112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 10132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang switch (statusCode) { 10142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.RINGING: 10156057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan case Response.CALL_IS_BEING_FORWARDED: 10166057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan case Response.QUEUED: 10176057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan case Response.SESSION_PROGRESS: 10186057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan // feedback any provisional responses (except TRYING) as 10196057cd00d95c756b78f22c67279cb982bc0674efHung-ying Tyan // ring back for better UX 102084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan if (mState == SipSession.State.OUTGOING_CALL) { 102184a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.OUTGOING_CALL_RING_BACK; 10229352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan cancelSessionTimer(); 10239ea96c6cade1f25d4d77dcbd24854df431548b36Hung-ying Tyan mProxy.onRingingBack(this); 10242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.OK: 10272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendInviteAck(event, mDialog); 102895b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerSessionDescription = extractContent(response); 10292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang establishCall(); 10302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10310e0633828928481658c0e09e5893f6214b57ba38Chung-yih Wang case Response.UNAUTHORIZED: 10322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.PROXY_AUTHENTICATION_REQUIRED: 1033a936b256eb1611b5d8b88d0cd61f21225152cc82Hung-ying Tyan if (handleAuthentication(event)) { 1034903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan addSipSession(this); 1035903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 10362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang case Response.REQUEST_PENDING: 10382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: 10392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-14.1; re-schedule invite 10402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10412d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang default: 10422d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 400) { 10432d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // error: an ack is sent automatically by the stack 1044903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan onError(response); 10452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (statusCode >= 300) { 10472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // TODO: handle 3xx (redirect) 10482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 10492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10512d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10522d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10532d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (END_CALL == evt) { 10542d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // RFC says that UA should not send out cancel when no 10552d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // response comes back yet. We are cheating for not checking 10562d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // response. 105784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.OUTGOING_CALL_CANCELING; 1058fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mSipHelper.sendCancel(mClientTransaction); 10599352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan startSessionTimer(CANCEL_CALL_TIMER); 10602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10610a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan } else if (isRequestEvent(Request.INVITE, evt)) { 10620a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan // Call self? Send BUSY HERE so server may redirect the call to 10630a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan // voice mailbox. 10640a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan RequestEvent event = (RequestEvent) evt; 10650a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan mSipHelper.sendInviteBusyHere(event, 10660a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan event.getServerTransaction()); 10670a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan return true; 10682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean outgoingCallToReady(EventObject evt) 10732d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 10742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 10752d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 10762d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 10772d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int statusCode = response.getStatusCode(); 10782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (expectResponse(Request.CANCEL, evt)) { 1079025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan if (statusCode == Response.OK) { 1080025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan // do nothing; wait for REQUEST_TERMINATED 1081025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan return true; 1082025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } 1083025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan } else if (expectResponse(Request.INVITE, evt)) { 10849352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan switch (statusCode) { 10859352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan case Response.OK: 1086025a39af346f39743c1e384b9000ce1baee36562Hung-ying Tyan outgoingCall(evt); // abort Cancel 10879352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan return true; 10889352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan case Response.REQUEST_TERMINATED: 10899352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan endCallNormally(); 10909352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan return true; 10912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 10932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 10942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 10952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 10962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (statusCode >= 400) { 10973d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(response); 10982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 10992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof TransactionTerminatedEvent) { 11012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-14.1: 11022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // if re-invite gets timed out, terminate the dialog; but 11032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // re-invite is not reliable, just let it go and pretend 11042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // nothing happened. 11052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang onError(new SipException("timed out")); 11062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 11082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private boolean inCall(EventObject evt) throws SipException { 11112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // expect END_CALL cmd, BYE request, hold call (MakeCallCommand) 11122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // OK retransmission is handled in SipStack 11132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (END_CALL == evt) { 11142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // rfc3261#section-15.1.1 11152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendBye(mDialog); 11162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 11172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 11182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.INVITE, evt)) { 11192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // got Re-INVITE 112084a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.INCOMING_CALL; 1121fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan RequestEvent event = mInviteReceived = (RequestEvent) evt; 112295b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh mPeerSessionDescription = extractContent(event.getRequest()); 11232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mServerTransaction = null; 11242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRinging(this, mPeerProfile, mPeerSessionDescription); 11252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 11262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (isRequestEvent(Request.BYE, evt)) { 11272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSipHelper.sendResponse((RequestEvent) evt, Response.OK); 11282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang endCallNormally(); 11292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 11302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof MakeCallCommand) { 11312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang // to change call 1132fb3a98b1d8d0ad040980d509c4c5341928b9460bHung-ying Tyan mState = SipSession.State.OUTGOING_CALL; 11332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mClientTransaction = mSipHelper.sendReinvite(mDialog, 11342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ((MakeCallCommand) evt).getSessionDescription()); 11359352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan startSessionTimer(((MakeCallCommand) evt).getTimeout()); 11362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return true; 11372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11382d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 11392d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11419352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan // timeout in seconds 11429352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private void startSessionTimer(int timeout) { 11439352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan if (timeout > 0) { 11449352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimer = new SessionTimer(); 11459352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimer.start(timeout); 11469352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 11479352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 11489352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 11499352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private void cancelSessionTimer() { 11509352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan if (mTimer != null) { 11519352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimer.cancel(); 11529352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimer = null; 11539352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 11549352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 11559352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 1156903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private String createErrorMessage(Response response) { 1157624d5b4e8c20516516d0bff74479b9f5abdfe61cHung-ying Tyan return String.format("%s (%d)", response.getReasonPhrase(), 1158624d5b4e8c20516516d0bff74479b9f5abdfe61cHung-ying Tyan response.getStatusCode()); 1159903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1160903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 11612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void establishCall() { 116284a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan mState = SipSession.State.IN_CALL; 11632d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mInCall = true; 11649352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan cancelSessionTimer(); 11652d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onCallEstablished(this, mPeerSessionDescription); 11662d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11682d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void endCallNormally() { 11692d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(); 11702d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onCallEnded(this); 11712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11722d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 117397963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private void endCallOnError(int errorCode, String message) { 11742d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang reset(); 117597963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan mProxy.onError(this, errorCode, message); 1176903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1177903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 1178903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private void endCallOnBusy() { 1179903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan reset(); 1180903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan mProxy.onCallBusy(this); 11812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 118397963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private void onError(int errorCode, String message) { 11849352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan cancelSessionTimer(); 11853d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan switch (mState) { 118684a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.REGISTERING: 118784a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.DEREGISTERING: 11883d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(errorCode, message); 11893d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan break; 11903d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan default: 11914189d99b6e4877352049b7447b7f0734ef99b9e8Hung-ying Tyan endCallOnError(errorCode, message); 11922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 11942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 11953d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 11963d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void onError(Throwable exception) { 11973d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan exception = getRootCause(exception); 11983d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(getErrorCode(exception), exception.toString()); 11993d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 12003d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 1201903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private void onError(Response response) { 12023d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan int statusCode = response.getStatusCode(); 1203ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan if (!mInCall && (statusCode == Response.BUSY_HERE)) { 12043d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan endCallOnBusy(); 1205903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 12063d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onError(getErrorCode(statusCode), createErrorMessage(response)); 1207903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1208903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1209903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 121097963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private int getErrorCode(int responseStatusCode) { 1211903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan switch (responseStatusCode) { 1212ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.TEMPORARILY_UNAVAILABLE: 1213ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.FORBIDDEN: 1214ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.GONE: 1215903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.NOT_FOUND: 1216ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.NOT_ACCEPTABLE: 1217ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.NOT_ACCEPTABLE_HERE: 1218ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan return SipErrorCode.PEER_NOT_REACHABLE; 1219ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan 1220ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.REQUEST_URI_TOO_LONG: 1221903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.ADDRESS_INCOMPLETE: 1222ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan case Response.AMBIGUOUS: 1223903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.INVALID_REMOTE_URI; 1224ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan 1225903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan case Response.REQUEST_TIMEOUT: 1226903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.TIME_OUT; 1227ae076d3981fda732d54b6c6e37e5659b2e7ba130Hung-ying Tyan 1228903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan default: 1229903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (responseStatusCode < 500) { 1230903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 1231903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 1232903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.SERVER_ERROR; 1233903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1234903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1235903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1236903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 1237903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan private Throwable getRootCause(Throwable exception) { 1238903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan Throwable cause = exception.getCause(); 1239903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan while (cause != null) { 1240903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception = cause; 1241903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan cause = exception.getCause(); 1242903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1243903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return exception; 1244903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1245903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 124697963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private int getErrorCode(Throwable exception) { 1247903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan String message = exception.getMessage(); 1248903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan if (exception instanceof UnknownHostException) { 1249c6548fd9eda7b58f5a2e2a9c01e3c7cafd42fafbHung-ying Tyan return SipErrorCode.SERVER_UNREACHABLE; 1250903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else if (exception instanceof IOException) { 1251903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.SOCKET_ERROR; 1252903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } else { 1253903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan return SipErrorCode.CLIENT_ERROR; 1254903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1255903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1256903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 12572d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void onRegistrationDone(int duration) { 12583d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 12592d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mProxy.onRegistrationDone(this, duration); 12602d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12612d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 126297963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan private void onRegistrationFailed(int errorCode, String message) { 12633d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan reset(); 126497963794af1e18674dd111e3ad344d90b16c922cHung-ying Tyan mProxy.onRegistrationFailed(this, errorCode, message); 1265903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan } 1266903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan 12672d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private void onRegistrationFailed(Throwable exception) { 1268903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception = getRootCause(exception); 1269903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan onRegistrationFailed(getErrorCode(exception), 1270903e1031605d715e904811b0dd06cc6a518f0048Hung-ying Tyan exception.toString()); 12712d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12723d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan 12733d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan private void onRegistrationFailed(Response response) { 12743d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan int statusCode = response.getStatusCode(); 12753d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan onRegistrationFailed(getErrorCode(statusCode), 12763d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan createErrorMessage(response)); 12773d7606aa607b24817e37c264f2141ed7b2d50be0Hung-ying Tyan } 12782d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12792d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12802d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 12812d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a request event matching the specified 12822d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * method; false otherwise 12832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 12842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean isRequestEvent(String method, EventObject event) { 12852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 12862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (event instanceof RequestEvent) { 12872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang RequestEvent requestEvent = (RequestEvent) event; 12882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return method.equals(requestEvent.getRequest().getMethod()); 12892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (Throwable e) { 12912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 12932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static String getCseqMethod(Message message) { 12962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((CSeqHeader) message.getHeader(CSeqHeader.NAME)).getMethod(); 12972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 12982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 12992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 13002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a response event and the CSeqHeader method 13012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * match the given arguments; false otherwise 13022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 13032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean expectResponse( 13042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String expectedMethod, EventObject evt) { 13052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 13062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 13072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 13082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 13092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 13112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13132d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang /** 13142d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * @return true if the event is a response event and the response code and 13152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang * CSeqHeader method match the given arguments; false otherwise 13162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang */ 13172d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static boolean expectResponse( 13182d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang int responseCode, String expectedMethod, EventObject evt) { 13192d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof ResponseEvent) { 13202d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang ResponseEvent event = (ResponseEvent) evt; 13212d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Response response = event.getResponse(); 13222d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (response.getStatusCode() == responseCode) { 13232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return expectedMethod.equalsIgnoreCase(getCseqMethod(response)); 13242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13252d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return false; 13272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static SipProfile createPeerProfile(Request request) 13302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throws SipException { 13312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang try { 13322d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang FromHeader fromHeader = 13332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang (FromHeader) request.getHeader(FromHeader.NAME); 13342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang Address address = fromHeader.getAddress(); 13352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang SipURI uri = (SipURI) address.getURI(); 13362d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang String username = uri.getUser(); 13372d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (username == null) username = ANONYMOUS; 133858ee2acba8953814cc4bf65d2f28f7dd498b5779Hung-ying Tyan int port = uri.getPort(); 133958ee2acba8953814cc4bf65d2f28f7dd498b5779Hung-ying Tyan SipProfile.Builder builder = 134058ee2acba8953814cc4bf65d2f28f7dd498b5779Hung-ying Tyan new SipProfile.Builder(username, uri.getHost()) 134158ee2acba8953814cc4bf65d2f28f7dd498b5779Hung-ying Tyan .setDisplayName(address.getDisplayName()); 134258ee2acba8953814cc4bf65d2f28f7dd498b5779Hung-ying Tyan if (port > 0) builder.setPort(port); 134358ee2acba8953814cc4bf65d2f28f7dd498b5779Hung-ying Tyan return builder.build(); 134499bf4e45c4566172189735b34b368b76660ca57aHung-ying Tyan } catch (IllegalArgumentException e) { 13452d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("createPeerProfile()", e); 13462d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } catch (ParseException e) { 13472d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang throw new SipException("createPeerProfile()", e); 13482d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13492d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13502d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 1351c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan private static boolean isLoggable(SipSessionImpl s) { 1352c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (s != null) { 1353c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan switch (s.mState) { 135484a357bb6a8005e1c5e924e96a8ecf310e77c47cHung-ying Tyan case SipSession.State.PINGING: 1355c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG_PING; 1356c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1357c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1358c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG; 1359c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1360c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan 13610a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan private static boolean isLoggable(EventObject evt) { 13620a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan return isLoggable(null, evt); 13630a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan } 13640a6e717fb6846f66b8dc853e079f2166307bfc60Hung-ying Tyan 1365c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan private static boolean isLoggable(SipSessionImpl s, EventObject evt) { 1366c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (!isLoggable(s)) return false; 1367c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (evt == null) return false; 1368c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan 1369c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (evt instanceof OptionsCommand) { 1370c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG_PING; 1371c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } else if (evt instanceof ResponseEvent) { 1372c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan Response response = ((ResponseEvent) evt).getResponse(); 1373c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan if (Request.OPTIONS.equals(response.getHeader(CSeqHeader.NAME))) { 1374c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG_PING; 1375c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1376c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG; 1377c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } else if (evt instanceof RequestEvent) { 1378c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return DEBUG; 1379c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1380c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan return false; 1381c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan } 1382c7510581b81d63536db7d46ca8533106c8cf57c6Hung-ying Tyan 13832d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private static String log(EventObject evt) { 13842d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang if (evt instanceof RequestEvent) { 13852d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((RequestEvent) evt).getRequest().toString(); 13862d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else if (evt instanceof ResponseEvent) { 13872d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return ((ResponseEvent) evt).getResponse().toString(); 13882d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } else { 13892d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return evt.toString(); 13902d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13912d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13922d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13932d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class OptionsCommand extends EventObject { 13942d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public OptionsCommand() { 13952d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(SipSessionGroup.this); 13962d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13972d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 13982d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 13992d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class RegisterCommand extends EventObject { 14002d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private int mDuration; 14012d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 14022d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public RegisterCommand(int duration) { 14032d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(SipSessionGroup.this); 14042d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mDuration = duration; 14052d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 14062d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 14072d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public int getDuration() { 14082d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mDuration; 14092d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 14102d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 14112d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 14122d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang private class MakeCallCommand extends EventObject { 141395b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh private String mSessionDescription; 14149352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan private int mTimeout; // in seconds 14152d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 14162d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public MakeCallCommand(SipProfile peerProfile, 141795b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh String sessionDescription) { 14189352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan this(peerProfile, sessionDescription, -1); 14199352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 14209352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan 14219352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public MakeCallCommand(SipProfile peerProfile, 14229352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan String sessionDescription, int timeout) { 14232d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang super(peerProfile); 14242d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang mSessionDescription = sessionDescription; 14259352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan mTimeout = timeout; 14262d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 14272d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 14282d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang public SipProfile getPeerProfile() { 14292d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return (SipProfile) getSource(); 14302d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 14312d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 143295b15c35608fe3ea679c8a478c6cbd841623371eChia-chi Yeh public String getSessionDescription() { 14332d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang return mSessionDescription; 14342d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang } 14352d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang 14369352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan public int getTimeout() { 14379352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan return mTimeout; 14389352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 14399352cf1a4d46492fc48a20f7d825a9bcb6e8b365Hung-ying Tyan } 14402d94231ef91c732f649ff7af9520ee9eac441b16Chung-yih Wang} 1441