Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d4fc334 authored by repo sync's avatar repo sync Committed by Android (Google) Code Review
Browse files

Merge "Add REFER handling."

parents 101eb481 307f15fa
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ public class SipAudioCall {
    private static final boolean RELEASE_SOCKET = true;
    private static final boolean DONT_RELEASE_SOCKET = false;
    private static final int SESSION_TIMEOUT = 5; // in seconds
    private static final int TRANSFER_TIMEOUT = 15; // in seconds

    /** Listener for events relating to a SIP call, such as when a call is being
     * recieved ("on ringing") or a call is outgoing ("on calling").
@@ -537,10 +538,14 @@ public class SipAudioCall {
                Log.v(TAG, "onCallTransferring mSipSession:"
                        + mSipSession + " newSession:" + newSession);
                mTransferringSession = newSession;
                // session changing request
                try {
                    if (sessionDescription == null) {
                        newSession.makeCall(newSession.getPeerProfile(),
                                createOffer().encode(), TRANSFER_TIMEOUT);
                    } else {
                        String answer = createAnswer(sessionDescription).encode();
                        newSession.answerCall(answer, SESSION_TIMEOUT);
                    }
                } catch (Throwable e) {
                    Log.e(TAG, "onCallTransferring()", e);
                    newSession.endCall();
+29 −3
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@ package com.android.server.sip;
import gov.nist.javax.sip.SipStackExt;
import gov.nist.javax.sip.clientauthutils.AccountManager;
import gov.nist.javax.sip.clientauthutils.AuthenticationHelper;
import gov.nist.javax.sip.header.extensions.ReferencesHeader;
import gov.nist.javax.sip.header.extensions.ReferredByHeader;
import gov.nist.javax.sip.header.extensions.ReplacesHeader;

import android.net.sip.SipProfile;
import android.util.Log;
@@ -284,14 +287,18 @@ class SipHelper {
    }

    public ClientTransaction sendInvite(SipProfile caller, SipProfile callee,
            String sessionDescription, String tag)
            throws SipException {
            String sessionDescription, String tag, ReferredByHeader referredBy,
            String replaces) throws SipException {
        try {
            Request request = createRequest(Request.INVITE, caller, callee, tag);
            if (referredBy != null) request.addHeader(referredBy);
            if (replaces != null) {
                request.addHeader(mHeaderFactory.createHeader(
                        ReplacesHeader.NAME, replaces));
            }
            request.setContent(sessionDescription,
                    mHeaderFactory.createContentTypeHeader(
                            "application", "sdp"));

            ClientTransaction clientTransaction =
                    mSipProvider.getNewClientTransaction(request);
            if (DEBUG) Log.d(TAG, "send INVITE: " + request);
@@ -455,6 +462,25 @@ class SipHelper {
        }
    }

    public void sendReferNotify(Dialog dialog, String content)
            throws SipException {
        try {
            Request request = dialog.createRequest(Request.NOTIFY);
            request.addHeader(mHeaderFactory.createSubscriptionStateHeader(
                    "active;expires=60"));
            // set content here
            request.setContent(content,
                    mHeaderFactory.createContentTypeHeader(
                            "message", "sipfrag"));
            request.addHeader(mHeaderFactory.createEventHeader(
                    ReferencesHeader.REFER));
            if (DEBUG) Log.d(TAG, "send NOTIFY: " + request);
            dialog.sendRequest(mSipProvider.getNewClientTransaction(request));
        } catch (ParseException e) {
            throw new SipException("sendReferNotify()", e);
        }
    }

    public void sendInviteRequestTerminated(Request inviteRequest,
            ServerTransaction inviteTransaction) throws SipException {
        try {
+96 −24
Original line number Diff line number Diff line
@@ -18,12 +18,15 @@ package com.android.server.sip;

import gov.nist.javax.sip.clientauthutils.AccountManager;
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.ReferTo;
import gov.nist.javax.sip.header.SIPHeaderNames;
import gov.nist.javax.sip.header.StatusLine;
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 gov.nist.javax.sip.message.SIPResponse;

import android.net.sip.ISipSession;
import android.net.sip.ISipSessionListener;
@@ -71,12 +74,15 @@ import javax.sip.address.SipURI;
import javax.sip.header.CSeqHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.MinExpiresHeader;
import javax.sip.header.ReferToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Message;
import javax.sip.message.Request;
import javax.sip.message.Response;


/**
 * Manages {@link ISipSession}'s for a SIP account.
 */
@@ -390,25 +396,26 @@ class SipSessionGroup implements SipListener {
        }
    }

    private class SipSessionCallReceiverImpl extends SipSessionImpl {
        public SipSessionCallReceiverImpl(ISipSessionListener listener) {
            super(listener);
        }

    private SipSessionImpl createNewSession(RequestEvent event,
                ISipSessionListener listener, ServerTransaction transaction)
                throws SipException {
            ISipSessionListener listener, ServerTransaction transaction,
            int newState) throws SipException {
        SipSessionImpl newSession = new SipSessionImpl(listener);
        newSession.mServerTransaction = transaction;
            newSession.mState = SipSession.State.INCOMING_CALL;
        newSession.mState = newState;
        newSession.mDialog = newSession.mServerTransaction.getDialog();
        newSession.mInviteReceived = event;
            newSession.mPeerProfile = createPeerProfile(event.getRequest());
        newSession.mPeerProfile = createPeerProfile((HeaderAddress)
                event.getRequest().getHeader(FromHeader.NAME));
        newSession.mPeerSessionDescription =
                extractContent(event.getRequest());
        return newSession;
    }

    private class SipSessionCallReceiverImpl extends SipSessionImpl {
        public SipSessionCallReceiverImpl(ISipSessionListener listener) {
            super(listener);
        }

        private int processInviteWithReplaces(RequestEvent event,
                ReplacesHeader replaces) {
            String callId = replaces.getCallId();
@@ -452,7 +459,8 @@ class SipSessionGroup implements SipListener {
                    // got INVITE w/ replaces request.
                    newSession = createNewSession(event,
                            replacedSession.mProxy.getListener(),
                            mSipHelper.getServerTransaction(event));
                            mSipHelper.getServerTransaction(event),
                            SipSession.State.INCOMING_CALL);
                    newSession.mProxy.onCallTransferring(newSession,
                            newSession.mPeerSessionDescription);
                } else {
@@ -461,7 +469,8 @@ class SipSessionGroup implements SipListener {
            } else {
                // New Incoming call.
                newSession = createNewSession(event, mProxy,
                        mSipHelper.sendRinging(event, generateTag()));
                        mSipHelper.sendRinging(event, generateTag()),
                        SipSession.State.INCOMING_CALL);
                mProxy.onRinging(newSession, newSession.mPeerProfile,
                        newSession.mPeerSessionDescription);
            }
@@ -507,6 +516,11 @@ class SipSessionGroup implements SipListener {

        private SipSessionImpl mKeepAliveSession;

        // the following three members are used for handling refer request.
        SipSessionImpl mReferSession;
        ReferredByHeader mReferredBy;
        String mReplaces;

        // lightweight timer
        class SessionTimer {
            private boolean mRunning = true;
@@ -556,6 +570,9 @@ class SipSessionGroup implements SipListener {
            mInviteReceived = null;
            mPeerSessionDescription = null;
            mAuthenticationRetryCount = 0;
            mReferSession = null;
            mReferredBy = null;
            mReplaces = null;

            if (mDialog != null) mDialog.delete();
            mDialog = null;
@@ -969,15 +986,26 @@ class SipSessionGroup implements SipListener {
            return (proxyAuth == null) ? null : proxyAuth.getNonce();
        }

        private String getResponseString(int statusCode) {
            StatusLine statusLine = new StatusLine();
            statusLine.setStatusCode(statusCode);
            statusLine.setReasonPhrase(SIPResponse.getReasonPhrase(statusCode));
            return statusLine.encode();
        }

        private boolean readyForCall(EventObject evt) throws SipException {
            // expect MakeCallCommand, RegisterCommand, DEREGISTER
            if (evt instanceof MakeCallCommand) {
                mState = SipSession.State.OUTGOING_CALL;
                MakeCallCommand cmd = (MakeCallCommand) evt;
                mPeerProfile = cmd.getPeerProfile();
                mClientTransaction = mSipHelper.sendInvite(mLocalProfile,
                        mPeerProfile, cmd.getSessionDescription(),
                        generateTag());
                if (mReferSession != null) {
                    mSipHelper.sendReferNotify(mReferSession.mDialog,
                            getResponseString(Response.TRYING));
                }
                mClientTransaction = mSipHelper.sendInvite(
                        mLocalProfile, mPeerProfile, cmd.getSessionDescription(),
                        generateTag(), mReferredBy, mReplaces);
                mDialog = mClientTransaction.getDialog();
                addSipSession(this);
                startSessionTimer(cmd.getTimeout());
@@ -1072,6 +1100,12 @@ class SipSessionGroup implements SipListener {
                    }
                    return true;
                case Response.OK:
                    if (mReferSession != null) {
                        mSipHelper.sendReferNotify(mReferSession.mDialog,
                                getResponseString(Response.OK));
                        // since we don't need to remember the session anymore.
                        mReferSession = null;
                    }
                    mSipHelper.sendInviteAck(event, mDialog);
                    mPeerSessionDescription = extractContent(response);
                    establishCall(true);
@@ -1087,6 +1121,10 @@ class SipSessionGroup implements SipListener {
                    // rfc3261#section-14.1; re-schedule invite
                    return true;
                default:
                    if (mReferSession != null) {
                        mSipHelper.sendReferNotify(mReferSession.mDialog,
                                getResponseString(Response.SERVICE_UNAVAILABLE));
                    }
                    if (statusCode >= 400) {
                        // error: an ack is sent automatically by the stack
                        onError(response);
@@ -1155,6 +1193,38 @@ class SipSessionGroup implements SipListener {
            return false;
        }

        private boolean processReferRequest(RequestEvent event)
                throws SipException {
            try {
                ReferToHeader referto = (ReferToHeader) event.getRequest()
                        .getHeader(ReferTo.NAME);
                Address address = referto.getAddress();
                SipURI uri = (SipURI) address.getURI();
                String replacesHeader = uri.getHeader(ReplacesHeader.NAME);
                String username = uri.getUser();
                if (username == null) {
                    mSipHelper.sendResponse(event, Response.BAD_REQUEST);
                    return false;
                }
                // send notify accepted
                mSipHelper.sendResponse(event, Response.ACCEPTED);
                SipSessionImpl newSession = createNewSession(event,
                        this.mProxy.getListener(),
                        mSipHelper.getServerTransaction(event),
                        SipSession.State.READY_TO_CALL);
                newSession.mReferSession = this;
                newSession.mReferredBy = (ReferredByHeader) event.getRequest()
                        .getHeader(ReferredByHeader.NAME);
                newSession.mReplaces = replacesHeader;
                newSession.mPeerProfile = createPeerProfile(referto);
                newSession.mProxy.onCallTransferring(newSession,
                        null);
                return true;
            } catch (IllegalArgumentException e) {
                throw new SipException("createPeerProfile()", e);
            }
        }

        private boolean inCall(EventObject evt) throws SipException {
            // expect END_CALL cmd, BYE request, hold call (MakeCallCommand)
            // OK retransmission is handled in SipStack
@@ -1175,6 +1245,8 @@ class SipSessionGroup implements SipListener {
                mSipHelper.sendResponse((RequestEvent) evt, Response.OK);
                endCallNormally();
                return true;
            } else if (isRequestEvent(Request.REFER, evt)) {
                return processReferRequest((RequestEvent) evt);
            } else if (evt instanceof MakeCallCommand) {
                // to change call
                mState = SipSession.State.OUTGOING_CALL;
@@ -1182,6 +1254,8 @@ class SipSessionGroup implements SipListener {
                        ((MakeCallCommand) evt).getSessionDescription());
                startSessionTimer(((MakeCallCommand) evt).getTimeout());
                return true;
            } else if (evt instanceof ResponseEvent) {
                if (expectResponse(Request.NOTIFY, evt)) return true;
            }
            return false;
        }
@@ -1558,12 +1632,10 @@ class SipSessionGroup implements SipListener {
        return false;
    }

    private static SipProfile createPeerProfile(Request request)
    private static SipProfile createPeerProfile(HeaderAddress header)
            throws SipException {
        try {
            FromHeader fromHeader =
                    (FromHeader) request.getHeader(FromHeader.NAME);
            Address address = fromHeader.getAddress();
            Address address = header.getAddress();
            SipURI uri = (SipURI) address.getURI();
            String username = uri.getUser();
            if (username == null) username = ANONYMOUS;