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

Commit a8439e20 authored by Aniket Kumar Lata's avatar Aniket Kumar Lata Committed by Eric Laurent
Browse files

audio: Add API to handle active device change

Add API to handle active device change based on
whether we are switching between:
null to 'X'
'X' to 'Y'
'X' to null
This API must be called from A2dpService to update
active device.
Same API also caters to device config change on
an already connected A2DP device.

Bug: 111812273
Test: make
Change-Id: I9f28092934ee611fbc2cd7c81447b4ed22288ac9
parent 9fbc205f
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -4047,6 +4047,36 @@ public class AudioManager {
        }
    }

     /**
     * Indicate A2DP source or sink active device change and eventually suppress
     * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
     * @param device Bluetooth device connected/disconnected
     * @param state  new connection state (BluetoothProfile.STATE_xxx)
     * @param profile profile for the A2DP device
     * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
     * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
     * @param a2dpVolume New volume for the connecting device. Does nothing if
     * disconnecting. Pass value -1 in case you want this field to be ignored
     * @param suppressNoisyIntent if true the
     * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
     * @return a delay in ms that the caller should wait before broadcasting
     * BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED intent.
     * {@hide}
     */
    public int handleBluetoothA2dpActiveDeviceChange(
                BluetoothDevice device, int state, int profile,
                boolean suppressNoisyIntent, int a2dpVolume) {
        final IAudioService service = getService();
        int delay = 0;
        try {
            delay = service.handleBluetoothA2dpActiveDeviceChange(device,
                state, profile, suppressNoisyIntent, a2dpVolume);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return delay;
    }

    /** {@hide} */
    public IRingtonePlayer getRingtonePlayer() {
        try {
+3 −0
Original line number Diff line number Diff line
@@ -155,6 +155,9 @@ interface IAudioService {

    void handleBluetoothA2dpDeviceConfigChange(in BluetoothDevice device);

    int handleBluetoothA2dpActiveDeviceChange(in BluetoothDevice device,
            int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);

    AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);

    boolean isCameraSoundForced();
+122 −3
Original line number Diff line number Diff line
@@ -270,6 +270,7 @@ public class AudioService extends IAudioService.Stub
    private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
    private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 106;
    private static final int MSG_A2DP_ACTIVE_DEVICE_CHANGE = 107;
    // end of messages handled under wakelock

    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -4671,6 +4672,7 @@ public class AudioService extends IAudioService.Stub
                msg == MSG_SET_HEARING_AID_CONNECTION_STATE ||
                msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
                msg == MSG_A2DP_DEVICE_CONFIG_CHANGE ||
                msg == MSG_A2DP_ACTIVE_DEVICE_CHANGE ||
                msg == MSG_BTA2DP_DOCK_TIMEOUT) {
                if (mLastDeviceConnectMsgTime >= time) {
                  // add a little delay to make sure messages are ordered as expected
@@ -4890,6 +4892,61 @@ public class AudioService extends IAudioService.Stub
        }
    }

    /**
     * @see AudioManager#handleBluetoothA2dpActiveDeviceChange(BluetoothDevice, int, int,
     *                                                          boolean, int)
     */
    public int handleBluetoothA2dpActiveDeviceChange(
            BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
            int a2dpVolume) {
        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
            throw new IllegalArgumentException("invalid profile " + profile);
        }

        synchronized (mConnectedDevices) {
            if (state == BluetoothA2dp.STATE_CONNECTED) {
                for (int i = 0; i < mConnectedDevices.size(); i++) {
                    DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
                    if (deviceSpec.mDeviceType != AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
                        continue;
                    }
                    // If A2DP device exists, this is either an active device change or
                    // device config change
                    String existingDevicekey = mConnectedDevices.keyAt(i);
                    String deviceName = device.getName();
                    String address = device.getAddress();
                    String newDeviceKey = makeDeviceListKey(
                            AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address);
                    int a2dpCodec = getA2dpCodec(device);
                    // Device not equal to existing device, active device change
                    if (!TextUtils.equals(existingDevicekey, newDeviceKey)) {
                        mConnectedDevices.remove(existingDevicekey);
                        mConnectedDevices.put(newDeviceKey, new DeviceListSpec(
                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, deviceName,
                                address, a2dpCodec));
                        queueMsgUnderWakeLock(mAudioHandler,
                                MSG_A2DP_ACTIVE_DEVICE_CHANGE,
                                0,
                                0,
                                new BluetoothA2dpDeviceInfo(
                                        device, a2dpVolume, a2dpCodec),
                                0 /* delay */);
                        return 0;
                    } else {
                        // Device config change for existing device
                        handleBluetoothA2dpDeviceConfigChange(device);
                        return 0;
                    }
                }
            }
        }

        // New device connection or a device disconnect
        return setBluetoothA2dpDeviceConnectionStateInt(
                    device, state, profile, suppressNoisyIntent,
                    AudioSystem.DEVICE_NONE, a2dpVolume);
    }

    private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
            AudioSystem.DEVICE_OUT_LINE |
@@ -5811,6 +5868,11 @@ public class AudioService extends IAudioService.Stub
                    mAudioEventWakeLock.release();
                    break;

                case MSG_A2DP_ACTIVE_DEVICE_CHANGE:
                    onBluetoothA2dpActiveDeviceChange((BluetoothA2dpDeviceInfo) msg.obj);
                    mAudioEventWakeLock.release();
                    break;

                case MSG_DISABLE_AUDIO_FOR_UID:
                    mPlaybackMonitor.disableAudioForUid( msg.arg1 == 1 /* disable */,
                            msg.arg2 /* uid */);
@@ -6277,12 +6339,12 @@ public class AudioService extends IAudioService.Stub
        BluetoothDevice btDevice = btInfo.getBtDevice();
        int a2dpCodec = btInfo.getCodec();

        if (DEBUG_DEVICES) {
            Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
        }
        if (btDevice == null) {
            return;
        }
        if (DEBUG_DEVICES) {
            Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
        }
        String address = btDevice.getAddress();
        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
            address = "";
@@ -6324,6 +6386,63 @@ public class AudioService extends IAudioService.Stub
        }
    }

    /** message handler for MSG_A2DP_ACTIVE_DEVICE_CHANGE */
    public void onBluetoothA2dpActiveDeviceChange(BluetoothA2dpDeviceInfo btInfo) {
        if (btInfo == null) {
            return;
        }
        BluetoothDevice btDevice = btInfo.getBtDevice();
        int a2dpVolume = btInfo.getVolume();
        int a2dpCodec = btInfo.getCodec();

        if (btDevice == null) {
            return;
        }
        if (DEBUG_DEVICES) {
            Log.d(TAG, "onBluetoothA2dpActiveDeviceChange btDevice=" + btDevice);
        }
        String address = btDevice.getAddress();
        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
            address = "";
        }
        mDeviceLogger.log(new AudioEventLogger.StringEvent(
                "onBluetoothA2dpActiveDeviceChange addr=" + address));

        int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
        synchronized (mConnectedDevices) {
            if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) {
                mDeviceLogger.log(new AudioEventLogger.StringEvent(
                        "A2dp config change ignored"));
                return;
            }
            final String key = makeDeviceListKey(device, address);
            final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
            if (deviceSpec == null) {
                return;
            }

            // Device is connected
            if (a2dpVolume != -1) {
                VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
                // Convert index to internal representation in VolumeStreamState
                a2dpVolume = a2dpVolume * 10;
                streamState.setIndex(a2dpVolume, device,
                        "onBluetoothA2dpActiveDeviceChange");
                setDeviceVolume(streamState, device);
            }

            if (AudioSystem.handleDeviceConfigChange(device, address,
                    btDevice.getName(), a2dpCodec) != AudioSystem.AUDIO_STATUS_OK) {
                int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
                // force A2DP device disconnection in case of error so that AudioService state is
                // consistent with audio policy manager state
                setBluetoothA2dpDeviceConnectionStateInt(
                        btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
                        false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
            }
        }
    }

    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
        // address is not used for now, but may be used when multiple a2dp devices are supported
        synchronized (mA2dpAvrcpLock) {