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

Commit 026d702d authored by Grace Jia's avatar Grace Jia
Browse files

Use STREAM_VOICE_CALL to play ringback when the active bluetooth

device is hearing aid device or LE audio device.

Bug: 192520750
Test: atest InCallTonePlayerTest
Change-Id: I64630bc4cb3f2e5c6e5dbf47fed0f9ad31b84ccb
parent 0ba96e08
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -45,6 +45,16 @@ public class CallAudioRoutePeripheralAdapter implements WiredHeadsetManager.List
        return mBluetoothRouteManager.isBluetoothAudioConnectedOrPending();
    }

    public boolean isHearingAidDeviceOn() {
        return mBluetoothRouteManager.isCachedHearingAidDevice(
                mBluetoothRouteManager.getBluetoothAudioConnectedDevice());
    }

    public boolean isLeAudioDeviceOn() {
        return mBluetoothRouteManager.isCachedLeAudioDevice(
                mBluetoothRouteManager.getBluetoothAudioConnectedDevice());
    }

    @Override
    public void onBluetoothDeviceListChanged() {
        mCallAudioRouteStateMachine.sendMessageWithSessionInfo(
+16 −3
Original line number Diff line number Diff line
@@ -182,6 +182,9 @@ public class InCallTonePlayer extends Thread {
    private static final int STATE_ON = 1;
    private static final int STATE_STOPPED = 2;

    // Invalid audio stream
    private static final int STREAM_INVALID = -1;

    /**
     * Keeps count of the number of actively playing tones so that we can notify CallAudioManager
     * when we need focus and when it can be release. This should only be manipulated from the main
@@ -260,6 +263,7 @@ public class InCallTonePlayer extends Thread {
            final int mediaResourceId; // The resourceId of the tone to play.  Used for media-based
                                      // tones.

            int stream = STREAM_INVALID;
            switch (mToneId) {
                case TONE_BUSY:
                    // TODO: CDMA-specific tones
@@ -327,6 +331,12 @@ public class InCallTonePlayer extends Thread {
                    toneVolume = RELATIVE_VOLUME_HIPRI;
                    toneLengthMillis = Integer.MAX_VALUE - TIMEOUT_BUFFER_MILLIS;
                    mediaResourceId = TONE_RESOURCE_ID_UNDEFINED;
                    // When a hearing aid device or a LE audio device is used, ring back tone should
                    // use STREAM_VOICE_CALL
                    if (mCallAudioRoutePeripheralAdapter.isLeAudioDeviceOn()
                            || mCallAudioRoutePeripheralAdapter.isHearingAidDeviceOn()) {
                        stream = AudioManager.STREAM_VOICE_CALL;
                    }
                    break;
                case TONE_UNOBTAINABLE_NUMBER:
                    toneType = ToneGenerator.TONE_SUP_ERROR;
@@ -358,10 +368,13 @@ public class InCallTonePlayer extends Thread {
                    throw new IllegalStateException("Bad toneId: " + mToneId);
            }

            int stream = AudioManager.STREAM_VOICE_CALL;
            // Don't override already valid stream values
            if (stream == STREAM_INVALID) {
                stream = AudioManager.STREAM_VOICE_CALL;
                if (mCallAudioRoutePeripheralAdapter.isBluetoothAudioOn()) {
                    stream = AudioManager.STREAM_BLUETOOTH_SCO;
                }
            }

            if (toneType != ToneGenerator.TONE_UNKNOWN) {
                playToneGeneratorTone(stream, toneVolume, toneType, toneLengthMillis);
+8 −0
Original line number Diff line number Diff line
@@ -644,6 +644,14 @@ public class BluetoothRouteManager extends StateMachine {
                mHfpActiveDeviceCache != null;
    }

    public boolean isCachedLeAudioDevice(BluetoothDevice device) {
        return mLeAudioActiveDeviceCache != null && mLeAudioActiveDeviceCache.equals(device);
    }

    public boolean isCachedHearingAidDevice(BluetoothDevice device) {
        return mHearingAidActiveDeviceCache != null && mHearingAidActiveDeviceCache.equals(device);
    }

    public Collection<BluetoothDevice> getConnectedDevices() {
        return mDeviceManager.getUniqueConnectedDevices();
    }
+64 −10
Original line number Diff line number Diff line
@@ -16,16 +16,23 @@

package com.android.server.telecom.tests;

import static com.android.server.telecom.bluetooth.BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.ToneGenerator;
import android.test.suitebuilder.annotation.SmallTest;
@@ -34,32 +41,40 @@ import androidx.test.filters.FlakyTest;

import com.android.server.telecom.CallAudioManager;
import com.android.server.telecom.CallAudioRoutePeripheralAdapter;
import com.android.server.telecom.CallAudioRouteStateMachine;
import com.android.server.telecom.DockManager;
import com.android.server.telecom.InCallTonePlayer;
import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.Timeouts;
import com.android.server.telecom.WiredHeadsetManager;
import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;

@RunWith(JUnit4.class)
public class InCallTonePlayerTest extends TelecomTestCase {

    private InCallTonePlayer.Factory mFactory;

    @Mock
    private CallAudioRoutePeripheralAdapter mCallAudioRoutePeripheralAdapter;

    @Mock
    private TelecomSystem.SyncRoot mLock;

    @Mock
    private ToneGenerator mToneGenerator;

    @Mock
    private InCallTonePlayer.ToneGeneratorFactory mToneGeneratorFactory;
    @Mock private BluetoothRouteManager mBluetoothRouteManager;
    @Mock private CallAudioRouteStateMachine mCallAudioRouteStateMachine;
    @Mock private Timeouts.Adapter mTimeoutsAdapter;
    @Mock private BluetoothDeviceManager mBluetoothDeviceManager;
    @Mock private TelecomSystem.SyncRoot mLock;
    @Mock private ToneGenerator mToneGenerator;
    @Mock private InCallTonePlayer.ToneGeneratorFactory mToneGeneratorFactory;
    @Mock private WiredHeadsetManager mWiredHeadsetManager;
    @Mock private DockManager mDockManager;
    @Mock private BluetoothDevice mDevice;
    @Mock private BluetoothAdapter mBluetoothAdapter;

    private InCallTonePlayer.MediaPlayerAdapter mMediaPlayerAdapter =
            new InCallTonePlayer.MediaPlayerAdapter() {
@@ -110,6 +125,9 @@ public class InCallTonePlayerTest extends TelecomTestCase {
        when(mToneGeneratorFactory.get(anyInt(), anyInt())).thenReturn(mToneGenerator);
        when(mMediaPlayerFactory.get(anyInt(), any())).thenReturn(mMediaPlayerAdapter);

        mCallAudioRoutePeripheralAdapter = new CallAudioRoutePeripheralAdapter(
                mCallAudioRouteStateMachine, mBluetoothRouteManager, mWiredHeadsetManager,
                mDockManager);
        mFactory = new InCallTonePlayer.Factory(mCallAudioRoutePeripheralAdapter, mLock,
                mToneGeneratorFactory, mMediaPlayerFactory, mAudioManagerAdapter);
        mFactory.setCallAudioManager(mCallAudioManager);
@@ -179,4 +197,40 @@ public class InCallTonePlayerTest extends TelecomTestCase {
        verify(mMediaPlayerFactory, timeout(5000)).get(anyInt(), any());
        verify(mCallAudioManager, timeout(5000)).setIsTonePlaying(eq(true));
    }

    @SmallTest
    @Test
    public void testRingbackAudioStreamHeadset() {
        when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
        mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
        when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
        when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);

        when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
        when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(false);

        mInCallTonePlayer = mFactory.createPlayer(InCallTonePlayer.TONE_RING_BACK);
        assertTrue(mInCallTonePlayer.startTone());
        verify(mToneGeneratorFactory, timeout(5000))
                .get(eq(AudioManager.STREAM_BLUETOOTH_SCO), anyInt());
        verify(mCallAudioManager, timeout(5000)).setIsTonePlaying(eq(true));
    }

    @SmallTest
    @Test
    public void testRingbackAudioStreamHearingAid() {
        when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
        mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
        when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
        when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);

        when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
        when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(true);

        mInCallTonePlayer = mFactory.createPlayer(InCallTonePlayer.TONE_RING_BACK);
        assertTrue(mInCallTonePlayer.startTone());
        verify(mToneGeneratorFactory, timeout(5000))
                .get(eq(AudioManager.STREAM_VOICE_CALL), anyInt());
        verify(mCallAudioManager, timeout(5000)).setIsTonePlaying(eq(true));
    }
}