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

Commit dc8653b2 authored by Vlad Popa's avatar Vlad Popa
Browse files

AbsVol: send per device the abs volume state to APM

Sending the normal computed index to the AudioPolicyManager together
with the devices which are operating in absolute volume mode. The APM is
responsible for avoiding the double attenuation based on this
information.

Flag: com.android.media.audio.abs_volume_index_fix
Test: logs manual - DEBUG_VOL = true
Bug: 340693050
Change-Id: I9435723b0bc100f74553ff87c1407355117194b6
parent ae648c05
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -713,6 +713,19 @@ android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
            AudioSystem::getForceUse(static_cast<audio_policy_force_use_t>(usage)));
}

static jint android_media_AudioSystem_setDeviceAbsoluteVolumeEnabled(JNIEnv *env, jobject thiz,
                                                                     jint device, jstring address,
                                                                     jboolean enabled,
                                                                     jint stream) {
    const char *c_address = env->GetStringUTFChars(address, nullptr);
    int state = check_AudioSystem_Command(
            AudioSystem::setDeviceAbsoluteVolumeEnabled(static_cast<audio_devices_t>(device),
                                                        c_address, enabled,
                                                        static_cast<audio_stream_type_t>(stream)));
    env->ReleaseStringUTFChars(address, c_address);
    return state;
}

static jint
android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
{
@@ -3373,6 +3386,7 @@ static const JNINativeMethod gMethods[] =
         MAKE_AUDIO_SYSTEM_METHOD(setPhoneState),
         MAKE_AUDIO_SYSTEM_METHOD(setForceUse),
         MAKE_AUDIO_SYSTEM_METHOD(getForceUse),
         MAKE_AUDIO_SYSTEM_METHOD(setDeviceAbsoluteVolumeEnabled),
         MAKE_AUDIO_SYSTEM_METHOD(initStreamVolume),
         MAKE_AUDIO_SYSTEM_METHOD(setStreamVolumeIndex),
         MAKE_AUDIO_SYSTEM_METHOD(getStreamVolumeIndex),
+4 −0
Original line number Diff line number Diff line
@@ -1764,6 +1764,10 @@ public class AudioSystem
    public static native int getForceUse(int usage);
    /** @hide */
    @UnsupportedAppUsage
    public static native int setDeviceAbsoluteVolumeEnabled(int nativeDeviceType,
            @NonNull String address, boolean enabled, int streamToDriveAbs);
    /** @hide */
    @UnsupportedAppUsage
    public static native int initStreamVolume(int stream, int indexMin, int indexMax);
    @UnsupportedAppUsage
    private static native int setStreamVolumeIndex(int stream, int index, int device);
+123 −22
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.media.audio.Flags.absVolumeIndexFix;
import static com.android.media.audio.Flags.alarmMinVolumeZero;
import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume;
import static com.android.media.audio.Flags.ringerModeAffectsAlarm;
@@ -632,6 +633,17 @@ public class AudioService extends IAudioService.Stub
    // If absolute volume is supported in AVRCP device
    private volatile boolean mAvrcpAbsVolSupported = false;
    private final Object mCachedAbsVolDrivingStreamsLock = new Object();
    // Contains for all the device types which support absolute volume the current streams that
    // are driving the volume changes
    @GuardedBy("mCachedAbsVolDrivingStreamsLock")
    private final HashMap<Integer, Integer> mCachedAbsVolDrivingStreams = new HashMap<>(
            Map.of(AudioSystem.DEVICE_OUT_BLE_HEADSET, AudioSystem.STREAM_MUSIC,
                    AudioSystem.DEVICE_OUT_BLE_SPEAKER, AudioSystem.STREAM_MUSIC,
                    AudioSystem.DEVICE_OUT_BLE_BROADCAST, AudioSystem.STREAM_MUSIC,
                    AudioSystem.DEVICE_OUT_HEARING_AID, AudioSystem.STREAM_MUSIC
            ));
    /**
    * Default stream type used for volume control in the absence of playback
    * e.g. user on homescreen, no app playing anything, presses hardware volume buttons, this
@@ -1472,6 +1484,13 @@ public class AudioService extends IAudioService.Stub
        // check on volume initialization
        checkVolumeRangeInitialization("AudioService()");
        synchronized (mCachedAbsVolDrivingStreamsLock) {
            mCachedAbsVolDrivingStreams.forEach((dev, stream) -> {
                mAudioSystem.setDeviceAbsoluteVolumeEnabled(dev, /*address=*/"", /*enabled=*/true,
                        stream);
            });
        }
    }
    private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener =
@@ -1911,6 +1930,14 @@ public class AudioService extends IAudioService.Stub
        }
        onIndicateSystemReady();
        synchronized (mCachedAbsVolDrivingStreamsLock) {
            mCachedAbsVolDrivingStreams.forEach((dev, stream) -> {
                mAudioSystem.setDeviceAbsoluteVolumeEnabled(dev, /*address=*/"", /*enabled=*/true,
                        stream);
            });
        }
        // indicate the end of reconfiguration phase to audio HAL
        AudioSystem.setParameters("restarting=false");
@@ -3737,8 +3764,10 @@ public class AudioService extends IAudioService.Stub
            int newIndex = mStreamStates[streamType].getIndex(device);
            int streamToDriveAbsVol = absVolumeIndexFix() ? getBluetoothContextualVolumeStream() :
                    AudioSystem.STREAM_MUSIC;
            // Check if volume update should be send to AVRCP
            if (streamTypeAlias == AudioSystem.STREAM_MUSIC
            if (streamTypeAlias == streamToDriveAbsVol
                    && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
                    && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                if (DEBUG_VOL) {
@@ -4540,6 +4569,8 @@ public class AudioService extends IAudioService.Stub
                + scoManagedByAudio());
        pw.println("\tcom.android.media.audio.vgsVssSyncMuteOrder:"
                + vgsVssSyncMuteOrder());
        pw.println("\tcom.android.media.audio.absVolumeIndexFix:"
                + absVolumeIndexFix());
    }
    private void dumpAudioMode(PrintWriter pw) {
@@ -4735,7 +4766,9 @@ public class AudioService extends IAudioService.Stub
            }
        }
        if (streamTypeAlias == AudioSystem.STREAM_MUSIC
        int streamToDriveAbsVol = absVolumeIndexFix() ? getBluetoothContextualVolumeStream() :
                AudioSystem.STREAM_MUSIC;
        if (streamTypeAlias == streamToDriveAbsVol
                && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)
                && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
            if (DEBUG_VOL) {
@@ -6184,6 +6217,17 @@ public class AudioService extends IAudioService.Stub
                setLeAudioVolumeOnModeUpdate(mode, device, streamAlias, index, maxIndex);
                synchronized (mCachedAbsVolDrivingStreamsLock) {
                    mCachedAbsVolDrivingStreams.replaceAll((absDev, stream) -> {
                        int streamToDriveAbs = getBluetoothContextualVolumeStream();
                        if (stream != streamToDriveAbs) {
                            mAudioSystem.setDeviceAbsoluteVolumeEnabled(absDev, /*address=*/
                                    "", /*enabled*/true, streamToDriveAbs);
                        }
                        return streamToDriveAbs;
                    });
                }
                // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
                // connections not started by the application changing the mode when pid changes
                mDeviceBroker.postSetModeOwner(mode, pid, uid);
@@ -8105,6 +8149,10 @@ public class AudioService extends IAudioService.Stub
            return mAudioVolumeGroup.name();
        }
        public int getId() {
            return mAudioVolumeGroup.getId();
        }
        /**
         * Volume group with non null minimum index are considered as non mutable, thus
         * bijectivity is broken with potential associated stream type.
@@ -8755,12 +8803,17 @@ public class AudioService extends IAudioService.Stub
        }
        private int getAbsoluteVolumeIndex(int index) {
            if (absVolumeIndexFix()) {
                // The attenuation is applied in the APM. No need to manipulate the index here
                return index;
            } else {
                /* Special handling for Bluetooth Absolute Volume scenario
                 * If we send full audio gain, some accessories are too loud even at its lowest
                 * volume. We are not able to enumerate all such accessories, so here is the
                 * workaround from phone side.
                 * Pre-scale volume at lowest volume steps 1 2 and 3.
             * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
                 * For volume step 0, set audio gain to 0 as some accessories won't mute on their
                 * end.
                 */
                if (index == 0) {
                    // 0% for volume 0
@@ -8774,6 +8827,7 @@ public class AudioService extends IAudioService.Stub
                }
                return index;
            }
        }
        private void setStreamVolumeIndex(int index, int device) {
            // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
@@ -8783,6 +8837,11 @@ public class AudioService extends IAudioService.Stub
                    && !isFullyMuted()) {
                index = 1;
            }
            if (DEBUG_VOL) {
                Log.d(TAG, "setStreamVolumeIndexAS(" + mStreamType + ", " + index + ", " + device
                        + ")");
            }
            mAudioSystem.setStreamVolumeIndexAS(mStreamType, index, device);
        }
@@ -8794,14 +8853,24 @@ public class AudioService extends IAudioService.Stub
            } else if (isAbsoluteVolumeDevice(device)
                    || isA2dpAbsoluteVolumeDevice(device)
                    || AudioSystem.isLeAudioDeviceType(device)) {
                // do not change the volume logic for dynamic abs behavior devices like HDMI
                if (absVolumeIndexFix() && isAbsoluteVolumeDevice(device)) {
                    index = getAbsoluteVolumeIndex((mIndexMax + 5) / 10);
                } else {
                    index = getAbsoluteVolumeIndex((getIndex(device) + 5) / 10);
                }
            } else if (isFullVolumeDevice(device)) {
                index = (mIndexMax + 5)/10;
            } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                if (absVolumeIndexFix()) {
                    index = getAbsoluteVolumeIndex((getIndex(device) + 5) / 10);
                } else {
                    index = (mIndexMax + 5) / 10;
                }
            } else {
                index = (getIndex(device) + 5)/10;
            }
            setStreamVolumeIndex(index, device);
        }
@@ -8819,11 +8888,22 @@ public class AudioService extends IAudioService.Stub
                                || isA2dpAbsoluteVolumeDevice(device)
                                || AudioSystem.isLeAudioDeviceType(device)) {
                            isAbsoluteVolume = true;
                            // do not change the volume logic for dynamic abs behavior devices
                            // like HDMI
                            if (absVolumeIndexFix() && isAbsoluteVolumeDevice(device)) {
                                index = getAbsoluteVolumeIndex((mIndexMax + 5) / 10);
                            } else {
                                index = getAbsoluteVolumeIndex((getIndex(device) + 5) / 10);
                            }
                        } else if (isFullVolumeDevice(device)) {
                            index = (mIndexMax + 5)/10;
                        } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) {
                            if (absVolumeIndexFix()) {
                                isAbsoluteVolume = true;
                                index = getAbsoluteVolumeIndex((getIndex(device) + 5) / 10);
                            } else {
                                index = (mIndexMax + 5) / 10;
                            }
                        } else {
                            index = (mIndexMap.valueAt(i) + 5)/10;
                        }
@@ -9820,6 +9900,27 @@ public class AudioService extends IAudioService.Stub
    /*package*/ void setAvrcpAbsoluteVolumeSupported(boolean support) {
        mAvrcpAbsVolSupported = support;
        if (absVolumeIndexFix()) {
            int a2dpDev = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
            synchronized (mCachedAbsVolDrivingStreamsLock) {
                mCachedAbsVolDrivingStreams.compute(a2dpDev, (dev, stream) -> {
                    if (stream != null && !mAvrcpAbsVolSupported) {
                        mAudioSystem.setDeviceAbsoluteVolumeEnabled(a2dpDev, /*address=*/
                                "", /*enabled*/false, AudioSystem.DEVICE_NONE);
                        return null;
                    }
                    // For A2DP and AVRCP we need to set the driving stream based on the
                    // BT contextual stream. Hence, we need to make sure in adjustStreamVolume
                    // and setStreamVolume that the driving abs volume stream is consistent.
                    int streamToDriveAbs = getBluetoothContextualVolumeStream();
                    if (stream == null || stream != streamToDriveAbs) {
                        mAudioSystem.setDeviceAbsoluteVolumeEnabled(a2dpDev, /*address=*/
                                "", /*enabled*/true, streamToDriveAbs);
                    }
                    return streamToDriveAbs;
                });
            }
        }
        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
+15 −0
Original line number Diff line number Diff line
@@ -597,6 +597,21 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback,
        return AudioSystem.getForceUse(usage);
    }

    /**
     * Same as {@link AudioSystem#setDeviceAbsoluteVolumeEnabled(int, String, boolean, int)}
     * @param nativeDeviceType the internal device type for which absolute volume is
     *                         enabled/disabled
     * @param address the address of the device for which absolute volume is enabled/disabled
     * @param enabled whether the absolute volume is enabled/disabled
     * @param streamToDriveAbs the stream that is controlling the absolute volume
     * @return status of indicating the success of this operation
     */
    public int setDeviceAbsoluteVolumeEnabled(int nativeDeviceType, @NonNull String address,
            boolean enabled, int streamToDriveAbs) {
        return AudioSystem.setDeviceAbsoluteVolumeEnabled(nativeDeviceType, address, enabled,
                streamToDriveAbs);
    }

    /**
     * Same as {@link AudioSystem#registerPolicyMixes(ArrayList, boolean)}
     * @param mixes
+3 −1
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import static android.view.KeyEvent.ACTION_DOWN;
import static android.view.KeyEvent.KEYCODE_VOLUME_UP;

import static com.android.media.audio.Flags.FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME;
import static com.android.media.audio.Flags.FLAG_ABS_VOLUME_INDEX_FIX;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -552,7 +553,7 @@ public class VolumeHelperTest {
    }

    @Test
    @RequiresFlagsDisabled(FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME)
    @RequiresFlagsDisabled({FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME, FLAG_ABS_VOLUME_INDEX_FIX})
    public void configurablePreScaleAbsoluteVolume_checkIndex() throws Exception {
        final int minIndex = mAm.getStreamMinVolume(STREAM_MUSIC);
        final int maxIndex = mAm.getStreamMaxVolume(STREAM_MUSIC);
@@ -607,6 +608,7 @@ public class VolumeHelperTest {

    @Test
    @RequiresFlagsEnabled(FLAG_DISABLE_PRESCALE_ABSOLUTE_VOLUME)
    @RequiresFlagsDisabled(FLAG_ABS_VOLUME_INDEX_FIX)
    public void disablePreScaleAbsoluteVolume_checkIndex() throws Exception {
        final int minIndex = mAm.getStreamMinVolume(STREAM_MUSIC);
        final int maxIndex = mAm.getStreamMaxVolume(STREAM_MUSIC);