am 9404e633: Merge "Add timer to SIP session creation process." into gingerbread
Merge commit '9404e633a55cd325b57732cdd776053b3886b611' into gingerbread-plus-aosp
* commit '9404e633a55cd325b57732cdd776053b3886b611':
Add timer to SIP session creation process.
diff --git a/services/java/com/android/server/sip/SipSessionGroup.java b/services/java/com/android/server/sip/SipSessionGroup.java
index 0822350..baf9a8e 100644
--- a/services/java/com/android/server/sip/SipSessionGroup.java
+++ b/services/java/com/android/server/sip/SipSessionGroup.java
@@ -84,7 +84,8 @@
private static final boolean DEBUG_PING = DEBUG && false;
private static final String ANONYMOUS = "anonymous";
private static final String SERVER_ERROR_PREFIX = "Response: ";
- private static final int EXPIRY_TIME = 3600;
+ private static final int EXPIRY_TIME = 3600; // in seconds
+ private static final int CANCEL_CALL_TIMER = 5; // in seconds
private static final EventObject DEREGISTER = new EventObject("Deregister");
private static final EventObject END_CALL = new EventObject("End call");
@@ -363,6 +364,40 @@
String mPeerSessionDescription;
boolean mInCall;
boolean mReRegisterFlag = false;
+ SessionTimer mTimer;
+
+ // lightweight timer
+ class SessionTimer {
+ private boolean mRunning = true;
+
+ void start(final int timeout) {
+ new Thread(new Runnable() {
+ public void run() {
+ sleep(timeout);
+ if (mRunning) timeout();
+ }
+ }).start();
+ }
+
+ synchronized void cancel() {
+ mRunning = false;
+ this.notify();
+ }
+
+ private void timeout() {
+ synchronized (SipSessionGroup.this) {
+ onError(SipErrorCode.TIME_OUT, "Session timed out!");
+ }
+ }
+
+ private synchronized void sleep(int timeout) {
+ try {
+ this.wait(timeout * 1000);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "session timer interrupted!");
+ }
+ }
+ }
public SipSessionImpl(ISipSessionListener listener) {
setListener(listener);
@@ -382,6 +417,8 @@
mServerTransaction = null;
mClientTransaction = null;
mPeerSessionDescription = null;
+
+ cancelSessionTimer();
}
public boolean isInCall() {
@@ -434,16 +471,16 @@
}).start();
}
- public void makeCall(SipProfile peerProfile,
- String sessionDescription) {
- doCommandAsync(
- new MakeCallCommand(peerProfile, sessionDescription));
+ public void makeCall(SipProfile peerProfile, String sessionDescription,
+ int timeout) {
+ doCommandAsync(new MakeCallCommand(peerProfile, sessionDescription,
+ timeout));
}
- public void answerCall(String sessionDescription) {
+ public void answerCall(String sessionDescription, int timeout) {
try {
- processCommand(
- new MakeCallCommand(mPeerProfile, sessionDescription));
+ processCommand(new MakeCallCommand(mPeerProfile,
+ sessionDescription, timeout));
} catch (SipException e) {
onError(e);
}
@@ -453,9 +490,15 @@
doCommandAsync(END_CALL);
}
- public void changeCall(String sessionDescription) {
- doCommandAsync(
- new MakeCallCommand(mPeerProfile, sessionDescription));
+ public void changeCall(String sessionDescription, int timeout) {
+ doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
+ timeout));
+ }
+
+ public void changeCallWithTimeout(
+ String sessionDescription, int timeout) {
+ doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
+ timeout));
}
public void register(int duration) {
@@ -800,6 +843,7 @@
addSipSession(this);
mState = SipSessionState.OUTGOING_CALL;
mProxy.onCalling(this);
+ startSessionTimer(cmd.getTimeout());
return true;
} else if (evt instanceof RegisterCommand) {
int duration = ((RegisterCommand) evt).getDuration();
@@ -831,6 +875,7 @@
((MakeCallCommand) evt).getSessionDescription(),
mServerTransaction);
mState = SipSessionState.INCOMING_CALL_ANSWERING;
+ startSessionTimer(((MakeCallCommand) evt).getTimeout());
return true;
} else if (END_CALL == evt) {
mSipHelper.sendInviteBusyHere(mInviteReceived,
@@ -873,6 +918,7 @@
if (mState == SipSessionState.OUTGOING_CALL) {
mState = SipSessionState.OUTGOING_CALL_RING_BACK;
mProxy.onRingingBack(this);
+ cancelSessionTimer();
}
return true;
case Response.OK:
@@ -885,10 +931,10 @@
if (handleAuthentication(event)) {
addSipSession(this);
} else if (mLastNonce == null) {
- endCallOnError(SipErrorCode.SERVER_ERROR,
+ onError(SipErrorCode.SERVER_ERROR,
"server does not provide challenge");
} else {
- endCallOnError(SipErrorCode.INVALID_CREDENTIALS,
+ onError(SipErrorCode.INVALID_CREDENTIALS,
"incorrect username or password");
}
return true;
@@ -914,6 +960,7 @@
// response.
mSipHelper.sendCancel(mClientTransaction);
mState = SipSessionState.OUTGOING_CALL_CANCELING;
+ startSessionTimer(CANCEL_CALL_TIMER);
return true;
}
return false;
@@ -926,9 +973,13 @@
Response response = event.getResponse();
int statusCode = response.getStatusCode();
if (expectResponse(Request.CANCEL, evt)) {
- if (statusCode == Response.OK) {
- // do nothing; wait for REQUEST_TERMINATED
- return true;
+ switch (statusCode) {
+ case Response.OK:
+ // do nothing; wait for REQUEST_TERMINATED
+ return true;
+ case Response.REQUEST_TERMINATED:
+ endCallNormally();
+ return true;
}
} else if (expectResponse(Request.INVITE, evt)) {
if (statusCode == Response.OK) {
@@ -978,11 +1029,27 @@
mClientTransaction = mSipHelper.sendReinvite(mDialog,
((MakeCallCommand) evt).getSessionDescription());
mState = SipSessionState.OUTGOING_CALL;
+ startSessionTimer(((MakeCallCommand) evt).getTimeout());
return true;
}
return false;
}
+ // timeout in seconds
+ private void startSessionTimer(int timeout) {
+ if (timeout > 0) {
+ mTimer = new SessionTimer();
+ mTimer.start(timeout);
+ }
+ }
+
+ private void cancelSessionTimer() {
+ if (mTimer != null) {
+ mTimer.cancel();
+ mTimer = null;
+ }
+ }
+
private String createErrorMessage(Response response) {
return String.format(SERVER_ERROR_PREFIX + "%s (%d)",
response.getReasonPhrase(), response.getStatusCode());
@@ -991,15 +1058,10 @@
private void establishCall() {
mState = SipSessionState.IN_CALL;
mInCall = true;
+ cancelSessionTimer();
mProxy.onCallEstablished(this, mPeerSessionDescription);
}
- private void fallbackToPreviousInCall(Throwable exception) {
- exception = getRootCause(exception);
- fallbackToPreviousInCall(getErrorCode(exception),
- exception.toString());
- }
-
private void fallbackToPreviousInCall(SipErrorCode errorCode,
String message) {
mState = SipSessionState.IN_CALL;
@@ -1022,6 +1084,7 @@
}
private void onError(SipErrorCode errorCode, String message) {
+ cancelSessionTimer();
switch (mState) {
case REGISTERING:
case DEREGISTERING:
@@ -1255,11 +1318,18 @@
private class MakeCallCommand extends EventObject {
private String mSessionDescription;
+ private int mTimeout; // in seconds
public MakeCallCommand(SipProfile peerProfile,
String sessionDescription) {
+ this(peerProfile, sessionDescription, -1);
+ }
+
+ public MakeCallCommand(SipProfile peerProfile,
+ String sessionDescription, int timeout) {
super(peerProfile);
mSessionDescription = sessionDescription;
+ mTimeout = timeout;
}
public SipProfile getPeerProfile() {
@@ -1269,6 +1339,9 @@
public String getSessionDescription() {
return mSessionDescription;
}
- }
+ public int getTimeout() {
+ return mTimeout;
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index 07dd35d..d7dc4ab 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -74,6 +74,7 @@
public class SipPhone extends SipPhoneBase {
private static final String LOG_TAG = "SipPhone";
private static final boolean LOCAL_DEBUG = true;
+ private static final int SESSION_TIMEOUT = 8; // in seconds
// A call that is ringing or (call) waiting
private SipCall ringingCall = new SipCall();
@@ -675,7 +676,7 @@
void acceptCall() throws CallStateException {
try {
- mSipAudioCall.answerCall();
+ mSipAudioCall.answerCall(SESSION_TIMEOUT);
} catch (SipException e) {
throw new CallStateException("acceptCall(): " + e);
}
@@ -693,7 +694,7 @@
void dial() throws SipException {
setState(Call.State.DIALING);
mSipAudioCall = mSipManager.makeAudioCall(mContext, mProfile,
- mPeer, null);
+ mPeer, null, SESSION_TIMEOUT);
mSipAudioCall.setRingbackToneEnabled(false);
mSipAudioCall.setListener(mAdapter);
}
@@ -701,7 +702,7 @@
void hold() throws CallStateException {
setState(Call.State.HOLDING);
try {
- mSipAudioCall.holdCall();
+ mSipAudioCall.holdCall(SESSION_TIMEOUT);
} catch (SipException e) {
throw new CallStateException("hold(): " + e);
}
@@ -711,7 +712,7 @@
mSipAudioCall.setAudioGroup(audioGroup);
setState(Call.State.ACTIVE);
try {
- mSipAudioCall.continueCall();
+ mSipAudioCall.continueCall(SESSION_TIMEOUT);
} catch (SipException e) {
throw new CallStateException("unhold(): " + e);
}
diff --git a/voip/java/android/net/sip/ISipSession.aidl b/voip/java/android/net/sip/ISipSession.aidl
index cd8bd2c..5661b8f 100644
--- a/voip/java/android/net/sip/ISipSession.aidl
+++ b/voip/java/android/net/sip/ISipSession.aidl
@@ -112,9 +112,11 @@
*
* @param callee the SIP profile to make the call to
* @param sessionDescription the session description of this call
+ * @param timeout the session will be timed out if the call is not
+ * established within {@code timeout} seconds
* @see ISipSessionListener
*/
- void makeCall(in SipProfile callee, String sessionDescription);
+ void makeCall(in SipProfile callee, String sessionDescription, int timeout);
/**
* Answers an incoming call with the specified session description. The
@@ -122,8 +124,10 @@
* {@link SipSessionState#INCOMING_CALL}.
*
* @param sessionDescription the session description to answer this call
+ * @param timeout the session will be timed out if the call is not
+ * established within {@code timeout} seconds
*/
- void answerCall(String sessionDescription);
+ void answerCall(String sessionDescription, int timeout);
/**
* Ends an established call, terminates an outgoing call or rejects an
@@ -140,6 +144,8 @@
* to call when the session state is in {@link SipSessionState#IN_CALL}.
*
* @param sessionDescription the new session description
+ * @param timeout the session will be timed out if the call is not
+ * established within {@code timeout} seconds
*/
- void changeCall(String sessionDescription);
+ void changeCall(String sessionDescription, int timeout);
}
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index 573760e..2a9a65b 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -158,12 +158,18 @@
void close();
/**
- * Initiates an audio call to the specified profile.
+ * Initiates an audio call to the specified profile. The attempt will be
+ * timed out if the call is not established within {@code timeout} seconds
+ * and {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+ * will be called.
*
* @param callee the SIP profile to make the call to
* @param sipManager the {@link SipManager} object to help make call with
+ * @param timeout the timeout value in seconds
+ * @see Listener.onError
*/
- void makeCall(SipProfile callee, SipManager sipManager) throws SipException;
+ void makeCall(SipProfile callee, SipManager sipManager, int timeout)
+ throws SipException;
/**
* Attaches an incoming call to this call object.
@@ -179,18 +185,38 @@
/**
* Puts a call on hold. When succeeds, {@link Listener#onCallHeld} is
- * called.
+ * called. The attempt will be timed out if the call is not established
+ * within {@code timeout} seconds and
+ * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+ * will be called.
+ *
+ * @param timeout the timeout value in seconds
+ * @see Listener.onError
*/
- void holdCall() throws SipException;
+ void holdCall(int timeout) throws SipException;
- /** Answers a call. */
- void answerCall() throws SipException;
+ /**
+ * Answers a call. The attempt will be timed out if the call is not
+ * established within {@code timeout} seconds and
+ * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+ * will be called.
+ *
+ * @param timeout the timeout value in seconds
+ * @see Listener.onError
+ */
+ void answerCall(int timeout) throws SipException;
/**
* Continues a call that's on hold. When succeeds,
- * {@link Listener#onCallEstablished} is called.
+ * {@link Listener#onCallEstablished} is called. The attempt will be timed
+ * out if the call is not established within {@code timeout} seconds and
+ * {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+ * will be called.
+ *
+ * @param timeout the timeout value in seconds
+ * @see Listener.onError
*/
- void continueCall() throws SipException;
+ void continueCall(int timeout) throws SipException;
/** Puts the device to speaker mode. */
void setSpeakerMode(boolean speakerMode);
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index 8bf486a..fcabcc4 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -55,6 +55,7 @@
private static final boolean DONT_RELEASE_SOCKET = false;
private static final String AUDIO = "audio";
private static final int DTMF = 101;
+ private static final int SESSION_TIMEOUT = 5; // in seconds
private Context mContext;
private SipProfile mLocalProfile;
@@ -144,12 +145,21 @@
if (closeRtp) stopCall(RELEASE_SOCKET);
stopRingbackTone();
stopRinging();
- mSipSession = null;
+
mInCall = false;
mHold = false;
mSessionId = -1L;
mErrorCode = null;
mErrorMessage = null;
+
+ if (mSipSession != null) {
+ try {
+ mSipSession.setListener(null);
+ } catch (RemoteException e) {
+ // don't care
+ }
+ mSipSession = null;
+ }
}
public synchronized SipProfile getLocalProfile() {
@@ -219,7 +229,7 @@
// session changing request
try {
mPeerSd = new SdpSessionDescription(sessionDescription);
- answerCall();
+ answerCall(SESSION_TIMEOUT);
} catch (Throwable e) {
Log.e(TAG, "onRinging()", e);
session.endCall();
@@ -346,14 +356,15 @@
}
public synchronized void makeCall(SipProfile peerProfile,
- SipManager sipManager) throws SipException {
+ SipManager sipManager, int timeout) throws SipException {
try {
mSipSession = sipManager.createSipSession(mLocalProfile, this);
if (mSipSession == null) {
throw new SipException(
"Failed to create SipSession; network available?");
}
- mSipSession.makeCall(peerProfile, createOfferSessionDescription());
+ mSipSession.makeCall(peerProfile, createOfferSessionDescription(),
+ timeout);
} catch (Throwable e) {
if (e instanceof SipException) {
throw (SipException) e;
@@ -376,10 +387,10 @@
}
}
- public synchronized void holdCall() throws SipException {
+ public synchronized void holdCall(int timeout) throws SipException {
if (mHold) return;
try {
- mSipSession.changeCall(createHoldSessionDescription());
+ mSipSession.changeCall(createHoldSessionDescription(), timeout);
mHold = true;
} catch (Throwable e) {
throwSipException(e);
@@ -389,21 +400,21 @@
if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
}
- public synchronized void answerCall() throws SipException {
+ public synchronized void answerCall(int timeout) throws SipException {
try {
stopRinging();
- mSipSession.answerCall(createAnswerSessionDescription());
+ mSipSession.answerCall(createAnswerSessionDescription(), timeout);
} catch (Throwable e) {
Log.e(TAG, "answerCall()", e);
throwSipException(e);
}
}
- public synchronized void continueCall() throws SipException {
+ public synchronized void continueCall(int timeout) throws SipException {
if (!mHold) return;
try {
mHold = false;
- mSipSession.changeCall(createContinueSessionDescription());
+ mSipSession.changeCall(createContinueSessionDescription(), timeout);
} catch (Throwable e) {
throwSipException(e);
}
diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java
index 5b1767d..36895cd 100644
--- a/voip/java/android/net/sip/SipManager.java
+++ b/voip/java/android/net/sip/SipManager.java
@@ -218,44 +218,55 @@
}
/**
- * Creates a {@link SipAudioCall} to make a call.
+ * Creates a {@link SipAudioCall} to make a call. The attempt will be timed
+ * out if the call is not established within {@code timeout} seconds and
+ * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+ * will be called.
*
* @param context context to create a {@link SipAudioCall} object
* @param localProfile the SIP profile to make the call from
* @param peerProfile the SIP profile to make the call to
* @param listener to listen to the call events from {@link SipAudioCall};
* can be null
+ * @param timeout the timeout value in seconds
* @return a {@link SipAudioCall} object
* @throws SipException if calling the SIP service results in an error
+ * @see SipAudioCall.Listener.onError
*/
public SipAudioCall makeAudioCall(Context context, SipProfile localProfile,
- SipProfile peerProfile, SipAudioCall.Listener listener)
+ SipProfile peerProfile, SipAudioCall.Listener listener, int timeout)
throws SipException {
SipAudioCall call = new SipAudioCallImpl(context, localProfile);
call.setListener(listener);
- call.makeCall(peerProfile, this);
+ call.makeCall(peerProfile, this, timeout);
return call;
}
/**
* Creates a {@link SipAudioCall} to make a call. To use this method, one
- * must call {@link #open(SipProfile)} first.
+ * must call {@link #open(SipProfile)} first. The attempt will be timed out
+ * if the call is not established within {@code timeout} seconds and
+ * {@code SipAudioCall.Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
+ * will be called.
*
* @param context context to create a {@link SipAudioCall} object
* @param localProfileUri URI of the SIP profile to make the call from
* @param peerProfileUri URI of the SIP profile to make the call to
* @param listener to listen to the call events from {@link SipAudioCall};
* can be null
+ * @param timeout the timeout value in seconds
* @return a {@link SipAudioCall} object
* @throws SipException if calling the SIP service results in an error
+ * @see SipAudioCall.Listener.onError
*/
public SipAudioCall makeAudioCall(Context context, String localProfileUri,
- String peerProfileUri, SipAudioCall.Listener listener)
+ String peerProfileUri, SipAudioCall.Listener listener, int timeout)
throws SipException {
try {
return makeAudioCall(context,
new SipProfile.Builder(localProfileUri).build(),
- new SipProfile.Builder(peerProfileUri).build(), listener);
+ new SipProfile.Builder(peerProfileUri).build(), listener,
+ timeout);
} catch (ParseException e) {
throw new SipException("build SipProfile", e);
}