Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc7fe5e2 authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Fix issue where focus is retained after call.

The new audio routing refactor code had an issue where the focus was
not released at the end of a call.  The root cause was that
CallAudioRouteController was not calling
`mCallAudioManager.notifyAudioOperationsComplete()` when focus goes
inactive.

The rest of the changes you see are just logging cleanups to standardize
how Audio/BT operations are logged so that external API calls are easy
to identify, and to add method names where they were missing in the
log statements.

Flag: com.android.server.telecom.flags.use_refactored_audio_route_switching
Fixes: 356920567
Test: Manually testing audio focus; ensured media playing resumes after
a call.
Test: Added new tests to the Telecom CUJ suite to cover audio focus loss
and gain during managed, self-managed and transactional voip incoming
and outgoing calls.
Test: Updated unit tests for CallAudioRouteController to ensure that we
signal audio operations complete to CallAudioManager when focus is lost.

Change-Id: I4deba2ee8224fa0de5348bf49f615ad45c1af361
parent f5cf4108
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -70,7 +70,7 @@ public class AudioRoute {
                return;
            }

            Log.i(this, "creating AudioRoute with type %s and address %s, retry count %d",
            Log.i(this, "createRetry; type=%s, address=%s, retryCount=%d",
                    DEVICE_TYPE_STRINGS.get(type), bluetoothAddress, retryCount);
            AudioDeviceInfo routeInfo = null;
            List<AudioDeviceInfo> infos = audioManager.getAvailableCommunicationDevices();
@@ -239,7 +239,8 @@ public class AudioRoute {
    void onDestRouteAsPendingRoute(boolean active, PendingAudioRoute pendingAudioRoute,
            BluetoothDevice device, AudioManager audioManager,
            BluetoothRouteManager bluetoothRouteManager, boolean isScoAudioConnected) {
        Log.i(this, "onDestRouteAsPendingRoute: active (%b), type (%d)", active, mAudioRouteType);
        Log.i(this, "onDestRouteAsPendingRoute: active (%b), type (%s)", active,
                DEVICE_TYPE_STRINGS.get(mAudioRouteType));
        if (pendingAudioRoute.isActive() && !active) {
            clearCommunicationDevice(pendingAudioRoute, bluetoothRouteManager, audioManager);
        } else if (active) {
@@ -281,8 +282,8 @@ public class AudioRoute {
                    if (result) {
                        pendingAudioRoute.setCommunicationDeviceType(mAudioRouteType);
                    }
                    Log.i(this, "Result of setting communication device for audio "
                            + "route (%s) - %b", this, result);
                    Log.i(this, "onDestRouteAsPendingRoute: route=%s, "
                            + "AudioManager#setCommunicationDevice()=%b", this, result);
                    break;
                }
            }
@@ -380,11 +381,11 @@ public class AudioRoute {

        int result = BluetoothStatusCodes.SUCCESS;
        if (pendingAudioRoute.getCommunicationDeviceType() == TYPE_BLUETOOTH_SCO) {
            Log.i(this, "Disconnecting SCO device.");
            Log.i(this, "clearCommunicationDevice: Disconnecting SCO device.");
            result = bluetoothRouteManager.getDeviceManager().disconnectSco();
        } else {
            Log.i(this, "Clearing communication device for audio type %d.",
                    pendingAudioRoute.getCommunicationDeviceType());
            Log.i(this, "clearCommunicationDevice: AudioManager#clearCommunicationDevice, type=%s",
                    DEVICE_TYPE_STRINGS.get(pendingAudioRoute.getCommunicationDeviceType()));
            audioManager.clearCommunicationDevice();
        }

+18 −2
Original line number Diff line number Diff line
@@ -288,12 +288,14 @@ public class CallAudioModeStateMachine extends StateMachine {
                            .getCurrentLocallyRequestedCommunicationDevice());
                }
                if (mFeatureFlags.setAudioModeBeforeAbandonFocus()) {
                    Log.i(this, "enter: AudioManager#setMode(MODE_NORMAL)");
                    mAudioManager.setMode(AudioManager.MODE_NORMAL);
                    mCallAudioManager.setCallAudioRouteFocusState(
                            CallAudioRouteStateMachine.NO_FOCUS);
                } else {
                    mCallAudioManager.setCallAudioRouteFocusState(
                            CallAudioRouteStateMachine.NO_FOCUS);
                    Log.i(this, "enter: AudioManager#setMode(MODE_NORMAL)");
                    mAudioManager.setMode(AudioManager.MODE_NORMAL);
                }
                mLocalLog.log("Mode MODE_NORMAL");
@@ -347,11 +349,14 @@ public class CallAudioModeStateMachine extends StateMachine {
                            + args.toString());
                    return HANDLED;
                case AUDIO_OPERATIONS_COMPLETE:
                    Log.i(LOG_TAG, "Abandoning audio focus: now UNFOCUSED");
                    if (mFeatureFlags.telecomResolveHiddenDependencies()) {
                        if (mCurrentAudioFocusRequest != null) {
                            Log.i(this, "AudioOperationsComplete: "
                                    + "AudioManager#abandonAudioFocusRequest(); now unfocused");
                            mAudioManager.abandonAudioFocusRequest(mCurrentAudioFocusRequest);
                            mCurrentAudioFocusRequest = null;
                        } else {
                            Log.i(this, "AudioOperationsComplete: already unfocused");
                        }
                    } else {
                        mAudioManager.abandonAudioFocusForCall();
@@ -377,6 +382,7 @@ public class CallAudioModeStateMachine extends StateMachine {
            mLocalLog.log("Enter AUDIO_PROCESSING");
            if (mIsInitialized) {
                mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
                Log.i(this, "enter: AudioManager#setMode(MODE_AUDIO_PROCESSING)");
                mAudioManager.setMode(NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING);
                mLocalLog.log("Mode MODE_CALL_SCREENING");
                mMostRecentMode = NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING;
@@ -431,7 +437,8 @@ public class CallAudioModeStateMachine extends StateMachine {
                    transitionTo(mStreamingFocusState);
                    return HANDLED;
                case AUDIO_OPERATIONS_COMPLETE:
                    Log.i(LOG_TAG, "Abandoning audio focus: now AUDIO_PROCESSING");
                    Log.i(LOG_TAG, "AudioManager#abandonAudioFocusRequest: now "
                            + "AUDIO_PROCESSING");
                    if (mFeatureFlags.telecomResolveHiddenDependencies()) {
                        if (mCurrentAudioFocusRequest != null) {
                            mAudioManager.abandonAudioFocusRequest(mCurrentAudioFocusRequest);
@@ -466,6 +473,7 @@ public class CallAudioModeStateMachine extends StateMachine {
                if (mCallAudioManager.startRinging()) {
                    if (mFeatureFlags.telecomResolveHiddenDependencies()) {
                        mCurrentAudioFocusRequest = RING_AUDIO_FOCUS_REQUEST;
                        Log.i(this, "tryStartRinging: AudioManager#requestAudioFocus(RING)");
                        mAudioManager.requestAudioFocus(RING_AUDIO_FOCUS_REQUEST);
                    } else {
                        mAudioManager.requestAudioFocusForCall(
@@ -474,6 +482,7 @@ public class CallAudioModeStateMachine extends StateMachine {
                    // Do not set MODE_RINGTONE if we were previously in the CALL_SCREENING mode --
                    // this trips up the audio system.
                    if (mAudioManager.getMode() != AudioManager.MODE_CALL_SCREENING) {
                        Log.i(this, "enter: AudioManager#setMode(MODE_RINGTONE)");
                        mAudioManager.setMode(AudioManager.MODE_RINGTONE);
                        mLocalLog.log("Mode MODE_RINGTONE");
                    }
@@ -569,11 +578,13 @@ public class CallAudioModeStateMachine extends StateMachine {
            mLocalLog.log("Enter SIM_CALL");
            if (mFeatureFlags.telecomResolveHiddenDependencies()) {
                mCurrentAudioFocusRequest = CALL_AUDIO_FOCUS_REQUEST;
                Log.i(this, "enter: AudioManager#requestAudioFocus(CALL)");
                mAudioManager.requestAudioFocus(CALL_AUDIO_FOCUS_REQUEST);
            } else {
                mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
            }
            Log.i(this, "enter: AudioManager#setMode(MODE_IN_CALL)");
            mAudioManager.setMode(AudioManager.MODE_IN_CALL);
            mLocalLog.log("Mode MODE_IN_CALL");
            mMostRecentMode = AudioManager.MODE_IN_CALL;
@@ -657,11 +668,13 @@ public class CallAudioModeStateMachine extends StateMachine {
            mLocalLog.log("Enter VOIP_CALL");
            if (mFeatureFlags.telecomResolveHiddenDependencies()) {
                mCurrentAudioFocusRequest = CALL_AUDIO_FOCUS_REQUEST;
                Log.i(this, "enter: AudioManager#requestAudioFocus(CALL)");
                mAudioManager.requestAudioFocus(CALL_AUDIO_FOCUS_REQUEST);
            } else {
                mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
            }
            Log.i(this, "enter: AudioManager#setMode(MODE_IN_COMMUNICATION)");
            mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
            mLocalLog.log("Mode MODE_IN_COMMUNICATION");
            mMostRecentMode = AudioManager.MODE_IN_COMMUNICATION;
@@ -740,6 +753,7 @@ public class CallAudioModeStateMachine extends StateMachine {
            Log.i(LOG_TAG, "Audio focus entering streaming state");
            mLocalLog.log("Enter Streaming");
            mLocalLog.log("Mode MODE_COMMUNICATION_REDIRECT");
            Log.i(this, "enter: AudioManager#setMode(MODE_COMMUNICATION_REDIRECT");
            mAudioManager.setMode(AudioManager.MODE_COMMUNICATION_REDIRECT);
            mMostRecentMode = AudioManager.MODE_NORMAL;
            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
@@ -817,11 +831,13 @@ public class CallAudioModeStateMachine extends StateMachine {
            mLocalLog.log("Enter TONE/HOLDING");
            if (mFeatureFlags.telecomResolveHiddenDependencies()) {
                mCurrentAudioFocusRequest = CALL_AUDIO_FOCUS_REQUEST;
                Log.i(this, "enter: AudioManager#requestAudioFocus(CALL)");
                mAudioManager.requestAudioFocus(CALL_AUDIO_FOCUS_REQUEST);
            } else {
                mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
                        AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
            }
            Log.i(this, "enter: AudioManager#setMode(%d)", mMostRecentMode);
            mAudioManager.setMode(mMostRecentMode);
            mLocalLog.log("Mode " + mMostRecentMode);
            mCallAudioManager.setCallAudioRouteFocusStateForEndTone();
+4 −0
Original line number Diff line number Diff line
@@ -789,6 +789,10 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        switch (focus) {
            case NO_FOCUS -> {
                if (mIsActive) {
                    // Notify the CallAudioModeStateMachine that audio operations are complete so
                    // that we can relinquish audio focus.
                    mCallAudioManager.notifyAudioOperationsComplete();

                    // Reset mute state after call ends.
                    handleMuteChanged(false);
                    // Route back to inactive route.
+87 −55

File changed.

Preview size limit exceeded, changes collapsed.

+9 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeAudio;
import android.media.AudioDeviceInfo;
import android.media.AudioFocusRequest;
import android.media.AudioManager;
import android.media.IAudioService;
import android.media.audiopolicy.AudioProductStrategy;
@@ -368,6 +369,11 @@ public class CallAudioRouteControllerTest extends TelecomTestCase {
        assertTrue(mController.isActive());

        mController.sendMessageWithSessionInfo(SWITCH_FOCUS, NO_FOCUS, 0);
        // Ensure we tell the CallAudioManager that audio operations are done so that we can ensure
        // audio focus is relinquished.
        verify(mCallAudioManager, timeout(TEST_TIMEOUT)).notifyAudioOperationsComplete();

        // Ensure the BT device is disconnected.
        verify(mBluetoothDeviceManager, timeout(TEST_TIMEOUT).atLeastOnce()).disconnectSco();
        assertFalse(mController.isActive());
    }
@@ -613,6 +619,9 @@ public class CallAudioRouteControllerTest extends TelecomTestCase {
                anyInt(), anyString());
        verify(mCallsManager, timeout(TEST_TIMEOUT).atLeastOnce()).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));
        // Ensure we tell the CallAudioManager that audio operations are done so that we can ensure
        // audio focus is relinquished.
        verify(mCallAudioManager, timeout(TEST_TIMEOUT)).notifyAudioOperationsComplete();
    }

    @SmallTest