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.
This commit is contained in:
Hung-ying Tyan
2010-09-16 23:40:28 -07:00
committed by Android Git Automerger
6 changed files with 182 additions and 54 deletions

View File

@@ -84,7 +84,8 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
mServerTransaction = null;
mClientTransaction = null;
mPeerSessionDescription = null;
cancelSessionTimer();
}
public boolean isInCall() {
@@ -434,16 +471,16 @@ class SipSessionGroup implements SipListener {
}).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 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
((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 @@ class SipSessionGroup implements SipListener {
if (mState == SipSessionState.OUTGOING_CALL) {
mState = SipSessionState.OUTGOING_CALL_RING_BACK;
mProxy.onRingingBack(this);
cancelSessionTimer();
}
return true;
case Response.OK:
@@ -885,10 +931,10 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
// response.
mSipHelper.sendCancel(mClientTransaction);
mState = SipSessionState.OUTGOING_CALL_CANCELING;
startSessionTimer(CANCEL_CALL_TIMER);
return true;
}
return false;
@@ -926,9 +973,13 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
}
private void onError(SipErrorCode errorCode, String message) {
cancelSessionTimer();
switch (mState) {
case REGISTERING:
case DEREGISTERING:
@@ -1255,11 +1318,18 @@ class SipSessionGroup implements SipListener {
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 @@ class SipSessionGroup implements SipListener {
public String getSessionDescription() {
return mSessionDescription;
}
}
public int getTimeout() {
return mTimeout;
}
}
}

View File

@@ -74,6 +74,7 @@ import java.util.List;
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 @@ public class SipPhone extends SipPhoneBase {
void acceptCall() throws CallStateException {
try {
mSipAudioCall.answerCall();
mSipAudioCall.answerCall(SESSION_TIMEOUT);
} catch (SipException e) {
throw new CallStateException("acceptCall(): " + e);
}
@@ -693,7 +694,7 @@ public class SipPhone extends SipPhoneBase {
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 @@ public class SipPhone extends SipPhoneBase {
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 @@ public class SipPhone extends SipPhoneBase {
mSipAudioCall.setAudioGroup(audioGroup);
setState(Call.State.ACTIVE);
try {
mSipAudioCall.continueCall();
mSipAudioCall.continueCall(SESSION_TIMEOUT);
} catch (SipException e) {
throw new CallStateException("unhold(): " + e);
}

View File

@@ -112,9 +112,11 @@ interface ISipSession {
*
* @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 @@ interface ISipSession {
* {@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 @@ interface ISipSession {
* 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);
}

View File

@@ -158,12 +158,18 @@ public interface SipAudioCall {
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 @@ public interface SipAudioCall {
/**
* 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);

View File

@@ -55,6 +55,7 @@ public class SipAudioCallImpl extends SipSessionAdapter
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 @@ public class SipAudioCallImpl extends SipSessionAdapter
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 @@ public class SipAudioCallImpl extends SipSessionAdapter
// 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 class SipAudioCallImpl extends SipSessionAdapter
}
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 class SipAudioCallImpl extends SipSessionAdapter
}
}
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 @@ public class SipAudioCallImpl extends SipSessionAdapter
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);
}

View File

@@ -218,44 +218,55 @@ public class SipManager {
}
/**
* 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);
}