Merge "SipAudioCallImpl: deliver call change failure and don't end call when getting an error in a call."
diff --git a/java/gov/nist/javax/sip/header/Via.java b/java/gov/nist/javax/sip/header/Via.java
index 2253394..be40962 100644
--- a/java/gov/nist/javax/sip/header/Via.java
+++ b/java/gov/nist/javax/sip/header/Via.java
@@ -96,6 +96,8 @@
*/
protected String comment;
+ private boolean rPortFlag = false;
+
/** Default constructor
*/
public Via() {
@@ -265,6 +267,7 @@
if (comment != null) {
buffer.append(SP).append(LPAREN).append(comment).append(RPAREN);
}
+ if (rPortFlag) buffer.append(";rport");
return buffer;
}
@@ -324,11 +327,7 @@
* Set the RPort flag parameter
*/
public void setRPort(){
- try {
- this.setParameter(Via.RPORT,"");
- } catch (ParseException e) {
- e.printStackTrace(); // should not occur
- }
+ rPortFlag = true;
}
/**
diff --git a/src/android/net/sip/SipSessionState.java b/src/android/net/sip/SipSessionState.java
index c43b011..5bab112 100644
--- a/src/android/net/sip/SipSessionState.java
+++ b/src/android/net/sip/SipSessionState.java
@@ -49,7 +49,10 @@
IN_CALL,
/** Some error occurs when making a remote call to {@link ISipSession}. */
- REMOTE_ERROR;
+ REMOTE_ERROR,
+
+ /** When an OPTIONS request is sent. */
+ PINGING;
/**
* Checks if the specified string represents the same state as this object.
diff --git a/src/com/android/sip/SipHelper.java b/src/com/android/sip/SipHelper.java
index 0e2280c..594857c 100644
--- a/src/com/android/sip/SipHelper.java
+++ b/src/com/android/sip/SipHelper.java
@@ -138,8 +138,10 @@
throws ParseException, SipException {
List<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(1);
ListeningPoint lp = getListeningPoint();
- viaHeaders.add(mHeaderFactory.createViaHeader(lp.getIPAddress(),
- lp.getPort(), lp.getTransport(), null));
+ ViaHeader viaHeader = mHeaderFactory.createViaHeader(lp.getIPAddress(),
+ lp.getPort(), lp.getTransport(), null);
+ viaHeader.setRPort();
+ viaHeaders.add(viaHeader);
return viaHeaders;
}
@@ -173,12 +175,15 @@
return uri;
}
- public void sendKeepAlive(SipProfile profile)
+ public ClientTransaction sendKeepAlive(SipProfile userProfile, String tag)
throws SipException {
try {
- String proxy = profile.getProxyAddress();
- if (proxy == null) proxy = profile.getSipDomain();
- getListeningPoint().sendHeartbeat(proxy, profile.getPort());
+ Request request = createRequest(Request.OPTIONS, userProfile, tag);
+
+ ClientTransaction clientTransaction =
+ mSipProvider.getNewClientTransaction(request);
+ clientTransaction.sendRequest();
+ return clientTransaction;
} catch (Exception e) {
throw new SipException("sendKeepAlive()", e);
}
@@ -187,19 +192,7 @@
public ClientTransaction sendRegister(SipProfile userProfile, String tag,
int expiry) throws SipException {
try {
- FromHeader fromHeader = createFromHeader(userProfile, tag);
- ToHeader toHeader = createToHeader(userProfile);
- SipURI requestURI = mAddressFactory.createSipURI("sip:"
- + userProfile.getSipDomain());
- List<ViaHeader> viaHeaders = createViaHeaders();
- CallIdHeader callIdHeader = createCallIdHeader();
- CSeqHeader cSeqHeader = createCSeqHeader(Request.REGISTER);
- MaxForwardsHeader maxForwards = createMaxForwardsHeader();
-
- Request request = mMessageFactory.createRequest(requestURI,
- Request.REGISTER, callIdHeader, cSeqHeader, fromHeader,
- toHeader, viaHeaders, maxForwards);
-
+ Request request = createRequest(Request.REGISTER, userProfile, tag);
if (expiry == 0) {
// remove all previous registrations by wildcard
// rfc3261#section-10.2.2
@@ -208,9 +201,6 @@
request.addHeader(createContactHeader(userProfile));
}
request.addHeader(mHeaderFactory.createExpiresHeader(expiry));
- Header userAgentHeader = mHeaderFactory.createHeader("User-Agent",
- "SIPAUA/0.1.001");
- request.addHeader(userAgentHeader);
ClientTransaction clientTransaction =
mSipProvider.getNewClientTransaction(request);
@@ -221,6 +211,25 @@
}
}
+ private Request createRequest(String requestType, SipProfile userProfile,
+ String tag) throws ParseException, SipException {
+ FromHeader fromHeader = createFromHeader(userProfile, tag);
+ ToHeader toHeader = createToHeader(userProfile);
+ SipURI requestURI = mAddressFactory.createSipURI("sip:"
+ + userProfile.getSipDomain());
+ List<ViaHeader> viaHeaders = createViaHeaders();
+ CallIdHeader callIdHeader = createCallIdHeader();
+ CSeqHeader cSeqHeader = createCSeqHeader(requestType);
+ MaxForwardsHeader maxForwards = createMaxForwardsHeader();
+ Request request = mMessageFactory.createRequest(requestURI,
+ requestType, callIdHeader, cSeqHeader, fromHeader,
+ toHeader, viaHeaders, maxForwards);
+ Header userAgentHeader = mHeaderFactory.createHeader("User-Agent",
+ "SIPAUA/0.1.001");
+ request.addHeader(userAgentHeader);
+ return request;
+ }
+
public ClientTransaction handleChallenge(ResponseEvent responseEvent,
AccountManager accountManager) throws SipException {
AuthenticationHelper authenticationHelper =
diff --git a/src/com/android/sip/SipServiceImpl.java b/src/com/android/sip/SipServiceImpl.java
index f926905..55ae2a7 100644
--- a/src/com/android/sip/SipServiceImpl.java
+++ b/src/com/android/sip/SipServiceImpl.java
@@ -479,22 +479,46 @@
private class KeepAliveProcess implements Runnable {
private SipSessionGroup.SipSessionImpl mSession;
- private static final int DURATION = 15;
+ private static final int INCREMENT = 15;
+ private static final int MAX_RETRY = 4;
+ private int interval = INCREMENT;
+ private boolean maxIntervalMeasured = false;
public KeepAliveProcess(SipSessionGroup.SipSessionImpl session) {
mSession = session;
}
public void start() {
- mTimer.set(DURATION * 1000, this);
+ mTimer.set(interval * 1000, this);
}
public void run() {
+ int retry = 0;
Log.d(TAG, " ~~~ keepalive");
- try {
+ mTimer.cancel(this);
+ for (retry = 0; retry < MAX_RETRY; ++retry) {
mSession.sendKeepAlive();
- } catch (SipException e) {
- Log.e(TAG, "Cannot send keepalive", e);
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "keepalive interrupted", e);
+ return;
+ }
+ if (SipSessionState.READY_TO_CALL.equals(mSession.getState())) {
+ break;
+ }
+ }
+ if (retry == MAX_RETRY) {
+ Log.w(TAG, "Server didn't respond SIP OPTIONS req:" + mSession);
+ return;
+ }
+ if (mSession.isReRegisterRequired()) {
+ mSession.register(EXPIRY_TIME);
+ interval -= INCREMENT;
+ maxIntervalMeasured = true;
+ } else {
+ if (!maxIntervalMeasured) interval += INCREMENT;
+ mTimer.set(interval * 1000, this);
}
}
@@ -616,6 +640,7 @@
FLog.d(TAG, "onRegistering(): " + session + ": " + mSession);
synchronized (SipServiceImpl.this) {
if (!isStopped() && (session != mSession)) return;
+ mRegistered = false;
try {
mProxy.onRegistering(session);
} catch (Throwable t) {
diff --git a/src/com/android/sip/SipSessionGroup.java b/src/com/android/sip/SipSessionGroup.java
index d05d5bd..5d16bcf 100644
--- a/src/com/android/sip/SipSessionGroup.java
+++ b/src/com/android/sip/SipSessionGroup.java
@@ -63,6 +63,7 @@
import javax.sip.header.CSeqHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
+import javax.sip.header.ViaHeader;
import javax.sip.message.Message;
import javax.sip.message.Request;
import javax.sip.message.Response;
@@ -87,6 +88,7 @@
private SipStack mSipStack;
private SipHelper mSipHelper;
private String mLastNonce;
+ private int mRPort;
// session that processes INVITE requests
private SipSessionImpl mCallReceiverSession;
@@ -320,6 +322,7 @@
ClientTransaction mClientTransaction;
byte[] mPeerSessionDescription;
boolean mInCall;
+ boolean mReRegisterFlag = false;
public SipSessionImpl(ISipSessionListener listener) {
setListener(listener);
@@ -422,9 +425,15 @@
}
}
- public void sendKeepAlive() throws SipException {
- synchronized (SipSessionGroup.this) {
- mSipHelper.sendKeepAlive(mLocalProfile);
+ public boolean isReRegisterRequired() {
+ return mReRegisterFlag;
+ }
+
+ public void sendKeepAlive() {
+ try {
+ process(new OptionsCommand());
+ } catch (SipException e) {
+ Log.e(TAG, "sendKeepAlive failed", e);
}
}
@@ -463,6 +472,9 @@
case DEREGISTERING:
processed = registeringToReady(evt);
break;
+ case PINGING:
+ processed = parseOptionsResult(evt);
+ break;
case READY_TO_CALL:
processed = readyForCall(evt);
break;
@@ -565,6 +577,31 @@
return expires;
}
+ private boolean parseOptionsResult(EventObject evt) {
+ if (expectResponse(Request.OPTIONS, evt)) {
+ ResponseEvent event = (ResponseEvent) evt;
+ int rPort = getRPortFromResponse(event.getResponse());
+ if (rPort != -1) {
+ if (mRPort == 0) mRPort = rPort;
+ if (mRPort != rPort) {
+ mReRegisterFlag = true;
+ Log.w(TAG, "The rport is changed, we need to re-register now!");
+ }
+ } else {
+ Log.w(TAG, "Remote side did not respect our rport request");
+ }
+ reset();
+ return true;
+ }
+ return false;
+ }
+
+ private int getRPortFromResponse(Response response) {
+ ViaHeader viaHeader = (ViaHeader)(response.getHeader(
+ SIPHeaderNames.VIA));
+ return (viaHeader == null) ? -1 : viaHeader.getRPort();
+ }
+
private boolean registeringToReady(EventObject evt)
throws SipException {
if (expectResponse(Request.REGISTER, evt)) {
@@ -663,6 +700,13 @@
mState = SipSessionState.DEREGISTERING;
mProxy.onRegistering(this);
return true;
+ } else if (evt instanceof OptionsCommand) {
+ mClientTransaction = mSipHelper.sendKeepAlive(mLocalProfile,
+ generateTag());
+ mDialog = mClientTransaction.getDialog();
+ mState = SipSessionState.PINGING;
+ addSipSession(this);
+ return true;
}
return false;
}
@@ -982,6 +1026,12 @@
}
}
+ private class OptionsCommand extends EventObject {
+ public OptionsCommand() {
+ super(SipSessionGroup.this);
+ }
+ }
+
private class RegisterCommand extends EventObject {
private int mDuration;
diff --git a/src/com/android/sip/WakeupTimer.java b/src/com/android/sip/WakeupTimer.java
index e0cc61d..6739081 100644
--- a/src/com/android/sip/WakeupTimer.java
+++ b/src/com/android/sip/WakeupTimer.java
@@ -90,8 +90,9 @@
for (MyEvent e : mEventQueue) {
int remainingTime = (int) (e.mTriggerTime - now);
remainingTime = remainingTime / minPeriod * minPeriod;
- e.mTriggerTime = now + remainingTime;
-
+ if (remainingTime != 0) {
+ e.mTriggerTime = now + remainingTime;
+ }
e.mPeriod = e.mMaxPeriod / minPeriod * minPeriod;
}
TreeSet<MyEvent> newQueue = new TreeSet<MyEvent>(