am 3294d44b: Add confcall management to SIP calls
Merge commit '3294d44b96f63f647fba3a03604eb028e28a42bc' into gingerbread-plus-aosp
* commit '3294d44b96f63f647fba3a03604eb028e28a42bc':
Add confcall management to SIP calls
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 8e08592..980affa 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -322,7 +322,9 @@
}
break;
}
- audioManager.setMode(mode);
+ // calling audioManager.setMode() multiple times in a short period of
+ // time seems to break the audio recorder in in-call mode
+ if (audioManager.getMode() != mode) audioManager.setMode(mode);
}
private Context getContext() {
diff --git a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
index d48f94a..6c989b4 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
@@ -85,8 +85,10 @@
protected void setState(Call.State state) {
switch (state) {
case ACTIVE:
- connectTimeReal = SystemClock.elapsedRealtime();
- connectTime = System.currentTimeMillis();
+ if (connectTime == 0) {
+ connectTimeReal = SystemClock.elapsedRealtime();
+ connectTime = System.currentTimeMillis();
+ }
break;
case DISCONNECTED:
duration = SystemClock.elapsedRealtime() - connectTimeReal;
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index a052db0..1325dd3 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -100,7 +100,7 @@
}
public String getPhoneName() {
- return mProfile.getProfileName();
+ return "SIP:" + getUriString(mProfile);
}
public String getSipUri() {
@@ -222,21 +222,25 @@
}
public void conference() throws CallStateException {
- if ((foregroundCall.getState() != SipCall.State.ACTIVE)
- || (foregroundCall.getState() != SipCall.State.ACTIVE)) {
- throw new CallStateException("wrong state to merge calls: fg="
- + foregroundCall.getState() + ", bg="
- + backgroundCall.getState());
+ synchronized (SipPhone.class) {
+ if ((foregroundCall.getState() != SipCall.State.ACTIVE)
+ || (foregroundCall.getState() != SipCall.State.ACTIVE)) {
+ throw new CallStateException("wrong state to merge calls: fg="
+ + foregroundCall.getState() + ", bg="
+ + backgroundCall.getState());
+ }
+ foregroundCall.merge(backgroundCall);
}
- foregroundCall.merge(backgroundCall);
}
public void conference(Call that) throws CallStateException {
- if (!(that instanceof SipCall)) {
- throw new CallStateException("expect " + SipCall.class
- + ", cannot merge with " + that.getClass());
+ synchronized (SipPhone.class) {
+ if (!(that instanceof SipCall)) {
+ throw new CallStateException("expect " + SipCall.class
+ + ", cannot merge with " + that.getClass());
+ }
+ foregroundCall.merge((SipCall) that);
}
- foregroundCall.merge((SipCall) that);
}
public boolean canTransfer() {
@@ -248,12 +252,14 @@
}
public void clearDisconnected() {
- ringingCall.clearDisconnected();
- foregroundCall.clearDisconnected();
- backgroundCall.clearDisconnected();
+ synchronized (SipPhone.class) {
+ ringingCall.clearDisconnected();
+ foregroundCall.clearDisconnected();
+ backgroundCall.clearDisconnected();
- updatePhoneState();
- notifyPreciseCallStateChanged();
+ updatePhoneState();
+ notifyPreciseCallStateChanged();
+ }
}
public void sendDtmf(char c) {
@@ -261,7 +267,9 @@
Log.e(LOG_TAG,
"sendDtmf called with invalid character '" + c + "'");
} else if (foregroundCall.getState().isAlive()) {
- foregroundCall.sendDtmf(c);
+ synchronized (SipPhone.class) {
+ foregroundCall.sendDtmf(c);
+ }
}
}
@@ -307,7 +315,9 @@
}
public void setMute(boolean muted) {
- foregroundCall.setMute(muted);
+ synchronized (SipPhone.class) {
+ foregroundCall.setMute(muted);
+ }
}
public boolean getMute() {
@@ -410,18 +420,20 @@
@Override
public void hangup() throws CallStateException {
- Log.v(LOG_TAG, "hang up call: " + getState() + ": " + this
- + " on phone " + getPhone());
- CallStateException excp = null;
- for (Connection c : connections) {
- try {
- c.hangup();
- } catch (CallStateException e) {
- excp = e;
+ synchronized (SipPhone.class) {
+ Log.v(LOG_TAG, "hang up call: " + getState() + ": " + this
+ + " on phone " + getPhone());
+ CallStateException excp = null;
+ for (Connection c : connections) {
+ try {
+ c.hangup();
+ } catch (CallStateException e) {
+ excp = e;
+ }
}
+ if (excp != null) throw excp;
+ setState(State.DISCONNECTING);
}
- if (excp != null) throw excp;
- setState(State.DISCONNECTING);
}
void initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) {
@@ -454,19 +466,20 @@
}
void hold() throws CallStateException {
- AudioGroup audioGroup = getAudioGroup();
- if (audioGroup == null) return;
- audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
setState(State.HOLDING);
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup != null) {
+ audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+ }
for (Connection c : connections) ((SipConnection) c).hold();
}
void unhold() throws CallStateException {
- AudioGroup audioGroup = getAudioGroup();
- if (audioGroup == null) return;
- audioGroup.setMode(AudioGroup.MODE_NORMAL);
setState(State.ACTIVE);
- for (Connection c : connections) ((SipConnection) c).unhold();
+ AudioGroup audioGroup = new AudioGroup();
+ for (Connection c : connections) {
+ ((SipConnection) c).unhold(audioGroup);
+ }
}
void setMute(boolean muted) {
@@ -483,17 +496,26 @@
}
void merge(SipCall that) throws CallStateException {
- AudioGroup myGroup = getAudioGroup();
+ AudioGroup audioGroup = getAudioGroup();
for (Connection c : that.connections) {
SipConnection conn = (SipConnection) c;
- conn.mergeTo(myGroup);
- connections.add(conn);
- conn.changeOwner(this);
+ add(conn);
+ if (conn.getState() == Call.State.HOLDING) {
+ conn.unhold(audioGroup);
+ }
}
- that.connections.clear();
that.setState(Call.State.IDLE);
}
+ private void add(SipConnection conn) {
+ SipCall call = conn.getCall();
+ if (call == this) return;
+ if (call != null) call.connections.remove(conn);
+
+ connections.add(conn);
+ conn.changeOwner(this);
+ }
+
void sendDtmf(char c) {
AudioGroup audioGroup = getAudioGroup();
if (audioGroup == null) return;
@@ -568,7 +590,6 @@
private class SipConnection extends SipConnectionBase {
private SipCall mOwner;
private SipAudioCall mSipAudioCall;
- private AudioGroup mOriginalGroup;
private Call.State mState = Call.State.IDLE;
private SipProfile mPeer;
private boolean mIncoming = false;
@@ -673,6 +694,7 @@
}
void hold() throws CallStateException {
+ setState(Call.State.HOLDING);
try {
mSipAudioCall.holdCall();
} catch (SipException e) {
@@ -680,7 +702,9 @@
}
}
- void unhold() throws CallStateException {
+ void unhold(AudioGroup audioGroup) throws CallStateException {
+ mSipAudioCall.setAudioGroup(audioGroup);
+ setState(Call.State.ACTIVE);
try {
mSipAudioCall.continueCall();
} catch (SipException e) {
@@ -688,16 +712,6 @@
}
}
- void mergeTo(AudioGroup group) throws CallStateException {
- AudioStream stream = mSipAudioCall.getAudioStream();
- if (stream == null) {
- throw new CallStateException("wrong state to merge: "
- + mSipAudioCall.getState());
- }
- if (mOriginalGroup == null) mOriginalGroup = getAudioGroup();
- stream.join(group);
- }
-
@Override
protected void setState(Call.State state) {
if (state == mState) return;
@@ -732,29 +746,36 @@
@Override
public void hangup() throws CallStateException {
- // TODO: need to pull AudioStream out of the AudioGroup in case
- // this conn was part of a conf call
- Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
- + ": on phone " + getPhone());
- try {
- mSipAudioCall.endCall();
- setState(Call.State.DISCONNECTING);
- setDisconnectCause(DisconnectCause.LOCAL);
- } catch (SipException e) {
- throw new CallStateException("hangup(): " + e);
+ synchronized (SipPhone.class) {
+ Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
+ + ": on phone " + getPhone().getPhoneName());
+ try {
+ mSipAudioCall.endCall();
+ setState(Call.State.DISCONNECTING);
+ setDisconnectCause(DisconnectCause.LOCAL);
+ } catch (SipException e) {
+ throw new CallStateException("hangup(): " + e);
+ }
}
}
@Override
public void separate() throws CallStateException {
- // TODO: what's this for SIP?
- /*
- if (!disconnected) {
- owner.separate(this);
- } else {
- throw new CallStateException ("disconnected");
+ synchronized (SipPhone.class) {
+ SipCall call = (SipCall) SipPhone.this.getBackgroundCall();
+ if (call.getState() != Call.State.IDLE) {
+ throw new CallStateException(
+ "cannot put conn back to a call in non-idle state: "
+ + call.getState());
+ }
+ Log.v(LOG_TAG, "separate conn: " + mPeer.getUriString()
+ + " from " + mOwner + " back to " + call);
+
+ AudioGroup audioGroup = call.getAudioGroup(); // may be null
+ call.add(this);
+ mSipAudioCall.setAudioGroup(audioGroup);
+ call.hold();
}
- */
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 36d65db..4b7e991 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -175,10 +175,6 @@
return state;
}
- public String getPhoneName() {
- return "SIP";
- }
-
public int getPhoneType() {
// FIXME: add SIP phone type
return Phone.PHONE_TYPE_GSM;
diff --git a/voip/java/android/net/sip/SipAudioCall.java b/voip/java/android/net/sip/SipAudioCall.java
index f4be839..3cdd114 100644
--- a/voip/java/android/net/sip/SipAudioCall.java
+++ b/voip/java/android/net/sip/SipAudioCall.java
@@ -244,7 +244,8 @@
* Also, the {@code AudioStream} may change its group during a call (e.g.,
* after the call is held/un-held). Finally, the {@code AudioGroup} object
* returned by this method is undefined after the call ends or the
- * {@link #close} method is called.
+ * {@link #close} method is called. If a group object is set by
+ * {@link #setAudioGroup(AudioGroup)}, then this method returns that object.
*
* @return the {@link AudioGroup} object or null if the RTP stream has not
* yet been set up
@@ -253,6 +254,15 @@
AudioGroup getAudioGroup();
/**
+ * Sets the {@link AudioGroup} object which the {@link AudioStream} object
+ * joins. If {@code audioGroup} is null, then the {@code AudioGroup} object
+ * will be dynamically created when needed.
+ *
+ * @see #getAudioStream
+ */
+ void setAudioGroup(AudioGroup audioGroup);
+
+ /**
* Checks if the call is established.
*
* @return true if the call is established
diff --git a/voip/java/android/net/sip/SipAudioCallImpl.java b/voip/java/android/net/sip/SipAudioCallImpl.java
index 7161309..b8ac6d7 100644
--- a/voip/java/android/net/sip/SipAudioCallImpl.java
+++ b/voip/java/android/net/sip/SipAudioCallImpl.java
@@ -70,7 +70,8 @@
private ISipSession mSipSession;
private SdpSessionDescription mPeerSd;
- private AudioStream mRtpSession;
+ private AudioStream mAudioStream;
+ private AudioGroup mAudioGroup;
private SdpSessionDescription.AudioCodec mCodec;
private long mSessionId = -1L; // SDP session ID
private boolean mInCall = false;
@@ -505,11 +506,19 @@
}
public synchronized AudioStream getAudioStream() {
- return mRtpSession;
+ return mAudioStream;
}
public synchronized AudioGroup getAudioGroup() {
- return ((mRtpSession == null) ? null : mRtpSession.getAudioGroup());
+ if (mAudioGroup != null) return mAudioGroup;
+ return ((mAudioStream == null) ? null : mAudioStream.getAudioGroup());
+ }
+
+ public synchronized void setAudioGroup(AudioGroup group) {
+ if ((mAudioStream != null) && (mAudioStream.getAudioGroup() != null)) {
+ mAudioStream.join(group);
+ }
+ mAudioGroup = group;
}
private SdpSessionDescription.AudioCodec getCodec(SdpSessionDescription sd) {
@@ -561,7 +570,7 @@
// TODO: get sample rate from sdp
mCodec = getCodec(peerSd);
- AudioStream audioStream = mRtpSession;
+ AudioStream audioStream = mAudioStream;
audioStream.associate(InetAddress.getByName(peerMediaAddress),
peerMediaPort);
audioStream.setCodec(convert(mCodec), mCodec.payloadType);
@@ -580,7 +589,7 @@
Log.d(TAG, " not sending");
audioStream.setMode(RtpStream.MODE_RECEIVE_ONLY);
}
- } else {
+
/* The recorder volume will be very low if the device is in
* IN_CALL mode. Therefore, we have to set the mode to NORMAL
* in order to have the normal microphone level.
@@ -590,14 +599,22 @@
.setMode(AudioManager.MODE_NORMAL);
}
- AudioGroup audioGroup = new AudioGroup();
- audioStream.join(audioGroup);
+ // AudioGroup logic:
+ AudioGroup audioGroup = getAudioGroup();
if (mHold) {
- audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
- } else if (mMuted) {
- audioGroup.setMode(AudioGroup.MODE_MUTED);
+ if (audioGroup != null) {
+ audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+ }
+ // don't create an AudioGroup here; doing so will fail if
+ // there's another AudioGroup out there that's active
} else {
- audioGroup.setMode(AudioGroup.MODE_NORMAL);
+ if (audioGroup == null) audioGroup = new AudioGroup();
+ audioStream.join(audioGroup);
+ if (mMuted) {
+ audioGroup.setMode(AudioGroup.MODE_MUTED);
+ } else {
+ audioGroup.setMode(AudioGroup.MODE_NORMAL);
+ }
}
} catch (Exception e) {
Log.e(TAG, "call()", e);
@@ -606,20 +623,20 @@
private void stopCall(boolean releaseSocket) {
Log.d(TAG, "stop audiocall");
- if (mRtpSession != null) {
- mRtpSession.join(null);
+ if (mAudioStream != null) {
+ mAudioStream.join(null);
if (releaseSocket) {
- mRtpSession.release();
- mRtpSession = null;
+ mAudioStream.release();
+ mAudioStream = null;
}
}
}
private int getLocalMediaPort() {
- if (mRtpSession != null) return mRtpSession.getLocalPort();
+ if (mAudioStream != null) return mAudioStream.getLocalPort();
try {
- AudioStream s = mRtpSession =
+ AudioStream s = mAudioStream =
new AudioStream(InetAddress.getByName(getLocalIp()));
return s.getLocalPort();
} catch (IOException e) {