Unhide SIP API.

Change-Id: I09468e3149a242a3b1e085ad220eb74f84ac6c68
This commit is contained in:
Hung-ying Tyan
2010-09-16 04:11:32 +08:00
parent 26cb01e880
commit 08faac3c26
10 changed files with 2170 additions and 144 deletions

File diff suppressed because it is too large Load Diff

View File

@ -364,6 +364,13 @@
android:description="@string/permdesc_nfcLlcp"
android:label="@string/permlab_nfcLlcp" />
<!-- Allows an application to use SIP service -->
<permission android:name="android.permission.USE_SIP"
android:permissionGroup="android.permission-group.NETWORK"
android:protectionLevel="dangerous"
android:description="@string/permdesc_use_sip"
android:label="@string/permlab_use_sip" />
<!-- Allows applications to call into AccountAuthenticators. Only
the system can get this permission. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"

View File

@ -1240,6 +1240,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_cache_filesystem">Allows an application to read and write the cache filesystem.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_use_sip">make/receive Internet calls</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_use_sip">Allows an application to use the SIP service to make/receive Internet calls.</string>
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->

View File

@ -43,9 +43,11 @@ import java.util.List;
import java.util.Map;
/**
* Class that handles an audio call over SIP.
* Class that handles an Internet audio call over SIP. {@link SipManager}
* facilitates instantiating a {@code SipAudioCall} object for making/receiving
* calls. See {@link SipManager#makeAudioCall} and
* {@link SipManager#takeAudioCall}.
*/
/** @hide */
public class SipAudioCall {
private static final String TAG = SipAudioCall.class.getSimpleName();
private static final boolean RELEASE_SOCKET = true;
@ -56,7 +58,7 @@ public class SipAudioCall {
public static class Listener {
/**
* Called when the call object is ready to make another call.
* The default implementation calls {@link #onChange}.
* The default implementation calls {@link #onChanged}.
*
* @param call the call object that is ready to make another call
*/
@ -66,7 +68,7 @@ public class SipAudioCall {
/**
* Called when a request is sent out to initiate a new call.
* The default implementation calls {@link #onChange}.
* The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@ -76,7 +78,7 @@ public class SipAudioCall {
/**
* Called when a new call comes in.
* The default implementation calls {@link #onChange}.
* The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
* @param caller the SIP profile of the caller
@ -87,7 +89,7 @@ public class SipAudioCall {
/**
* Called when a RINGING response is received for the INVITE request
* sent. The default implementation calls {@link #onChange}.
* sent. The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@ -97,7 +99,7 @@ public class SipAudioCall {
/**
* Called when the session is established.
* The default implementation calls {@link #onChange}.
* The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@ -107,7 +109,7 @@ public class SipAudioCall {
/**
* Called when the session is terminated.
* The default implementation calls {@link #onChange}.
* The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@ -117,7 +119,7 @@ public class SipAudioCall {
/**
* Called when the peer is busy during session initialization.
* The default implementation calls {@link #onChange}.
* The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@ -127,7 +129,7 @@ public class SipAudioCall {
/**
* Called when the call is on hold.
* The default implementation calls {@link #onChange}.
* The default implementation calls {@link #onChanged}.
*
* @param call the call object that carries out the audio call
*/
@ -257,8 +259,10 @@ public class SipAudioCall {
*
* @return true if the call is established
*/
public synchronized boolean isInCall() {
return mInCall;
public boolean isInCall() {
synchronized (this) {
return mInCall;
}
}
/**
@ -266,8 +270,10 @@ public class SipAudioCall {
*
* @return true if the call is on hold
*/
public synchronized boolean isOnHold() {
return mHold;
public boolean isOnHold() {
synchronized (this) {
return mHold;
}
}
/**
@ -299,8 +305,10 @@ public class SipAudioCall {
*
* @return the local SIP profile
*/
public synchronized SipProfile getLocalProfile() {
return mLocalProfile;
public SipProfile getLocalProfile() {
synchronized (this) {
return mLocalProfile;
}
}
/**
@ -308,8 +316,10 @@ public class SipAudioCall {
*
* @return the peer's SIP profile
*/
public synchronized SipProfile getPeerProfile() {
return (mSipSession == null) ? null : mSipSession.getPeerProfile();
public SipProfile getPeerProfile() {
synchronized (this) {
return (mSipSession == null) ? null : mSipSession.getPeerProfile();
}
}
/**
@ -318,9 +328,11 @@ public class SipAudioCall {
*
* @return the session state
*/
public synchronized int getState() {
if (mSipSession == null) return SipSession.State.READY_TO_CALL;
return mSipSession.getState();
public int getState() {
synchronized (this) {
if (mSipSession == null) return SipSession.State.READY_TO_CALL;
return mSipSession.getState();
}
}
@ -330,8 +342,10 @@ public class SipAudioCall {
* @return the session object that carries this call
* @hide
*/
public synchronized SipSession getSipSession() {
return mSipSession;
public SipSession getSipSession() {
synchronized (this) {
return mSipSession;
}
}
private SipSession.Listener createListener() {
@ -364,22 +378,25 @@ public class SipAudioCall {
}
@Override
public synchronized void onRinging(SipSession session,
public void onRinging(SipSession session,
SipProfile peerProfile, String sessionDescription) {
if ((mSipSession == null) || !mInCall
|| !session.getCallId().equals(mSipSession.getCallId())) {
// should not happen
session.endCall();
return;
}
synchronized (SipAudioCall.this) {
if ((mSipSession == null) || !mInCall
|| !session.getCallId().equals(
mSipSession.getCallId())) {
// should not happen
session.endCall();
return;
}
// session changing request
try {
String answer = createAnswer(sessionDescription).encode();
mSipSession.answerCall(answer, SESSION_TIMEOUT);
} catch (Throwable e) {
Log.e(TAG, "onRinging()", e);
session.endCall();
// session changing request
try {
String answer = createAnswer(sessionDescription).encode();
mSipSession.answerCall(answer, SESSION_TIMEOUT);
} catch (Throwable e) {
Log.e(TAG, "onRinging()", e);
session.endCall();
}
}
}
@ -508,18 +525,22 @@ public class SipAudioCall {
* @throws SipException if the SIP service fails to attach this object to
* the session
*/
public synchronized void attachCall(SipSession session,
String sessionDescription) throws SipException {
mSipSession = session;
mPeerSd = sessionDescription;
Log.v(TAG, "attachCall()" + mPeerSd);
try {
session.setListener(createListener());
public void attachCall(SipSession session, String sessionDescription)
throws SipException {
synchronized (this) {
mSipSession = session;
mPeerSd = sessionDescription;
Log.v(TAG, "attachCall()" + mPeerSd);
try {
session.setListener(createListener());
if (getState() == SipSession.State.INCOMING_CALL) startRinging();
} catch (Throwable e) {
Log.e(TAG, "attachCall()", e);
throwSipException(e);
if (getState() == SipSession.State.INCOMING_CALL) {
startRinging();
}
} catch (Throwable e) {
Log.e(TAG, "attachCall()", e);
throwSipException(e);
}
}
}
@ -529,7 +550,7 @@ public class SipAudioCall {
* and {@code Listener.onError(SipAudioCall, SipErrorCode.TIME_OUT, String)}
* will be called.
*
* @param callee the SIP profile to make the call to
* @param peerProfile the SIP profile to make the call to
* @param sipSession the {@link SipSession} for carrying out the call
* @param timeout the timeout value in seconds. Default value (defined by
* SIP protocol) is used if {@code timeout} is zero or negative.
@ -537,15 +558,19 @@ public class SipAudioCall {
* @throws SipException if the SIP service fails to create a session for the
* call
*/
public synchronized void makeCall(SipProfile peerProfile,
SipSession sipSession, int timeout) throws SipException {
mSipSession = sipSession;
try {
mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp()));
sipSession.setListener(createListener());
sipSession.makeCall(peerProfile, createOffer().encode(), timeout);
} catch (IOException e) {
throw new SipException("makeCall()", e);
public void makeCall(SipProfile peerProfile, SipSession sipSession,
int timeout) throws SipException {
synchronized (this) {
mSipSession = sipSession;
try {
mAudioStream = new AudioStream(InetAddress.getByName(
getLocalIp()));
sipSession.setListener(createListener());
sipSession.makeCall(peerProfile, createOffer().encode(),
timeout);
} catch (IOException e) {
throw new SipException("makeCall()", e);
}
}
}
@ -553,13 +578,15 @@ public class SipAudioCall {
* Ends a call.
* @throws SipException if the SIP service fails to end the call
*/
public synchronized void endCall() throws SipException {
stopRinging();
stopCall(RELEASE_SOCKET);
mInCall = false;
public void endCall() throws SipException {
synchronized (this) {
stopRinging();
stopCall(RELEASE_SOCKET);
mInCall = false;
// perform the above local ops first and then network op
if (mSipSession != null) mSipSession.endCall();
// perform the above local ops first and then network op
if (mSipSession != null) mSipSession.endCall();
}
}
/**
@ -574,13 +601,15 @@ public class SipAudioCall {
* @see Listener.onError
* @throws SipException if the SIP service fails to hold the call
*/
public synchronized void holdCall(int timeout) throws SipException {
public void holdCall(int timeout) throws SipException {
synchronized (this) {
if (mHold) return;
mSipSession.changeCall(createHoldOffer().encode(), timeout);
mHold = true;
mSipSession.changeCall(createHoldOffer().encode(), timeout);
mHold = true;
AudioGroup audioGroup = getAudioGroup();
if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
AudioGroup audioGroup = getAudioGroup();
if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
}
}
/**
@ -594,13 +623,16 @@ public class SipAudioCall {
* @see Listener.onError
* @throws SipException if the SIP service fails to answer the call
*/
public synchronized void answerCall(int timeout) throws SipException {
stopRinging();
try {
mAudioStream = new AudioStream(InetAddress.getByName(getLocalIp()));
mSipSession.answerCall(createAnswer(mPeerSd).encode(), timeout);
} catch (IOException e) {
throw new SipException("answerCall()", e);
public void answerCall(int timeout) throws SipException {
synchronized (this) {
stopRinging();
try {
mAudioStream = new AudioStream(InetAddress.getByName(
getLocalIp()));
mSipSession.answerCall(createAnswer(mPeerSd).encode(), timeout);
} catch (IOException e) {
throw new SipException("answerCall()", e);
}
}
}
@ -616,12 +648,14 @@ public class SipAudioCall {
* @see Listener.onError
* @throws SipException if the SIP service fails to unhold the call
*/
public synchronized void continueCall(int timeout) throws SipException {
if (!mHold) return;
mSipSession.changeCall(createContinueOffer().encode(), timeout);
mHold = false;
AudioGroup audioGroup = getAudioGroup();
if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_NORMAL);
public void continueCall(int timeout) throws SipException {
synchronized (this) {
if (!mHold) return;
mSipSession.changeCall(createContinueOffer().encode(), timeout);
mHold = false;
AudioGroup audioGroup = getAudioGroup();
if (audioGroup != null) audioGroup.setMode(AudioGroup.MODE_NORMAL);
}
}
private SimpleSessionDescription createOffer() {
@ -739,12 +773,15 @@ public class SipAudioCall {
}
/** Toggles mute. */
public synchronized void toggleMute() {
AudioGroup audioGroup = getAudioGroup();
if (audioGroup != null) {
audioGroup.setMode(
mMuted ? AudioGroup.MODE_NORMAL : AudioGroup.MODE_MUTED);
mMuted = !mMuted;
public void toggleMute() {
synchronized (this) {
AudioGroup audioGroup = getAudioGroup();
if (audioGroup != null) {
audioGroup.setMode(mMuted
? AudioGroup.MODE_NORMAL
: AudioGroup.MODE_MUTED);
mMuted = !mMuted;
}
}
}
@ -753,14 +790,18 @@ public class SipAudioCall {
*
* @return true if the call is muted
*/
public synchronized boolean isMuted() {
return mMuted;
public boolean isMuted() {
synchronized (this) {
return mMuted;
}
}
/** Puts the device to speaker mode. */
public synchronized void setSpeakerMode(boolean speakerMode) {
((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
.setSpeakerphoneOn(speakerMode);
public void setSpeakerMode(boolean speakerMode) {
synchronized (this) {
((AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE))
.setSpeakerphoneOn(speakerMode);
}
}
/**
@ -785,14 +826,16 @@ public class SipAudioCall {
* inputs.
* @param result the result message to send when done
*/
public synchronized void sendDtmf(int code, Message result) {
AudioGroup audioGroup = getAudioGroup();
if ((audioGroup != null) && (mSipSession != null)
&& (SipSession.State.IN_CALL == getState())) {
Log.v(TAG, "send DTMF: " + code);
audioGroup.sendDtmf(code);
public void sendDtmf(int code, Message result) {
synchronized (this) {
AudioGroup audioGroup = getAudioGroup();
if ((audioGroup != null) && (mSipSession != null)
&& (SipSession.State.IN_CALL == getState())) {
Log.v(TAG, "send DTMF: " + code);
audioGroup.sendDtmf(code);
}
if (result != null) result.sendToTarget();
}
if (result != null) result.sendToTarget();
}
/**
@ -806,8 +849,10 @@ public class SipAudioCall {
* yet been set up
* @hide
*/
public synchronized AudioStream getAudioStream() {
return mAudioStream;
public AudioStream getAudioStream() {
synchronized (this) {
return mAudioStream;
}
}
/**
@ -824,9 +869,11 @@ public class SipAudioCall {
* @see #getAudioStream
* @hide
*/
public synchronized AudioGroup getAudioGroup() {
if (mAudioGroup != null) return mAudioGroup;
return ((mAudioStream == null) ? null : mAudioStream.getGroup());
public AudioGroup getAudioGroup() {
synchronized (this) {
if (mAudioGroup != null) return mAudioGroup;
return ((mAudioStream == null) ? null : mAudioStream.getGroup());
}
}
/**
@ -837,11 +884,13 @@ public class SipAudioCall {
* @see #getAudioStream
* @hide
*/
public synchronized void setAudioGroup(AudioGroup group) {
if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) {
mAudioStream.join(group);
public void setAudioGroup(AudioGroup group) {
synchronized (this) {
if ((mAudioStream != null) && (mAudioStream.getGroup() != null)) {
mAudioStream.join(group);
}
mAudioGroup = group;
}
mAudioGroup = group;
}
/**
@ -981,8 +1030,10 @@ public class SipAudioCall {
*
* @param enabled true to enable; false to disable
*/
public synchronized void setRingbackToneEnabled(boolean enabled) {
mRingbackToneEnabled = enabled;
public void setRingbackToneEnabled(boolean enabled) {
synchronized (this) {
mRingbackToneEnabled = enabled;
}
}
/**
@ -990,8 +1041,10 @@ public class SipAudioCall {
*
* @param enabled true to enable; false to disable
*/
public synchronized void setRingtoneEnabled(boolean enabled) {
mRingtoneEnabled = enabled;
public void setRingtoneEnabled(boolean enabled) {
synchronized (this) {
mRingtoneEnabled = enabled;
}
}
private void startRingbackTone() {

View File

@ -19,10 +19,9 @@ package android.net.sip;
/**
* Defines error code returned in
* {@link SipRegistrationListener#onRegistrationFailed},
* {@link ISipSessionListener#onError},
* {@link ISipSessionListener#onCallChangeFailed} and
* {@link ISipSessionListener#onRegistrationFailed}.
* @hide
* {@link SipSession.Listener#onError},
* {@link SipSession.Listener#onCallChangeFailed} and
* {@link SipSession.Listener#onRegistrationFailed}.
*/
public class SipErrorCode {
/** Not an error. */

View File

@ -18,7 +18,6 @@ package android.net.sip;
/**
* General SIP-related exception class.
* @hide
*/
public class SipException extends Exception {
public SipException() {

View File

@ -48,7 +48,8 @@ import java.text.ParseException;
* <li>process SIP events directly with a {@link SipSession} created by
* {@link #createSipSession}.</li>
* </ul>
* @hide
* {@code SipManager} can only be instantiated if SIP API is supported by the
* device. (See {@link #isApiSupported}).
*/
public class SipManager {
/**
@ -58,10 +59,17 @@ public class SipManager {
*/
public static final int INCOMING_CALL_RESULT_CODE = 101;
/** Part of the incoming call intent. */
/**
* Key to retrieve the call ID from an incoming call intent.
* @see #open(SipProfile, PendingIntent, SipRegistrationListener)
*/
public static final String EXTRA_CALL_ID = "android:sipCallID";
/** Part of the incoming call intent. */
/**
* Key to retrieve the offered session description from an incoming call
* intent.
* @see #open(SipProfile, PendingIntent, SipRegistrationListener)
*/
public static final String EXTRA_OFFER_SD = "android:sipOfferSD";
/**
@ -178,7 +186,11 @@ public class SipManager {
* make subsequent calls through {@link #makeAudioCall}. If the
* auto-registration option is enabled in the profile, the SIP service
* will register the profile to the corresponding SIP provider periodically
* in order to receive calls from the provider.
* in order to receive calls from the provider. When the SIP service
* receives a new call, it will send out an intent with the provided action
* string. The intent contains a call ID extra and an offer session
* description string extra. Use {@link #getCallId} and
* {@link #getOfferSessionDescription} to retrieve those extras.
*
* @param localProfile the SIP profile to receive incoming calls for
* @param incomingCallPendingIntent When an incoming call is received, the
@ -194,6 +206,9 @@ public class SipManager {
* @throws NullPointerException if {@code incomingCallPendingIntent} is null
* @throws SipException if the profile contains incorrect settings or
* calling the SIP service results in an error
* @see #isIncomingCallIntent
* @see #getCallId
* @see #getOfferSessionDescription
*/
public void open(SipProfile localProfile,
PendingIntent incomingCallPendingIntent,
@ -291,7 +306,8 @@ public class SipManager {
* @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
* @param timeout the timeout value in seconds. Default value (defined by
* SIP protocol) is used if {@code timeout} is zero or negative.
* @return a {@link SipAudioCall} object
* @throws SipException if calling the SIP service results in an error
* @see SipAudioCall.Listener.onError
@ -321,7 +337,8 @@ public class SipManager {
* @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
* @param timeout the timeout value in seconds. Default value (defined by
* SIP protocol) is used if {@code timeout} is zero or negative.
* @return a {@link SipAudioCall} object
* @throws SipException if calling the SIP service results in an error
* @see SipAudioCall.Listener.onError
@ -489,7 +506,7 @@ public class SipManager {
}
/**
* Gets the {@link ISipSession} that handles the incoming call. For audio
* Gets the {@link SipSession} that handles the incoming call. For audio
* calls, consider to use {@link SipAudioCall} to handle the incoming call.
* See {@link #takeAudioCall}. Note that the method may be called only once
* for the same intent. For subsequent calls on the same intent, the method
@ -498,11 +515,12 @@ public class SipManager {
* @param incomingCallIntent the incoming call broadcast intent
* @return the session object that handles the incoming call
*/
public ISipSession getSessionFor(Intent incomingCallIntent)
public SipSession getSessionFor(Intent incomingCallIntent)
throws SipException {
try {
String callId = getCallId(incomingCallIntent);
return mSipService.getPendingSession(callId);
ISipSession s = mSipService.getPendingSession(callId);
return new SipSession(s);
} catch (RemoteException e) {
throw new SipException("getSessionFor()", e);
}
@ -514,8 +532,8 @@ public class SipManager {
}
/**
* Creates a {@link ISipSession} with the specified profile. Use other
* methods, if applicable, instead of interacting with {@link ISipSession}
* Creates a {@link SipSession} with the specified profile. Use other
* methods, if applicable, instead of interacting with {@link SipSession}
* directly.
*
* @param localProfile the SIP profile the session is associated with

View File

@ -33,7 +33,6 @@ import javax.sip.address.URI;
/**
* Class containing a SIP account, domain and server information.
* @hide
*/
public class SipProfile implements Parcelable, Serializable, Cloneable {
private static final long serialVersionUID = 1L;

View File

@ -18,7 +18,6 @@ package android.net.sip;
/**
* Listener class to listen to SIP registration events.
* @hide
*/
public interface SipRegistrationListener {
/**

View File

@ -22,14 +22,12 @@ import android.util.Log;
/**
* A SIP session that is associated with a SIP dialog or a standalone
* transaction not within a dialog.
* @hide
*/
public final class SipSession {
private static final String TAG = "SipSession";
/**
* Defines {@link SipSession} states.
* @hide
*/
public static class State {
/** When session is ready to initiate a call or transaction. */
@ -101,7 +99,6 @@ public final class SipSession {
/**
* Listener class that listens to {@link SipSession} events.
* @hide
*/
public static class Listener {
/**
@ -281,7 +278,7 @@ public final class SipSession {
/**
* Gets the session state. The value returned must be one of the states in
* {@link SipSessionState}.
* {@link State}.
*
* @return the session state
*/
@ -339,7 +336,7 @@ public final class SipSession {
* Performs registration to the server specified by the associated local
* profile. The session listener is called back upon success or failure of
* registration. The method is only valid to call when the session state is
* in {@link SipSessionState#READY_TO_CALL}.
* in {@link State#READY_TO_CALL}.
*
* @param duration duration in second before the registration expires
* @see Listener
@ -357,7 +354,7 @@ public final class SipSession {
* profile. Unregistration is technically the same as registration with zero
* expiration duration. The session listener is called back upon success or
* failure of unregistration. The method is only valid to call when the
* session state is in {@link SipSessionState#READY_TO_CALL}.
* session state is in {@link State#READY_TO_CALL}.
*
* @see Listener
*/
@ -372,7 +369,7 @@ public final class SipSession {
/**
* Initiates a call to the specified profile. The session listener is called
* back upon defined session events. The method is only valid to call when
* the session state is in {@link SipSessionState#READY_TO_CALL}.
* the session state is in {@link State#READY_TO_CALL}.
*
* @param callee the SIP profile to make the call to
* @param sessionDescription the session description of this call
@ -393,7 +390,7 @@ public final class SipSession {
/**
* Answers an incoming call with the specified session description. The
* method is only valid to call when the session state is in
* {@link SipSessionState#INCOMING_CALL}.
* {@link State#INCOMING_CALL}.
*
* @param sessionDescription the session description to answer this call
* @param timeout the session will be timed out if the call is not
@ -411,10 +408,10 @@ public final class SipSession {
/**
* Ends an established call, terminates an outgoing call or rejects an
* incoming call. The method is only valid to call when the session state is
* in {@link SipSessionState#IN_CALL},
* {@link SipSessionState#INCOMING_CALL},
* {@link SipSessionState#OUTGOING_CALL} or
* {@link SipSessionState#OUTGOING_CALL_RING_BACK}.
* in {@link State#IN_CALL},
* {@link State#INCOMING_CALL},
* {@link State#OUTGOING_CALL} or
* {@link State#OUTGOING_CALL_RING_BACK}.
*/
public void endCall() {
try {
@ -426,7 +423,7 @@ public final class SipSession {
/**
* Changes the session description during a call. The method is only valid
* to call when the session state is in {@link SipSessionState#IN_CALL}.
* to call when the session state is in {@link State#IN_CALL}.
*
* @param sessionDescription the new session description
* @param timeout the session will be timed out if the call is not