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

Commit c78b49af authored by Eric Laurent's avatar Eric Laurent
Browse files

Audio: use preferred device for strategy for communication route

Replaced use of forced usage for communication by set preferred device
for strategy to control communication route in audio policy manager.

Also do not use forced usage for record which was redundant with forced
usage for communication.

Bug: 161358428
Test: audio smoke tests

Change-Id: I665257fc5903b663096104b0424781d9799635a5
parent 202c7f64
Loading
Loading
Loading
Loading
+18 −10
Original line number Diff line number Diff line
@@ -298,20 +298,25 @@ static sp<JNIAudioPortCallback> setJniCallback(JNIEnv* env,
    return old;
}

#define check_AudioSystem_Command(status) _check_AudioSystem_Command(__func__, (status))
#define check_AudioSystem_Command(...) _check_AudioSystem_Command(__func__, __VA_ARGS__)

static int _check_AudioSystem_Command(const char* caller, status_t status)
{
    ALOGE_IF(status, "Command failed for %s: %d", caller, status);
static int _check_AudioSystem_Command(const char *caller, status_t status,
                                      std::vector<status_t> ignoredErrors = {}) {
    int jniStatus = kAudioStatusOk;
    switch (status) {
    case DEAD_OBJECT:
        return kAudioStatusMediaServerDied;
        jniStatus = kAudioStatusMediaServerDied;
        break;
    case NO_ERROR:
        return kAudioStatusOk;
        break;
    default:
        if (std::find(begin(ignoredErrors), end(ignoredErrors), status) == end(ignoredErrors)) {
            jniStatus = kAudioStatusError;
        }
        break;
    }
    return kAudioStatusError;
    ALOGE_IF(jniStatus != kAudioStatusOk, "Command failed for %s: %d", caller, status);
    return jniStatus;
}

static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes,
@@ -2350,9 +2355,12 @@ static jint android_media_AudioSystem_setDevicesRoleForStrategy(JNIEnv *env, job

static jint android_media_AudioSystem_removeDevicesRoleForStrategy(JNIEnv *env, jobject thiz,
                                                                   jint strategy, jint role) {
    return (jint)check_AudioSystem_Command(
            AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)strategy,
                                                      (device_role_t)role));
    return (jint)
            check_AudioSystem_Command(AudioSystem::removeDevicesRoleForStrategy((product_strategy_t)
                                                                                        strategy,
                                                                                (device_role_t)
                                                                                        role),
                                      {NAME_NOT_FOUND});
}

static jint android_media_AudioSystem_getDevicesForRoleAndStrategy(JNIEnv *env, jobject thiz,
+9 −5
Original line number Diff line number Diff line
@@ -120,7 +120,13 @@ public final class AudioDeviceAttributes implements Parcelable {
        mAddress = address;
    }

    /*package*/ AudioDeviceAttributes(int nativeType, @NonNull String address) {
    /**
     * @hide
     * Constructor from internal device type and address
     * @param type the internal device type, as defined in {@link AudioSystem}
     * @param address the address of the device, or an empty string for devices without one
     */
    public AudioDeviceAttributes(int nativeType, @NonNull String address) {
        mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
        mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
        mAddress = address;
@@ -191,10 +197,8 @@ public final class AudioDeviceAttributes implements Parcelable {
    public String toString() {
        return new String("AudioDeviceAttributes:"
                + " role:" + roleToString(mRole)
                + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(
                        AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType))
                        : AudioSystem.getInputDeviceName(
                                AudioDeviceInfo.convertDeviceTypeToInternalDevice(mType)))
                + " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
                        : AudioSystem.getInputDeviceName(mNativeType))
                + " addr:" + mAddress);
    }

+1 −1
Original line number Diff line number Diff line
@@ -1730,7 +1730,7 @@ public class AudioSystem
        int[] types = new int[devices.size()];
        String[] addresses = new String[devices.size()];
        for (int i = 0; i < devices.size(); ++i) {
            types[i] = AudioDeviceInfo.convertDeviceTypeToInternalDevice(devices.get(i).getType());
            types[i] = devices.get(i).getInternalType();
            addresses[i] = devices.get(i).getAddress();
        }
        return setDevicesRoleForStrategy(strategy, role, types, addresses);
+93 −37
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.server.audio;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHeadset;
@@ -34,6 +35,7 @@ import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.MediaMetrics;
import android.media.audiopolicy.AudioProductStrategy;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -51,6 +53,7 @@ import android.util.PrintWriterPrinter;
import com.android.internal.annotations.GuardedBy;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -77,7 +80,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
    private final @NonNull Context mContext;

    /** Forced device usage for communications sent to AudioSystem */
    private int mForcedUseForComm;
    private AudioDeviceAttributes mPreferredDeviceforComm;
    private int mCommunicationStrategyId = -1;

    // Manages all connected devices, only ever accessed on the message loop
    private final AudioDeviceInventory mDeviceInventory;
@@ -133,10 +137,23 @@ import java.util.concurrent.atomic.AtomicBoolean;
        init();
    }

    private void initCommunicationStrategyId() {
        List<AudioProductStrategy> strategies = AudioProductStrategy.getAudioProductStrategies();
        for (AudioProductStrategy strategy : strategies) {
            if (strategy.getAudioAttributesForLegacyStreamType(AudioSystem.STREAM_VOICE_CALL)
                    != null) {
                mCommunicationStrategyId = strategy.getId();
                return;
            }
        }
        mCommunicationStrategyId = -1;
    }

    private void init() {
        setupMessaging(mContext);

        mForcedUseForComm = AudioSystem.FORCE_NONE;
        mPreferredDeviceforComm = null;
        initCommunicationStrategyId();
    }

    /*package*/ Context getContext() {
@@ -221,8 +238,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
            synchronized (mDeviceStateLock) {
                AudioDeviceAttributes device = null;
                if (on) {
                    device = new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
                            AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
                    device = new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_SPEAKER, "");
                } else {
                    CommunicationRouteClient client = getCommunicationRouteClientForPid(pid);
                    if (client == null || !client.requestsSpeakerphone()) {
@@ -275,6 +291,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
        if (AudioService.DEBUG_COMM_RTE) {
            Log.v(TAG, "setCommunicationRouteForClient: device: " + device);
        }
        AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
                                        "setCommunicationRouteForClient for pid: " + pid
                                        + " device: " + device
                                        + " from API: " + eventSource)).printLog(TAG));

        final boolean wasBtScoRequested = isBluetoothScoRequested();
        final boolean wasSpeakerphoneRequested = isSpeakerphoneRequested();
@@ -393,7 +413,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
     * @return true if speakerphone is active, false otherwise.
     */
    /*package*/ boolean isSpeakerphoneOn() {
        return getForcedUseForComm() == AudioSystem.FORCE_SPEAKER;
        AudioDeviceAttributes device = getPreferredDeviceForComm();
        if (device == null) {
            return false;
        }
        return device.getInternalType() == AudioSystem.DEVICE_OUT_SPEAKER;
    }

    /**
@@ -560,7 +584,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
     * @return true if Bluetooth SCO is active , false otherwise.
     */
    /*package*/ boolean isBluetoothScoOn() {
        return getForcedUseForComm() == AudioSystem.FORCE_BT_SCO;
        AudioDeviceAttributes device = getPreferredDeviceForComm();
        if (device == null) {
            return false;
        }
        return AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType());
    }

    /*package*/ AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
@@ -612,8 +640,8 @@ import java.util.concurrent.atomic.AtomicBoolean;

        synchronized (mSetModeLock) {
            synchronized (mDeviceStateLock) {
                AudioDeviceAttributes device = new AudioDeviceAttributes(
                        AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BLUETOOTH_SCO, "");
                AudioDeviceAttributes device =
                        new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, "");
                setCommunicationRouteForClient(cb, pid, device, scoAudioMode, eventSource);
            }
        }
@@ -643,10 +671,19 @@ import java.util.concurrent.atomic.AtomicBoolean;
        return mDeviceInventory.setPreferredDevicesForStrategySync(strategy, devices);
    }

    /*package*/ void postSetPreferredDevicesForStrategy(int strategy,
            @NonNull List<AudioDeviceAttributes> devices) {
        sendILMsgNoDelay(MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy, devices);
    }

    /*package*/ int removePreferredDevicesForStrategySync(int strategy) {
        return mDeviceInventory.removePreferredDevicesForStrategySync(strategy);
    }

    /*package*/ void postRemovePreferredDevicesForStrategy(int strategy) {
        sendIMsgNoDelay(MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY, SENDMSG_REPLACE, strategy);
    }

    /*package*/ void registerStrategyPreferredDevicesDispatcher(
            @NonNull IStrategyPreferredDevicesDispatcher dispatcher) {
        mDeviceInventory.registerStrategyPreferredDevicesDispatcher(dispatcher);
@@ -971,9 +1008,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
            pw.println("  " + prefix + "pid: " + cl.getPid() + " device: "
                        + cl.getDevice() + " cb: " + cl.getBinder()); });

        pw.println("\n" + prefix + "mForcedUseForComm: "
                +  AudioSystem.forceUseConfigToString(mForcedUseForComm));
        pw.println(prefix + "mModeOwnerPid: " + mModeOwnerPid);
        pw.println("\n" + prefix + "mPreferredDeviceforComm: "
                +  mPreferredDeviceforComm);
        pw.println(prefix + "mCommunicationStrategyId: "
                +  mCommunicationStrategyId);

        pw.println("\n" + prefix + "mModeOwnerPid: " + mModeOwnerPid);

        mBtHelper.dump(pw, prefix);
    }
@@ -1068,6 +1108,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
                case MSG_RESTORE_DEVICES:
                    synchronized (mSetModeLock) {
                        synchronized (mDeviceStateLock) {
                            initCommunicationStrategyId();
                            mDeviceInventory.onRestoreDevices();
                            mBtHelper.onAudioServerDiedRestoreA2dp();
                            onUpdateCommunicationRoute("MSG_RESTORE_DEVICES");
@@ -1277,6 +1318,17 @@ import java.util.concurrent.atomic.AtomicBoolean;
                    final int strategy = msg.arg1;
                    mDeviceInventory.onSaveRemovePreferredDevices(strategy);
                } break;
                case MSG_IL_SET_PREF_DEVICES_FOR_STRATEGY: {
                    final int strategy = msg.arg1;
                    final List<AudioDeviceAttributes> devices =
                            (List<AudioDeviceAttributes>) msg.obj;
                    setPreferredDevicesForStrategySync(strategy, devices);

                } break;
                case MSG_I_REMOVE_PREF_DEVICES_FOR_STRATEGY: {
                    final int strategy = msg.arg1;
                    removePreferredDevicesForStrategySync(strategy);
                } break;
                case MSG_CHECK_MUTE_MUSIC:
                    checkMessagesMuteMusic(0);
                    break;
@@ -1369,7 +1421,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
    private static final int MSG_I_SAVE_CLEAR_PREF_DEVICES_FOR_CAPTURE_PRESET = 38;

    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 boolean isMessageHandledUnderWakelock(int msgId) {
        switch(msgId) {
@@ -1609,16 +1662,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
     * @return selected forced usage for communication.
     */
    @GuardedBy("mDeviceStateLock")
    private int getForcedUseForComm() {
    @Nullable private AudioDeviceAttributes getPreferredDeviceForComm() {
        boolean btSCoOn = mBluetoothScoOn && mBtHelper.isBluetoothScoOn();

        if (btSCoOn) {
            return AudioSystem.FORCE_BT_SCO;
            // Use the SCO device known to BtHelper so that it matches exactly
            // what has been communicated to audio policy manager. The device
            // returned by requestedCommunicationDevice() can be a dummy SCO device if legacy
            // APIs are used to start SCO audio.
            AudioDeviceAttributes device = mBtHelper.getHeadsetAudioDevice();
            if (device != null) {
                return device;
            }
        if (isSpeakerphoneRequested()) {
            return AudioSystem.FORCE_SPEAKER;
        }
        return AudioSystem.FORCE_NONE;
        AudioDeviceAttributes device = requestedCommunicationDevice();
        if (device == null
                || AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(device.getInternalType())) {
            // Do not indicate BT SCO selection if SCO is requested but SCO is not ON
            return null;
        }
        return device;
    }

    /**
@@ -1628,30 +1690,24 @@ import java.util.concurrent.atomic.AtomicBoolean;
    // @GuardedBy("mSetModeLock")
    @GuardedBy("mDeviceStateLock")
    private void onUpdateCommunicationRoute(String eventSource) {
        mForcedUseForComm = getForcedUseForComm();

        mPreferredDeviceforComm = getPreferredDeviceForComm();
        if (AudioService.DEBUG_COMM_RTE) {
            Log.v(TAG, "onUpdateCommunicationRoute, mForcedUseForComm: " + mForcedUseForComm
                    + " eventSource: " + eventSource);
            Log.v(TAG, "onUpdateCommunicationRoute, mPreferredDeviceforComm: "
                    + mPreferredDeviceforComm + " eventSource: " + eventSource);
        }

        if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
            AudioSystem.setParameters("BT_SCO=on");
            setForceUse_Async(
                    AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO, eventSource);
            setForceUse_Async(
                    AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO, eventSource);
        } else {
        if (mPreferredDeviceforComm == null
                || !AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(
                        mPreferredDeviceforComm.getInternalType())) {
            AudioSystem.setParameters("BT_SCO=off");
            setForceUse_Async(
                    AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, eventSource);
            if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
                setForceUse_Async(
                        AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER, eventSource);
        } else {
                setForceUse_Async(
                        AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE, eventSource);
            AudioSystem.setParameters("BT_SCO=on");
        }
        if (mPreferredDeviceforComm == null) {
            postRemovePreferredDevicesForStrategy(mCommunicationStrategyId);
        } else {
            postSetPreferredDevicesForStrategy(
                    mCommunicationStrategyId, Arrays.asList(mPreferredDeviceforComm));
        }
        mAudioService.postUpdateRingerModeServiceInt();
        dispatchCommunicationDevice();
+4 −0
Original line number Diff line number Diff line
@@ -648,6 +648,10 @@ public class AudioDeviceInventory {
    /*package*/ int setPreferredDevicesForStrategySync(int strategy,
            @NonNull List<AudioDeviceAttributes> devices) {
        final long identity = Binder.clearCallingIdentity();

        AudioService.sDeviceLogger.log((new AudioEventLogger.StringEvent(
                                "setPreferredDevicesForStrategySync, strategy: " + strategy
                                + " devices: " + devices)).printLog(TAG));
        final int status = mAudioSystem.setDevicesRoleForStrategy(
                strategy, AudioSystem.DEVICE_ROLE_PREFERRED, devices);
        Binder.restoreCallingIdentity(identity);
Loading