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

Commit 85162b65 authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge changes from topic "presubmit-am-ff7699f855c14d1ca2c8a3438a9402f0" into sc-v2-dev-plus-aosp

* changes:
  [conflict] audioservice: improve SCO audio control logic 2p: a0b2ee74
  audioservice: improve SCO audio control logic
parents a0be2d5c e23d3a05
Loading
Loading
Loading
Loading
+146 −29
Original line number Diff line number Diff line
@@ -251,8 +251,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
                        return;
                    }
                }
                setCommunicationRouteForClient(
                        cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource);
                postSetCommunicationRouteForClient(new CommunicationClientInfo(
                        cb, pid, device, BtHelper.SCO_MODE_UNDEFINED, eventSource));
            }
        }
    }
@@ -282,8 +282,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
                        return false;
                    }
                }
                setCommunicationRouteForClient(
                        cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource);
                postSetCommunicationRouteForClient(new CommunicationClientInfo(
                        cb, pid, deviceAttr, BtHelper.SCO_MODE_UNDEFINED, eventSource));
            }
        }
        return true;
@@ -347,26 +347,35 @@ import java.util.concurrent.atomic.AtomicBoolean;
    }

    /**
     * Returns the device currently requested for communication use case.
     * If the current audio mode owner is in the communication route client list,
     * use this preference.
     * Otherwise use first client's preference (first client corresponds to latest request).
     * null is returned if no client is in the list.
     * @return AudioDeviceAttributes the requested device for communication.
     * Returns the communication client with the highest priority:
     * - 1) the client which is currently also controlling the audio mode
     * - 2) the first client in the stack if there is no audio mode owner
     * - 3) no client otherwise
     * @return CommunicationRouteClient the client driving the communication use case routing.
     */

    @GuardedBy("mDeviceStateLock")
    private AudioDeviceAttributes requestedCommunicationDevice() {
        AudioDeviceAttributes device = null;
        for (CommunicationRouteClient cl : mCommunicationRouteClients) {
            if (cl.getPid() == mModeOwnerPid) {
                device = cl.getDevice();
    private CommunicationRouteClient topCommunicationRouteClient() {
        for (CommunicationRouteClient crc : mCommunicationRouteClients) {
            if (crc.getPid() == mModeOwnerPid) {
                return crc;
            }
        }
        if (!mCommunicationRouteClients.isEmpty() && mModeOwnerPid == 0) {
            device = mCommunicationRouteClients.get(0).getDevice();
            return mCommunicationRouteClients.get(0);
        }
        return null;
    }

    /**
     * Returns the device currently requested for communication use case.
     * Use the device requested by the communication route client selected by
     * {@link #topCommunicationRouteClient()} if any or none otherwise.
     * @return AudioDeviceAttributes the requested device for communication.
     */
    @GuardedBy("mDeviceStateLock")
    private AudioDeviceAttributes requestedCommunicationDevice() {
        CommunicationRouteClient crc = topCommunicationRouteClient();
        AudioDeviceAttributes device = crc != null ? crc.getDevice() : null;
        if (AudioService.DEBUG_COMM_RTE) {
            Log.v(TAG, "requestedCommunicationDevice, device: "
                    + device + " mode owner pid: " + mModeOwnerPid);
@@ -696,7 +705,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
        }
        synchronized (mDeviceStateLock) {
            mBluetoothScoOn = on;
            sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource);
            postUpdateCommunicationRouteClient(eventSource);
        }
    }

@@ -756,7 +765,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
            synchronized (mDeviceStateLock) {
                AudioDeviceAttributes device =
                        new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
                setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource);

                postSetCommunicationRouteForClient(new CommunicationClientInfo(
                        cb, pid, device, scoAudioMode, eventSource));
            }
        }
    }
@@ -774,8 +785,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
                if (client == null || !client.requestsBluetoothSco()) {
                    return;
                }
                setCommunicationRouteForClient(
                        cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource);
                postSetCommunicationRouteForClient(new CommunicationClientInfo(
                        cb, pid, null, BtHelper.SCO_MODE_UNDEFINED, eventSource));
            }
        }
    }
@@ -976,6 +987,61 @@ import java.util.concurrent.atomic.AtomicBoolean;
                MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET, SENDMSG_QUEUE, capturePreset);
    }

    /*package*/ void postUpdateCommunicationRouteClient(String eventSource) {
        sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE, eventSource);
    }

    /*package*/ void postSetCommunicationRouteForClient(CommunicationClientInfo info) {
        sendLMsgNoDelay(MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT, SENDMSG_QUEUE, info);
    }

    /*package*/ void postScoAudioStateChanged(int state) {
        sendIMsgNoDelay(MSG_I_SCO_AUDIO_STATE_CHANGED, SENDMSG_QUEUE, state);
    }

    /*package*/ static final class CommunicationClientInfo {
        final @NonNull IBinder mCb;
        final int mPid;
        final @NonNull AudioDeviceAttributes mDevice;
        final int mScoAudioMode;
        final @NonNull String mEventSource;

        CommunicationClientInfo(@NonNull IBinder cb, int pid, @NonNull AudioDeviceAttributes device,
                int scoAudioMode, @NonNull String eventSource) {
            mCb = cb;
            mPid = pid;
            mDevice = device;
            mScoAudioMode = scoAudioMode;
            mEventSource = eventSource;
        }

        // redefine equality op so we can match messages intended for this client
        @Override
        public boolean equals(Object o) {
            if (o == null) {
                return false;
            }
            if (this == o) {
                return true;
            }
            if (!(o instanceof CommunicationClientInfo)) {
                return false;
            }

            return mCb.equals(((CommunicationClientInfo) o).mCb)
                    && mPid == ((CommunicationClientInfo) o).mPid;
        }

        @Override
        public String toString() {
            return "CommunicationClientInfo mCb=" + mCb.toString()
                    +"mPid=" + mPid
                    +"mDevice=" + mDevice.toString()
                    +"mScoAudioMode=" + mScoAudioMode
                    +"mEventSource=" + mEventSource;
        }
    }

    //---------------------------------------------------------------------
    // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
    // only call from a "handle"* method or "on"* method
@@ -1252,18 +1318,30 @@ import java.util.concurrent.atomic.AtomicBoolean;
                        synchronized (mDeviceStateLock) {
                            mModeOwnerPid = msg.arg1;
                            if (msg.arg2 != AudioSystem.MODE_RINGTONE) {
                                onUpdateCommunicationRoute("setNewModeOwner");
                                onUpdateCommunicationRouteClient("setNewModeOwner");
                            }
                        }
                    }
                    break;
                case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:

                case MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT:
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                            onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
                            CommunicationClientInfo info = (CommunicationClientInfo) msg.obj;
                            setCommunicationRouteForClient(info.mCb, info.mPid, info.mDevice,
                                    info.mScoAudioMode, info.mEventSource);
                        }
                    }
                    break;

                case MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT:
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                            onUpdateCommunicationRouteClient((String) msg.obj);
                        }
                    }
                    break;

                case MSG_L_UPDATE_COMMUNICATION_ROUTE:
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
@@ -1271,6 +1349,23 @@ import java.util.concurrent.atomic.AtomicBoolean;
                        }
                    }
                    break;

                case MSG_L_COMMUNICATION_ROUTE_CLIENT_DIED:
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                            onCommunicationRouteClientDied((CommunicationRouteClient) msg.obj);
                        }
                    }
                    break;

                case MSG_I_SCO_AUDIO_STATE_CHANGED:
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                            mBtHelper.onScoAudioStateChanged(msg.arg1);
                        }
                    }
                    break;

                case MSG_TOGGLE_HDMI:
                    synchronized (mDeviceStateLock) {
                        mDeviceInventory.onToggleHdmi();
@@ -1424,6 +1519,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
    private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE = 39;
    private static final int MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY = 40;
    private static final int MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY = 41;
    private static final int MSG_L_SET_COMMUNICATION_ROUTE_FOR_CLIENT = 42;
    private static final int MSG_L_UPDATE_COMMUNICATION_ROUTE_CLIENT = 43;
    private static final int MSG_I_SCO_AUDIO_STATE_CHANGED = 44;

    private static final int MSG_L_BT_ACTIVE_DEVICE_CHANGE_EXT = 45;
    //
@@ -1642,9 +1740,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
            return;
        }
        Log.w(TAG, "Communication client died");
        setCommunicationRouteForClient(
                client.getBinder(), client.getPid(), null, BtHelper.SCO_MODE_UNDEFINED,
                "onCommunicationRouteClientDied");
        removeCommunicationRouteClient(client.getBinder(), true);
        onUpdateCommunicationRouteClient("onCommunicationRouteClientDied");
    }

    /**
@@ -1698,11 +1795,31 @@ import java.util.concurrent.atomic.AtomicBoolean;
            AudioSystem.setParameters("BT_SCO=on");
        }
        if (preferredCommunicationDevice == null) {
            postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
            removePreferredDevicesForStrategySync(mCommunicationStrategyId);
        } else {
            postSetPreferredDevicesForStrategy(
            setPreferredDevicesForStrategySync(
                    mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
        }
        onUpdatePhoneStrategyDevice(preferredCommunicationDevice);
    }

    /**
     * Select new communication device from communication route client at the top of the stack
     * and restore communication route including restarting SCO audio if needed.
     */
    // @GuardedBy("mSetModeLock")
    @GuardedBy("mDeviceStateLock")
    private void onUpdateCommunicationRouteClient(String eventSource) {
        onUpdateCommunicationRoute(eventSource);
        CommunicationRouteClient crc = topCommunicationRouteClient();
        if (AudioService.DEBUG_COMM_RTE) {
            Log.v(TAG, "onUpdateCommunicationRouteClient, crc: "
                    + crc + " eventSource: " + eventSource);
        }
        if (crc != null) {
            setCommunicationRouteForClient(crc.getBinder(), crc.getPid(), crc.getDevice(),
                    BtHelper.SCO_MODE_UNDEFINED, eventSource);
        }
    }

    private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
+75 −58
Original line number Diff line number Diff line
@@ -304,11 +304,22 @@ public class BtHelper {
            BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
            setBtScoActiveDevice(btDevice);
        } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
            boolean broadcast = false;
            int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
            int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
            Log.i(TAG,"receiveBtEvent ACTION_AUDIO_STATE_CHANGED: "+btState);
            switch (btState) {
            mDeviceBroker.postScoAudioStateChanged(btState);
        }
    }

    /**
     * Exclusively called from AudioDeviceBroker when handling MSG_I_SCO_AUDIO_STATE_CHANGED
     * as part of the serialization of the communication route selection
     */
    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
    void onScoAudioStateChanged(int state) {
        boolean broadcast = false;
        int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
        switch (state) {
            case BluetoothHeadset.STATE_AUDIO_CONNECTED:
                scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
                if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL
@@ -329,9 +340,7 @@ public class BtHelper {
                // 2) If audio was connected then disconnected via Bluetooth APIs and
                // we still have pending activation requests by apps: this is indicated by
                // state SCO_STATE_ACTIVE_EXTERNAL and BT SCO is requested.
                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ
                            || (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL
                                    && mDeviceBroker.isBluetoothScoRequested())) {
                if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
                    if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
                            && connectBluetoothScoAudioHelper(mBluetoothHeadset,
                            mBluetoothHeadsetDevice, mScoAudioMode)) {
@@ -363,9 +372,8 @@ public class BtHelper {
            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
            sendStickyBroadcastToAll(newIntent);
        }
        }
    }

    }
    /**
     *
     * @return false if SCO isn't connected
@@ -744,6 +752,15 @@ public class BtHelper {
                case SCO_STATE_ACTIVE_INTERNAL:
                    Log.w(TAG, "requestScoState: already in ACTIVE mode, simply return");
                    break;
                case SCO_STATE_ACTIVE_EXTERNAL:
                    /* Confirm SCO Audio connection to requesting app as it is already connected
                     * externally (i.e. through SCO APIs by Telecom service).
                     * Once SCO Audio is disconnected by the external owner, we will reconnect it
                     * automatically on behalf of the requesting app and the state will move to
                     * SCO_STATE_ACTIVE_INTERNAL.
                     */
                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
                    break;
                default:
                    Log.w(TAG, "requestScoState: failed to connect in state "
                            + mScoAudioState + ", scoAudioMode=" + scoAudioMode);