Loading src/com/android/server/telecom/Call.java +47 −0 Original line number Diff line number Diff line Loading @@ -156,6 +156,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, void onCallHoldFailed(Call call); void onCallSwitchFailed(Call call); void onConnectionEvent(Call call, String event, Bundle extras); void onCallStreamingStateChanged(Call call, boolean isStreaming); void onExternalCallChanged(Call call, boolean isExternalCall); void onRttInitiationFailure(Call call, int reason); void onRemoteRttRequest(Call call, int requestId); Loading Loading @@ -243,6 +244,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, @Override public void onConnectionEvent(Call call, String event, Bundle extras) {} @Override public void onCallStreamingStateChanged(Call call, boolean isStreaming) {} @Override public void onExternalCallChanged(Call call, boolean isExternalCall) {} @Override public void onRttInitiationFailure(Call call, int reason) {} Loading Loading @@ -534,6 +537,11 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, private boolean mIsTransactionalCall = false; /** * Indicates whether this call is streaming. */ private boolean mIsStreaming = false; /** * Indicates whether the {@link PhoneAccount} associated with an self-managed call want to * expose the call to an {@link android.telecom.InCallService} which declares the metadata Loading Loading @@ -4390,4 +4398,43 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, mDisconnectFuture = null; } } public boolean isStreaming() { synchronized (mLock) { return mIsStreaming; } } public void startStreaming() { if (!mIsTransactionalCall) { throw new UnsupportedOperationException( "Can't streaming call created by non voip apps"); } synchronized (mLock) { if (mIsStreaming) { // ignore return; } mIsStreaming = true; for (Listener listener : mListeners) { listener.onCallStreamingStateChanged(this, true /** isStreaming */); } } } public void stopStreaming() { synchronized (mLock) { if (!mIsStreaming) { // ignore return; } mIsStreaming = false; for (Listener listener : mListeners) { listener.onCallStreamingStateChanged(this, false /** isStreaming */); } } } } src/com/android/server/telecom/CallAudioManager.java +33 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ public class CallAudioManager extends CallsManagerListenerBase { private final RingbackPlayer mRingbackPlayer; private final DtmfLocalTonePlayer mDtmfLocalTonePlayer; private Call mStreamingCall; private Call mForegroundCall; private boolean mIsTonePlaying = false; private boolean mIsDisconnectedTonePlaying = false; Loading @@ -78,6 +79,7 @@ public class CallAudioManager extends CallsManagerListenerBase { mRingingCalls = new LinkedHashSet<>(1); mHoldingCalls = new LinkedHashSet<>(1); mAudioProcessingCalls = new LinkedHashSet<>(1); mStreamingCall = null; mCalls = new HashSet<>(); mCallStateToCalls = new SparseArray<LinkedHashSet<Call>>() {{ put(CallState.CONNECTING, mActiveDialingOrConnectingCalls); Loading Loading @@ -221,6 +223,36 @@ public class CallAudioManager extends CallsManagerListenerBase { } } /** * Handles the changes to the streaming state of a call. * @param call The call * @param isStreaming {@code true} if the call is streaming, {@code false} otherwise */ @Override public void onCallStreamingStateChanged(Call call, boolean isStreaming) { if (isStreaming) { if (mStreamingCall == null) { mStreamingCall = call; mCallAudioModeStateMachine.sendMessageWithArgs( CallAudioModeStateMachine.START_CALL_STREAMING, makeArgsForModeStateMachine()); } else { Log.w(LOG_TAG, "Unexpected streaming call request for call %s while call " + "s is streaming.", call.getId(), mStreamingCall.getId()); } } else { if (mStreamingCall == call) { mStreamingCall = null; mCallAudioModeStateMachine.sendMessageWithArgs( CallAudioModeStateMachine.STOP_CALL_STREAMING, makeArgsForModeStateMachine()); } else { Log.w(LOG_TAG, "Unexpected call streaming stop request for call %s while this call " + "is not streaming.", call.getId()); } } } /** * Determines if {@link CallAudioManager} should do any audio routing operations for a call. * We ignore child calls of a conference and external calls for audio routing purposes. Loading Loading @@ -759,6 +791,7 @@ public class CallAudioManager extends CallsManagerListenerBase { .setHasHoldingCalls(mHoldingCalls.size() > 0) .setHasAudioProcessingCalls(mAudioProcessingCalls.size() > 0) .setIsTonePlaying(mIsTonePlaying) .setIsStreaming(mStreamingCall != null) .setForegroundCallIsVoip( mForegroundCall != null && isCallVoip(mForegroundCall)) .setSession(Log.createSubsession()).build(); Loading src/com/android/server/telecom/CallAudioModeStateMachine.java +114 −9 Original line number Diff line number Diff line Loading @@ -50,17 +50,19 @@ public class CallAudioModeStateMachine extends StateMachine { public boolean hasAudioProcessingCalls; public boolean isTonePlaying; public boolean foregroundCallIsVoip; public boolean isStreaming; public Session session; private MessageArgs(boolean hasActiveOrDialingCalls, boolean hasRingingCalls, boolean hasHoldingCalls, boolean hasAudioProcessingCalls, boolean isTonePlaying, boolean foregroundCallIsVoip, Session session) { boolean foregroundCallIsVoip, boolean isStreaming, Session session) { this.hasActiveOrDialingCalls = hasActiveOrDialingCalls; this.hasRingingCalls = hasRingingCalls; this.hasHoldingCalls = hasHoldingCalls; this.hasAudioProcessingCalls = hasAudioProcessingCalls; this.isTonePlaying = isTonePlaying; this.foregroundCallIsVoip = foregroundCallIsVoip; this.isStreaming = isStreaming; this.session = session; } Loading @@ -73,6 +75,7 @@ public class CallAudioModeStateMachine extends StateMachine { ", hasAudioProcessingCalls=" + hasAudioProcessingCalls + ", isTonePlaying=" + isTonePlaying + ", foregroundCallIsVoip=" + foregroundCallIsVoip + ", isStreaming=" + isStreaming + ", session=" + session + '}'; } Loading @@ -84,6 +87,7 @@ public class CallAudioModeStateMachine extends StateMachine { private boolean mHasAudioProcessingCalls; private boolean mIsTonePlaying; private boolean mForegroundCallIsVoip; private boolean mIsStreaming; private Session mSession; public Builder setHasActiveOrDialingCalls(boolean hasActiveOrDialingCalls) { Loading Loading @@ -121,9 +125,15 @@ public class CallAudioModeStateMachine extends StateMachine { return this; } public Builder setIsStreaming(boolean isStraeming) { mIsStreaming = isStraeming; return this; } public MessageArgs build() { return new MessageArgs(mHasActiveOrDialingCalls, mHasRingingCalls, mHasHoldingCalls, mHasAudioProcessingCalls, mIsTonePlaying, mForegroundCallIsVoip, mSession); mHasAudioProcessingCalls, mIsTonePlaying, mForegroundCallIsVoip, mIsStreaming, mSession); } } } Loading @@ -138,7 +148,8 @@ public class CallAudioModeStateMachine extends StateMachine { public static final int ENTER_RING_FOCUS_FOR_TESTING = 4; public static final int ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING = 5; public static final int ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING = 6; public static final int ABANDON_FOCUS_FOR_TESTING = 7; public static final int ENTER_STREAMING_FOCUS_FOR_TESTING = 7; public static final int ABANDON_FOCUS_FOR_TESTING = 8; public static final int NO_MORE_ACTIVE_OR_DIALING_CALLS = 1001; public static final int NO_MORE_RINGING_CALLS = 1002; Loading @@ -161,6 +172,9 @@ public class CallAudioModeStateMachine extends StateMachine { // to release focus for other apps to take over. public static final int AUDIO_OPERATIONS_COMPLETE = 6001; public static final int START_CALL_STREAMING = 7001; public static final int STOP_CALL_STREAMING = 7002; public static final int RUN_RUNNABLE = 9001; private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{ Loading @@ -183,6 +197,8 @@ public class CallAudioModeStateMachine extends StateMachine { put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE"); put(RINGER_MODE_CHANGE, "RINGER_MODE_CHANGE"); put(AUDIO_OPERATIONS_COMPLETE, "AUDIO_OPERATIONS_COMPLETE"); put(START_CALL_STREAMING, "START_CALL_STREAMING"); put(STOP_CALL_STREAMING, "STOP_CALL_STREAMING"); put(RUN_RUNNABLE, "RUN_RUNNABLE"); }}; Loading @@ -193,6 +209,7 @@ public class CallAudioModeStateMachine extends StateMachine { AudioProcessingFocusState.class.getSimpleName(); public static final String CALL_STATE_NAME = SimCallFocusState.class.getSimpleName(); public static final String RING_STATE_NAME = RingingFocusState.class.getSimpleName(); public static final String STREAMING_STATE_NAME = StreamingFocusState.class.getSimpleName(); public static final String COMMS_STATE_NAME = VoipCallFocusState.class.getSimpleName(); private class BaseState extends State { Loading @@ -214,6 +231,9 @@ public class CallAudioModeStateMachine extends StateMachine { case ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING: transitionTo(mAudioProcessingFocusState); return HANDLED; case ENTER_STREAMING_FOCUS_FOR_TESTING: transitionTo(mStreamingFocusState); return HANDLED; case ABANDON_FOCUS_FOR_TESTING: transitionTo(mUnfocusedState); return HANDLED; Loading Loading @@ -280,6 +300,9 @@ public class CallAudioModeStateMachine extends StateMachine { " Args are: \n" + args.toString()); transitionTo(mOtherFocusState); return HANDLED; case START_CALL_STREAMING: transitionTo(mStreamingFocusState); return HANDLED; case TONE_STARTED_PLAYING: // This shouldn't happen either, but perform the action anyway. Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n" Loading Loading @@ -353,6 +376,9 @@ public class CallAudioModeStateMachine extends StateMachine { Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n" + args.toString()); return HANDLED; case START_CALL_STREAMING: transitionTo(mStreamingFocusState); return HANDLED; case AUDIO_OPERATIONS_COMPLETE: Log.i(LOG_TAG, "Abandoning audio focus: now AUDIO_PROCESSING"); mAudioManager.abandonAudioFocusForCall(); Loading Loading @@ -625,6 +651,79 @@ public class CallAudioModeStateMachine extends StateMachine { Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused" + " state"); return HANDLED; case START_CALL_STREAMING: transitionTo(mStreamingFocusState); return HANDLED; default: // The forced focus switch commands are handled by BaseState. return NOT_HANDLED; } } } private class StreamingFocusState extends BaseState { @Override public void enter() { Log.i(LOG_TAG, "Audio focus entering streaming state"); mAudioManager.setMode(AudioManager.MODE_CALL_REDIRECT); mMostRecentMode = AudioManager.MODE_NORMAL; mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS); mCallAudioManager.getCallAudioRouteStateMachine().sendMessageWithSessionInfo( CallAudioRouteStateMachine.STREAMING_FORCE_ENABLED); } private void preExit() { mCallAudioManager.getCallAudioRouteStateMachine().sendMessageWithSessionInfo( CallAudioRouteStateMachine.STREAMING_FORCE_DISABLED); } @Override public boolean processMessage(Message msg) { if (super.processMessage(msg) == HANDLED) { return HANDLED; } MessageArgs args = (MessageArgs) msg.obj; switch (msg.what) { case NO_MORE_ACTIVE_OR_DIALING_CALLS: // Do nothing. return HANDLED; case NO_MORE_RINGING_CALLS: // Do nothing. return HANDLED; case NO_MORE_HOLDING_CALLS: // Do nothing. return HANDLED; case NO_MORE_AUDIO_PROCESSING_CALLS: // Do nothing. return HANDLED; case NEW_ACTIVE_OR_DIALING_CALL: // Only possible for emergency call BaseState destState = calculateProperStateFromArgs(args); if (destState != this) { preExit(); transitionTo(destState); } return HANDLED; case NEW_RINGING_CALL: // Only possible for emergency call preExit(); transitionTo(mRingingFocusState); return HANDLED; case NEW_HOLDING_CALL: // Do nothing. return HANDLED; case NEW_AUDIO_PROCESSING_CALL: // Do nothing. return HANDLED; case START_CALL_STREAMING: // Can happen as a duplicate message return HANDLED; case TONE_STARTED_PLAYING: // Do nothing. return HANDLED; case STOP_CALL_STREAMING: transitionTo(calculateProperStateFromArgs(args)); return HANDLED; default: // The forced focus switch commands are handled by BaseState. return NOT_HANDLED; Loading Loading @@ -707,6 +806,7 @@ public class CallAudioModeStateMachine extends StateMachine { private final BaseState mSimCallFocusState = new SimCallFocusState(); private final BaseState mVoipCallFocusState = new VoipCallFocusState(); private final BaseState mAudioProcessingFocusState = new AudioProcessingFocusState(); private final BaseState mStreamingFocusState = new StreamingFocusState(); private final BaseState mOtherFocusState = new OtherFocusState(); private final AudioManager mAudioManager; Loading Loading @@ -745,6 +845,7 @@ public class CallAudioModeStateMachine extends StateMachine { addState(mSimCallFocusState); addState(mVoipCallFocusState); addState(mAudioProcessingFocusState); addState(mStreamingFocusState); addState(mOtherFocusState); setInitialState(mUnfocusedState); start(); Loading @@ -754,6 +855,7 @@ public class CallAudioModeStateMachine extends StateMachine { .setHasHoldingCalls(false) .setIsTonePlaying(false) .setForegroundCallIsVoip(false) .setIsStreaming(false) .setSession(Log.createSubsession()) .build()); } Loading Loading @@ -807,12 +909,15 @@ public class CallAudioModeStateMachine extends StateMachine { // switch to the appropriate focus. // Otherwise abandon focus. // The order matters here. If there are active calls, holding focus for them takes priority. // After that, we want to prioritize holding calls over ringing calls so that when a // call-waiting call gets answered, there's no transition in and out of the ringing focus // state. After that, we want tones since we actually hold focus during them, then the // audio processing state because that will release focus. if (args.hasActiveOrDialingCalls) { // The order matters here. If there is streaming call, holding streaming route for them // takes priority. After that, holding focus for active calls takes priority. After that, we // want to prioritize holding calls over ringing calls so that when a call-waiting call gets // answered, there's no transition in and out of the ringing focus state. After that, we // want tones since we actually hold focus during them, then the audio processing state // because that will release focus. if (args.isStreaming) { return mSimCallFocusState; } else if (args.hasActiveOrDialingCalls) { if (args.foregroundCallIsVoip) { return mVoipCallFocusState; } else { Loading src/com/android/server/telecom/CallAudioRouteStateMachine.java +81 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,9 @@ public class CallAudioRouteStateMachine extends StateMachine { /** Direct the audio stream through the device's speakerphone. */ public static final int ROUTE_SPEAKER = CallAudioState.ROUTE_SPEAKER; /** Direct the audio stream through another device. */ public static final int ROUTE_STREAMING = CallAudioState.ROUTE_STREAMING; /** Valid values for msg.what */ public static final int CONNECT_WIRED_HEADSET = 1; public static final int DISCONNECT_WIRED_HEADSET = 2; Loading @@ -129,6 +132,10 @@ public class CallAudioRouteStateMachine extends StateMachine { public static final int SPEAKER_ON = 1006; public static final int SPEAKER_OFF = 1007; // Messages denoting that the streaming route switch request was sent. public static final int STREAMING_FORCE_ENABLED = 1008; public static final int STREAMING_FORCE_DISABLED = 1009; public static final int USER_SWITCH_EARPIECE = 1101; public static final int USER_SWITCH_BLUETOOTH = 1102; public static final int USER_SWITCH_HEADSET = 1103; Loading Loading @@ -545,6 +552,8 @@ public class CallAudioRouteStateMachine extends StateMachine { case DISCONNECT_DOCK: // Nothing to do here return HANDLED; case STREAMING_FORCE_ENABLED: transitionTo(mStreamingState); default: return NOT_HANDLED; } Loading Loading @@ -629,6 +638,9 @@ public class CallAudioRouteStateMachine extends StateMachine { mCallAudioManager.notifyAudioOperationsComplete(); } return HANDLED; case STREAMING_FORCE_ENABLED: transitionTo(mStreamingState); return HANDLED; default: return NOT_HANDLED; } Loading Loading @@ -1106,6 +1118,9 @@ public class CallAudioRouteStateMachine extends StateMachine { case DISCONNECT_DOCK: // Nothing to do here return HANDLED; case STREAMING_FORCE_ENABLED: transitionTo(mStreamingState); return HANDLED; default: return NOT_HANDLED; } Loading Loading @@ -1331,6 +1346,68 @@ public class CallAudioRouteStateMachine extends StateMachine { case DISCONNECT_DOCK: sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE); return HANDLED; case STREAMING_FORCE_ENABLED: transitionTo(mStreamingState); return HANDLED; default: return NOT_HANDLED; } } } class StreamingState extends AudioState { @Override public void enter() { super.enter(); updateSystemAudioState(); } @Override public void updateSystemAudioState() { updateInternalCallAudioState(); setSystemAudioState(mCurrentCallAudioState); } @Override public boolean isActive() { return true; } @Override public int getRouteCode() { return CallAudioState.ROUTE_STREAMING; } @Override public boolean processMessage(Message msg) { if (super.processMessage(msg) == HANDLED) { return HANDLED; } switch (msg.what) { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: case SPEAKER_OFF: // Nothing to do here return HANDLED; case SPEAKER_ON: // fall through case BT_AUDIO_CONNECTED: case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: case SWITCH_HEADSET: case USER_SWITCH_HEADSET: case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: return HANDLED; case SWITCH_FOCUS: if (msg.arg1 == NO_FOCUS) { reinitialize(); mCallAudioManager.notifyAudioOperationsComplete(); } return HANDLED; case STREAMING_FORCE_DISABLED: reinitialize(); return HANDLED; default: return NOT_HANDLED; } Loading Loading @@ -1399,6 +1476,7 @@ public class CallAudioRouteStateMachine extends StateMachine { private final QuiescentHeadsetRoute mQuiescentHeadsetRoute = new QuiescentHeadsetRoute(); private final QuiescentBluetoothRoute mQuiescentBluetoothRoute = new QuiescentBluetoothRoute(); private final QuiescentSpeakerRoute mQuiescentSpeakerRoute = new QuiescentSpeakerRoute(); private final StreamingState mStreamingState = new StreamingState(); /** * A few pieces of hidden state. Used to avoid exponential explosion of number of explicit Loading Loading @@ -1495,6 +1573,7 @@ public class CallAudioRouteStateMachine extends StateMachine { addState(mQuiescentHeadsetRoute); addState(mQuiescentBluetoothRoute); addState(mQuiescentSpeakerRoute); addState(mStreamingState); mStateNameToRouteCode = new HashMap<>(8); Loading @@ -1507,12 +1586,14 @@ public class CallAudioRouteStateMachine extends StateMachine { mStateNameToRouteCode.put(mActiveBluetoothRoute.getName(), ROUTE_BLUETOOTH); mStateNameToRouteCode.put(mActiveHeadsetRoute.getName(), ROUTE_WIRED_HEADSET); mStateNameToRouteCode.put(mActiveSpeakerRoute.getName(), ROUTE_SPEAKER); mStateNameToRouteCode.put(mStreamingState.getName(), ROUTE_STREAMING); mRouteCodeToQuiescentState = new HashMap<>(4); mRouteCodeToQuiescentState.put(ROUTE_EARPIECE, mQuiescentEarpieceRoute); mRouteCodeToQuiescentState.put(ROUTE_BLUETOOTH, mQuiescentBluetoothRoute); mRouteCodeToQuiescentState.put(ROUTE_SPEAKER, mQuiescentSpeakerRoute); mRouteCodeToQuiescentState.put(ROUTE_WIRED_HEADSET, mQuiescentHeadsetRoute); mRouteCodeToQuiescentState.put(ROUTE_STREAMING, mStreamingState); } public void setCallAudioManager(CallAudioManager callAudioManager) { Loading src/com/android/server/telecom/CallStreamingController.java 0 → 100644 +378 −0 File added.Preview size limit exceeded, changes collapsed. Show changes Loading
src/com/android/server/telecom/Call.java +47 −0 Original line number Diff line number Diff line Loading @@ -156,6 +156,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, void onCallHoldFailed(Call call); void onCallSwitchFailed(Call call); void onConnectionEvent(Call call, String event, Bundle extras); void onCallStreamingStateChanged(Call call, boolean isStreaming); void onExternalCallChanged(Call call, boolean isExternalCall); void onRttInitiationFailure(Call call, int reason); void onRemoteRttRequest(Call call, int requestId); Loading Loading @@ -243,6 +244,8 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, @Override public void onConnectionEvent(Call call, String event, Bundle extras) {} @Override public void onCallStreamingStateChanged(Call call, boolean isStreaming) {} @Override public void onExternalCallChanged(Call call, boolean isExternalCall) {} @Override public void onRttInitiationFailure(Call call, int reason) {} Loading Loading @@ -534,6 +537,11 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, private boolean mIsTransactionalCall = false; /** * Indicates whether this call is streaming. */ private boolean mIsStreaming = false; /** * Indicates whether the {@link PhoneAccount} associated with an self-managed call want to * expose the call to an {@link android.telecom.InCallService} which declares the metadata Loading Loading @@ -4390,4 +4398,43 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable, mDisconnectFuture = null; } } public boolean isStreaming() { synchronized (mLock) { return mIsStreaming; } } public void startStreaming() { if (!mIsTransactionalCall) { throw new UnsupportedOperationException( "Can't streaming call created by non voip apps"); } synchronized (mLock) { if (mIsStreaming) { // ignore return; } mIsStreaming = true; for (Listener listener : mListeners) { listener.onCallStreamingStateChanged(this, true /** isStreaming */); } } } public void stopStreaming() { synchronized (mLock) { if (!mIsStreaming) { // ignore return; } mIsStreaming = false; for (Listener listener : mListeners) { listener.onCallStreamingStateChanged(this, false /** isStreaming */); } } } }
src/com/android/server/telecom/CallAudioManager.java +33 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ public class CallAudioManager extends CallsManagerListenerBase { private final RingbackPlayer mRingbackPlayer; private final DtmfLocalTonePlayer mDtmfLocalTonePlayer; private Call mStreamingCall; private Call mForegroundCall; private boolean mIsTonePlaying = false; private boolean mIsDisconnectedTonePlaying = false; Loading @@ -78,6 +79,7 @@ public class CallAudioManager extends CallsManagerListenerBase { mRingingCalls = new LinkedHashSet<>(1); mHoldingCalls = new LinkedHashSet<>(1); mAudioProcessingCalls = new LinkedHashSet<>(1); mStreamingCall = null; mCalls = new HashSet<>(); mCallStateToCalls = new SparseArray<LinkedHashSet<Call>>() {{ put(CallState.CONNECTING, mActiveDialingOrConnectingCalls); Loading Loading @@ -221,6 +223,36 @@ public class CallAudioManager extends CallsManagerListenerBase { } } /** * Handles the changes to the streaming state of a call. * @param call The call * @param isStreaming {@code true} if the call is streaming, {@code false} otherwise */ @Override public void onCallStreamingStateChanged(Call call, boolean isStreaming) { if (isStreaming) { if (mStreamingCall == null) { mStreamingCall = call; mCallAudioModeStateMachine.sendMessageWithArgs( CallAudioModeStateMachine.START_CALL_STREAMING, makeArgsForModeStateMachine()); } else { Log.w(LOG_TAG, "Unexpected streaming call request for call %s while call " + "s is streaming.", call.getId(), mStreamingCall.getId()); } } else { if (mStreamingCall == call) { mStreamingCall = null; mCallAudioModeStateMachine.sendMessageWithArgs( CallAudioModeStateMachine.STOP_CALL_STREAMING, makeArgsForModeStateMachine()); } else { Log.w(LOG_TAG, "Unexpected call streaming stop request for call %s while this call " + "is not streaming.", call.getId()); } } } /** * Determines if {@link CallAudioManager} should do any audio routing operations for a call. * We ignore child calls of a conference and external calls for audio routing purposes. Loading Loading @@ -759,6 +791,7 @@ public class CallAudioManager extends CallsManagerListenerBase { .setHasHoldingCalls(mHoldingCalls.size() > 0) .setHasAudioProcessingCalls(mAudioProcessingCalls.size() > 0) .setIsTonePlaying(mIsTonePlaying) .setIsStreaming(mStreamingCall != null) .setForegroundCallIsVoip( mForegroundCall != null && isCallVoip(mForegroundCall)) .setSession(Log.createSubsession()).build(); Loading
src/com/android/server/telecom/CallAudioModeStateMachine.java +114 −9 Original line number Diff line number Diff line Loading @@ -50,17 +50,19 @@ public class CallAudioModeStateMachine extends StateMachine { public boolean hasAudioProcessingCalls; public boolean isTonePlaying; public boolean foregroundCallIsVoip; public boolean isStreaming; public Session session; private MessageArgs(boolean hasActiveOrDialingCalls, boolean hasRingingCalls, boolean hasHoldingCalls, boolean hasAudioProcessingCalls, boolean isTonePlaying, boolean foregroundCallIsVoip, Session session) { boolean foregroundCallIsVoip, boolean isStreaming, Session session) { this.hasActiveOrDialingCalls = hasActiveOrDialingCalls; this.hasRingingCalls = hasRingingCalls; this.hasHoldingCalls = hasHoldingCalls; this.hasAudioProcessingCalls = hasAudioProcessingCalls; this.isTonePlaying = isTonePlaying; this.foregroundCallIsVoip = foregroundCallIsVoip; this.isStreaming = isStreaming; this.session = session; } Loading @@ -73,6 +75,7 @@ public class CallAudioModeStateMachine extends StateMachine { ", hasAudioProcessingCalls=" + hasAudioProcessingCalls + ", isTonePlaying=" + isTonePlaying + ", foregroundCallIsVoip=" + foregroundCallIsVoip + ", isStreaming=" + isStreaming + ", session=" + session + '}'; } Loading @@ -84,6 +87,7 @@ public class CallAudioModeStateMachine extends StateMachine { private boolean mHasAudioProcessingCalls; private boolean mIsTonePlaying; private boolean mForegroundCallIsVoip; private boolean mIsStreaming; private Session mSession; public Builder setHasActiveOrDialingCalls(boolean hasActiveOrDialingCalls) { Loading Loading @@ -121,9 +125,15 @@ public class CallAudioModeStateMachine extends StateMachine { return this; } public Builder setIsStreaming(boolean isStraeming) { mIsStreaming = isStraeming; return this; } public MessageArgs build() { return new MessageArgs(mHasActiveOrDialingCalls, mHasRingingCalls, mHasHoldingCalls, mHasAudioProcessingCalls, mIsTonePlaying, mForegroundCallIsVoip, mSession); mHasAudioProcessingCalls, mIsTonePlaying, mForegroundCallIsVoip, mIsStreaming, mSession); } } } Loading @@ -138,7 +148,8 @@ public class CallAudioModeStateMachine extends StateMachine { public static final int ENTER_RING_FOCUS_FOR_TESTING = 4; public static final int ENTER_TONE_OR_HOLD_FOCUS_FOR_TESTING = 5; public static final int ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING = 6; public static final int ABANDON_FOCUS_FOR_TESTING = 7; public static final int ENTER_STREAMING_FOCUS_FOR_TESTING = 7; public static final int ABANDON_FOCUS_FOR_TESTING = 8; public static final int NO_MORE_ACTIVE_OR_DIALING_CALLS = 1001; public static final int NO_MORE_RINGING_CALLS = 1002; Loading @@ -161,6 +172,9 @@ public class CallAudioModeStateMachine extends StateMachine { // to release focus for other apps to take over. public static final int AUDIO_OPERATIONS_COMPLETE = 6001; public static final int START_CALL_STREAMING = 7001; public static final int STOP_CALL_STREAMING = 7002; public static final int RUN_RUNNABLE = 9001; private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{ Loading @@ -183,6 +197,8 @@ public class CallAudioModeStateMachine extends StateMachine { put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE"); put(RINGER_MODE_CHANGE, "RINGER_MODE_CHANGE"); put(AUDIO_OPERATIONS_COMPLETE, "AUDIO_OPERATIONS_COMPLETE"); put(START_CALL_STREAMING, "START_CALL_STREAMING"); put(STOP_CALL_STREAMING, "STOP_CALL_STREAMING"); put(RUN_RUNNABLE, "RUN_RUNNABLE"); }}; Loading @@ -193,6 +209,7 @@ public class CallAudioModeStateMachine extends StateMachine { AudioProcessingFocusState.class.getSimpleName(); public static final String CALL_STATE_NAME = SimCallFocusState.class.getSimpleName(); public static final String RING_STATE_NAME = RingingFocusState.class.getSimpleName(); public static final String STREAMING_STATE_NAME = StreamingFocusState.class.getSimpleName(); public static final String COMMS_STATE_NAME = VoipCallFocusState.class.getSimpleName(); private class BaseState extends State { Loading @@ -214,6 +231,9 @@ public class CallAudioModeStateMachine extends StateMachine { case ENTER_AUDIO_PROCESSING_FOCUS_FOR_TESTING: transitionTo(mAudioProcessingFocusState); return HANDLED; case ENTER_STREAMING_FOCUS_FOR_TESTING: transitionTo(mStreamingFocusState); return HANDLED; case ABANDON_FOCUS_FOR_TESTING: transitionTo(mUnfocusedState); return HANDLED; Loading Loading @@ -280,6 +300,9 @@ public class CallAudioModeStateMachine extends StateMachine { " Args are: \n" + args.toString()); transitionTo(mOtherFocusState); return HANDLED; case START_CALL_STREAMING: transitionTo(mStreamingFocusState); return HANDLED; case TONE_STARTED_PLAYING: // This shouldn't happen either, but perform the action anyway. Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n" Loading Loading @@ -353,6 +376,9 @@ public class CallAudioModeStateMachine extends StateMachine { Log.w(LOG_TAG, "Tone started playing unexpectedly. Args are: \n" + args.toString()); return HANDLED; case START_CALL_STREAMING: transitionTo(mStreamingFocusState); return HANDLED; case AUDIO_OPERATIONS_COMPLETE: Log.i(LOG_TAG, "Abandoning audio focus: now AUDIO_PROCESSING"); mAudioManager.abandonAudioFocusForCall(); Loading Loading @@ -625,6 +651,79 @@ public class CallAudioModeStateMachine extends StateMachine { Log.w(LOG_TAG, "Should not be seeing AUDIO_OPERATIONS_COMPLETE in a focused" + " state"); return HANDLED; case START_CALL_STREAMING: transitionTo(mStreamingFocusState); return HANDLED; default: // The forced focus switch commands are handled by BaseState. return NOT_HANDLED; } } } private class StreamingFocusState extends BaseState { @Override public void enter() { Log.i(LOG_TAG, "Audio focus entering streaming state"); mAudioManager.setMode(AudioManager.MODE_CALL_REDIRECT); mMostRecentMode = AudioManager.MODE_NORMAL; mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS); mCallAudioManager.getCallAudioRouteStateMachine().sendMessageWithSessionInfo( CallAudioRouteStateMachine.STREAMING_FORCE_ENABLED); } private void preExit() { mCallAudioManager.getCallAudioRouteStateMachine().sendMessageWithSessionInfo( CallAudioRouteStateMachine.STREAMING_FORCE_DISABLED); } @Override public boolean processMessage(Message msg) { if (super.processMessage(msg) == HANDLED) { return HANDLED; } MessageArgs args = (MessageArgs) msg.obj; switch (msg.what) { case NO_MORE_ACTIVE_OR_DIALING_CALLS: // Do nothing. return HANDLED; case NO_MORE_RINGING_CALLS: // Do nothing. return HANDLED; case NO_MORE_HOLDING_CALLS: // Do nothing. return HANDLED; case NO_MORE_AUDIO_PROCESSING_CALLS: // Do nothing. return HANDLED; case NEW_ACTIVE_OR_DIALING_CALL: // Only possible for emergency call BaseState destState = calculateProperStateFromArgs(args); if (destState != this) { preExit(); transitionTo(destState); } return HANDLED; case NEW_RINGING_CALL: // Only possible for emergency call preExit(); transitionTo(mRingingFocusState); return HANDLED; case NEW_HOLDING_CALL: // Do nothing. return HANDLED; case NEW_AUDIO_PROCESSING_CALL: // Do nothing. return HANDLED; case START_CALL_STREAMING: // Can happen as a duplicate message return HANDLED; case TONE_STARTED_PLAYING: // Do nothing. return HANDLED; case STOP_CALL_STREAMING: transitionTo(calculateProperStateFromArgs(args)); return HANDLED; default: // The forced focus switch commands are handled by BaseState. return NOT_HANDLED; Loading Loading @@ -707,6 +806,7 @@ public class CallAudioModeStateMachine extends StateMachine { private final BaseState mSimCallFocusState = new SimCallFocusState(); private final BaseState mVoipCallFocusState = new VoipCallFocusState(); private final BaseState mAudioProcessingFocusState = new AudioProcessingFocusState(); private final BaseState mStreamingFocusState = new StreamingFocusState(); private final BaseState mOtherFocusState = new OtherFocusState(); private final AudioManager mAudioManager; Loading Loading @@ -745,6 +845,7 @@ public class CallAudioModeStateMachine extends StateMachine { addState(mSimCallFocusState); addState(mVoipCallFocusState); addState(mAudioProcessingFocusState); addState(mStreamingFocusState); addState(mOtherFocusState); setInitialState(mUnfocusedState); start(); Loading @@ -754,6 +855,7 @@ public class CallAudioModeStateMachine extends StateMachine { .setHasHoldingCalls(false) .setIsTonePlaying(false) .setForegroundCallIsVoip(false) .setIsStreaming(false) .setSession(Log.createSubsession()) .build()); } Loading Loading @@ -807,12 +909,15 @@ public class CallAudioModeStateMachine extends StateMachine { // switch to the appropriate focus. // Otherwise abandon focus. // The order matters here. If there are active calls, holding focus for them takes priority. // After that, we want to prioritize holding calls over ringing calls so that when a // call-waiting call gets answered, there's no transition in and out of the ringing focus // state. After that, we want tones since we actually hold focus during them, then the // audio processing state because that will release focus. if (args.hasActiveOrDialingCalls) { // The order matters here. If there is streaming call, holding streaming route for them // takes priority. After that, holding focus for active calls takes priority. After that, we // want to prioritize holding calls over ringing calls so that when a call-waiting call gets // answered, there's no transition in and out of the ringing focus state. After that, we // want tones since we actually hold focus during them, then the audio processing state // because that will release focus. if (args.isStreaming) { return mSimCallFocusState; } else if (args.hasActiveOrDialingCalls) { if (args.foregroundCallIsVoip) { return mVoipCallFocusState; } else { Loading
src/com/android/server/telecom/CallAudioRouteStateMachine.java +81 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,9 @@ public class CallAudioRouteStateMachine extends StateMachine { /** Direct the audio stream through the device's speakerphone. */ public static final int ROUTE_SPEAKER = CallAudioState.ROUTE_SPEAKER; /** Direct the audio stream through another device. */ public static final int ROUTE_STREAMING = CallAudioState.ROUTE_STREAMING; /** Valid values for msg.what */ public static final int CONNECT_WIRED_HEADSET = 1; public static final int DISCONNECT_WIRED_HEADSET = 2; Loading @@ -129,6 +132,10 @@ public class CallAudioRouteStateMachine extends StateMachine { public static final int SPEAKER_ON = 1006; public static final int SPEAKER_OFF = 1007; // Messages denoting that the streaming route switch request was sent. public static final int STREAMING_FORCE_ENABLED = 1008; public static final int STREAMING_FORCE_DISABLED = 1009; public static final int USER_SWITCH_EARPIECE = 1101; public static final int USER_SWITCH_BLUETOOTH = 1102; public static final int USER_SWITCH_HEADSET = 1103; Loading Loading @@ -545,6 +552,8 @@ public class CallAudioRouteStateMachine extends StateMachine { case DISCONNECT_DOCK: // Nothing to do here return HANDLED; case STREAMING_FORCE_ENABLED: transitionTo(mStreamingState); default: return NOT_HANDLED; } Loading Loading @@ -629,6 +638,9 @@ public class CallAudioRouteStateMachine extends StateMachine { mCallAudioManager.notifyAudioOperationsComplete(); } return HANDLED; case STREAMING_FORCE_ENABLED: transitionTo(mStreamingState); return HANDLED; default: return NOT_HANDLED; } Loading Loading @@ -1106,6 +1118,9 @@ public class CallAudioRouteStateMachine extends StateMachine { case DISCONNECT_DOCK: // Nothing to do here return HANDLED; case STREAMING_FORCE_ENABLED: transitionTo(mStreamingState); return HANDLED; default: return NOT_HANDLED; } Loading Loading @@ -1331,6 +1346,68 @@ public class CallAudioRouteStateMachine extends StateMachine { case DISCONNECT_DOCK: sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE); return HANDLED; case STREAMING_FORCE_ENABLED: transitionTo(mStreamingState); return HANDLED; default: return NOT_HANDLED; } } } class StreamingState extends AudioState { @Override public void enter() { super.enter(); updateSystemAudioState(); } @Override public void updateSystemAudioState() { updateInternalCallAudioState(); setSystemAudioState(mCurrentCallAudioState); } @Override public boolean isActive() { return true; } @Override public int getRouteCode() { return CallAudioState.ROUTE_STREAMING; } @Override public boolean processMessage(Message msg) { if (super.processMessage(msg) == HANDLED) { return HANDLED; } switch (msg.what) { case SWITCH_EARPIECE: case USER_SWITCH_EARPIECE: case SPEAKER_OFF: // Nothing to do here return HANDLED; case SPEAKER_ON: // fall through case BT_AUDIO_CONNECTED: case SWITCH_BLUETOOTH: case USER_SWITCH_BLUETOOTH: case SWITCH_HEADSET: case USER_SWITCH_HEADSET: case SWITCH_SPEAKER: case USER_SWITCH_SPEAKER: return HANDLED; case SWITCH_FOCUS: if (msg.arg1 == NO_FOCUS) { reinitialize(); mCallAudioManager.notifyAudioOperationsComplete(); } return HANDLED; case STREAMING_FORCE_DISABLED: reinitialize(); return HANDLED; default: return NOT_HANDLED; } Loading Loading @@ -1399,6 +1476,7 @@ public class CallAudioRouteStateMachine extends StateMachine { private final QuiescentHeadsetRoute mQuiescentHeadsetRoute = new QuiescentHeadsetRoute(); private final QuiescentBluetoothRoute mQuiescentBluetoothRoute = new QuiescentBluetoothRoute(); private final QuiescentSpeakerRoute mQuiescentSpeakerRoute = new QuiescentSpeakerRoute(); private final StreamingState mStreamingState = new StreamingState(); /** * A few pieces of hidden state. Used to avoid exponential explosion of number of explicit Loading Loading @@ -1495,6 +1573,7 @@ public class CallAudioRouteStateMachine extends StateMachine { addState(mQuiescentHeadsetRoute); addState(mQuiescentBluetoothRoute); addState(mQuiescentSpeakerRoute); addState(mStreamingState); mStateNameToRouteCode = new HashMap<>(8); Loading @@ -1507,12 +1586,14 @@ public class CallAudioRouteStateMachine extends StateMachine { mStateNameToRouteCode.put(mActiveBluetoothRoute.getName(), ROUTE_BLUETOOTH); mStateNameToRouteCode.put(mActiveHeadsetRoute.getName(), ROUTE_WIRED_HEADSET); mStateNameToRouteCode.put(mActiveSpeakerRoute.getName(), ROUTE_SPEAKER); mStateNameToRouteCode.put(mStreamingState.getName(), ROUTE_STREAMING); mRouteCodeToQuiescentState = new HashMap<>(4); mRouteCodeToQuiescentState.put(ROUTE_EARPIECE, mQuiescentEarpieceRoute); mRouteCodeToQuiescentState.put(ROUTE_BLUETOOTH, mQuiescentBluetoothRoute); mRouteCodeToQuiescentState.put(ROUTE_SPEAKER, mQuiescentSpeakerRoute); mRouteCodeToQuiescentState.put(ROUTE_WIRED_HEADSET, mQuiescentHeadsetRoute); mRouteCodeToQuiescentState.put(ROUTE_STREAMING, mStreamingState); } public void setCallAudioManager(CallAudioManager callAudioManager) { Loading
src/com/android/server/telecom/CallStreamingController.java 0 → 100644 +378 −0 File added.Preview size limit exceeded, changes collapsed. Show changes