diff options
5 files changed, 159 insertions, 23 deletions
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index d48cdc4645c6..eaff7608ce3b 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -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), diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 293c561f166c..d148afd3c15d 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -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); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 2a23b9ca522e..68347a085be1 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -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,24 +8803,30 @@ public class AudioService extends IAudioService.Stub } private int getAbsoluteVolumeIndex(int index) { - /* 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. - */ - if (index == 0) { - // 0% for volume 0 - index = 0; - } else if (!disablePrescaleAbsoluteVolume() && index > 0 && index <= 3) { - // Pre-scale for volume steps 1 2 and 3 - index = (int) (mIndexMax * mPrescaleAbsoluteVolume[index - 1]) / 10; + if (absVolumeIndexFix()) { + // The attenuation is applied in the APM. No need to manipulate the index here + return index; } else { - // otherwise, full gain - index = (mIndexMax + 5) / 10; + /* 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. + */ + if (index == 0) { + // 0% for volume 0 + index = 0; + } else if (!disablePrescaleAbsoluteVolume() && index > 0 && index <= 3) { + // Pre-scale for volume steps 1 2 and 3 + index = (int) (mIndexMax * mPrescaleAbsoluteVolume[index - 1]) / 10; + } else { + // otherwise, full gain + index = (mIndexMax + 5) / 10; + } + return index; } - return index; } private void setStreamVolumeIndex(int index, int device) { @@ -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)) { - index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); + // 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) { - index = (mIndexMax + 5)/10; + 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; - index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); + // 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) { - index = (mIndexMax + 5)/10; + 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); diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java index 7202fa286453..7f4bc74bd59e 100644 --- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java +++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java @@ -598,6 +598,21 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback, } /** + * 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 * @param register diff --git a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java index 23728db34c34..271720573e38 100644 --- a/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/VolumeHelperTest.java @@ -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); |