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

Commit 84e9721f authored by Jan Sebechlebsky's avatar Jan Sebechlebsky
Browse files

Bypass audio focus handling for VDM

When VirtualDevice is configured with custom
device policy for audio, the audio tied to device
specific session id is likely rerouted to loopback
and streamed to different destination.

In this situation it's not desired that the playback
on VDM affects playback on the native device and vice-versa.

This change modifies AudioManager so the requests for audio
focus are ignored for VDM playback. This allows apps to write
universal code for focus-aware audio playback which will behave
correctly on native and virtual devices.

Bug: 261698699
Bug: 249777386
Test: atest AudioFocusTest
Change-Id: If48d841cb64b66d7d08e62bcbb9179fab5910aaa
parent 714a0f90
Loading
Loading
Loading
Loading
+32 −11
Original line number Diff line number Diff line
@@ -105,6 +105,7 @@ public class AudioManager {

    private Context mOriginalContext;
    private Context mApplicationContext;
    private int mOriginalContextDeviceId = DEVICE_ID_DEFAULT;
    private @Nullable VirtualDeviceManager mVirtualDeviceManager; // Lazy initialized.
    private long mVolumeKeyUpTime;
    private static final String TAG = "AudioManager";
@@ -844,6 +845,7 @@ public class AudioManager {
    }

    private void setContext(Context context) {
        mOriginalContextDeviceId = context.getDeviceId();
        mApplicationContext = context.getApplicationContext();
        if (mApplicationContext != null) {
            mOriginalContext = null;
@@ -3794,7 +3796,7 @@ public class AudioManager {
    }

    /**
     * Checks whether this {@link AudioManager} instance is asociated with {@link VirtualDevice}
     * Checks whether this {@link AudioManager} instance is associated with {@link VirtualDevice}
     * configured with custom device policy for audio. If there is such device, request to play
     * sound effect is forwarded to {@link VirtualDeviceManager}.
     *
@@ -3803,18 +3805,24 @@ public class AudioManager {
     * false otherwise.
     */
    private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) {
        int deviceId = getContext().getDeviceId();
        if (deviceId != DEVICE_ID_DEFAULT) {
        if (hasCustomPolicyVirtualDeviceContext()) {
            VirtualDeviceManager vdm = getVirtualDeviceManager();
            if (vdm != null && vdm.getDevicePolicy(deviceId, POLICY_TYPE_AUDIO)
                    != DEVICE_POLICY_DEFAULT) {
                vdm.playSoundEffect(deviceId, effectType);
            vdm.playSoundEffect(mOriginalContextDeviceId, effectType);
            return true;
        }
        return false;
    }

    private boolean hasCustomPolicyVirtualDeviceContext() {
        if (mOriginalContextDeviceId == DEVICE_ID_DEFAULT) {
            return false;
        }

        VirtualDeviceManager vdm = getVirtualDeviceManager();
        return vdm != null && vdm.getDevicePolicy(mOriginalContextDeviceId, POLICY_TYPE_AUDIO)
                != DEVICE_POLICY_DEFAULT;
    }

    /**
     *  Load Sound effects.
     *  This method must be called when sound effects are enabled.
@@ -4513,6 +4521,16 @@ public class AudioManager {
            throw new IllegalArgumentException(
                    "Illegal null audio policy when locking audio focus");
        }

        if (hasCustomPolicyVirtualDeviceContext()) {
            // If the focus request was made within context associated with VirtualDevice
            // configured with custom device policy for audio, bypass audio service focus handling.
            // The custom device policy for audio means that audio associated with this device
            // is likely rerouted to VirtualAudioDevice and playback on the VirtualAudioDevice
            // shouldn't affect non-virtual audio tracks (and vice versa).
            return AUDIOFOCUS_REQUEST_GRANTED;
        }

        registerAudioFocusRequest(afr);
        final IAudioService service = getService();
        final int status;
@@ -4785,16 +4803,19 @@ public class AudioManager {
    @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
    // have been done by a matching requestAudioFocus
    public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
        int status = AUDIOFOCUS_REQUEST_FAILED;
        if (hasCustomPolicyVirtualDeviceContext()) {
            // If this AudioManager instance is running within VirtualDevice context configured
            // with custom device policy for audio, the audio focus handling is bypassed.
            return AUDIOFOCUS_REQUEST_GRANTED;
        }
        unregisterAudioFocusRequest(l);
        final IAudioService service = getService();
        try {
            status = service.abandonAudioFocus(mAudioFocusDispatcher,
            return service.abandonAudioFocus(mAudioFocusDispatcher,
                    getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return status;
    }

    //====================================================================