diff options
| author | 2010-08-18 14:37:59 +0800 | |
|---|---|---|
| committer | 2010-08-24 17:54:47 +0800 | |
| commit | 3294d44b96f63f647fba3a03604eb028e28a42bc (patch) | |
| tree | f6e4ed0b30c0edb0e681f39eef43292da250148a | |
| parent | a83987d2ccc6b235dd3dd5cc6206c257dfe9e0a8 (diff) | |
Add confcall management to SIP calls
and fix the bug of re-assigning connectTime's in SipConnection,
and adding synchronization for SipPhone to be thread-safe,
and set normal audio mode when call not on hold instead of on hold in SipAudioCallImpl,
and fix re-entrance problem in CallManager.setAudioMode() for in-call mode.
Change-Id: I54f39dab052062de1ce141e5358d892d30453a3a
6 files changed, 142 insertions, 94 deletions
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java index 8e085928154e..980affa75cf4 100644 --- a/telephony/java/com/android/internal/telephony/CallManager.java +++ b/telephony/java/com/android/internal/telephony/CallManager.java @@ -322,7 +322,9 @@ public final class CallManager { } 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 d48f94ab81bd..6c989b4a0ef4 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 @@ abstract class SipConnectionBase extends Connection { 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 a052db0ddb44..1325dd34f08a 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 class SipPhone extends SipPhoneBase { } public String getPhoneName() { - return mProfile.getProfileName(); + return "SIP:" + getUriString(mProfile); } public String getSipUri() { @@ -222,21 +222,25 @@ public class SipPhone extends SipPhoneBase { } 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 class SipPhone extends SipPhoneBase { } 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 @@ public class SipPhone extends SipPhoneBase { 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 class SipPhone extends SipPhoneBase { } public void setMute(boolean muted) { - foregroundCall.setMute(muted); + synchronized (SipPhone.class) { + foregroundCall.setMute(muted); + } } public boolean getMute() { @@ -410,18 +420,20 @@ public class SipPhone extends SipPhoneBase { @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 @@ public class SipPhone extends SipPhoneBase { } 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 @@ public class SipPhone extends SipPhoneBase { } 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 @@ public class SipPhone extends SipPhoneBase { 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 @@ public class SipPhone extends SipPhoneBase { } void hold() throws CallStateException { + setState(Call.State.HOLDING); try { mSipAudioCall.holdCall(); } catch (SipException e) { @@ -680,7 +702,9 @@ public class SipPhone extends SipPhoneBase { } } - 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 @@ public class SipPhone extends SipPhoneBase { } } - 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 @@ public class SipPhone extends SipPhoneBase { @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 36d65dbbd0b6..4b7e991527e9 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 @@ abstract class SipPhoneBase extends PhoneBase { 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 f4be839da72b..3cdd11489d7e 100644 --- a/voip/java/android/net/sip/SipAudioCall.java +++ b/voip/java/android/net/sip/SipAudioCall.java @@ -244,7 +244,8 @@ public interface SipAudioCall { * 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 @@ public interface SipAudioCall { 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 7161309ec46d..b8ac6d73522a 100644 --- a/voip/java/android/net/sip/SipAudioCallImpl.java +++ b/voip/java/android/net/sip/SipAudioCallImpl.java @@ -70,7 +70,8 @@ public class SipAudioCallImpl extends SipSessionAdapter 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 class SipAudioCallImpl extends SipSessionAdapter } 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 @@ public class SipAudioCallImpl extends SipSessionAdapter // 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 @@ public class SipAudioCallImpl extends SipSessionAdapter 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 @@ public class SipAudioCallImpl extends SipSessionAdapter .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 @@ public class SipAudioCallImpl extends SipSessionAdapter 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) { |