diff options
author | repo sync <cywang@google.com> | 2011-06-23 19:40:36 +0800 |
---|---|---|
committer | repo sync <cywang@google.com> | 2011-06-27 16:20:28 +0800 |
commit | 1aceda35cc607856ec2e960e0c6cfc6aea87ab8e (patch) | |
tree | df58a646008282041c3f1e1b959a888e01f0f6fe /voip/java | |
parent | 14f14863c508ff38fb2fe925c89e2bb2228fcffe (diff) | |
download | frameworks_base-1aceda35cc607856ec2e960e0c6cfc6aea87ab8e.zip frameworks_base-1aceda35cc607856ec2e960e0c6cfc6aea87ab8e.tar.gz frameworks_base-1aceda35cc607856ec2e960e0c6cfc6aea87ab8e.tar.bz2 |
Support Invite w/ Replaces request.
bug:3326870
Change-Id: Idbfbe7e3cc6ba83874d42bfb7d149866f454e70a
Diffstat (limited to 'voip/java')
-rw-r--r-- | voip/java/android/net/sip/ISipSessionListener.aidl | 8 | ||||
-rw-r--r-- | voip/java/android/net/sip/SipAudioCall.java | 57 | ||||
-rw-r--r-- | voip/java/android/net/sip/SipSession.java | 21 | ||||
-rw-r--r-- | voip/java/android/net/sip/SipSessionAdapter.java | 4 | ||||
-rw-r--r-- | voip/java/com/android/server/sip/SipHelper.java | 2 | ||||
-rw-r--r-- | voip/java/com/android/server/sip/SipSessionGroup.java | 89 | ||||
-rw-r--r-- | voip/java/com/android/server/sip/SipSessionListenerProxy.java | 14 |
7 files changed, 180 insertions, 15 deletions
diff --git a/voip/java/android/net/sip/ISipSessionListener.aidl b/voip/java/android/net/sip/ISipSessionListener.aidl index 5920bca..690700c 100644 --- a/voip/java/android/net/sip/ISipSessionListener.aidl +++ b/voip/java/android/net/sip/ISipSessionListener.aidl @@ -72,6 +72,14 @@ interface ISipSessionListener { void onCallBusy(in ISipSession session); /** + * Called when the call is being transferred to a new one. + * + * @param newSession the new session that the call will be transferred to + * @param sessionDescription the new peer's session description + */ + void onCallTransferring(in ISipSession newSession, String sessionDescription); + + /** * Called when an error occurs during session initialization and * termination. * diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java index b46f826..2666b69 100644 --- a/voip/java/android/net/sip/SipAudioCall.java +++ b/voip/java/android/net/sip/SipAudioCall.java @@ -170,6 +170,7 @@ public class SipAudioCall { private SipProfile mLocalProfile; private SipAudioCall.Listener mListener; private SipSession mSipSession; + private SipSession mTransferringSession; private long mSessionId = System.currentTimeMillis(); private String mPeerSd; @@ -347,6 +348,27 @@ public class SipAudioCall { } } + private synchronized void transferToNewSession() { + if (mTransferringSession == null) return; + SipSession origin = mSipSession; + mSipSession = mTransferringSession; + mTransferringSession = null; + + // stop the replaced call. + if (mAudioStream != null) { + mAudioStream.join(null); + } else { + try { + mAudioStream = new AudioStream(InetAddress.getByName( + getLocalIp())); + } catch (Throwable t) { + Log.i(TAG, "transferToNewSession(): " + t); + } + } + if (origin != null) origin.endCall(); + startAudio(); + } + private SipSession.Listener createListener() { return new SipSession.Listener() { @Override @@ -404,6 +426,13 @@ public class SipAudioCall { mPeerSd = sessionDescription; Log.v(TAG, "onCallEstablished()" + mPeerSd); + // TODO: how to notify the UI that the remote party is changed + if ((mTransferringSession != null) + && (session == mTransferringSession)) { + transferToNewSession(); + return; + } + Listener listener = mListener; if (listener != null) { try { @@ -420,7 +449,17 @@ public class SipAudioCall { @Override public void onCallEnded(SipSession session) { - Log.d(TAG, "sip call ended: " + session); + Log.d(TAG, "sip call ended: " + session + " mSipSession:" + mSipSession); + // reset the trasnferring session if it is the one. + if (session == mTransferringSession) { + mTransferringSession = null; + return; + } + // or ignore the event if the original session is being + // transferred to the new one. + if ((mTransferringSession != null) || + (session != mSipSession)) return; + Listener listener = mListener; if (listener != null) { try { @@ -489,6 +528,22 @@ public class SipAudioCall { public void onRegistrationDone(SipSession session, int duration) { // irrelevant } + + @Override + public void onCallTransferring(SipSession newSession, + String sessionDescription) { + Log.v(TAG, "onCallTransferring mSipSession:" + + mSipSession + " newSession:" + newSession); + mTransferringSession = newSession; + // session changing request + try { + String answer = createAnswer(sessionDescription).encode(); + newSession.answerCall(answer, SESSION_TIMEOUT); + } catch (Throwable e) { + Log.e(TAG, "onCallTransferring()", e); + newSession.endCall(); + } + } }; } diff --git a/voip/java/android/net/sip/SipSession.java b/voip/java/android/net/sip/SipSession.java index 5629b3c..5ba1626 100644 --- a/voip/java/android/net/sip/SipSession.java +++ b/voip/java/android/net/sip/SipSession.java @@ -160,6 +160,17 @@ public final class SipSession { } /** + * Called when the call is being transferred to a new one. + * + * @hide + * @param newSession the new session that the call will be transferred to + * @param sessionDescription the new peer's session description + */ + public void onCallTransferring(SipSession newSession, + String sessionDescription) { + } + + /** * Called when an error occurs during session initialization and * termination. * @@ -489,6 +500,16 @@ public final class SipSession { } } + public void onCallTransferring(ISipSession session, + String sessionDescription) { + if (mListener != null) { + mListener.onCallTransferring( + new SipSession(session, SipSession.this.mListener), + sessionDescription); + + } + } + public void onCallChangeFailed(ISipSession session, int errorCode, String message) { if (mListener != null) { diff --git a/voip/java/android/net/sip/SipSessionAdapter.java b/voip/java/android/net/sip/SipSessionAdapter.java index 86aca37..f538983 100644 --- a/voip/java/android/net/sip/SipSessionAdapter.java +++ b/voip/java/android/net/sip/SipSessionAdapter.java @@ -42,6 +42,10 @@ public class SipSessionAdapter extends ISipSessionListener.Stub { public void onCallBusy(ISipSession session) { } + public void onCallTransferring(ISipSession session, + String sessionDescription) { + } + public void onCallChangeFailed(ISipSession session, int errorCode, String message) { } diff --git a/voip/java/com/android/server/sip/SipHelper.java b/voip/java/com/android/server/sip/SipHelper.java index 018e6de..47950e3 100644 --- a/voip/java/com/android/server/sip/SipHelper.java +++ b/voip/java/com/android/server/sip/SipHelper.java @@ -314,7 +314,7 @@ class SipHelper { } } - private ServerTransaction getServerTransaction(RequestEvent event) + public ServerTransaction getServerTransaction(RequestEvent event) throws SipException { ServerTransaction transaction = event.getServerTransaction(); if (transaction == null) { diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java index 2d0dd9c..481e306 100644 --- a/voip/java/com/android/server/sip/SipSessionGroup.java +++ b/voip/java/com/android/server/sip/SipSessionGroup.java @@ -21,6 +21,8 @@ import gov.nist.javax.sip.clientauthutils.UserCredentials; import gov.nist.javax.sip.header.SIPHeaderNames; import gov.nist.javax.sip.header.ProxyAuthenticate; import gov.nist.javax.sip.header.WWWAuthenticate; +import gov.nist.javax.sip.header.extensions.ReferredByHeader; +import gov.nist.javax.sip.header.extensions.ReplacesHeader; import gov.nist.javax.sip.message.SIPMessage; import android.net.sip.ISipSession; @@ -365,24 +367,85 @@ class SipSessionGroup implements SipListener { super(listener); } + private SipSessionImpl createNewSession(RequestEvent event, + ISipSessionListener listener, ServerTransaction transaction) + throws SipException { + SipSessionImpl newSession = new SipSessionImpl(listener); + newSession.mServerTransaction = transaction; + newSession.mState = SipSession.State.INCOMING_CALL; + newSession.mDialog = newSession.mServerTransaction.getDialog(); + newSession.mInviteReceived = event; + newSession.mPeerProfile = createPeerProfile(event.getRequest()); + newSession.mPeerSessionDescription = + extractContent(event.getRequest()); + return newSession; + } + + private int processInviteWithReplaces(RequestEvent event, + ReplacesHeader replaces) { + String callId = replaces.getCallId(); + SipSessionImpl session = mSessionMap.get(callId); + if (session == null) { + return Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST; + } + + Dialog dialog = session.mDialog; + if (dialog == null) return Response.DECLINE; + + if (!dialog.getLocalTag().equals(replaces.getToTag()) || + !dialog.getRemoteTag().equals(replaces.getFromTag())) { + // No match is found, returns 481. + return Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST; + } + + ReferredByHeader referredBy = (ReferredByHeader) event.getRequest() + .getHeader(ReferredByHeader.NAME); + if ((referredBy == null) || + !dialog.getRemoteParty().equals(referredBy.getAddress())) { + return Response.CALL_OR_TRANSACTION_DOES_NOT_EXIST; + } + return Response.OK; + } + + private void processNewInviteRequest(RequestEvent event) + throws SipException { + ReplacesHeader replaces = (ReplacesHeader) event.getRequest() + .getHeader(ReplacesHeader.NAME); + SipSessionImpl newSession = null; + if (replaces != null) { + int response = processInviteWithReplaces(event, replaces); + if (DEBUG) { + Log.v(TAG, "ReplacesHeader: " + replaces + + " response=" + response); + } + if (response == Response.OK) { + SipSessionImpl replacedSession = + mSessionMap.get(replaces.getCallId()); + // got INVITE w/ replaces request. + newSession = createNewSession(event, + replacedSession.mProxy.getListener(), + mSipHelper.getServerTransaction(event)); + newSession.mProxy.onCallTransferring(newSession, + newSession.mPeerSessionDescription); + } else { + mSipHelper.sendResponse(event, response); + } + } else { + // New Incoming call. + newSession = createNewSession(event, mProxy, + mSipHelper.sendRinging(event, generateTag())); + mProxy.onRinging(newSession, newSession.mPeerProfile, + newSession.mPeerSessionDescription); + } + if (newSession != null) addSipSession(newSession); + } + public boolean process(EventObject evt) throws SipException { if (isLoggable(this, evt)) Log.d(TAG, " ~~~~~ " + this + ": " + SipSession.State.toString(mState) + ": processing " + log(evt)); if (isRequestEvent(Request.INVITE, evt)) { - RequestEvent event = (RequestEvent) evt; - SipSessionImpl newSession = new SipSessionImpl(mProxy); - newSession.mState = SipSession.State.INCOMING_CALL; - newSession.mServerTransaction = mSipHelper.sendRinging(event, - generateTag()); - newSession.mDialog = newSession.mServerTransaction.getDialog(); - newSession.mInviteReceived = event; - newSession.mPeerProfile = createPeerProfile(event.getRequest()); - newSession.mPeerSessionDescription = - extractContent(event.getRequest()); - addSipSession(newSession); - mProxy.onRinging(newSession, newSession.mPeerProfile, - newSession.mPeerSessionDescription); + processNewInviteRequest((RequestEvent) evt); return true; } else if (isRequestEvent(Request.OPTIONS, evt)) { mSipHelper.sendResponse((RequestEvent) evt, Response.OK); diff --git a/voip/java/com/android/server/sip/SipSessionListenerProxy.java b/voip/java/com/android/server/sip/SipSessionListenerProxy.java index f8be0a8..8655a3a 100644 --- a/voip/java/com/android/server/sip/SipSessionListenerProxy.java +++ b/voip/java/com/android/server/sip/SipSessionListenerProxy.java @@ -110,6 +110,20 @@ class SipSessionListenerProxy extends ISipSessionListener.Stub { }); } + public void onCallTransferring(final ISipSession newSession, + final String sessionDescription) { + if (mListener == null) return; + proxy(new Runnable() { + public void run() { + try { + mListener.onCallTransferring(newSession, sessionDescription); + } catch (Throwable t) { + handle(t, "onCallTransferring()"); + } + } + }); + } + public void onCallBusy(final ISipSession session) { if (mListener == null) return; proxy(new Runnable() { |