summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java2
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java339
2 files changed, 289 insertions, 52 deletions
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 25b9228d3b37..92553b9705b7 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1432,6 +1432,8 @@ public class AudioDeviceBroker {
}
mCurCommunicationPortId = portId;
+ mAudioService.postScoDeviceActive(isBluetoothScoActive());
+
final int nbDispatchers = mCommDevDispatchers.beginBroadcast();
for (int i = 0; i < nbDispatchers; i++) {
try {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c4518a95cc72..3d41f05de0b8 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -65,6 +65,7 @@ import static com.android.media.audio.Flags.absVolumeIndexFix;
import static com.android.media.audio.Flags.alarmMinVolumeZero;
import static com.android.media.audio.Flags.audioserverPermissions;
import static com.android.media.audio.Flags.disablePrescaleAbsoluteVolume;
+import static com.android.media.audio.Flags.replaceStreamBtSco;
import static com.android.media.audio.Flags.ringerModeAffectsAlarm;
import static com.android.media.audio.Flags.setStreamVolumeOrder;
import static com.android.media.audio.Flags.vgsVssSyncMuteOrder;
@@ -461,6 +462,7 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_CONFIGURATION_CHANGED = 54;
private static final int MSG_BROADCAST_MASTER_MUTE = 55;
private static final int MSG_UPDATE_CONTEXTUAL_VOLUMES = 56;
+ private static final int MSG_SCO_DEVICE_ACTIVE_UPDATE = 57;
/**
* Messages handled by the {@link SoundDoseHelper}, do not exceed
@@ -715,6 +717,8 @@ public class AudioService extends IAudioService.Stub
* @see System#MUTE_STREAMS_AFFECTED */
private int mUserMutableStreams;
+ private final AtomicBoolean mScoDeviceActive = new AtomicBoolean(false);
+
@NonNull
private SoundEffectsHelper mSfxHelper;
@@ -1470,6 +1474,9 @@ public class AudioService extends IAudioService.Stub
synchronized (VolumeStreamState.class) {
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
VolumeStreamState streamState = mStreamStates[streamType];
+ if (streamState == null) {
+ continue;
+ }
int groupId = getVolumeGroupForStreamType(streamType);
if (groupId != AudioVolumeGroup.DEFAULT_VOLUME_GROUP
&& sVolumeGroupStates.indexOfKey(groupId) >= 0) {
@@ -2078,7 +2085,7 @@ public class AudioService extends IAudioService.Stub
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
VolumeStreamState streamState = mStreamStates[streamType];
final int res = AudioSystem.initStreamVolume(
- streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
+ streamType, MIN_STREAM_VOLUME[streamType], MAX_STREAM_VOLUME[streamType]);
if (res != AudioSystem.AUDIO_STATUS_OK) {
status = res;
Log.e(TAG, "Failed to initStreamVolume (" + res + ") for stream " + streamType);
@@ -2236,11 +2243,13 @@ public class AudioService extends IAudioService.Stub
synchronized (VolumeStreamState.class) {
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- mStreamStates[streamType]
- .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
- // apply stream volume
- if (!mStreamStates[streamType].mIsMuted) {
- mStreamStates[streamType].applyAllVolumes();
+ if (mStreamVolumeAlias[streamType] >= 0) {
+ mStreamStates[streamType]
+ .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
+ // apply stream volume
+ if (!mStreamStates[streamType].mIsMuted) {
+ mStreamStates[streamType].applyAllVolumes();
+ }
}
}
}
@@ -2331,6 +2340,10 @@ public class AudioService extends IAudioService.Stub
* @param caller caller of this method
*/
private void updateVolumeStates(int device, int streamType, String caller) {
+ if (replaceStreamBtSco() && streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
+ return;
+ }
+
// Handle device volume aliasing of SPEAKER_SAFE.
if (device == AudioSystem.DEVICE_OUT_SPEAKER_SAFE) {
device = AudioSystem.DEVICE_OUT_SPEAKER;
@@ -2366,7 +2379,9 @@ public class AudioService extends IAudioService.Stub
{
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
- mStreamStates[streamType].checkFixedVolumeDevices();
+ if (mStreamStates[streamType] != null) {
+ mStreamStates[streamType].checkFixedVolumeDevices();
+ }
}
}
@@ -2380,9 +2395,9 @@ public class AudioService extends IAudioService.Stub
// that has the the MODIFY_PHONE_STATE permission.
for (int i = 0; i < mStreamStates.length; i++) {
final VolumeStreamState vss = mStreamStates[i];
- if (vss.mIndexMin > 0 &&
- (vss.mStreamType != AudioSystem.STREAM_VOICE_CALL &&
- vss.mStreamType != AudioSystem.STREAM_BLUETOOTH_SCO)) {
+ if (vss != null && vss.mIndexMin > 0
+ && (vss.mStreamType != AudioSystem.STREAM_VOICE_CALL
+ && vss.mStreamType != AudioSystem.STREAM_BLUETOOTH_SCO)) {
mMuteAffectedStreams &= ~(1 << vss.mStreamType);
}
}
@@ -2394,8 +2409,11 @@ public class AudioService extends IAudioService.Stub
VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
for (int i = 0; i < numStreamTypes; i++) {
- streams[i] =
- new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);
+ // a negative mStreamVolumeAlias value means the stream state type is not supported
+ if (mStreamVolumeAlias[i] >= 0) {
+ streams[i] =
+ new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);
+ }
}
checkAllFixedVolumeDevices();
@@ -2428,7 +2446,7 @@ public class AudioService extends IAudioService.Stub
continue;
}
}
- if (stream != streamVolumeAlias) {
+ if (streamVolumeAlias >= 0 && stream != streamVolumeAlias) {
AudioSystem.DEFAULT_STREAM_VOLUME[stream] =
getUiDefaultRescaledIndex(streamVolumeAlias, stream);
}
@@ -2440,10 +2458,37 @@ public class AudioService extends IAudioService.Stub
srcStream, dstStream) + 5) / 10;
}
+ private static int replaceBtScoStreamWithVoiceCall(int streamType, String caller) {
+ if (replaceStreamBtSco() && streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
+ if (DEBUG_VOL) {
+ Log.d(TAG,
+ "Deprecating STREAM_BLUETOOTH_SCO, using STREAM_VOICE_CALL instead for "
+ + "caller: " + caller);
+ }
+ streamType = AudioSystem.STREAM_VOICE_CALL;
+ }
+ return streamType;
+ }
+
+ private boolean isStreamBluetoothSco(int streamType) {
+ if (replaceStreamBtSco()) {
+ if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
+ // this should not happen, throwing exception
+ throw new IllegalArgumentException("STREAM_BLUETOOTH_SCO is deprecated");
+ }
+ return streamType == AudioSystem.STREAM_VOICE_CALL && mScoDeviceActive.get();
+ } else {
+ return streamType == AudioSystem.STREAM_BLUETOOTH_SCO;
+ }
+ }
+
private void dumpStreamStates(PrintWriter pw) {
pw.println("\nStream volumes (device: index)");
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int i = 0; i < numStreamTypes; i++) {
+ if (replaceStreamBtSco() && i == AudioSystem.STREAM_BLUETOOTH_SCO) {
+ continue;
+ }
StringBuilder alias = new StringBuilder();
if (mStreamVolumeAlias[i] != i) {
alias.append(" (aliased to: ")
@@ -2505,6 +2550,13 @@ public class AudioService extends IAudioService.Stub
mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias;
mStreamVolumeAlias[AudioSystem.STREAM_ASSISTANT] = assistantStreamAlias;
+ if (replaceStreamBtSco()) {
+ // we do not support STREAM_BLUETOOTH_SCO, this will lead to having
+ // mStreanStates[STREAM_BLUETOOTH_SCO] = null
+ // TODO: replace arrays with SparseIntArrays to avoid null checks
+ mStreamVolumeAlias[AudioSystem.STREAM_BLUETOOTH_SCO] = -1;
+ }
+
if (updateVolumes && mStreamStates != null) {
updateDefaultVolumes();
@@ -3064,7 +3116,7 @@ public class AudioService extends IAudioService.Stub
return 0;
}
- return ((step * dstRange + srcRange / 2) / srcRange);
+ return (step * dstRange + srcRange / 2) / srcRange;
}
///////////////////////////////////////////////////////////////////////////
@@ -3538,7 +3590,7 @@ public class AudioService extends IAudioService.Stub
return;
}
- final int streamType;
+ int streamType;
synchronized (mForceControlStreamLock) {
// Request lock in case mVolumeControlStream is changed by other thread.
if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1
@@ -3563,6 +3615,8 @@ public class AudioService extends IAudioService.Stub
final boolean isMute = isMuteAdjust(direction);
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "adjustSuggestedStreamVolume");
+
ensureValidStreamType(streamType);
final int resolvedStream = mStreamVolumeAlias[streamType];
@@ -3640,6 +3694,8 @@ public class AudioService extends IAudioService.Stub
if (mUseFixedVolume) {
return;
}
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "adjustStreamVolume");
+
if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
+ ", flags=" + flags + ", caller=" + caller);
@@ -3656,8 +3712,9 @@ public class AudioService extends IAudioService.Stub
// that the calling app have the MODIFY_PHONE_STATE permission.
if (isMuteAdjust &&
(streamType == AudioSystem.STREAM_VOICE_CALL ||
- streamType == AudioSystem.STREAM_BLUETOOTH_SCO) &&
- mContext.checkPermission(MODIFY_PHONE_STATE, pid, uid)
+ // TODO: when replaceStreamBtSco flag is rolled out remove next condition
+ isStreamBluetoothSco(streamType))
+ && mContext.checkPermission(MODIFY_PHONE_STATE, pid, uid)
!= PackageManager.PERMISSION_GRANTED) {
Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
@@ -3725,7 +3782,8 @@ public class AudioService extends IAudioService.Stub
}
} else {
// convert one UI step (+/-1) into a number of internal units on the stream alias
- step = rescaleStep(10, streamType, streamTypeAlias);
+ step = rescaleStep((int) (10 * streamState.getIndexStepFactor()), streamType,
+ streamTypeAlias);
}
// If either the client forces allowing ringer modes for this adjustment,
@@ -3865,7 +3923,6 @@ public class AudioService extends IAudioService.Stub
}
final int newIndex = mStreamStates[streamType].getIndex(device);
-
if (adjustVolume) {
synchronized (mHdmiClientLock) {
if (mHdmiManager != null) {
@@ -3949,9 +4006,9 @@ public class AudioService extends IAudioService.Stub
List<Integer> streamsToMute = new ArrayList<>();
for (int stream = 0; stream < mStreamStates.length; stream++) {
VolumeStreamState vss = mStreamStates[stream];
- if (streamAlias == mStreamVolumeAlias[stream] && vss.isMutable()) {
- if (!(mCameraSoundForced
- && (vss.getStreamType()
+ if (vss != null && streamAlias == mStreamVolumeAlias[stream]
+ && vss.isMutable()) {
+ if (!(mCameraSoundForced && (vss.getStreamType()
== AudioSystem.STREAM_SYSTEM_ENFORCED))) {
boolean changed = vss.mute(state, /* apply= */ false,
"muteAliasStreams");
@@ -3972,8 +4029,14 @@ public class AudioService extends IAudioService.Stub
private void broadcastMuteSetting(int streamType, boolean isMuted) {
// Stream mute changed, fire the intent.
Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
- intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, isMuted);
+ if (replaceStreamBtSco() && isStreamBluetoothSco(streamType)) {
+ intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
+ AudioSystem.STREAM_BLUETOOTH_SCO);
+ // in this case broadcast for both sco and voice_call streams the mute status
+ sendBroadcastToAll(intent, null /* options */);
+ }
+ intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
sendBroadcastToAll(intent, null /* options */);
}
@@ -4092,7 +4155,7 @@ public class AudioService extends IAudioService.Stub
setStreamVolumeInt(stream, index, device, false, caller, hasModifyAudioSettings);
// setting non-zero volume for a muted stream unmutes the stream and vice versa
// except for BT SCO stream where only explicit mute is allowed to comply to BT requirements
- if ((streamType != AudioSystem.STREAM_BLUETOOTH_SCO) && canChangeMute) {
+ if (!isStreamBluetoothSco(streamType) && canChangeMute) {
// As adjustStreamVolume with muteAdjust flags mute/unmutes stream and aliased streams.
muteAliasStreams(stream, index == 0);
}
@@ -4381,6 +4444,9 @@ public class AudioService extends IAudioService.Stub
@Nullable AudioDeviceAttributes ada,
String callingPackage, String attributionTag,
boolean canChangeMuteAndUpdateController) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType,
+ "setStreamVolumeWithAttributionInt");
+
if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Log.w(TAG, "Trying to call setStreamVolume() for a11y without"
+ " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage);
@@ -4388,7 +4454,7 @@ public class AudioService extends IAudioService.Stub
}
if ((streamType == AudioManager.STREAM_VOICE_CALL) && (index == 0)
&& (mContext.checkCallingOrSelfPermission(MODIFY_PHONE_STATE)
- != PackageManager.PERMISSION_GRANTED)) {
+ != PackageManager.PERMISSION_GRANTED) && !isStreamBluetoothSco(streamType)) {
Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL and index 0 without"
+ " MODIFY_PHONE_STATE callingPackage=" + callingPackage);
return;
@@ -4631,6 +4697,8 @@ public class AudioService extends IAudioService.Stub
+ vgsVssSyncMuteOrder());
pw.println("\tcom.android.media.audio.absVolumeIndexFix:"
+ absVolumeIndexFix());
+ pw.println("\tcom.android.media.audio.replaceStreamBtSco:"
+ + replaceStreamBtSco());
}
private void dumpAudioMode(PrintWriter pw) {
@@ -4719,12 +4787,13 @@ public class AudioService extends IAudioService.Stub
if (mUseFixedVolume) {
return;
}
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "setStreamVolume");
ensureValidStreamType(streamType);
int streamTypeAlias = mStreamVolumeAlias[streamType];
VolumeStreamState streamState = mStreamStates[streamTypeAlias];
- if ((streamType == AudioManager.STREAM_VOICE_CALL)
+ if (!replaceStreamBtSco() && (streamType == AudioManager.STREAM_VOICE_CALL)
&& isInCommunication() && mDeviceBroker.isBluetoothScoActive()) {
Log.i(TAG, "setStreamVolume for STREAM_VOICE_CALL, switching to STREAM_BLUETOOTH_SCO");
streamType = AudioManager.STREAM_BLUETOOTH_SCO;
@@ -4918,6 +4987,9 @@ public class AudioService extends IAudioService.Stub
!= PackageManager.PERMISSION_GRANTED) {
return;
}
+
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "forceVolumeControlStream");
+
if (DEBUG_VOL) { Log.d(TAG, String.format("forceVolumeControlStream(%d)", streamType)); }
synchronized(mForceControlStreamLock) {
if (mVolumeControlStream != -1 && streamType != -1) {
@@ -5095,6 +5167,8 @@ public class AudioService extends IAudioService.Stub
if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
streamType = getActiveStreamType(streamType);
}
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "isStreamMute");
+
synchronized (VolumeStreamState.class) {
ensureValidStreamType(streamType);
return mStreamStates[streamType].mIsMuted;
@@ -5268,6 +5342,8 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "getStreamVolume");
+
ensureValidStreamType(streamType);
int device = getDeviceForStream(streamType);
return getStreamVolume(streamType, device);
@@ -5328,6 +5404,7 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#getStreamMaxVolume(int) */
public int getStreamMaxVolume(int streamType) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "getStreamMaxVolume");
ensureValidStreamType(streamType);
return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
}
@@ -5335,6 +5412,7 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#getStreamMinVolumeInt(int)
* Part of service interface, check permissions here */
public int getStreamMinVolume(int streamType) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "getStreamMinVolume");
ensureValidStreamType(streamType);
final boolean isPrivileged =
Binder.getCallingUid() == Process.SYSTEM_UID
@@ -5349,7 +5427,10 @@ public class AudioService extends IAudioService.Stub
public int getLastAudibleStreamVolume(int streamType) {
super.getLastAudibleStreamVolume_enforcePermission();
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "getLastAudibleStreamVolume");
+
ensureValidStreamType(streamType);
+
int device = getDeviceForStream(streamType);
return (mStreamStates[streamType].getIndex(device) + 5) / 10;
}
@@ -5422,7 +5503,7 @@ public class AudioService extends IAudioService.Stub
}
ArrayList<Integer> res = new ArrayList(1);
for (int stream : mStreamVolumeAlias) {
- if (!res.contains(stream)) {
+ if (stream >= 0 && !res.contains(stream)) {
res.add(stream);
}
}
@@ -5438,6 +5519,9 @@ public class AudioService extends IAudioService.Stub
public @AudioManager.PublicStreamTypes
int getStreamTypeAlias(@AudioManager.PublicStreamTypes int sourceStreamType) {
super.getStreamTypeAlias_enforcePermission();
+
+ sourceStreamType = replaceBtScoStreamWithVoiceCall(sourceStreamType, "getStreamTypeAlias");
+
// verify parameters
ensureValidStreamType(sourceStreamType);
@@ -6548,6 +6632,10 @@ public class AudioService extends IAudioService.Stub
for (int streamType = 0; streamType < numStreamTypes; streamType++) {
VolumeStreamState streamState = mStreamStates[streamType];
+ if (streamState == null) {
+ continue;
+ }
+
if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
continue;
}
@@ -7023,14 +7111,17 @@ public class AudioService extends IAudioService.Stub
@Override
public boolean isStreamAffectedByRingerMode(int streamType) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "isStreamAffectedByRingerMode");
return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
}
public boolean isStreamAffectedByCurrentZen(int streamType) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "isStreamAffectedByCurrentZen");
return (mZenModeAffectedStreams & (1 << streamType)) != 0;
}
private boolean isStreamMutedByRingerOrZenMode(int streamType) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "isStreamMutedByRingerOrZenMode");
return (sRingerAndZenModeMutedStreams & (1 << streamType)) != 0;
}
@@ -7145,6 +7236,7 @@ public class AudioService extends IAudioService.Stub
@Override
public boolean isStreamAffectedByMute(int streamType) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "isStreamAffectedByMute");
return (mMuteAffectedStreams & (1 << streamType)) != 0;
}
@@ -7220,11 +7312,15 @@ public class AudioService extends IAudioService.Stub
case AudioSystem.PLATFORM_VOICE:
if (isInCommunication()
|| mAudioSystem.isStreamActive(AudioManager.STREAM_VOICE_CALL, 0)) {
- if (mDeviceBroker.isBluetoothScoActive()) {
- // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
+ if (!replaceStreamBtSco() && mDeviceBroker.isBluetoothScoActive()) {
+ if (DEBUG_VOL) {
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
+ }
return AudioSystem.STREAM_BLUETOOTH_SCO;
} else {
- // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
+ if (DEBUG_VOL) {
+ Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
+ }
return AudioSystem.STREAM_VOICE_CALL;
}
} else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
@@ -7260,7 +7356,7 @@ public class AudioService extends IAudioService.Stub
}
default:
if (isInCommunication()) {
- if (mDeviceBroker.isBluetoothScoActive()) {
+ if (!replaceStreamBtSco() && mDeviceBroker.isBluetoothScoActive()) {
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
return AudioSystem.STREAM_BLUETOOTH_SCO;
} else {
@@ -7294,6 +7390,10 @@ public class AudioService extends IAudioService.Stub
}
break;
}
+
+ suggestedStreamType = replaceBtScoStreamWithVoiceCall(suggestedStreamType,
+ "getActiveStreamType");
+
if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
+ suggestedStreamType);
return suggestedStreamType;
@@ -7426,7 +7526,7 @@ public class AudioService extends IAudioService.Stub
: Math.min(idx + 1, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]);
// update the VolumeStreamState for STREAM_ALARM and its aliases
for (int stream : mStreamVolumeAlias) {
- if (mStreamVolumeAlias[stream] == AudioSystem.STREAM_ALARM) {
+ if (stream >= 0 && mStreamVolumeAlias[stream] == AudioSystem.STREAM_ALARM) {
mStreamStates[stream].updateNoPermMinIndex(safeIndex);
}
}
@@ -7441,6 +7541,7 @@ public class AudioService extends IAudioService.Stub
*/
@VisibleForTesting
public int getDeviceForStream(int stream) {
+ stream = replaceBtScoStreamWithVoiceCall(stream, "getDeviceForStream");
return selectOneAudioDevice(getDeviceSetForStream(stream));
}
@@ -7502,6 +7603,8 @@ public class AudioService extends IAudioService.Stub
@Override
@Deprecated
public int getDeviceMaskForStream(int streamType) {
+ streamType = replaceBtScoStreamWithVoiceCall(streamType, "getDeviceMaskForStream");
+
ensureValidStreamType(streamType);
// no permission required
final long token = Binder.clearCallingIdentity();
@@ -7536,6 +7639,7 @@ public class AudioService extends IAudioService.Stub
*/
@NonNull
public Set<Integer> getDeviceSetForStream(int stream) {
+ stream = replaceBtScoStreamWithVoiceCall(stream, "getDeviceSetForStream");
ensureValidStreamType(stream);
synchronized (VolumeStreamState.class) {
return mStreamStates[stream].observeDevicesForStream_syncVSS(true);
@@ -7546,7 +7650,7 @@ public class AudioService extends IAudioService.Stub
synchronized (mSettingsLock) {
synchronized (VolumeStreamState.class) {
for (int stream = 0; stream < mStreamStates.length; stream++) {
- if (stream != skipStream) {
+ if (stream != skipStream && mStreamStates[stream] != null) {
Set<Integer> deviceSet =
mStreamStates[stream].observeDevicesForStream_syncVSS(
false /*checkOthers*/);
@@ -7576,6 +7680,19 @@ public class AudioService extends IAudioService.Stub
0 /*delay*/);
}
+ /*package*/ void postScoDeviceActive(boolean scoDeviceActive) {
+ sendMsg(mAudioHandler,
+ MSG_SCO_DEVICE_ACTIVE_UPDATE,
+ SENDMSG_QUEUE, scoDeviceActive ? 1 : 0 /*arg1*/, 0 /*arg2*/, null /*obj*/,
+ 0 /*delay*/);
+ }
+
+ private void onUpdateScoDeviceActive(boolean scoDeviceActive) {
+ if (mScoDeviceActive.compareAndSet(!scoDeviceActive, scoDeviceActive)) {
+ getVssVolumeForStream(AudioSystem.STREAM_VOICE_CALL).updateIndexFactors();
+ }
+ }
+
/**
* @see AudioDeviceVolumeManager#setDeviceAbsoluteMultiVolumeBehavior
*
@@ -8032,9 +8149,10 @@ public class AudioService extends IAudioService.Stub
private void initVolumeGroupStates() {
for (final AudioVolumeGroup avg : getAudioVolumeGroups()) {
try {
- // if no valid attributes, this volume group is not controllable, throw exception
- ensureValidAttributes(avg);
- sVolumeGroupStates.append(avg.getId(), new VolumeGroupState(avg));
+ // if no valid attributes, this volume group is not controllable
+ if (ensureValidAttributes(avg)) {
+ sVolumeGroupStates.append(avg.getId(), new VolumeGroupState(avg));
+ }
} catch (IllegalArgumentException e) {
// Volume Groups without attributes are not controllable through set/get volume
// using attributes. Do not append them.
@@ -8055,13 +8173,21 @@ public class AudioService extends IAudioService.Stub
}
}
- private void ensureValidAttributes(AudioVolumeGroup avg) {
+ private boolean ensureValidAttributes(AudioVolumeGroup avg) {
boolean hasAtLeastOneValidAudioAttributes = avg.getAudioAttributes().stream()
.anyMatch(aa -> !aa.equals(AudioProductStrategy.getDefaultAttributes()));
if (!hasAtLeastOneValidAudioAttributes) {
throw new IllegalArgumentException("Volume Group " + avg.name()
+ " has no valid audio attributes");
}
+ if (replaceStreamBtSco()) {
+ for (int streamType : avg.getLegacyStreamTypes()) {
+ if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
+ return false;
+ }
+ }
+ }
+ return true;
}
private void readVolumeGroupsSettings(boolean userSwitch) {
@@ -8168,8 +8294,14 @@ public class AudioService extends IAudioService.Stub
break;
}
}
- mIndexMin = MIN_STREAM_VOLUME[mPublicStreamType];
- mIndexMax = MAX_STREAM_VOLUME[mPublicStreamType];
+
+ if (replaceStreamBtSco()) {
+ mIndexMin = mStreamStates[mPublicStreamType].getMinIndex() / 10;
+ mIndexMax = mStreamStates[mPublicStreamType].getMaxIndex() / 10;
+ } else {
+ mIndexMin = MIN_STREAM_VOLUME[mPublicStreamType];
+ mIndexMax = MAX_STREAM_VOLUME[mPublicStreamType];
+ }
} else if (!avg.getAudioAttributes().isEmpty()) {
mIndexMin = AudioSystem.getMinVolumeIndexForAttributes(mAudioAttributes);
mIndexMax = AudioSystem.getMaxVolumeIndexForAttributes(mAudioAttributes);
@@ -8202,7 +8334,7 @@ public class AudioService extends IAudioService.Stub
*/
private boolean isVssMuteBijective(int stream) {
return isStreamAffectedByMute(stream)
- && (getMinIndex() == (mStreamStates[stream].mIndexMin + 5) / 10)
+ && (getMinIndex() == (mStreamStates[stream].getMinIndex() + 5) / 10)
&& (getMinIndex() == 0 || isCallStream(stream));
}
@@ -8247,6 +8379,8 @@ public class AudioService extends IAudioService.Stub
}
return;
}
+
+ float stepFactor = mStreamStates[mPublicStreamType].getIndexStepFactor();
switch (direction) {
case AudioManager.ADJUST_TOGGLE_MUTE: {
// Note: If muted by volume 0, unmute will restore volume 0.
@@ -8267,7 +8401,8 @@ public class AudioService extends IAudioService.Stub
break;
case AudioManager.ADJUST_RAISE:
// As for stream, RAISE during mute will increment the index
- setVolumeIndex(Math.min(previousIndex + 1, mIndexMax), device, flags);
+ setVolumeIndex(Math.min((int) ((previousIndex + 1) * stepFactor),
+ mIndexMax), device, flags);
break;
case AudioManager.ADJUST_LOWER:
// For stream, ADJUST_LOWER on a muted VSS is a no-op
@@ -8276,7 +8411,8 @@ public class AudioService extends IAudioService.Stub
if (isMuted() && previousIndex != 0) {
mute(false);
} else {
- int newIndex = Math.max(previousIndex - 1, mIndexMin);
+ int newIndex = Math.max((int) ((previousIndex - 1) * stepFactor),
+ mIndexMin);
setVolumeIndex(newIndex, device, flags);
}
break;
@@ -8342,9 +8478,20 @@ public class AudioService extends IAudioService.Stub
if (mHasValidStreamType && isVssMuteBijective(mPublicStreamType)
&& mStreamStates[mPublicStreamType].isFullyMuted()) {
index = 0;
- } else if (mPublicStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0) {
+ } else if (isStreamBluetoothSco(mPublicStreamType) && index == 0) {
index = 1;
}
+
+ if (replaceStreamBtSco()) {
+ index = (int) (mIndexMin + (index - mIndexMin)
+ / mStreamStates[mPublicStreamType].getIndexStepFactor());
+ }
+
+ if (DEBUG_VOL) {
+ Log.d(TAG, "setVolumeIndexInt(" + mAudioVolumeGroup.getId() + ", " + index + ", "
+ + device + ")");
+ }
+
// Set the volume index
mAudioSystem.setVolumeIndexForAttributes(mAudioAttributes, index, device);
}
@@ -8610,7 +8757,6 @@ public class AudioService extends IAudioService.Stub
}
}
-
// NOTE: Locking order for synchronized objects related to volume or ringer mode management:
// 1 mScoclient OR mSafeMediaVolumeState
// 2 mSetModeLock
@@ -8624,6 +8770,17 @@ public class AudioService extends IAudioService.Stub
private int mIndexMinNoPerm;
private int mIndexMax;
+ /**
+ * Variable used to determine the size of an incremental step when calling the
+ * adjustStreamVolume methods with raise/lower adjustments. This can change dynamically
+ * for some streams.
+ *
+ * <p>STREAM_VOICE_CALL has a different step value when is streaming on a SCO device.
+ * Internally we are using the same volume range but through the step factor we force the
+ * number of UI volume steps.
+ */
+ private float mIndexStepFactor = 1.f;
+
private boolean mIsMuted = false;
private boolean mIsMutedInternally = false;
private String mVolumeIndexSettingName;
@@ -8665,10 +8822,10 @@ public class AudioService extends IAudioService.Stub
mStreamType = streamType;
mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
- mIndexMinNoPerm = mIndexMin; // may be overwritten later in updateNoPermMinIndex()
mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
+
final int status = AudioSystem.initStreamVolume(
- streamType, mIndexMin / 10, mIndexMax / 10);
+ streamType, MIN_STREAM_VOLUME[streamType], MAX_STREAM_VOLUME[streamType]);
if (status != AudioSystem.AUDIO_STATUS_OK) {
sLifecycleLogger.enqueue(new EventLogger.StringEvent(
"VSS() stream:" + streamType + " initStreamVolume=" + status)
@@ -8677,6 +8834,9 @@ public class AudioService extends IAudioService.Stub
"VSS()" /*obj*/, 2 * INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
}
+ updateIndexFactors();
+ mIndexMinNoPerm = mIndexMin; // may be overwritten later in updateNoPermMinIndex()
+
readSettings();
mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
@@ -8700,6 +8860,38 @@ public class AudioService extends IAudioService.Stub
mStreamDevicesChangedOptions = streamDevicesChangedOptions.toBundle();
}
+ public void updateIndexFactors() {
+ if (!replaceStreamBtSco()) {
+ return;
+ }
+
+ synchronized (this) {
+ if (mStreamType == AudioSystem.STREAM_VOICE_CALL) {
+ if (MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO]
+ > MAX_STREAM_VOLUME[mStreamType]) {
+ mIndexMax = MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10;
+ }
+
+ // SCO devices have a different min index
+ if (isStreamBluetoothSco(mStreamType)) {
+ mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10;
+ mIndexStepFactor = 1.f;
+ } else {
+ mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] * 10;
+ mIndexStepFactor = (float) (mIndexMax - mIndexMin) / (float) (
+ MAX_STREAM_VOLUME[mStreamType] * 10
+ - MIN_STREAM_VOLUME[mStreamType] * 10);
+ }
+
+ if (mVolumeGroupState != null) {
+ mVolumeGroupState.mIndexMin = mIndexMin;
+ }
+
+ mIndexMinNoPerm = mIndexMin;
+ }
+ }
+ }
+
/**
* Associate a {@link volumeGroupState} on the {@link VolumeStreamState}.
* <p> It helps to synchronize the index, mute attributes on the maching
@@ -8712,6 +8904,11 @@ public class AudioService extends IAudioService.Stub
mVolumeGroupState.setSettingName(mVolumeIndexSettingName);
}
}
+
+ public float getIndexStepFactor() {
+ return mIndexStepFactor;
+ }
+
/**
* Update the minimum index that can be used without MODIFY_AUDIO_SETTINGS permission
* @param index minimum index expressed in "UI units", i.e. no 10x factor
@@ -8870,15 +9067,20 @@ public class AudioService extends IAudioService.Stub
}
}
+ @GuardedBy("VolumeStreamState.class")
private void setStreamVolumeIndex(int index, int device) {
// Only set audio policy BT SCO stream volume to 0 when the stream is actually muted.
// This allows RX path muting by the audio HAL only when explicitly muted but not when
// index is just set to 0 to repect BT requirements
- if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0
- && !isFullyMuted()) {
+ if (isStreamBluetoothSco(mStreamType) && index == 0 && !isFullyMuted()) {
index = 1;
}
+ if (replaceStreamBtSco()) {
+ index = (int) (mIndexMin + (index * 10 - mIndexMin) / getIndexStepFactor() + 5)
+ / 10;
+ }
+
if (DEBUG_VOL) {
Log.d(TAG, "setStreamVolumeIndexAS(" + mStreamType + ", " + index + ", " + device
+ ")");
@@ -8887,6 +9089,7 @@ public class AudioService extends IAudioService.Stub
}
// must be called while synchronized VolumeStreamState.class
+ @GuardedBy("VolumeStreamState.class")
/*package*/ void applyDeviceVolume_syncVSS(int device) {
int index;
if (isFullyMuted()) {
@@ -9053,8 +9256,19 @@ public class AudioService extends IAudioService.Stub
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE,
oldIndex);
+ int extraStreamType = mStreamType;
+ // TODO: remove this when deprecating STREAM_BLUETOOTH_SCO
+ if (isStreamBluetoothSco(mStreamType)) {
+ mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
+ AudioSystem.STREAM_BLUETOOTH_SCO);
+ extraStreamType = AudioSystem.STREAM_BLUETOOTH_SCO;
+ } else {
+ mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
+ mStreamType);
+ }
mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
mStreamVolumeAlias[mStreamType]);
+
if (mStreamType == mStreamVolumeAlias[mStreamType]) {
String aliasStreamIndexesString = "";
if (!aliasStreamIndexes.isEmpty()) {
@@ -9062,9 +9276,21 @@ public class AudioService extends IAudioService.Stub
" aliased streams: " + aliasStreamIndexes;
}
AudioService.sVolumeLogger.enqueue(new VolChangedBroadcastEvent(
- mStreamType, aliasStreamIndexesString, index, oldIndex));
+ extraStreamType, aliasStreamIndexesString, index, oldIndex));
+ if (extraStreamType != mStreamType) {
+ AudioService.sVolumeLogger.enqueue(new VolChangedBroadcastEvent(
+ mStreamType, aliasStreamIndexesString, index, oldIndex));
+ }
}
sendBroadcastToAll(mVolumeChanged, mVolumeChangedOptions);
+ if (extraStreamType != mStreamType) {
+ // send multiple intents in case we merged voice call and bt sco streams
+ mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE,
+ mStreamType);
+ // do not use the options in thid case which could discard
+ // the previous intent
+ sendBroadcastToAll(mVolumeChanged, null);
+ }
}
}
}
@@ -9090,8 +9316,8 @@ public class AudioService extends IAudioService.Stub
index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
}
final VolumeInfo vi = new VolumeInfo.Builder(mStreamType)
- .setMinVolumeIndex(mIndexMin)
- .setMaxVolumeIndex(mIndexMax)
+ .setMinVolumeIndex(getMinIndex())
+ .setMaxVolumeIndex(getMaxIndex())
.setVolumeIndex(index)
.setMuted(isFullyMuted())
.build();
@@ -9280,7 +9506,7 @@ public class AudioService extends IAudioService.Stub
public void doMute() {
synchronized (VolumeStreamState.class) {
// If associated to volume group, update group cache
- updateVolumeGroupIndex(getDeviceForStream(mStreamType), /* forceMuteState= */ true);
+ updateVolumeGroupIndex(getDeviceForStream(mStreamType), /* forceMuteState= */true);
// Set the new mute volume. This propagates the values to
// the audio system, otherwise the volume won't be changed
@@ -9844,6 +10070,10 @@ public class AudioService extends IAudioService.Stub
onUpdateContextualVolumes();
break;
+ case MSG_SCO_DEVICE_ACTIVE_UPDATE:
+ onUpdateScoDeviceActive(msg.arg1 != 0);
+ break;
+
case MusicFxHelper.MSG_EFFECT_CLIENT_GONE:
mMusicFxHelper.handleMessage(msg);
break;
@@ -12257,6 +12487,11 @@ public class AudioService extends IAudioService.Stub
if (mController == null)
return;
try {
+ // TODO: remove this when deprecating STREAM_BLUETOOTH_SCO
+ if (isStreamBluetoothSco(streamType)) {
+ // TODO: notify both sco and voice_call about volume changes
+ streamType = AudioSystem.STREAM_BLUETOOTH_SCO;
+ }
mController.volumeChanged(streamType, flags);
} catch (RemoteException e) {
Log.w(TAG, "Error calling volumeChanged", e);