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

Commit 463dc7c6 authored by Pranav Madapurmath's avatar Pranav Madapurmath
Browse files

Resolve user switch baseline route for video calls

Ensure that when there's an explicit user request to switch baseline
route that we don't skip earpiece (i.e. during a video call). This stems
from the user not being able to turn speaker off during a carrier video
call.

Bug: 374037591
Flag: com.android.server.telecom.flags.fix_user_request_baseline_route_video_call
Test: atest CallAudioRouteControllerTest
Change-Id: Iae9d1ae7720f0ddde565a05bdd2d5b341b9f3dd7
parent 9c8427ea
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -118,3 +118,14 @@ flag {
    purpose: PURPOSE_BUGFIX
  }
}

# OWNER=pmadapurmath TARGET=25Q2
flag {
  name: "fix_user_request_baseline_route_video_call"
  namespace: "telecom"
  description: "Ensure that audio is routed out of speaker in a video call when we receive USER_SWITCH_BASELINE_ROUTE."
  bug: "374037591"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
+24 −16
Original line number Diff line number Diff line
@@ -310,12 +310,12 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
                            break;
                        case SWITCH_BASELINE_ROUTE:
                            address = (String) ((SomeArgs) msg.obj).arg2;
                            handleSwitchBaselineRoute(msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE,
                                    address);
                            handleSwitchBaselineRoute(false,
                                    msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE, address);
                            break;
                        case USER_SWITCH_BASELINE_ROUTE:
                            handleSwitchBaselineRoute(msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE,
                                    null);
                            handleSwitchBaselineRoute(true,
                                    msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE, null);
                            break;
                        case SPEAKER_ON:
                            handleSpeakerOn();
@@ -888,7 +888,7 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
                    // speaker, route back to earpiece). If we're on BT, remain on BT if it's still
                    // connected.
                    AudioRoute route = mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()
                            ? calculateBaselineRoute(true, null)
                            ? calculateBaselineRoute(false, true, null)
                            : mCurrentRoute;
                    routeTo(false, route);
                    // Clear pending messages
@@ -1009,7 +1009,8 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        }
    }

    private void handleSwitchBaselineRoute(boolean includeBluetooth, String btAddressToExclude) {
    private void handleSwitchBaselineRoute(boolean isExplicitUserRequest, boolean includeBluetooth,
            String btAddressToExclude) {
        Log.i(this, "handleSwitchBaselineRoute: includeBluetooth: %b, "
                + "btAddressToExclude: %s", includeBluetooth, btAddressToExclude);
        boolean areExcludedBtAndDestBtSame = btAddressToExclude != null
@@ -1027,7 +1028,8 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
            Log.i(this, "BT device with address (%s) is currently connecting/connected. "
                    + "Ignore route switch.");
        } else {
            routeTo(mIsActive, calculateBaselineRoute(includeBluetooth, btAddressToExclude));
            routeTo(mIsActive, calculateBaselineRoute(isExplicitUserRequest, includeBluetooth,
                    btAddressToExclude));
        }
    }

@@ -1238,14 +1240,19 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        return mAudioManager.getPreferredDeviceForStrategy(strategy);
    }

    private AudioRoute getPreferredAudioRouteFromDefault(boolean includeBluetooth,
            String btAddressToExclude) {
        boolean skipEarpiece;
    private AudioRoute getPreferredAudioRouteFromDefault(boolean isExplicitUserRequest,
            boolean includeBluetooth, String btAddressToExclude) {
        boolean skipEarpiece = false;
        Call foregroundCall = mCallAudioManager.getForegroundCall();
        if (!mFeatureFlags.fixUserRequestBaselineRouteVideoCall()) {
            isExplicitUserRequest = false;
        }
        if (!isExplicitUserRequest) {
            synchronized (mTelecomLock) {
                skipEarpiece = foregroundCall != null
                        && VideoProfile.isVideo(foregroundCall.getVideoState());
            }
        }
        // Route to earpiece, wired, or speaker route if there are not bluetooth routes or if there
        // are only wearables available.
        AudioRoute activeWatchOrNonWatchDeviceRoute =
@@ -1344,7 +1351,7 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        Log.i(this, "getBaseRoute: preferred audio route is %s", destRoute);
        if (destRoute == null || (destRoute.getBluetoothAddress() != null && (!includeBluetooth
                || destRoute.getBluetoothAddress().equals(btAddressToExclude)))) {
            destRoute = getPreferredAudioRouteFromDefault(includeBluetooth, btAddressToExclude);
            destRoute = getPreferredAudioRouteFromDefault(false, includeBluetooth, btAddressToExclude);
        }
        if (destRoute != null && !getCallSupportedRoutes().contains(destRoute)) {
            destRoute = null;
@@ -1353,8 +1360,9 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        return destRoute;
    }

    private AudioRoute calculateBaselineRoute(boolean includeBluetooth, String btAddressToExclude) {
        AudioRoute destRoute = getPreferredAudioRouteFromDefault(
    private AudioRoute calculateBaselineRoute(boolean isExplicitUserRequest,
            boolean includeBluetooth, String btAddressToExclude) {
        AudioRoute destRoute = getPreferredAudioRouteFromDefault(isExplicitUserRequest,
                includeBluetooth, btAddressToExclude);
        if (destRoute != null && !getCallSupportedRoutes().contains(destRoute)) {
            destRoute = null;
+6 −2
Original line number Diff line number Diff line
@@ -270,12 +270,16 @@ public class BluetoothStateReceiver extends BroadcastReceiver {
                    if (!mBluetoothDeviceManager.setCommunicationDeviceForAddress(
                            device.getAddress())) {
                        Log.i(this, "handleActiveDeviceChanged: Failed to set "
                                + "communication device for %s. Sending PENDING_ROUTE_FAILED to "
                                + "pending audio route.", device);
                                + "communication device for %s.", device);
                        if (!mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()) {
                            Log.i(this, "Sending PENDING_ROUTE_FAILED "
                                    + "to pending audio route.");
                            mCallAudioRouteAdapter.getPendingAudioRoute()
                                    .onMessageReceived(new Pair<>(PENDING_ROUTE_FAILED,
                                            device.getAddress()), device.getAddress());
                        } else {
                            Log.i(this, "Refrain from sending PENDING_ROUTE_FAILED"
                                    + " to pending audio route.");
                        }
                    } else {
                        // Track the currently set communication device.
+41 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static com.android.server.telecom.CallAudioRouteAdapter.STREAMING_FORCE_D
import static com.android.server.telecom.CallAudioRouteAdapter.STREAMING_FORCE_ENABLED;
import static com.android.server.telecom.CallAudioRouteAdapter.SWITCH_BASELINE_ROUTE;
import static com.android.server.telecom.CallAudioRouteAdapter.SWITCH_FOCUS;
import static com.android.server.telecom.CallAudioRouteAdapter.USER_SWITCH_BASELINE_ROUTE;
import static com.android.server.telecom.CallAudioRouteAdapter.USER_SWITCH_BLUETOOTH;
import static com.android.server.telecom.CallAudioRouteAdapter.USER_SWITCH_EARPIECE;
import static com.android.server.telecom.CallAudioRouteAdapter.USER_SWITCH_HEADSET;
@@ -194,6 +195,7 @@ public class CallAudioRouteControllerTest extends TelecomTestCase {
        when(mFeatureFlags.useRefactoredAudioRouteSwitching()).thenReturn(true);
        when(mFeatureFlags.resolveActiveBtRoutingAndBtTimingIssue()).thenReturn(false);
        when(mFeatureFlags.newAudioPathSpeakerBroadcastAndUnfocusedRouting()).thenReturn(false);
        when(mFeatureFlags.fixUserRequestBaselineRouteVideoCall()).thenReturn(false);
    }

    @After
@@ -1058,6 +1060,45 @@ public class CallAudioRouteControllerTest extends TelecomTestCase {
                any(CallAudioState.class), eq(expectedState));
    }

    @Test
    @SmallTest
    public void testUserSwitchBaselineRouteVideoCall() {
        when(mFeatureFlags.fixUserRequestBaselineRouteVideoCall()).thenReturn(true);
        mController.initialize();
        mController.setActive(true);
        // Set capabilities for video call.
        when(mCall.getVideoState()).thenReturn(VideoProfile.STATE_BIDIRECTIONAL);

        // Turn on speaker
        mController.sendMessageWithSessionInfo(SPEAKER_ON);
        CallAudioState expectedState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, null,
                new HashSet<>());
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));

        // USER_SWITCH_BASELINE_ROUTE (explicit user request). Verify that audio is routed back to
        // earpiece.
        mController.sendMessageWithSessionInfo(USER_SWITCH_BASELINE_ROUTE,
                CallAudioRouteController.INCLUDE_BLUETOOTH_IN_BASELINE);
        mController.sendMessageWithSessionInfo(SPEAKER_OFF);
        expectedState = new CallAudioState(false, CallAudioState.ROUTE_EARPIECE,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, null,
                new HashSet<>());
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));

        // SWITCH_BASELINE_ROUTE. Verify that audio is routed to speaker for non-user requests.
        mController.sendMessageWithSessionInfo(SWITCH_BASELINE_ROUTE,
                CallAudioRouteController.INCLUDE_BLUETOOTH_IN_BASELINE);
        mController.sendMessageWithSessionInfo(SPEAKER_ON);
        expectedState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, null,
                new HashSet<>());
        verify(mCallsManager, timeout(TEST_TIMEOUT)).onCallAudioStateChanged(
                any(CallAudioState.class), eq(expectedState));
    }

    private void verifyConnectBluetoothDevice(int audioType) {
        mController.initialize();
        mController.setActive(true);