@Override protected void onCallEnded(DisconnectCause cause) { if (getDisconnectCause() != DisconnectCause.LOCAL) { setDisconnectCause(cause); } synchronized (SipPhone.class) { setState(Call.State.DISCONNECTED); SipAudioCall sipAudioCall = mSipAudioCall; // FIXME: This goes null and is synchronized, but many uses aren't sync'd mSipAudioCall = null; String sessionState = (sipAudioCall == null) ? "" : (sipAudioCall.getState() + ", "); if (SCN_DBG) log( "[SipAudioCallAdapter] onCallEnded: " + mPeer.getUriString() + ": " + sessionState + "cause: " + getDisconnectCause() + ", on phone " + getPhone()); if (sipAudioCall != null) { sipAudioCall.setListener(null); sipAudioCall.close(); } mOwner.onConnectionEnded(SipConnection.this); } }
@Override public void hangup() throws CallStateException { synchronized (SipPhone.class) { if (SCN_DBG) log( "hangup: conn=" + mPeer.getUriString() + ": " + mState + ": on phone " + getPhone().getPhoneName()); if (!mState.isAlive()) return; try { SipAudioCall sipAudioCall = mSipAudioCall; if (sipAudioCall != null) { sipAudioCall.setListener(null); sipAudioCall.endCall(); } } catch (SipException e) { throw new CallStateException("hangup(): " + e); } finally { mAdapter.onCallEnded( ((mState == Call.State.INCOMING) || (mState == Call.State.WAITING)) ? DisconnectCause.INCOMING_REJECTED : DisconnectCause.LOCAL); } } }
@Override public void separate() throws CallStateException { synchronized (SipPhone.class) { SipCall call = (getPhone() == SipPhone.this) ? (SipCall) getBackgroundCall() : (SipCall) getForegroundCall(); if (call.getState() != Call.State.IDLE) { throw new CallStateException( "cannot put conn back to a call in non-idle state: " + call.getState()); } if (SCN_DBG) log("separate: conn=" + mPeer.getUriString() + " from " + mOwner + " back to " + call); // separate the AudioGroup and connection from the original call Phone originalPhone = getPhone(); AudioGroup audioGroup = call.getAudioGroup(); // may be null call.add(this); mSipAudioCall.setAudioGroup(audioGroup); // put the original call to bg; and the separated call becomes // fg if it was in bg originalPhone.switchHoldingAndActive(); // start audio and notify the phone app of the state change call = (SipCall) getForegroundCall(); mSipAudioCall.startAudio(); call.onConnectionStateChanged(this); } }
void unhold(AudioGroup audioGroup) throws CallStateException { mSipAudioCall.setAudioGroup(audioGroup); setState(Call.State.ACTIVE); try { mSipAudioCall.continueCall(TIMEOUT_HOLD_CALL); } catch (SipException e) { throw new CallStateException("unhold(): " + e); } }
public boolean canTake(Object incomingCall) { // FIXME: Is synchronizing on the class necessary, should we use a mLockObj? // Also there are many things not synchronized, of course // this may be true of CdmaPhone and GsmPhone too!!! synchronized (SipPhone.class) { if (!(incomingCall instanceof SipAudioCall)) { if (DBG) log("canTake: ret=false, not a SipAudioCall"); return false; } if (mRingingCall.getState().isAlive()) { if (DBG) log("canTake: ret=false, ringingCall not alive"); return false; } // FIXME: is it true that we cannot take any incoming call if // both foreground and background are active if (mForegroundCall.getState().isAlive() && mBackgroundCall.getState().isAlive()) { if (DBG) { log("canTake: ret=false," + " foreground and background both alive"); } return false; } try { SipAudioCall sipAudioCall = (SipAudioCall) incomingCall; if (DBG) log("canTake: taking call from: " + sipAudioCall.getPeerProfile().getUriString()); String localUri = sipAudioCall.getLocalProfile().getUriString(); if (localUri.equals(mProfile.getUriString())) { boolean makeCallWait = mForegroundCall.getState().isAlive(); mRingingCall.initIncomingCall(sipAudioCall, makeCallWait); if (sipAudioCall.getState() != SipSession.State.INCOMING_CALL) { // Peer cancelled the call! if (DBG) log(" canTake: call cancelled !!"); mRingingCall.reset(); } return true; } } catch (Exception e) { // Peer may cancel the call at any time during the time we hook // up ringingCall with sipAudioCall. Clean up ringingCall when // that happens. if (DBG) log(" canTake: exception e=" + e); mRingingCall.reset(); } if (DBG) log("canTake: NOT taking !!"); return false; } }
void acceptCall() throws CallStateException { try { mSipAudioCall.answerCall(TIMEOUT_ANSWER_CALL); } catch (SipException e) { throw new CallStateException("acceptCall(): " + e); } }
@Override public void onCallEnded(SipAudioCall call) { if (SACA_DBG) log("onCallEnded: call=" + call); onCallEnded( call.isInCall() ? Connection.DisconnectCause.NORMAL : Connection.DisconnectCause.INCOMING_MISSED); }
void hold() throws CallStateException { setState(Call.State.HOLDING); try { mSipAudioCall.holdCall(TIMEOUT_HOLD_CALL); } catch (SipException e) { throw new CallStateException("hold(): " + e); } }
void initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) { SipProfile callee = sipAudioCall.getPeerProfile(); SipConnection c = new SipConnection(this, callee); mConnections.add(c); Call.State newState = makeCallWait ? State.WAITING : State.INCOMING; c.initIncomingCall(sipAudioCall, newState); setState(newState); notifyNewRingingConnectionP(c); }
private static Call.State getCallStateFrom(SipAudioCall sipAudioCall) { if (sipAudioCall.isOnHold()) return Call.State.HOLDING; int sessionState = sipAudioCall.getState(); switch (sessionState) { case SipSession.State.READY_TO_CALL: return Call.State.IDLE; case SipSession.State.INCOMING_CALL: case SipSession.State.INCOMING_CALL_ANSWERING: return Call.State.INCOMING; case SipSession.State.OUTGOING_CALL: return Call.State.DIALING; case SipSession.State.OUTGOING_CALL_RING_BACK: return Call.State.ALERTING; case SipSession.State.OUTGOING_CALL_CANCELING: return Call.State.DISCONNECTING; case SipSession.State.IN_CALL: return Call.State.ACTIVE; default: slog("illegal connection state: " + sessionState); return Call.State.DISCONNECTED; } }
AudioGroup getAudioGroup() { if (mSipAudioCall == null) return null; return mSipAudioCall.getAudioGroup(); }
boolean getMute() { return (mSipAudioCall == null) ? false : mSipAudioCall.isMuted(); }
void setMute(boolean muted) { if ((mSipAudioCall != null) && (muted != mSipAudioCall.isMuted())) { if (SCN_DBG) log("setState: prev muted=" + !muted + " new muted=" + muted); mSipAudioCall.toggleMute(); } }
@Override public void onCallEstablished(SipAudioCall call) { onChanged(call); // Race onChanged synchronized this isn't if (mState == Call.State.ACTIVE) call.startAudio(); }
@Override public void onCallHeld(SipAudioCall call) { onChanged(call); // Race onChanged synchronized this isn't if (mState == Call.State.HOLDING) call.startAudio(); }
void dial() throws SipException { setState(Call.State.DIALING); mSipAudioCall = mSipManager.makeAudioCall(mProfile, mPeer, null, TIMEOUT_MAKE_CALL); mSipAudioCall.setListener(mAdapter); }
void initIncomingCall(SipAudioCall sipAudioCall, Call.State newState) { setState(newState); mSipAudioCall = sipAudioCall; sipAudioCall.setListener(mAdapter); // call back to set state mIncoming = true; }