198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang/* 298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Copyright (C) 2010 The Android Open Source Project 398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Licensed under the Apache License, Version 2.0 (the "License"); 598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * you may not use this file except in compliance with the License. 698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * You may obtain a copy of the License at 798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * http://www.apache.org/licenses/LICENSE-2.0 998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 1098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Unless required by applicable law or agreed to in writing, software 1198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * distributed under the License is distributed on an "AS IS" BASIS, 1298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * See the License for the specific language governing permissions and 1498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * limitations under the License. 1598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 1698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 1798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangpackage android.net.sip; 1898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 193adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport android.content.Context; 203adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport android.media.AudioManager; 213adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport android.net.rtp.AudioCodec; 2298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.net.rtp.AudioGroup; 2398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.net.rtp.AudioStream; 243adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport android.net.rtp.RtpStream; 253adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport android.net.sip.SimpleSessionDescription.Media; 263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport android.net.wifi.WifiManager; 2798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wangimport android.os.Message; 289329db04f13480ccdff013dcc00cdb96f12a921cWink Savilleimport android.telephony.Rlog; 29bb18b405c539e483cce67ae207bd7e6263c0d071repo syncimport android.text.TextUtils; 303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport java.io.IOException; 313adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport java.net.InetAddress; 323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyanimport java.net.UnknownHostException; 3398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 3498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang/** 3516b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * Handles an Internet audio call over SIP. You can instantiate this class with {@link SipManager}, 3616b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * using {@link SipManager#makeAudioCall makeAudioCall()} and {@link SipManager#takeAudioCall 3716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * takeAudioCall()}. 38d3666076203ecc553211f8fa443ef259667ddd5eHung-ying Tyan * 3916b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <p class="note"><strong>Note:</strong> Using this class require the 40d3666076203ecc553211f8fa443ef259667ddd5eHung-ying Tyan * {@link android.Manifest.permission#INTERNET} and 41b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * {@link android.Manifest.permission#USE_SIP} permissions. In addition, {@link 4216b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * #startAudio} requires the 43d3666076203ecc553211f8fa443ef259667ddd5eHung-ying Tyan * {@link android.Manifest.permission#RECORD_AUDIO}, 4416b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link android.Manifest.permission#ACCESS_WIFI_STATE}, and 4516b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link android.Manifest.permission#WAKE_LOCK} permissions; and {@link #setSpeakerMode 4616b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * setSpeakerMode()} requires the 4716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} permission.</p> 48b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * 49b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * <div class="special reference"> 50b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * <h3>Developer Guides</h3> 51b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * <p>For more information about using SIP, read the 52b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * <a href="{@docRoot}guide/topics/network/sip.html">Session Initiation Protocol</a> 53b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * developer guide.</p> 54b4074803f775e5a4616287804f3405fd17eecab3Joe Fernandez * </div> 5598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 567a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyanpublic class SipAudioCall { 579329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final String LOG_TAG = SipAudioCall.class.getSimpleName(); 589329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private static final boolean DBG = true; 593adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private static final boolean RELEASE_SOCKET = true; 603adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private static final boolean DONT_RELEASE_SOCKET = false; 613adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private static final int SESSION_TIMEOUT = 5; // in seconds 62f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync private static final int TRANSFER_TIMEOUT = 15; // in seconds 633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 6416b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main /** Listener for events relating to a SIP call, such as when a call is being 6516b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * recieved ("on ringing") or a call is outgoing ("on calling"). 6616b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <p>Many of these events are also received by {@link SipSession.Listener}.</p> 6716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main */ 683adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public static class Listener { 6998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 7098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Called when the call object is ready to make another call. 714e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * The default implementation calls {@link #onChanged}. 7298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 7398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that is ready to make another call 7498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 753adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onReadyToCall(SipAudioCall call) { 763adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onChanged(call); 773adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 7998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 8098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Called when a request is sent out to initiate a new call. 814e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * The default implementation calls {@link #onChanged}. 8298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 8398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that carries out the audio call 8498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCalling(SipAudioCall call) { 863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onChanged(call); 873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 8998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 9098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Called when a new call comes in. 914e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * The default implementation calls {@link #onChanged}. 9298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 9398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that carries out the audio call 9498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param caller the SIP profile of the caller 9598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 963adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onRinging(SipAudioCall call, SipProfile caller) { 973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onChanged(call); 983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 9998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 10098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 1013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Called when a RINGING response is received for the INVITE request 1024e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * sent. The default implementation calls {@link #onChanged}. 10398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 10498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that carries out the audio call 10598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 1063adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onRingingBack(SipAudioCall call) { 1073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onChanged(call); 1083adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 11098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 11198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Called when the session is established. 1124e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * The default implementation calls {@link #onChanged}. 11398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 11498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that carries out the audio call 11598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 1163adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCallEstablished(SipAudioCall call) { 1173adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onChanged(call); 1183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 12098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 12198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Called when the session is terminated. 1224e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * The default implementation calls {@link #onChanged}. 12398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 12498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that carries out the audio call 12598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 1263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCallEnded(SipAudioCall call) { 1273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onChanged(call); 1283adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 12998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 13098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 13198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Called when the peer is busy during session initialization. 1324e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * The default implementation calls {@link #onChanged}. 13398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 13498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that carries out the audio call 13598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 1363adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCallBusy(SipAudioCall call) { 1373adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onChanged(call); 1383adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 13998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 14098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 14198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Called when the call is on hold. 1424e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * The default implementation calls {@link #onChanged}. 14398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 14498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that carries out the audio call 14598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 1463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCallHeld(SipAudioCall call) { 1473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onChanged(call); 1483adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 14998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 15098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 1513adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Called when an error occurs. The default implementation is no op. 15298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 15398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param call the call object that carries out the audio call 154188f70fdaf7d8cd20e9386051d06ca5a3ba0b683Hung-ying Tyan * @param errorCode error code of this error 15598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param errorMessage error message 156a0171082cfc4b860a82dcf5ebbd498b253f1032fHung-ying Tyan * @see SipErrorCode 15798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 1583adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onError(SipAudioCall call, int errorCode, 1593adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan String errorMessage) { 1603adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // no-op 1613adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 1623adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 1633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan /** 1643adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Called when an event occurs and the corresponding callback is not 1653adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * overridden. The default implementation is no op. Error events are 1663adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * not re-directed to this callback and are handled in {@link #onError}. 1673adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan */ 1683adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onChanged(SipAudioCall call) { 1693adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // no-op 1703adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 17198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang } 17298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 1733adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private Context mContext; 1743adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private SipProfile mLocalProfile; 1753adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private SipAudioCall.Listener mListener; 1763adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private SipSession mSipSession; 17722ecc3df834674605daf86f7edf20169b6ca800brepo sync private SipSession mTransferringSession; 1783adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 1793adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private long mSessionId = System.currentTimeMillis(); 1803adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private String mPeerSd; 1813adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 1823adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private AudioStream mAudioStream; 1833adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private AudioGroup mAudioGroup; 1843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 1853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private boolean mInCall = false; 1863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private boolean mMuted = false; 1873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private boolean mHold = false; 1883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 1893adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private WifiManager mWm; 1903adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private WifiManager.WifiLock mWifiHighPerfLock; 1913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 1923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private int mErrorCode = SipErrorCode.NO_ERROR; 1933adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private String mErrorMessage; 1943adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 19598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 1963adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Creates a call object with the local SIP profile. 1973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @param context the context for accessing system services such as 1983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * ringtone, audio, WIFI etc 19998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 2003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public SipAudioCall(Context context, SipProfile localProfile) { 2013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mContext = context; 2023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mLocalProfile = localProfile; 2033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mWm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 20498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang } 20598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 20698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 20798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Sets the listener to listen to the audio call events. The method calls 20816b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link #setListener setListener(listener, false)}. 20998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 21098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param listener to listen to the audio call events of this object 21198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @see #setListener(Listener, boolean) 21298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 2133adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void setListener(SipAudioCall.Listener listener) { 2143adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan setListener(listener, false); 2153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 21698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 21798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 21898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Sets the listener to listen to the audio call events. A 21998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * {@link SipAudioCall} can only hold one listener at a time. Subsequent 22098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * calls to this method override the previous listener. 22198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 22298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param listener to listen to the audio call events of this object 22398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param callbackImmediately set to true if the caller wants to be called 22498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * back immediately on the current state 22598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 2263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void setListener(SipAudioCall.Listener listener, 2273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan boolean callbackImmediately) { 2283adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mListener = listener; 2293adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 2303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if ((listener == null) || !callbackImmediately) { 2313adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // do nothing 2323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if (mErrorCode != SipErrorCode.NO_ERROR) { 2333adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onError(this, mErrorCode, mErrorMessage); 2343adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if (mInCall) { 2353adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mHold) { 2363adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onCallHeld(this); 2373adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else { 2383adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onCallEstablished(this); 2393adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 2403adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else { 2413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan int state = getState(); 2423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan switch (state) { 2433adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan case SipSession.State.READY_TO_CALL: 2443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onReadyToCall(this); 2453adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan break; 2463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan case SipSession.State.INCOMING_CALL: 2473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onRinging(this, getPeerProfile()); 2483adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan break; 2493adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan case SipSession.State.OUTGOING_CALL: 2503adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onCalling(this); 2513adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan break; 2523adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan case SipSession.State.OUTGOING_CALL_RING_BACK: 2533adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onRingingBack(this); 2543adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan break; 2553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 2563adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 2573adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable t) { 2589329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("setListener()", t); 2593adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 2603adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 2613adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 2623adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan /** 2633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Checks if the call is established. 2643adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * 2653adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @return true if the call is established 2663adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan */ 2674e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public boolean isInCall() { 2684e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 2694e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return mInCall; 2704e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 2713adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 2723adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 2733adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan /** 2743adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Checks if the call is on hold. 2753adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * 2763adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @return true if the call is on hold 2773adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan */ 2784e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public boolean isOnHold() { 2794e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 2804e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return mHold; 2814e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 2823adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 28398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 28498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 285ecd6e06707e7ce1001a05e919063da1c4b10d746Hung-ying Tyan * Closes this object. This object is not usable after being closed. 28698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 2873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void close() { 2883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan close(true); 2893adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 2903adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 2913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private synchronized void close(boolean closeRtp) { 2923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (closeRtp) stopCall(RELEASE_SOCKET); 2933adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 2943adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mInCall = false; 2953adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mHold = false; 2963adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mSessionId = System.currentTimeMillis(); 2973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mErrorCode = SipErrorCode.NO_ERROR; 2983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mErrorMessage = null; 2993adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 3003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mSipSession != null) { 3013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mSipSession.setListener(null); 3023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mSipSession = null; 3033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 3043adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 30598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 30698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 3073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Gets the local SIP profile. 30898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 3093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @return the local SIP profile 31098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 3114e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public SipProfile getLocalProfile() { 3124e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 3134e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return mLocalProfile; 3144e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 3153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 31698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 31798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 3183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Gets the peer's SIP profile. 3193adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * 3203adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @return the peer's SIP profile 321ecd6e06707e7ce1001a05e919063da1c4b10d746Hung-ying Tyan */ 3224e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public SipProfile getPeerProfile() { 3234e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 3244e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return (mSipSession == null) ? null : mSipSession.getPeerProfile(); 3254e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 3263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 3273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 3283adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan /** 3293adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Gets the state of the {@link SipSession} that carries this call. 3303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * The value returned must be one of the states in {@link SipSession.State}. 3313adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * 3323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @return the session state 3333adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan */ 3344e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public int getState() { 3354e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 3364e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan if (mSipSession == null) return SipSession.State.READY_TO_CALL; 3374e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return mSipSession.getState(); 3384e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 3393adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 3403adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 3413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 3423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan /** 3433adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Gets the {@link SipSession} that carries this call. 3443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * 3453adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @return the session object that carries this call 3463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @hide 3473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan */ 3484e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public SipSession getSipSession() { 3494e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 3504e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return mSipSession; 3514e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 3523adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 3533adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 35422ecc3df834674605daf86f7edf20169b6ca800brepo sync private synchronized void transferToNewSession() { 35522ecc3df834674605daf86f7edf20169b6ca800brepo sync if (mTransferringSession == null) return; 35622ecc3df834674605daf86f7edf20169b6ca800brepo sync SipSession origin = mSipSession; 35722ecc3df834674605daf86f7edf20169b6ca800brepo sync mSipSession = mTransferringSession; 35822ecc3df834674605daf86f7edf20169b6ca800brepo sync mTransferringSession = null; 35922ecc3df834674605daf86f7edf20169b6ca800brepo sync 36022ecc3df834674605daf86f7edf20169b6ca800brepo sync // stop the replaced call. 36122ecc3df834674605daf86f7edf20169b6ca800brepo sync if (mAudioStream != null) { 36222ecc3df834674605daf86f7edf20169b6ca800brepo sync mAudioStream.join(null); 36322ecc3df834674605daf86f7edf20169b6ca800brepo sync } else { 36422ecc3df834674605daf86f7edf20169b6ca800brepo sync try { 36522ecc3df834674605daf86f7edf20169b6ca800brepo sync mAudioStream = new AudioStream(InetAddress.getByName( 36622ecc3df834674605daf86f7edf20169b6ca800brepo sync getLocalIp())); 36722ecc3df834674605daf86f7edf20169b6ca800brepo sync } catch (Throwable t) { 3689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("transferToNewSession():", t); 36922ecc3df834674605daf86f7edf20169b6ca800brepo sync } 37022ecc3df834674605daf86f7edf20169b6ca800brepo sync } 37122ecc3df834674605daf86f7edf20169b6ca800brepo sync if (origin != null) origin.endCall(); 37222ecc3df834674605daf86f7edf20169b6ca800brepo sync startAudio(); 37322ecc3df834674605daf86f7edf20169b6ca800brepo sync } 37422ecc3df834674605daf86f7edf20169b6ca800brepo sync 3753adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private SipSession.Listener createListener() { 3763adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan return new SipSession.Listener() { 3773adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 3783adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCalling(SipSession session) { 3799329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("onCalling: session=" + session); 3803adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Listener listener = mListener; 3813adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (listener != null) { 3823adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 3833adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onCalling(SipAudioCall.this); 3843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable t) { 3859329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onCalling():", t); 3863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 3873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 3883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 3893adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 3903adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 3913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onRingingBack(SipSession session) { 3929329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("onRingingBackk: " + session); 3933adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Listener listener = mListener; 3943adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (listener != null) { 3953adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 3963adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onRingingBack(SipAudioCall.this); 3973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable t) { 3989329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onRingingBack():", t); 3993adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 4033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 4044e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void onRinging(SipSession session, 4053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan SipProfile peerProfile, String sessionDescription) { 406bb18b405c539e483cce67ae207bd7e6263c0d071repo sync // this callback is triggered only for reinvite. 4074e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (SipAudioCall.this) { 4084e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan if ((mSipSession == null) || !mInCall 4094e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan || !session.getCallId().equals( 4104e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mSipSession.getCallId())) { 4114e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan // should not happen 4124e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan session.endCall(); 4134e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return; 4144e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 4153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 4164e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan // session changing request 4174e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan try { 4184e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan String answer = createAnswer(sessionDescription).encode(); 4194e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mSipSession.answerCall(answer, SESSION_TIMEOUT); 4204e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } catch (Throwable e) { 4219329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onRinging():", e); 4224e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan session.endCall(); 4234e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 4243adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4253adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 4273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 4283adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCallEstablished(SipSession session, 4293adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan String sessionDescription) { 4303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mPeerSd = sessionDescription; 4319329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("onCallEstablished(): " + mPeerSd); 4323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 43322ecc3df834674605daf86f7edf20169b6ca800brepo sync // TODO: how to notify the UI that the remote party is changed 43422ecc3df834674605daf86f7edf20169b6ca800brepo sync if ((mTransferringSession != null) 43522ecc3df834674605daf86f7edf20169b6ca800brepo sync && (session == mTransferringSession)) { 43622ecc3df834674605daf86f7edf20169b6ca800brepo sync transferToNewSession(); 43722ecc3df834674605daf86f7edf20169b6ca800brepo sync return; 43822ecc3df834674605daf86f7edf20169b6ca800brepo sync } 43922ecc3df834674605daf86f7edf20169b6ca800brepo sync 4403adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Listener listener = mListener; 4413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (listener != null) { 4423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 4433adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mHold) { 4443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onCallHeld(SipAudioCall.this); 4453adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else { 4463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onCallEstablished(SipAudioCall.this); 4473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4483adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable t) { 4499329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onCallEstablished(): ", t); 4503adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4513adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4523adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4533adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 4543adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 4553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCallEnded(SipSession session) { 4569329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("onCallEnded: " + session + " mSipSession:" + mSipSession); 45722ecc3df834674605daf86f7edf20169b6ca800brepo sync // reset the trasnferring session if it is the one. 45822ecc3df834674605daf86f7edf20169b6ca800brepo sync if (session == mTransferringSession) { 45922ecc3df834674605daf86f7edf20169b6ca800brepo sync mTransferringSession = null; 46022ecc3df834674605daf86f7edf20169b6ca800brepo sync return; 46122ecc3df834674605daf86f7edf20169b6ca800brepo sync } 46222ecc3df834674605daf86f7edf20169b6ca800brepo sync // or ignore the event if the original session is being 46322ecc3df834674605daf86f7edf20169b6ca800brepo sync // transferred to the new one. 46422ecc3df834674605daf86f7edf20169b6ca800brepo sync if ((mTransferringSession != null) || 46522ecc3df834674605daf86f7edf20169b6ca800brepo sync (session != mSipSession)) return; 46622ecc3df834674605daf86f7edf20169b6ca800brepo sync 4673adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Listener listener = mListener; 4683adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (listener != null) { 4693adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 4703adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onCallEnded(SipAudioCall.this); 4713adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable t) { 4729329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onCallEnded(): ", t); 4733adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4743adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4753adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan close(); 4763adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4773adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 4783adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 4793adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCallBusy(SipSession session) { 4809329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("onCallBusy: " + session); 4813adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Listener listener = mListener; 4823adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (listener != null) { 4833adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 4843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onCallBusy(SipAudioCall.this); 4853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable t) { 4869329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onCallBusy(): ", t); 4873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4893adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan close(false); 4903adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 4913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 4923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 4933adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onCallChangeFailed(SipSession session, int errorCode, 4943adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan String message) { 4959329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("onCallChangedFailed: " + message); 4963adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mErrorCode = errorCode; 4973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mErrorMessage = message; 4983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Listener listener = mListener; 4993adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (listener != null) { 5003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 5013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onError(SipAudioCall.this, mErrorCode, 5023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan message); 5033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable t) { 5049329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onCallBusy():", t); 5053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5063adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5083adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 5093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 5103adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onError(SipSession session, int errorCode, 5113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan String message) { 5123adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan SipAudioCall.this.onError(errorCode, message); 5133adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5143adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 5153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 5163adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onRegistering(SipSession session) { 5173adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // irrelevant 5183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5193adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 5203adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 5213adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onRegistrationTimeout(SipSession session) { 5223adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // irrelevant 5233adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5243adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 5253adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 5263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onRegistrationFailed(SipSession session, int errorCode, 5273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan String message) { 5283adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // irrelevant 5293adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 5313adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan @Override 5323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void onRegistrationDone(SipSession session, int duration) { 5333adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // irrelevant 5343adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 53522ecc3df834674605daf86f7edf20169b6ca800brepo sync 53622ecc3df834674605daf86f7edf20169b6ca800brepo sync @Override 53722ecc3df834674605daf86f7edf20169b6ca800brepo sync public void onCallTransferring(SipSession newSession, 53822ecc3df834674605daf86f7edf20169b6ca800brepo sync String sessionDescription) { 5399329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("onCallTransferring: mSipSession=" 5409329db04f13480ccdff013dcc00cdb96f12a921cWink Saville + mSipSession + " newSession=" + newSession); 54122ecc3df834674605daf86f7edf20169b6ca800brepo sync mTransferringSession = newSession; 54222ecc3df834674605daf86f7edf20169b6ca800brepo sync try { 543f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync if (sessionDescription == null) { 544f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.makeCall(newSession.getPeerProfile(), 545f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync createOffer().encode(), TRANSFER_TIMEOUT); 546f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } else { 547f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync String answer = createAnswer(sessionDescription).encode(); 548f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync newSession.answerCall(answer, SESSION_TIMEOUT); 549f0af349a5b7b7df47e6b1b53e028cecdff50caa6repo sync } 55022ecc3df834674605daf86f7edf20169b6ca800brepo sync } catch (Throwable e) { 5519329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onCallTransferring()", e); 55222ecc3df834674605daf86f7edf20169b6ca800brepo sync newSession.endCall(); 55322ecc3df834674605daf86f7edf20169b6ca800brepo sync } 55422ecc3df834674605daf86f7edf20169b6ca800brepo sync } 5553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan }; 5563adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5573adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 5583adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private void onError(int errorCode, String message) { 5599329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("onError: " 5603adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan + SipErrorCode.toString(errorCode) + ": " + message); 5613adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mErrorCode = errorCode; 5623adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mErrorMessage = message; 5633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Listener listener = mListener; 5643adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (listener != null) { 5653adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 5663adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan listener.onError(this, errorCode, message); 5673adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable t) { 5689329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("onError():", t); 5693adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5703adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5713adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan synchronized (this) { 5723adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if ((errorCode == SipErrorCode.DATA_CONNECTION_LOST) 5733adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan || !isInCall()) { 5743adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan close(true); 5753adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5763adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 5773adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 578ecd6e06707e7ce1001a05e919063da1c4b10d746Hung-ying Tyan 579ecd6e06707e7ce1001a05e919063da1c4b10d746Hung-ying Tyan /** 58098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Attaches an incoming call to this call object. 58198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 58298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param session the session that receives the incoming call 5836d0ef774a2492b0996ded3a43c300c7f72a94897Chia-chi Yeh * @param sessionDescription the session description of the incoming call 5843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @throws SipException if the SIP service fails to attach this object to 58538ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan * the session or VOIP API is not supported by the device 58638ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan * @see SipManager#isVoipSupported 5873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan */ 5884e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void attachCall(SipSession session, String sessionDescription) 5894e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan throws SipException { 59038ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan if (!SipManager.isVoipSupported(mContext)) { 59138ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan throw new SipException("VOIP API is not supported"); 59238ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan } 59338ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan 5944e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 5954e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mSipSession = session; 5964e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mPeerSd = sessionDescription; 5979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("attachCall(): " + mPeerSd); 5984e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan try { 5994e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan session.setListener(createListener()); 6004e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } catch (Throwable e) { 6019329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("attachCall()", e); 6024e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan throwSipException(e); 6034e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 6043adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 6053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 6063adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 6073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan /** 6083adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Initiates an audio call to the specified profile. The attempt will be 6093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * timed out if the call is not established within {@code timeout} seconds 61016b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * and {@link Listener#onError onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} 6113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * will be called. 6123adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * 6134e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan * @param peerProfile the SIP profile to make the call to 6147a4ec7268fbfb56e22f1cb8497d37ed733d8aa8eHung-ying Tyan * @param sipSession the {@link SipSession} for carrying out the call 6153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @param timeout the timeout value in seconds. Default value (defined by 6163adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * SIP protocol) is used if {@code timeout} is zero or negative. 61716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * @see Listener#onError 6183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @throws SipException if the SIP service fails to create a session for the 61938ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan * call or VOIP API is not supported by the device 62038ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan * @see SipManager#isVoipSupported 62198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 6224e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void makeCall(SipProfile peerProfile, SipSession sipSession, 6234e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan int timeout) throws SipException { 6249329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("makeCall: " + peerProfile + " session=" + sipSession + " timeout=" + timeout); 62538ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan if (!SipManager.isVoipSupported(mContext)) { 62638ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan throw new SipException("VOIP API is not supported"); 62738ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan } 62838ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan 6294e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 6304e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mSipSession = sipSession; 6314e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan try { 6324e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mAudioStream = new AudioStream(InetAddress.getByName( 6334e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan getLocalIp())); 6344e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan sipSession.setListener(createListener()); 6354e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan sipSession.makeCall(peerProfile, createOffer().encode(), 6364e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan timeout); 6374e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } catch (IOException e) { 6389329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("makeCall:", e); 6394e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan throw new SipException("makeCall()", e); 6404e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 6413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 6423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 64398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 6443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan /** 6453adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Ends a call. 6463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @throws SipException if the SIP service fails to end the call 6473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan */ 6484e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void endCall() throws SipException { 6499329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("endCall: mSipSession" + mSipSession); 6504e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 6514e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan stopCall(RELEASE_SOCKET); 6524e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mInCall = false; 6533adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 6544e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan // perform the above local ops first and then network op 6554e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan if (mSipSession != null) mSipSession.endCall(); 6564e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 6573adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 65898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 65998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 660901503e1cf8b6cfac1540a22c325eb5cdd879429Hung-ying Tyan * Puts a call on hold. When succeeds, {@link Listener#onCallHeld} is 661f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * called. The attempt will be timed out if the call is not established 662f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * within {@code timeout} seconds and 66316b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link Listener#onError onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} 664f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * will be called. 665f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * 6663adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @param timeout the timeout value in seconds. Default value (defined by 6673adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * SIP protocol) is used if {@code timeout} is zero or negative. 66816b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * @see Listener#onError 6693adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @throws SipException if the SIP service fails to hold the call 67098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 6714e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void holdCall(int timeout) throws SipException { 6729329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("holdCall: mSipSession" + mSipSession + " timeout=" + timeout); 6734e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 67444afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan if (mHold) return; 67538ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan if (mSipSession == null) { 6769329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("holdCall:"); 67738ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan throw new SipException("Not in a call to hold call"); 67838ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan } 6794e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mSipSession.changeCall(createHoldOffer().encode(), timeout); 6804e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mHold = true; 68144afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan setAudioGroupMode(); 6824e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 6833adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 68498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 685f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan /** 686f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * Answers a call. The attempt will be timed out if the call is not 687f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * established within {@code timeout} seconds and 68816b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link Listener#onError onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} 689f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * will be called. 690f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * 6913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @param timeout the timeout value in seconds. Default value (defined by 6923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * SIP protocol) is used if {@code timeout} is zero or negative. 69316b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * @see Listener#onError 6943adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @throws SipException if the SIP service fails to answer the call 695f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan */ 6964e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void answerCall(int timeout) throws SipException { 6979329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("answerCall: mSipSession" + mSipSession + " timeout=" + timeout); 6984e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 69938ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan if (mSipSession == null) { 70038ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan throw new SipException("No call to answer"); 70138ee75e8c0722118d26a23afe5b509b6a09302f4Hung-ying Tyan } 7024e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan try { 7034e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mAudioStream = new AudioStream(InetAddress.getByName( 7044e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan getLocalIp())); 7054e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mSipSession.answerCall(createAnswer(mPeerSd).encode(), timeout); 7064e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } catch (IOException e) { 7079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("answerCall:", e); 7084e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan throw new SipException("answerCall()", e); 7094e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 7103adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 71298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 71398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 71498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Continues a call that's on hold. When succeeds, 715f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * {@link Listener#onCallEstablished} is called. The attempt will be timed 716f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * out if the call is not established within {@code timeout} seconds and 71716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link Listener#onError onError(SipAudioCall, SipErrorCode.TIME_OUT, String)} 718f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * will be called. 719f498e98d2e2910e866ec0728cebbe676dd475d9eHung-ying Tyan * 7203adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @param timeout the timeout value in seconds. Default value (defined by 7213adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * SIP protocol) is used if {@code timeout} is zero or negative. 72216b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * @see Listener#onError 7233adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @throws SipException if the SIP service fails to unhold the call 72498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 7254e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void continueCall(int timeout) throws SipException { 7269329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("continueCall: mSipSession" + mSipSession + " timeout=" + timeout); 7274e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 7284e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan if (!mHold) return; 7294e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mSipSession.changeCall(createContinueOffer().encode(), timeout); 7304e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mHold = false; 73144afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan setAudioGroupMode(); 7324e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 7333adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 73498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 7353adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private SimpleSessionDescription createOffer() { 7363adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan SimpleSessionDescription offer = 7373adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan new SimpleSessionDescription(mSessionId, getLocalIp()); 7383adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan AudioCodec[] codecs = AudioCodec.getCodecs(); 7393adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Media media = offer.newMedia( 7403adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); 7413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan for (AudioCodec codec : AudioCodec.getCodecs()) { 7423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); 7433adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan media.setRtpPayload(127, "telephone-event/8000", "0-15"); 7459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("createOffer: offer=" + offer); 7463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan return offer; 7473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 74898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 7493adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private SimpleSessionDescription createAnswer(String offerSd) { 750bb18b405c539e483cce67ae207bd7e6263c0d071repo sync if (TextUtils.isEmpty(offerSd)) return createOffer(); 7513adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan SimpleSessionDescription offer = 7523adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan new SimpleSessionDescription(offerSd); 7533adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan SimpleSessionDescription answer = 7543adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan new SimpleSessionDescription(mSessionId, getLocalIp()); 7553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan AudioCodec codec = null; 7563adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan for (Media media : offer.getMedia()) { 7573adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if ((codec == null) && (media.getPort() > 0) 7583adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan && "audio".equals(media.getType()) 7593adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan && "RTP/AVP".equals(media.getProtocol())) { 7603adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Find the first audio codec we supported. 7613adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan for (int type : media.getRtpPayloadTypes()) { 7623adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan codec = AudioCodec.getCodec(type, media.getRtpmap(type), 7633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan media.getFmtp(type)); 7643adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (codec != null) { 7653adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan break; 7663adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7673adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7683adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (codec != null) { 7693adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Media reply = answer.newMedia( 7703adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); 7713adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan reply.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); 77298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 7733adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Check if DTMF is supported in the same media. 7743adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan for (int type : media.getRtpPayloadTypes()) { 7753adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan String rtpmap = media.getRtpmap(type); 7763adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if ((type != codec.type) && (rtpmap != null) 7773adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan && rtpmap.startsWith("telephone-event")) { 7783adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan reply.setRtpPayload( 7793adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan type, rtpmap, media.getFmtp(type)); 7803adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7813adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7823adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 7833adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Handle recvonly and sendonly. 7843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (media.getAttribute("recvonly") != null) { 7853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan answer.setAttribute("sendonly", ""); 7863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if(media.getAttribute("sendonly") != null) { 7873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan answer.setAttribute("recvonly", ""); 7883adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if(offer.getAttribute("recvonly") != null) { 7893adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan answer.setAttribute("sendonly", ""); 7903adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if(offer.getAttribute("sendonly") != null) { 7913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan answer.setAttribute("recvonly", ""); 7923adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7933adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan continue; 7943adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7953adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 7963adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Reject the media. 7973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Media reply = answer.newMedia( 7983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan media.getType(), 0, 1, media.getProtocol()); 7993adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan for (String format : media.getFormats()) { 8003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan reply.setFormat(format, null); 8013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (codec == null) { 8049329db04f13480ccdff013dcc00cdb96f12a921cWink Saville loge("createAnswer: no suitable codes"); 8053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan throw new IllegalStateException("Reject SDP: no suitable codecs"); 8063adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8079329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("createAnswer: answer=" + answer); 8083adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan return answer; 8093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8103adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 8113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private SimpleSessionDescription createHoldOffer() { 8123adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan SimpleSessionDescription offer = createContinueOffer(); 8133adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan offer.setAttribute("sendonly", ""); 8149329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("createHoldOffer: offer=" + offer); 8153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan return offer; 8163adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8173adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 8183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private SimpleSessionDescription createContinueOffer() { 8199329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("createContinueOffer"); 8203adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan SimpleSessionDescription offer = 8213adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan new SimpleSessionDescription(mSessionId, getLocalIp()); 8223adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan Media media = offer.newMedia( 8233adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan "audio", mAudioStream.getLocalPort(), 1, "RTP/AVP"); 8243adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan AudioCodec codec = mAudioStream.getCodec(); 8253adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan media.setRtpPayload(codec.type, codec.rtpmap, codec.fmtp); 8263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan int dtmfType = mAudioStream.getDtmfType(); 8273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (dtmfType != -1) { 8283adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan media.setRtpPayload(dtmfType, "telephone-event/8000", "0-15"); 8293adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan return offer; 8313adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 8333adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private void grabWifiHighPerfLock() { 8343adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mWifiHighPerfLock == null) { 8359329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("grabWifiHighPerfLock:"); 8363adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mWifiHighPerfLock = ((WifiManager) 8373adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mContext.getSystemService(Context.WIFI_SERVICE)) 8389329db04f13480ccdff013dcc00cdb96f12a921cWink Saville .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, LOG_TAG); 8393adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mWifiHighPerfLock.acquire(); 8403adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 8433adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private void releaseWifiHighPerfLock() { 8443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mWifiHighPerfLock != null) { 8459329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("releaseWifiHighPerfLock:"); 8463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mWifiHighPerfLock.release(); 8473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mWifiHighPerfLock = null; 8483adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8493adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8503adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 8513adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private boolean isWifiOn() { 8523adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan return (mWm.getConnectionInfo().getBSSID() == null) ? false : true; 8533adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8543adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 8553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan /** Toggles mute. */ 8564e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void toggleMute() { 8574e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 85844afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan mMuted = !mMuted; 85944afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan setAudioGroupMode(); 8603adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8613adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 86298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 86398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 86498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Checks if the call is muted. 86598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 86698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @return true if the call is muted 86798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 8684e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public boolean isMuted() { 8694e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 8704e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return mMuted; 8714e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 8723adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 8733adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 874d3666076203ecc553211f8fa443ef259667ddd5eHung-ying Tyan /** 875d3666076203ecc553211f8fa443ef259667ddd5eHung-ying Tyan * Puts the device to speaker mode. 87616b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <p class="note"><strong>Note:</strong> Requires the 87716b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS} permission.</p> 87844afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan * 87944afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan * @param speakerMode set true to enable speaker mode; false to disable 880d3666076203ecc553211f8fa443ef259667ddd5eHung-ying Tyan */ 8814e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void setSpeakerMode(boolean speakerMode) { 8824e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 8834e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)) 8844e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan .setSpeakerphoneOn(speakerMode); 88544afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan setAudioGroupMode(); 8864e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 8873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 88898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 88944afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan private boolean isSpeakerOn() { 89044afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan return ((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE)) 89144afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan .isSpeakerphoneOn(); 89244afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan } 89344afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan 89498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 89516b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2883</a>, 89616b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * event 0--9 maps to decimal 8973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * value 0--9, '*' to 10, '#' to 11, event 'A'--'D' to 12--15, and event 8983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * flash to 16. Currently, event flash is not supported. 89998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 9003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @param code the DTMF code to send. Value 0 to 15 (inclusive) are valid 9013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * inputs. 90298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 9033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void sendDtmf(int code) { 9043adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan sendDtmf(code, null); 9053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 90698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 90798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 90816b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2883</a>, 90916b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * event 0--9 maps to decimal 9103adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * value 0--9, '*' to 10, '#' to 11, event 'A'--'D' to 12--15, and event 9113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * flash to 16. Currently, event flash is not supported. 91298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 9133adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @param code the DTMF code to send. Value 0 to 15 (inclusive) are valid 9143adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * inputs. 91598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @param result the result message to send when done 91698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 9174e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void sendDtmf(int code, Message result) { 9184e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 9194e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan AudioGroup audioGroup = getAudioGroup(); 9204e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan if ((audioGroup != null) && (mSipSession != null) 9214e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan && (SipSession.State.IN_CALL == getState())) { 9229329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("sendDtmf: code=" + code + " result=" + result); 9234e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan audioGroup.sendDtmf(code); 9244e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 9254e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan if (result != null) result.sendToTarget(); 9263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 9273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 92898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 92998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 93098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Gets the {@link AudioStream} object used in this call. The object 93198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * represents the RTP stream that carries the audio data to and from the 93298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * peer. The object may not be created before the call is established. And 93398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * it is undefined after the call ends or the {@link #close} method is 93498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * called. 93598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 93698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @return the {@link AudioStream} object or null if the RTP stream has not 93798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * yet been set up 9383adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @hide 93998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 9404e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public AudioStream getAudioStream() { 9414e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 9424e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return mAudioStream; 9434e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 9443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 94598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 94698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 94798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Gets the {@link AudioGroup} object which the {@link AudioStream} object 94898cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * joins. The group object may not exist before the call is established. 94998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * Also, the {@code AudioStream} may change its group during a call (e.g., 95098cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * after the call is held/un-held). Finally, the {@code AudioGroup} object 95198cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * returned by this method is undefined after the call ends or the 9520ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan * {@link #close} method is called. If a group object is set by 9530ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan * {@link #setAudioGroup(AudioGroup)}, then this method returns that object. 95498cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * 95598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @return the {@link AudioGroup} object or null if the RTP stream has not 95698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * yet been set up 95798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang * @see #getAudioStream 9583adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @hide 95998cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 9604e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public AudioGroup getAudioGroup() { 9614e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 9624e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan if (mAudioGroup != null) return mAudioGroup; 9634e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan return ((mAudioStream == null) ? null : mAudioStream.getGroup()); 9644e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 9653adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 96698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 96798cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang /** 9680ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan * Sets the {@link AudioGroup} object which the {@link AudioStream} object 9690ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan * joins. If {@code audioGroup} is null, then the {@code AudioGroup} object 97044afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan * will be dynamically created when needed. Note that the mode of the 97144afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan * {@code AudioGroup} is not changed according to the audio settings (i.e., 97244afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan * hold, mute, speaker phone) of this object. This is mainly used to merge 97344afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan * multiple {@code SipAudioCall} objects to form a conference call. The 97444afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan * settings of the first object (that merges others) override others'. 9750ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan * 9760ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan * @see #getAudioStream 9773adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * @hide 9780ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan */ 9794e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan public void setAudioGroup(AudioGroup group) { 9804e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan synchronized (this) { 9819329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("setAudioGroup: group=" + group); 9824e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) { 9834e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mAudioStream.join(group); 9844e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan } 9854e22f5d6687c18440e2f38c7e242d66ad834d1d7Hung-ying Tyan mAudioGroup = group; 9863adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 9873adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 9880ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan 9890ca131a2c0474ace43678a130eeee0d491a5fac4Hung-ying Tyan /** 9903adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * Starts the audio for the established call. This method should be called 9913adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan * after {@link Listener#onCallEstablished} is called. 99216b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * <p class="note"><strong>Note:</strong> Requires the 993d3666076203ecc553211f8fa443ef259667ddd5eHung-ying Tyan * {@link android.Manifest.permission#RECORD_AUDIO}, 994d3666076203ecc553211f8fa443ef259667ddd5eHung-ying Tyan * {@link android.Manifest.permission#ACCESS_WIFI_STATE} and 99516b441b4ad92c6a5cbc6f27cb3705eaaaaee20c1Scott Main * {@link android.Manifest.permission#WAKE_LOCK} permissions.</p> 99698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang */ 9973adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan public void startAudio() { 9983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan try { 9993adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan startAudioInternal(); 10003adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (UnknownHostException e) { 10013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onError(SipErrorCode.PEER_NOT_REACHABLE, e.getMessage()); 10023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } catch (Throwable e) { 10033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan onError(SipErrorCode.CLIENT_ERROR, e.getMessage()); 10043adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 100698cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 10073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private synchronized void startAudioInternal() throws UnknownHostException { 10089329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) loge("startAudioInternal: mPeerSd=" + mPeerSd); 10093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mPeerSd == null) { 10103adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan throw new IllegalStateException("mPeerSd = null"); 10113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 101298cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 10133adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stopCall(DONT_RELEASE_SOCKET); 10143adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mInCall = true; 101598cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 10163adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Run exact the same logic in createAnswer() to setup mAudioStream. 10173adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan SimpleSessionDescription offer = 10183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan new SimpleSessionDescription(mPeerSd); 10193adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan AudioStream stream = mAudioStream; 10203adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan AudioCodec codec = null; 10213adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan for (Media media : offer.getMedia()) { 10223adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if ((codec == null) && (media.getPort() > 0) 10233adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan && "audio".equals(media.getType()) 10243adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan && "RTP/AVP".equals(media.getProtocol())) { 10253adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Find the first audio codec we supported. 10263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan for (int type : media.getRtpPayloadTypes()) { 10273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan codec = AudioCodec.getCodec( 10283adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan type, media.getRtpmap(type), media.getFmtp(type)); 10293adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (codec != null) { 10303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan break; 10313adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10323adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10333adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 10343adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (codec != null) { 10353adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Associate with the remote host. 10363adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan String address = media.getAddress(); 10373adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (address == null) { 10383adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan address = offer.getAddress(); 10393adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10403adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.associate(InetAddress.getByName(address), 10413adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan media.getPort()); 10423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 10433adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setDtmfType(-1); 10443adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setCodec(codec); 10453adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Check if DTMF is supported in the same media. 10463adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan for (int type : media.getRtpPayloadTypes()) { 10473adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan String rtpmap = media.getRtpmap(type); 10483adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if ((type != codec.type) && (rtpmap != null) 10493adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan && rtpmap.startsWith("telephone-event")) { 10503adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setDtmfType(type); 10513adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10523adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10533adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 10543adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // Handle recvonly and sendonly. 10553adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mHold) { 10563adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setMode(RtpStream.MODE_NORMAL); 10573adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if (media.getAttribute("recvonly") != null) { 10583adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setMode(RtpStream.MODE_SEND_ONLY); 10593adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if(media.getAttribute("sendonly") != null) { 10603adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setMode(RtpStream.MODE_RECEIVE_ONLY); 10613adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if(offer.getAttribute("recvonly") != null) { 10623adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setMode(RtpStream.MODE_SEND_ONLY); 10633adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else if(offer.getAttribute("sendonly") != null) { 10643adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setMode(RtpStream.MODE_RECEIVE_ONLY); 10653adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else { 10663adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.setMode(RtpStream.MODE_NORMAL); 10673adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10683adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan break; 10693adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10703adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10713adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10723adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (codec == null) { 10733adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan throw new IllegalStateException("Reject SDP: no suitable codecs"); 10743adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 10753adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 10763adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (isWifiOn()) grabWifiHighPerfLock(); 10773adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 10783adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // AudioGroup logic: 10793adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan AudioGroup audioGroup = getAudioGroup(); 10803adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mHold) { 10813adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // don't create an AudioGroup here; doing so will fail if 10823adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan // there's another AudioGroup out there that's active 10833adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else { 10843adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (audioGroup == null) audioGroup = new AudioGroup(); 10853adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan stream.join(audioGroup); 108644afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan } 108744afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan setAudioGroupMode(); 108844afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan } 108944afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan 109044afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan // set audio group mode based on current audio configuration 109144afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan private void setAudioGroupMode() { 109244afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan AudioGroup audioGroup = getAudioGroup(); 10939329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("setAudioGroupMode: audioGroup=" + audioGroup); 109444afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan if (audioGroup != null) { 109544afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan if (mHold) { 109644afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan audioGroup.setMode(AudioGroup.MODE_ON_HOLD); 109744afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan } else if (mMuted) { 10983adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan audioGroup.setMode(AudioGroup.MODE_MUTED); 109944afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan } else if (isSpeakerOn()) { 110044afaba6d2381a83caf6d6a5f3b1982d47572f3cHung-ying Tyan audioGroup.setMode(AudioGroup.MODE_ECHO_SUPPRESSION); 11013adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else { 11023adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan audioGroup.setMode(AudioGroup.MODE_NORMAL); 11033adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11043adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11053adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11063adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 11073adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private void stopCall(boolean releaseSocket) { 11089329db04f13480ccdff013dcc00cdb96f12a921cWink Saville if (DBG) log("stopCall: releaseSocket=" + releaseSocket); 11093adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan releaseWifiHighPerfLock(); 11103adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (mAudioStream != null) { 11113adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mAudioStream.join(null); 11123adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 11133adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (releaseSocket) { 11143adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mAudioStream.release(); 11153adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan mAudioStream = null; 11163adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11173adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11183adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11193adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 11203adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private String getLocalIp() { 11213adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan return mSipSession.getLocalIp(); 11223adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 112398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang 11243adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan private void throwSipException(Throwable throwable) throws SipException { 11253adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan if (throwable instanceof SipException) { 11263adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan throw (SipException) throwable; 11273adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } else { 11283adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan throw new SipException("", throwable); 11293adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11303adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 11313adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan 11329329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void log(String s) { 11339329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.d(LOG_TAG, s); 11349329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 11359329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 11369329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void loge(String s) { 11379329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.e(LOG_TAG, s); 11389329db04f13480ccdff013dcc00cdb96f12a921cWink Saville } 11399329db04f13480ccdff013dcc00cdb96f12a921cWink Saville 11409329db04f13480ccdff013dcc00cdb96f12a921cWink Saville private void loge(String s, Throwable t) { 11419329db04f13480ccdff013dcc00cdb96f12a921cWink Saville Rlog.e(LOG_TAG, s, t); 11423adf1946e78b52686fa5458e24645b05da57dc22Hung-ying Tyan } 114398cee0ce2354234e72bafb836864ec10a490ea4dChung-yih Wang} 1144