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

Commit fca1e603 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

Remote volume changes

When the user plays media remotely, and presses on the volume
 keys with the screen off, verify whether not only local playback
 is active, but also if remote playback is active to see if
 the volume should be adjusted.
When adjusting the volume with screen off, adjust the remote
 volume if applicable.

When controlling volume, give priority to local media playback.

Bug 11169862

Change-Id: I88a8c003969177d50d4c1569ec6cd2a7c153a341
parent 5bd70c5e
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -1570,6 +1570,24 @@ public class AudioManager {
        return AudioSystem.isStreamActiveRemotely(STREAM_MUSIC, 0);
    }

    /**
     * @hide
     * Checks whether any local or remote media playback is active.
     * Local playback refers to playback for instance on the device's speakers or wired headphones.
     * Remote playback refers to playback for instance on a wireless display mirroring the
     *    devices's, or on a device using a Cast-like protocol.
     * @return true if media playback, from which the device is aware, is active.
     */
    public boolean isLocalOrRemoteMusicActive() {
        IAudioService service = getService();
        try {
            return service.isLocalOrRemoteMusicActive();
        } catch (RemoteException e) {
            Log.e(TAG, "Dead object in isLocalOrRemoteMusicActive()", e);
            return false;
        }
    }

    /**
     * @hide
     * Checks whether the current audio focus is exclusive.
+56 −23
Original line number Diff line number Diff line
@@ -751,6 +751,26 @@ public class AudioService extends IAudioService.Stub {
    ///////////////////////////////////////////////////////////////////////////
    // IPC methods
    ///////////////////////////////////////////////////////////////////////////
    /** @see AudioManager#isLocalOrRemoteMusicActive() */
    public boolean isLocalOrRemoteMusicActive() {
        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
            // local / wired / BT playback active
            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
            return true;
        }
        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
            // remote "cast-like" playback active
            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
            return true;
        }
        if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
            // remote submix playback active
            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
            return true;
        }
        if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
        return false;
    }

    /** @see AudioManager#adjustVolume(int, int) */
    public void adjustVolume(int direction, int flags, String callingPackage) {
@@ -763,10 +783,10 @@ public class AudioService extends IAudioService.Stub {
    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
            String callingPackage) {
        if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
        } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage);
        } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
        }
    }

@@ -2612,6 +2632,17 @@ public class AudioService extends IAudioService.Stub {
        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
    }

    /**
     * For code clarity for getActiveStreamType(int)
     * @param delay_ms max time since last STREAM_MUSIC activity to consider
     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
     *     in the last "delay_ms" ms.
     */
    private boolean isAfMusicActiveRecently(int delay_ms) {
        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
    }

    private int getActiveStreamType(int suggestedStreamType) {
        if (mVoiceCapable) {
            if (isInCommunication()) {
@@ -2624,23 +2655,22 @@ public class AudioService extends IAudioService.Stub {
                    return AudioSystem.STREAM_VOICE_CALL;
                }
            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
                // volume can have priority over STREAM_MUSIC
                if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
                    if (DEBUG_VOL)
                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
                    return STREAM_REMOTE_MUSIC;
                } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC,
                            DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
                    if (DEBUG_VOL)
                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
                    return AudioSystem.STREAM_MUSIC;
                } else
                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
                    {
                        if (DEBUG_VOL)
                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
                        return STREAM_REMOTE_MUSIC;
                    } else {
                        if (DEBUG_VOL)
                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
                        return AudioSystem.STREAM_RING;
                }
            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
            } else if (isAfMusicActiveRecently(0)) {
                if (DEBUG_VOL)
                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
                return AudioSystem.STREAM_MUSIC;
@@ -2666,14 +2696,17 @@ public class AudioService extends IAudioService.Stub {
                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
                return AudioSystem.STREAM_NOTIFICATION;
            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
                if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
                    // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
                    // volume can have priority over STREAM_MUSIC
                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
                    return AudioSystem.STREAM_MUSIC;
                } else
                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
                    {
                        if (DEBUG_VOL)
                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
                        return STREAM_REMOTE_MUSIC;
                } else {
                    if (DEBUG_VOL)
                        Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
                    return AudioSystem.STREAM_MUSIC;
                }
            } else {
+2 −0
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ interface IAudioService {

    void adjustVolume(int direction, int flags, String callingPackage);

    boolean isLocalOrRemoteMusicActive();

    oneway void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
            String callingPackage);

+23 −11
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.Ringtone;
import android.media.RingtoneManager;
@@ -3645,7 +3646,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }

    /**
     * @return Whether music is being played right now.
     * @return Whether music is being played right now "locally" (e.g. on the device's speakers
     *    or wired headphones) or "remotely" (e.g. on a device using the Cast protocol and
     *    controlled by this device, or through remote submix).
     */
    boolean isMusicActive() {
        final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
@@ -3653,7 +3656,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
            return false;
        }
        return am.isMusicActive();
        return am.isLocalOrRemoteMusicActive();
    }

    /**
@@ -3666,19 +3669,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            return;
        }
        try {
            // since audio is playing, we shouldn't have to hold a wake lock
            // when audio is playing locally, we shouldn't have to hold a wake lock
            // during the call, but we do it as a precaution for the rare possibility
            // that the music stops right before we call this
            // that the music stops right before we call this.
            // Otherwise we might also be in a remote playback case.
            // TODO: Actually handle MUTE.
            mBroadcastWakeLock.acquire();
            if (stream == AudioSystem.STREAM_MUSIC) {
                audioService.adjustLocalOrRemoteStreamVolume(stream,
                        keycode == KeyEvent.KEYCODE_VOLUME_UP
                                ? AudioManager.ADJUST_RAISE
                                : AudioManager.ADJUST_LOWER,
                        mContext.getOpPackageName());
            } else {
                audioService.adjustStreamVolume(stream,
                        keycode == KeyEvent.KEYCODE_VOLUME_UP
                                ? AudioManager.ADJUST_RAISE
                                : AudioManager.ADJUST_LOWER,
                        0,
                        mContext.getOpPackageName());
            }
        } catch (RemoteException e) {
            Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e);
            Log.w(TAG, "IAudioService.adjust*StreamVolume() threw RemoteException " + e);
        } finally {
            mBroadcastWakeLock.release();
        }