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

Commit 429defcc authored by Eric Laurent's avatar Eric Laurent
Browse files

AudioService: handle SCO audio activaton for regular VoIP apps

With new SCO audio state management, the audio framework must still call
BluetoothHeadset.startScoUsingVirtualVoiceCall() and stopScoUsingVirtualVoiceCall()
When the activation request comes from apps other than Telecom and Bluetooth.

Bug: 265057196
Flag: android.media.audio.sco_managed_by_audio
Test: make

Change-Id: Ic60e73fc64e7a6095611a75de5b6ae986a3099c9
parent 1d74a5f2
Loading
Loading
Loading
Loading
+91 −19
Original line number Original line Diff line number Diff line
@@ -51,6 +51,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemClock;
@@ -374,6 +375,16 @@ public class AudioDeviceBroker {
                deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged, deviceInfo.mEventSource);
                deviceInfo.mScoAudioMode, deviceInfo.mIsPrivileged, deviceInfo.mEventSource);
    }
    }


    /**
     * Indicates if a Bluetooth SCO activation request owner is controlling
     * the SCO audio state itself or not.
     * @param uid the UI of the SOC request owner app
     * @return true if we should control SCO audio state, false otherwise
     */
    private boolean shouldStartScoForUid(int uid) {
        return !(uid == Process.BLUETOOTH_UID || uid == Process.PHONE_UID);
    }

    @GuardedBy("mDeviceStateLock")
    @GuardedBy("mDeviceStateLock")
    /*package*/ void setCommunicationRouteForClient(
    /*package*/ void setCommunicationRouteForClient(
                            IBinder cb, int uid, AudioDeviceAttributes device,
                            IBinder cb, int uid, AudioDeviceAttributes device,
@@ -388,7 +399,7 @@ public class AudioDeviceBroker {
                                        + " device: " + device + " isPrivileged: " + isPrivileged
                                        + " device: " + device + " isPrivileged: " + isPrivileged
                                        + " from API: " + eventSource)).printLog(TAG));
                                        + " from API: " + eventSource)).printLog(TAG));


        final boolean wasBtScoRequested = isBluetoothScoRequested();
        final int previousBtScoRequesterUid = bluetoothScoRequestOwnerUid();
        CommunicationRouteClient client;
        CommunicationRouteClient client;


        // Save previous client route in case of failure to start BT SCO audio
        // Save previous client route in case of failure to start BT SCO audio
@@ -412,8 +423,40 @@ public class AudioDeviceBroker {
        if (client == null) {
        if (client == null) {
            return;
            return;
        }
        }
        if (!mScoManagedByAudio) {
        final int btScoRequesterUid = bluetoothScoRequestOwnerUid();
            boolean isBtScoRequested = isBluetoothScoRequested();
        final boolean isBtScoRequested = btScoRequesterUid != -1;
        final boolean wasBtScoRequested = previousBtScoRequesterUid != -1;

        if (mScoManagedByAudio) {
            if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive()
                    || !mBtHelper.isBluetoothScoRequestedInternally())) {
                boolean scoStarted = false;
                if (shouldStartScoForUid(btScoRequesterUid)) {
                    scoStarted = mBtHelper.startBluetoothSco(scoAudioMode, eventSource);
                    if (!scoStarted) {
                        Log.w(TAG, "setCommunicationRouteForClient: "
                                + "failure to start BT SCO for uid: " + uid);
                        // clean up or restore previous client selection
                        if (prevClientDevice != null) {
                            addCommunicationRouteClient(cb, uid, prevClientDevice, prevPrivileged);
                        } else {
                            removeCommunicationRouteClient(cb, true);
                        }
                        postBroadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                    }
                } else {
                    scoStarted = true;
                }
                if (scoStarted) {
                    setBluetoothScoOn(true, "setCommunicationRouteForClient");
                }
            } else if (!isBtScoRequested && wasBtScoRequested) {
                if (shouldStartScoForUid(previousBtScoRequesterUid)) {
                    mBtHelper.stopBluetoothSco(eventSource);
                }
                setBluetoothScoOn(false, "setCommunicationRouteForClient");
            }
        } else {
            if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive()
            if (isBtScoRequested && (!wasBtScoRequested || !isBluetoothScoActive()
                    || !mBtHelper.isBluetoothScoRequestedInternally())) {
                    || !mBtHelper.isBluetoothScoRequestedInternally())) {
                if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
                if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
@@ -575,12 +618,12 @@ public class AudioDeviceBroker {
    @GuardedBy("mDeviceStateLock")
    @GuardedBy("mDeviceStateLock")
    /*package*/ void updateCommunicationRouteClientState(
    /*package*/ void updateCommunicationRouteClientState(
                            CommunicationRouteClient client, boolean wasActive) {
                            CommunicationRouteClient client, boolean wasActive) {
        boolean wasBtScoRequested = isBluetoothScoRequested();
        int btScoRequesterUid = bluetoothScoRequestOwnerUid();
        client.setPlaybackActive(mAudioService.isPlaybackActiveForUid(client.getUid()));
        client.setPlaybackActive(mAudioService.isPlaybackActiveForUid(client.getUid()));
        client.setRecordingActive(mAudioService.isRecordingActiveForUid(client.getUid()));
        client.setRecordingActive(mAudioService.isRecordingActiveForUid(client.getUid()));
        if (wasActive != client.isActive()) {
        if (wasActive != client.isActive()) {
            postUpdateCommunicationRouteClient(
            postUpdateCommunicationRouteClient(
                    wasBtScoRequested, "updateCommunicationRouteClientState");
                    btScoRequesterUid, "updateCommunicationRouteClientState");
        }
        }
    }
    }


@@ -762,6 +805,22 @@ public class AudioDeviceBroker {
        return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
        return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
    }
    }


    /**
     * Helper method on top of isBluetoothScoRequested() returning the UID of the
     * BT SCO route request owner of -1 if SCO is not requested.
     * @return the UID of the BT SCO route request owner of -1 if SCO is not requested.
     */
    @GuardedBy("mDeviceStateLock")
    /*package*/ int bluetoothScoRequestOwnerUid() {
        if (!isBluetoothScoRequested()) {
            return -1;
        }
        CommunicationRouteClient crc = topCommunicationRouteClient();
        if (crc == null) {
            return -1;
        }
        return crc.getUid();
    }
    /**
    /**
     * Helper method on top of isDeviceRequestedForCommunication() indicating if
     * Helper method on top of isDeviceRequestedForCommunication() indicating if
     * Bluetooth LE Audio communication device is currently requested or not.
     * Bluetooth LE Audio communication device is currently requested or not.
@@ -1148,15 +1207,18 @@ public class AudioDeviceBroker {
        }
        }
    }
    }


    @GuardedBy("mDeviceStateLock")
    /*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
    /*package*/ void setBluetoothScoOn(boolean on, String eventSource) {
        synchronized (mBluetoothAudioStateLock) {
        synchronized (mBluetoothAudioStateLock) {
            boolean isBtScoRequested = isBluetoothScoRequested();
            int btScoRequesterUId = bluetoothScoRequestOwnerUid();
            Log.i(TAG, "setBluetoothScoOn: " + on + ", mBluetoothScoOn: "
            Log.i(TAG, "setBluetoothScoOn: " + on + ", mBluetoothScoOn: "
                    + mBluetoothScoOn + ", isBtScoRequested: " + isBtScoRequested
                    + mBluetoothScoOn + ", btScoRequesterUId: " + btScoRequesterUId
                    + ", from: " + eventSource);
                    + ", from: " + eventSource);
            mBluetoothScoOn = on;
            mBluetoothScoOn = on;
            updateAudioHalBluetoothState();
            updateAudioHalBluetoothState();
            postUpdateCommunicationRouteClient(isBtScoRequested, eventSource);
            if (!mScoManagedByAudio) {
                postUpdateCommunicationRouteClient(btScoRequesterUId, eventSource);
            }
        }
        }
    }
    }


@@ -1510,9 +1572,9 @@ public class AudioDeviceBroker {
    }
    }


    /*package*/ void postUpdateCommunicationRouteClient(
    /*package*/ void postUpdateCommunicationRouteClient(
            boolean wasBtScoRequested, String eventSource) {
            int btScoRequesterUid, String eventSource) {
        sendILMsgNoDelay(MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE,
        sendILMsgNoDelay(MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT, SENDMSG_QUEUE,
                wasBtScoRequested ? 1 : 0, eventSource);
                btScoRequesterUid, eventSource);
    }
    }


    /*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) {
    /*package*/ void postSetCommunicationDeviceForClient(CommunicationDeviceInfo info) {
@@ -1865,7 +1927,7 @@ public class AudioDeviceBroker {
                                        || btInfo.mProfile == BluetoothProfile.HEARING_AID
                                        || btInfo.mProfile == BluetoothProfile.HEARING_AID
                                        || (mScoManagedByAudio
                                        || (mScoManagedByAudio
                                            && btInfo.mProfile == BluetoothProfile.HEADSET)) {
                                            && btInfo.mProfile == BluetoothProfile.HEADSET)) {
                                    onUpdateCommunicationRouteClient(isBluetoothScoRequested(),
                                    onUpdateCommunicationRouteClient(bluetoothScoRequestOwnerUid(),
                                            "setBluetoothActiveDevice");
                                            "setBluetoothActiveDevice");
                                }
                                }
                            }
                            }
@@ -1927,11 +1989,11 @@ public class AudioDeviceBroker {
                case MSG_I_SET_MODE_OWNER:
                case MSG_I_SET_MODE_OWNER:
                    synchronized (mSetModeLock) {
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                        synchronized (mDeviceStateLock) {
                            boolean wasBtScoRequested = isBluetoothScoRequested();
                            int btScoRequesterUid = bluetoothScoRequestOwnerUid();
                            mAudioModeOwner = (AudioModeInfo) msg.obj;
                            mAudioModeOwner = (AudioModeInfo) msg.obj;
                            if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
                            if (mAudioModeOwner.mMode != AudioSystem.MODE_RINGTONE) {
                                onUpdateCommunicationRouteClient(
                                onUpdateCommunicationRouteClient(
                                        wasBtScoRequested, "setNewModeOwner");
                                        btScoRequesterUid, "setNewModeOwner");
                            }
                            }
                        }
                        }
                    }
                    }
@@ -1958,7 +2020,7 @@ public class AudioDeviceBroker {
                case MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT:
                case MSG_IL_UPDATE_COMMUNICATION_ROUTE_CLIENT:
                    synchronized (mSetModeLock) {
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                        synchronized (mDeviceStateLock) {
                            onUpdateCommunicationRouteClient(msg.arg1 == 1, (String) msg.obj);
                            onUpdateCommunicationRouteClient(msg.arg1, (String) msg.obj);
                        }
                        }
                    }
                    }
                    break;
                    break;
@@ -2457,7 +2519,7 @@ public class AudioDeviceBroker {
    @Nullable private AudioDeviceAttributes preferredCommunicationDevice() {
    @Nullable private AudioDeviceAttributes preferredCommunicationDevice() {
        boolean btSCoOn = mBtHelper.isBluetoothScoOn();
        boolean btSCoOn = mBtHelper.isBluetoothScoOn();
        synchronized (mBluetoothAudioStateLock) {
        synchronized (mBluetoothAudioStateLock) {
            btSCoOn = btSCoOn && mBluetoothScoOn;
            btSCoOn = (btSCoOn || mScoManagedByAudio) && mBluetoothScoOn;
        }
        }


        if (btSCoOn) {
        if (btSCoOn) {
@@ -2522,19 +2584,29 @@ public class AudioDeviceBroker {
     */
     */
    // @GuardedBy("mSetModeLock")
    // @GuardedBy("mSetModeLock")
    @GuardedBy("mDeviceStateLock")
    @GuardedBy("mDeviceStateLock")
    private void onUpdateCommunicationRouteClient(boolean wasBtScoRequested, String eventSource) {
    private void onUpdateCommunicationRouteClient(
            int previousBtScoRequesterUid, String eventSource) {
        CommunicationRouteClient crc = topCommunicationRouteClient();
        CommunicationRouteClient crc = topCommunicationRouteClient();
        if (AudioService.DEBUG_COMM_RTE) {
        if (AudioService.DEBUG_COMM_RTE) {
            Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc
            Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc
                    + " wasBtScoRequested: " + wasBtScoRequested + " eventSource: " + eventSource);
                    + " previousBtScoRequesterUid: " + previousBtScoRequesterUid
                    + " eventSource: " + eventSource);
        }
        }
        if (crc != null) {
        if (crc != null) {
            setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
            setCommunicationRouteForClient(crc.getBinder(), crc.getUid(), crc.getDevice(),
                    BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
                    BtHelper.SCO_MODE_UNDEFINED, crc.isPrivileged(), eventSource);
        } else {
        } else {
            if (!mScoManagedByAudio && !isBluetoothScoRequested() && wasBtScoRequested) {
            boolean wasScoRequested = previousBtScoRequesterUid != -1;
            if (!isBluetoothScoRequested() && wasScoRequested) {
                if (mScoManagedByAudio) {
                    if (shouldStartScoForUid(previousBtScoRequesterUid)) {
                        mBtHelper.stopBluetoothSco(eventSource);
                        mBtHelper.stopBluetoothSco(eventSource);
                    }
                    }
                    setBluetoothScoOn(false, eventSource);
                } else {
                    mBtHelper.stopBluetoothSco(eventSource);
                }
            }
            updateCommunicationRoute(eventSource);
            updateCommunicationRoute(eventSource);
        }
        }
    }
    }
+46 −57
Original line number Original line Diff line number Diff line
@@ -404,23 +404,8 @@ public class BtHelper {
    private void onScoAudioStateChanged(int state) {
    private void onScoAudioStateChanged(int state) {
        boolean broadcast = false;
        boolean broadcast = false;
        int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
        int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
        Log.i(TAG, "onScoAudioStateChanged state: " + state + " mScoAudioState: " + mScoAudioState);
        Log.i(TAG, "onScoAudioStateChanged  state: " + state
        if (mDeviceBroker.isScoManagedByAudio()) {
                + ", mScoAudioState: " + mScoAudioState);
            switch (state) {
                case BluetoothHeadset.STATE_AUDIO_CONNECTED:
                    mDeviceBroker.setBluetoothScoOn(true, "BtHelper.onScoAudioStateChanged");
                    scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
                    broadcast = true;
                    break;
                case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
                    mDeviceBroker.setBluetoothScoOn(false, "BtHelper.onScoAudioStateChanged");
                    scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
                    broadcast = true;
                    break;
                default:
                    break;
            }
        } else {
        switch (state) {
        switch (state) {
            case BluetoothHeadset.STATE_AUDIO_CONNECTED:
            case BluetoothHeadset.STATE_AUDIO_CONNECTED:
                scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
                scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
@@ -431,10 +416,14 @@ public class BtHelper {
                    // broadcast intent if the connection was initated by AudioService
                    // broadcast intent if the connection was initated by AudioService
                    broadcast = true;
                    broadcast = true;
                }
                }
                if (!mDeviceBroker.isScoManagedByAudio()) {
                    mDeviceBroker.setBluetoothScoOn(true, "BtHelper.onScoAudioStateChanged");
                    mDeviceBroker.setBluetoothScoOn(true, "BtHelper.onScoAudioStateChanged");
                }
                break;
                break;
            case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
            case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
                if (!mDeviceBroker.isScoManagedByAudio()) {
                    mDeviceBroker.setBluetoothScoOn(false, "BtHelper.onScoAudioStateChanged");
                    mDeviceBroker.setBluetoothScoOn(false, "BtHelper.onScoAudioStateChanged");
                }
                scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
                scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
                // There are two cases where we want to immediately reconnect audio:
                // There are two cases where we want to immediately reconnect audio:
                // 1) If a new start request was received while disconnecting: this was
                // 1) If a new start request was received while disconnecting: this was
@@ -466,8 +455,8 @@ public class BtHelper {
            default:
            default:
                break;
                break;
        }
        }
        }
        if (broadcast) {
        if (broadcast) {
            Log.i(TAG, "onScoAudioStateChanged  broadcasting state: " + scoAudioState);
            broadcastScoConnectionState(scoAudioState);
            broadcastScoConnectionState(scoAudioState);
            //FIXME: this is to maintain compatibility with deprecated intent
            //FIXME: this is to maintain compatibility with deprecated intent
            // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
            // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.