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

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

Merge "AudioDeviceBroker: fix speakerphone state reporting" into sc-dev

parents 3ede93e2 b79ef23e
Loading
Loading
Loading
Loading
+145 −86
Original line number Original line Diff line number Diff line
@@ -80,9 +80,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
    private final @NonNull AudioService mAudioService;
    private final @NonNull AudioService mAudioService;
    private final @NonNull Context mContext;
    private final @NonNull Context mContext;


    /** Forced device usage for communications sent to AudioSystem */
    /** ID for Communication strategy retrieved form audio policy manager */
    private AudioDeviceAttributes mPreferredCommunicationDevice;
    private int mCommunicationStrategyId = -1;
    private int mCommunicationStrategyId = -1;
    /** Active communication device reported by audio policy manager */
    private AudioDeviceInfo mActiveCommunicationDevice;
    /** Last preferred device set for communication strategy */
    private AudioDeviceAttributes mPreferredCommunicationDevice;


    // Manages all connected devices, only ever accessed on the message loop
    // Manages all connected devices, only ever accessed on the message loop
    private final AudioDeviceInventory mDeviceInventory;
    private final AudioDeviceInventory mDeviceInventory;
@@ -153,8 +156,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
    private void init() {
    private void init() {
        setupMessaging(mContext);
        setupMessaging(mContext);


        mPreferredCommunicationDevice = null;
        initCommunicationStrategyId();
        initCommunicationStrategyId();
        mPreferredCommunicationDevice = null;
        updateActiveCommunicationDevice();


        mSystemServer.registerUserStartedReceiver(mContext);
        mSystemServer.registerUserStartedReceiver(mContext);
    }
    }
@@ -300,7 +304,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
                                        + " from API: " + eventSource)).printLog(TAG));
                                        + " from API: " + eventSource)).printLog(TAG));


        final boolean wasBtScoRequested = isBluetoothScoRequested();
        final boolean wasBtScoRequested = isBluetoothScoRequested();
        final boolean wasSpeakerphoneRequested = isSpeakerphoneRequested();
        CommunicationRouteClient client;
        CommunicationRouteClient client;




@@ -341,16 +344,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
            mBtHelper.stopBluetoothSco(eventSource);
            mBtHelper.stopBluetoothSco(eventSource);
        }
        }


        if (wasSpeakerphoneRequested != isSpeakerphoneRequested()) {
            try {
                mContext.sendBroadcastAsUser(
                        new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
                                .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
            } catch (Exception e) {
                Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
            }
        }

        sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource);
        sendLMsgNoDelay(MSG_L_UPDATE_COMMUNICATION_ROUTE, SENDMSG_QUEUE, eventSource);
    }
    }


@@ -386,9 +379,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
     * Returns the device currently requested for communication use case.
     * Returns the device currently requested for communication use case.
     * @return AudioDeviceInfo the requested device for communication.
     * @return AudioDeviceInfo the requested device for communication.
     */
     */
    AudioDeviceInfo getCommunicationDevice() {
    /* package */ AudioDeviceInfo getCommunicationDevice() {
        synchronized (mDeviceStateLock) {
        synchronized (mDeviceStateLock) {
            AudioDeviceAttributes device = requestedCommunicationDevice();
            updateActiveCommunicationDevice();
            return mActiveCommunicationDevice;
        }
    }

    /**
     * Updates currently active communication device (mActiveCommunicationDevice).
     */
    @GuardedBy("mDeviceStateLock")
    void updateActiveCommunicationDevice() {
        AudioDeviceAttributes device = preferredCommunicationDevice();
        if (device == null) {
        if (device == null) {
            AudioAttributes attr =
            AudioAttributes attr =
                    AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(
                    AudioProductStrategy.getAudioAttributesForStrategyWithLegacyStreamType(
@@ -396,56 +399,99 @@ import java.util.concurrent.atomic.AtomicBoolean;
            List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr);
            List<AudioDeviceAttributes> devices = AudioSystem.getDevicesForAttributes(attr);
            if (devices.isEmpty()) {
            if (devices.isEmpty()) {
                if (mAudioService.isPlatformVoice()) {
                if (mAudioService.isPlatformVoice()) {
                        Log.w(TAG, "getCommunicationDevice(): no device for phone strategy");
                    Log.w(TAG,
                            "updateActiveCommunicationDevice(): no device for phone strategy");
                }
                }
                    return null;
                mActiveCommunicationDevice = null;
                return;
            }
            }
            device = devices.get(0);
            device = devices.get(0);
        }
        }
            return AudioManager.getDeviceInfoFromTypeAndAddress(
        mActiveCommunicationDevice = AudioManager.getDeviceInfoFromTypeAndAddress(
                device.getType(), device.getAddress());
                device.getType(), device.getAddress());
    }
    }

    /**
     * Indicates if the device which type is passed as argument is currently resquested to be used
     * for communication.
     * @param deviceType the device type the query applies to.
     * @return true if this device type is requested for communication.
     */
    private boolean isDeviceRequestedForCommunication(int deviceType) {
        synchronized (mDeviceStateLock) {
            AudioDeviceAttributes device = requestedCommunicationDevice();
            return device != null && device.getType() == deviceType;
        }
    }

    /**
     * Indicates if the device which type is passed as argument is currently either resquested
     * to be used for communication or selected for an other reason (e.g bluetooth SCO audio
     * is active for SCO device).
     * @param deviceType the device type the query applies to.
     * @return true if this device type is requested for communication.
     */
    private boolean isDeviceOnForCommunication(int deviceType) {
        synchronized (mDeviceStateLock) {
            AudioDeviceAttributes device = preferredCommunicationDevice();
            return device != null && device.getType() == deviceType;
        }
    }

    /**
     * Indicates if the device which type is passed as argument is active for communication.
     * Active means not only currently used by audio policy manager for communication strategy
     * but also explicitly requested for use by communication strategy.
     * @param deviceType the device type the query applies to.
     * @return true if this device type is requested for communication.
     */
    private boolean isDeviceActiveForCommunication(int deviceType) {
        return mActiveCommunicationDevice != null
                && mActiveCommunicationDevice.getType() == deviceType
                && mPreferredCommunicationDevice != null
                && mPreferredCommunicationDevice.getType() == deviceType;
    }
    }


    /**
    /**
     * Helper method on top of requestedCommunicationDevice() indicating if
     * Helper method on top of isDeviceRequestedForCommunication() indicating if
     * speakerphone ON is currently requested or not.
     * speakerphone ON is currently requested or not.
     * @return true if speakerphone ON requested, false otherwise.
     * @return true if speakerphone ON requested, false otherwise.
     */
     */

    private boolean isSpeakerphoneRequested() {
    private boolean isSpeakerphoneRequested() {
        synchronized (mDeviceStateLock) {
        return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
            AudioDeviceAttributes device = requestedCommunicationDevice();
            return device != null
                    && device.getType()
                        == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
        }
    }
    }


    /**
    /**
     * Indicates if active route selection for communication is speakerphone.
     * Indicates if preferred route selection for communication is speakerphone.
     * @return true if speakerphone is active, false otherwise.
     * @return true if speakerphone is active, false otherwise.
     */
     */
    /*package*/ boolean isSpeakerphoneOn() {
    /*package*/ boolean isSpeakerphoneOn() {
        AudioDeviceAttributes device = getPreferredCommunicationDevice();
        return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
        if (device == null) {
            return false;
    }
    }
        return device.getInternalType() == AudioSystem.DEVICE_OUT_SPEAKER;

    private boolean isSpeakerphoneActive() {
        return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
    }
    }


    /**
    /**
     * Helper method on top of requestedCommunicationDevice() indicating if
     * Helper method on top of isDeviceRequestedForCommunication() indicating if
     * Bluetooth SCO ON is currently requested or not.
     * Bluetooth SCO ON is currently requested or not.
     * @return true if Bluetooth SCO ON is requested, false otherwise.
     * @return true if Bluetooth SCO ON is requested, false otherwise.
     */
     */
    /*package*/ boolean isBluetoothScoRequested() {
    /*package*/ boolean isBluetoothScoRequested() {
        synchronized (mDeviceStateLock) {
        return isDeviceRequestedForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
            AudioDeviceAttributes device = requestedCommunicationDevice();
    }
            return device != null

                    && device.getType()
    /**
                        == AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
     * Indicates if preferred route selection for communication is Bluetooth SCO.
     * @return true if Bluetooth SCO is preferred , false otherwise.
     */
    /*package*/ boolean isBluetoothScoOn() {
        return isDeviceOnForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
    }
    }

    /*package*/ boolean isBluetoothScoActive() {
        return isDeviceActiveForCommunication(AudioDeviceInfo.TYPE_BLUETOOTH_SCO);
    }
    }


    /*package*/ void setWiredDeviceConnectionState(int type,
    /*package*/ void setWiredDeviceConnectionState(int type,
@@ -593,18 +639,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
        }
        }
    }
    }


    /**
     * Indicates if active route selection for communication is Bluetooth SCO.
     * @return true if Bluetooth SCO is active , false otherwise.
     */
    /*package*/ boolean isBluetoothScoOn() {
        AudioDeviceAttributes device = getPreferredCommunicationDevice();
        if (device == null) {
            return false;
        }
        return AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType());
    }

    /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
    /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
        synchronized (mDeviceStateLock) {
        synchronized (mDeviceStateLock) {
            return mDeviceInventory.startWatchingRoutes(observer);
            return mDeviceInventory.startWatchingRoutes(observer);
@@ -748,8 +782,8 @@ import java.util.concurrent.atomic.AtomicBoolean;


    @GuardedBy("mDeviceStateLock")
    @GuardedBy("mDeviceStateLock")
    private void dispatchCommunicationDevice() {
    private void dispatchCommunicationDevice() {
        AudioDeviceInfo device = getCommunicationDevice();
        int portId = (mActiveCommunicationDevice == null) ? 0
        int portId = (device == null) ? 0 : device.getId();
                : mActiveCommunicationDevice.getId();
        if (portId == mCurCommunicationPortId) {
        if (portId == mCurCommunicationPortId) {
            return;
            return;
        }
        }
@@ -1022,12 +1056,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
            pw.println("  " + prefix + "pid: " + cl.getPid() + " device: "
            pw.println("  " + prefix + "pid: " + cl.getPid() + " device: "
                        + cl.getDevice() + " cb: " + cl.getBinder()); });
                        + cl.getDevice() + " cb: " + cl.getBinder()); });


        pw.println("\n" + prefix + "mPreferredCommunicationDevice: "
        pw.println("\n" + prefix + "Computed Preferred communication device: "
                +  preferredCommunicationDevice());
        pw.println("\n" + prefix + "Applied Preferred communication device: "
                +  mPreferredCommunicationDevice);
                +  mPreferredCommunicationDevice);

        pw.println(prefix + "Active communication device: "
        AudioDeviceInfo device = getCommunicationDevice();
                +  ((mActiveCommunicationDevice == null) ? "None"
        pw.println(prefix + "Selected Communication Device: "
                        : new AudioDeviceAttributes(mActiveCommunicationDevice)));
                +  ((device == null) ? "None" : new AudioDeviceAttributes(device)));


        pw.println(prefix + "mCommunicationStrategyId: "
        pw.println(prefix + "mCommunicationStrategyId: "
                +  mCommunicationStrategyId);
                +  mCommunicationStrategyId);
@@ -1128,6 +1163,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
                    synchronized (mSetModeLock) {
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                        synchronized (mDeviceStateLock) {
                            initCommunicationStrategyId();
                            initCommunicationStrategyId();
                            updateActiveCommunicationDevice();
                            mDeviceInventory.onRestoreDevices();
                            mDeviceInventory.onRestoreDevices();
                            mBtHelper.onAudioServerDiedRestoreA2dp();
                            mBtHelper.onAudioServerDiedRestoreA2dp();
                            onUpdateCommunicationRoute("MSG_RESTORE_DEVICES");
                            onUpdateCommunicationRoute("MSG_RESTORE_DEVICES");
@@ -1340,11 +1376,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
                    final List<AudioDeviceAttributes> devices =
                    final List<AudioDeviceAttributes> devices =
                            (List<AudioDeviceAttributes>) msg.obj;
                            (List<AudioDeviceAttributes>) msg.obj;
                    setPreferredDevicesForStrategySync(strategy, devices);
                    setPreferredDevicesForStrategySync(strategy, devices);

                    if (strategy == mCommunicationStrategyId) {
                        onUpdatePhoneStrategyDevice(devices.isEmpty() ? null : devices.get(0));
                    }
                } break;
                } break;
                case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: {
                case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: {
                    final int strategy = msg.arg1;
                    final int strategy = msg.arg1;
                    removePreferredDevicesForStrategySync(strategy);
                    removePreferredDevicesForStrategySync(strategy);
                    if (strategy == mCommunicationStrategyId) {
                        onUpdatePhoneStrategyDevice(null);
                    }
                } break;
                } break;
                case MSG_CHECK_MUTE_MUSIC:
                case MSG_CHECK_MUTE_MUSIC:
                    checkMessagesMuteMusic(0);
                    checkMessagesMuteMusic(0);
@@ -1672,14 +1713,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
    }
    }


    /**
    /**
     * Determines which forced usage for communication should be sent to audio policy manager
     * Determines which preferred device for phone strategy should be sent to audio policy manager
     * as a function of current SCO audio activation state and active communication route requests.
     * as a function of current SCO audio activation state and active communication route requests.
     * SCO audio state has the highest priority as it can result from external activation by
     * SCO audio state has the highest priority as it can result from external activation by
     * telephony service.
     * telephony service.
     * @return selected forced usage for communication.
     * @return selected forced usage for communication.
     */
     */
    @GuardedBy("mDeviceStateLock")
    @GuardedBy("mDeviceStateLock")
    @Nullable private AudioDeviceAttributes getPreferredCommunicationDevice() {
    @Nullable private AudioDeviceAttributes preferredCommunicationDevice() {
        boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();
        boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();
        if (btSCoOn) {
        if (btSCoOn) {
            // Use the SCO device known to BtHelper so that it matches exactly
            // Use the SCO device known to BtHelper so that it matches exactly
@@ -1692,8 +1733,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
            }
            }
        }
        }
        AudioDeviceAttributes device = requestedCommunicationDevice();
        AudioDeviceAttributes device = requestedCommunicationDevice();
        if (device == null
        if (device == null || device.getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
                || AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType())) {
            // Do not indicate BT SCO selection if SCO is requested but SCO is not ON
            // Do not indicate BT SCO selection if SCO is requested but SCO is not ON
            return null;
            return null;
        }
        }
@@ -1707,31 +1747,50 @@ import java.util.concurrent.atomic.AtomicBoolean;
    // @GuardedBy("mSetModeLock")
    // @GuardedBy("mSetModeLock")
    @GuardedBy("mDeviceStateLock")
    @GuardedBy("mDeviceStateLock")
    private void onUpdateCommunicationRoute(String eventSource) {
    private void onUpdateCommunicationRoute(String eventSource) {
        mPreferredCommunicationDevice = getPreferredCommunicationDevice();
        AudioDeviceAttributes preferredCommunicationDevice = preferredCommunicationDevice();
        if (AudioService.DEBUG_COMM_RTE) {
        if (AudioService.DEBUG_COMM_RTE) {
            Log.v(TAG, "onUpdateCommunicationRoute, mPreferredCommunicationDevice: "
            Log.v(TAG, "onUpdateCommunicationRoute, preferredCommunicationDevice: "
                    + mPreferredCommunicationDevice + " eventSource: " + eventSource);
                    + preferredCommunicationDevice + " eventSource: " + eventSource);
        }
        }
        AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
        AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
                "onUpdateCommunicationRoute, mPreferredCommunicationDevice: "
                "onUpdateCommunicationRoute, preferredCommunicationDevice: "
                + mPreferredCommunicationDevice + " eventSource: " + eventSource)));
                + preferredCommunicationDevice + " eventSource: " + eventSource)));


        if (mPreferredCommunicationDevice == null
        if (preferredCommunicationDevice == null
                || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(
                || preferredCommunicationDevice.getType() != AudioDeviceInfo.TYPE_BLUETOOTH_SCO) {
                        mPreferredCommunicationDevice.getInternalType())) {
            AudioSystem.setParameters("BT_SCO=off");
            AudioSystem.setParameters("BT_SCO=off");
        } else {
        } else {
            AudioSystem.setParameters("BT_SCO=on");
            AudioSystem.setParameters("BT_SCO=on");
        }
        }
        if (mPreferredCommunicationDevice == null) {
        if (preferredCommunicationDevice == null) {
            postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
            postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
        } else {
        } else {
            postSetPreferredDevicesForStrategy(
            postSetPreferredDevicesForStrategy(
                    mCommunicationStrategyId, Arrays.asList(mPreferredCommunicationDevice));
                    mCommunicationStrategyId, Arrays.asList(preferredCommunicationDevice));
        }
    }

    private void onUpdatePhoneStrategyDevice(AudioDeviceAttributes device) {
        synchronized (mSetModeLock) {
            synchronized (mDeviceStateLock) {
                boolean wasSpeakerphoneActive = isSpeakerphoneActive();
                mPreferredCommunicationDevice = device;
                updateActiveCommunicationDevice();
                if (wasSpeakerphoneActive != isSpeakerphoneActive()) {
                    try {
                        mContext.sendBroadcastAsUser(
                                new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
                                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
                                                  UserHandle.ALL);
                    } catch (Exception e) {
                        Log.w(TAG, "failed to broadcast ACTION_SPEAKERPHONE_STATE_CHANGED: " + e);
                    }
                }
                }
                mAudioService.postUpdateRingerModeServiceInt();
                mAudioService.postUpdateRingerModeServiceInt();
                dispatchCommunicationDevice();
                dispatchCommunicationDevice();
            }
            }
        }
    }


    private CommunicationRouteClient removeCommunicationRouteClient(
    private CommunicationRouteClient removeCommunicationRouteClient(
                    IBinder cb, boolean unregister) {
                    IBinder cb, boolean unregister) {
+3 −3
Original line number Original line Diff line number Diff line
@@ -4192,7 +4192,7 @@ public class AudioService extends IAudioService.Stub
        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
                || ringerMode == AudioManager.RINGER_MODE_SILENT;
                || ringerMode == AudioManager.RINGER_MODE_SILENT;
        final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE
        final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE
                && mDeviceBroker.isBluetoothScoOn();
                && mDeviceBroker.isBluetoothScoActive();
        // Ask audio policy engine to force use Bluetooth SCO channel if needed
        // Ask audio policy engine to force use Bluetooth SCO channel if needed
        final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid()
        final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid()
                + "/" + Binder.getCallingPid();
                + "/" + Binder.getCallingPid();
@@ -5600,7 +5600,7 @@ public class AudioService extends IAudioService.Stub
        switch (mPlatformType) {
        switch (mPlatformType) {
        case AudioSystem.PLATFORM_VOICE:
        case AudioSystem.PLATFORM_VOICE:
            if (isInCommunication()) {
            if (isInCommunication()) {
                if (mDeviceBroker.isBluetoothScoOn()) {
                if (mDeviceBroker.isBluetoothScoActive()) {
                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
                    return AudioSystem.STREAM_BLUETOOTH_SCO;
                    return AudioSystem.STREAM_BLUETOOTH_SCO;
                } else {
                } else {
@@ -5636,7 +5636,7 @@ public class AudioService extends IAudioService.Stub
            }
            }
        default:
        default:
            if (isInCommunication()) {
            if (isInCommunication()) {
                if (mDeviceBroker.isBluetoothScoOn()) {
                if (mDeviceBroker.isBluetoothScoActive()) {
                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
                    return AudioSystem.STREAM_BLUETOOTH_SCO;
                    return AudioSystem.STREAM_BLUETOOTH_SCO;
                } else {
                } else {