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 Diff line number Diff line
@@ -51,6 +51,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -374,6 +375,16 @@ public class AudioDeviceBroker {
                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")
    /*package*/ void setCommunicationRouteForClient(
                            IBinder cb, int uid, AudioDeviceAttributes device,
@@ -388,7 +399,7 @@ public class AudioDeviceBroker {
                                        + " device: " + device + " isPrivileged: " + isPrivileged
                                        + " from API: " + eventSource)).printLog(TAG));

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

        // Save previous client route in case of failure to start BT SCO audio
@@ -412,8 +423,40 @@ public class AudioDeviceBroker {
        if (client == null) {
            return;
        }
        if (!mScoManagedByAudio) {
            boolean isBtScoRequested = isBluetoothScoRequested();
        final int btScoRequesterUid = bluetoothScoRequestOwnerUid();
        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()
                    || !mBtHelper.isBluetoothScoRequestedInternally())) {
                if (!mBtHelper.startBluetoothSco(scoAudioMode, eventSource)) {
@@ -575,12 +618,12 @@ public class AudioDeviceBroker {
    @GuardedBy("mDeviceStateLock")
    /*package*/ void updateCommunicationRouteClientState(
                            CommunicationRouteClient client, boolean wasActive) {
        boolean wasBtScoRequested = isBluetoothScoRequested();
        int btScoRequesterUid = bluetoothScoRequestOwnerUid();
        client.setPlaybackActive(mAudioService.isPlaybackActiveForUid(client.getUid()));
        client.setRecordingActive(mAudioService.isRecordingActiveForUid(client.getUid()));
        if (wasActive != client.isActive()) {
            postUpdateCommunicationRouteClient(
                    wasBtScoRequested, "updateCommunicationRouteClientState");
                    btScoRequesterUid, "updateCommunicationRouteClientState");
        }
    }

@@ -762,6 +805,22 @@ public class AudioDeviceBroker {
        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
     * 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) {
        synchronized (mBluetoothAudioStateLock) {
            boolean isBtScoRequested = isBluetoothScoRequested();
            int btScoRequesterUId = bluetoothScoRequestOwnerUid();
            Log.i(TAG, "setBluetoothScoOn: " + on + ", mBluetoothScoOn: "
                    + mBluetoothScoOn + ", isBtScoRequested: " + isBtScoRequested
                    + mBluetoothScoOn + ", btScoRequesterUId: " + btScoRequesterUId
                    + ", from: " + eventSource);
            mBluetoothScoOn = on;
            updateAudioHalBluetoothState();
            postUpdateCommunicationRouteClient(isBtScoRequested, eventSource);
            if (!mScoManagedByAudio) {
                postUpdateCommunicationRouteClient(btScoRequesterUId, eventSource);
            }
        }
    }

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

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

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

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