diff options
| -rw-r--r-- | services/core/java/com/android/server/audio/AudioService.java | 487 | ||||
| -rw-r--r-- | services/core/java/com/android/server/audio/SoundDoseHelper.java | 6 |
2 files changed, 288 insertions, 205 deletions
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 3d41f05de0b8..00b7b8ee3ebb 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -496,19 +496,40 @@ public class AudioService extends IAudioService.Stub private AudioSystemThread mAudioSystemThread; /** @see AudioHandler */ private AudioHandler mAudioHandler; - /** @see VolumeStreamState */ - private VolumeStreamState[] mStreamStates; + /** + * @see VolumeStreamState + * Mapping which contains for each stream type its associated {@link VolumeStreamState} + **/ + private SparseArray<VolumeStreamState> mStreamStates; /*package*/ int getVssVolumeForDevice(int stream, int device) { - return mStreamStates[stream].getIndex(device); + final VolumeStreamState streamState = mStreamStates.get(stream); + return streamState != null ? streamState.getIndex(device) : -1; + } + + @Nullable + /*package*/ VolumeStreamState getVssForStream(int stream) { + return mStreamStates.get(stream); } - /*package*/ VolumeStreamState getVssVolumeForStream(int stream) { - return mStreamStates[stream]; + @NonNull + /*package*/ VolumeStreamState getVssForStreamOrDefault(int stream) { + VolumeStreamState streamState = mStreamStates.get(stream); + if (streamState == null) { + if (replaceStreamBtSco()) { + throw new IllegalArgumentException("No VolumeStreamState for stream " + stream); + } else { + Log.e(TAG, "No VolumeStreamState for stream " + stream + + ". Returning default state for STREAM_MUSIC", new Exception()); + streamState = mStreamStates.get(AudioSystem.STREAM_MUSIC); + } + } + return streamState; } /*package*/ int getMaxVssVolumeForStream(int stream) { - return mStreamStates[stream].getMaxIndex(); + final VolumeStreamState streamState = mStreamStates.get(stream); + return streamState != null ? streamState.getMaxIndex() : -1; } private SettingsObserver mSettingsObserver; @@ -550,13 +571,13 @@ public class AudioService extends IAudioService.Stub 0 // STREAM_ASSISTANT }; - /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings + /* sStreamVolumeAlias[] indicates for each stream if it uses the volume settings * of another stream: This avoids multiplying the volume settings for hidden * stream types that follow other stream behavior for volume settings * NOTE: do not create loops in aliases! * Some streams alias to different streams according to device category (phone or tablet) or * use case (in call vs off call...). See updateStreamVolumeAlias() for more details. - * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device + * sStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/ private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] { @@ -621,12 +642,12 @@ public class AudioService extends IAudioService.Stub AudioSystem.STREAM_MUSIC, // STREAM_ACCESSIBILITY AudioSystem.STREAM_MUSIC // STREAM_ASSISTANT }; - protected static int[] mStreamVolumeAlias; + protected static SparseIntArray sStreamVolumeAlias; private static final int UNSET_INDEX = -1; /** * Map AudioSystem.STREAM_* constants to app ops. This should be used - * after mapping through mStreamVolumeAlias. + * after mapping through sStreamVolumeAlias. */ private static final int[] STREAM_VOLUME_OPS = new int[] { AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL @@ -1416,7 +1437,7 @@ public class AudioService extends IAudioService.Stub mRecordMonitor = new RecordingActivityMonitor(mContext); mRecordMonitor.registerRecordingCallback(mVoiceRecordingActivityMonitor, true); - // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[] + // must be called before readPersistedSettings() which needs a valid sStreamVolumeAlias[] // array initialized by updateStreamVolumeAlias() updateStreamVolumeAlias(false /*updateVolumes*/, TAG); readPersistedSettings(); @@ -1473,7 +1494,7 @@ public class AudioService extends IAudioService.Stub int numStreamTypes = AudioSystem.getNumStreamTypes(); synchronized (VolumeStreamState.class) { for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - VolumeStreamState streamState = mStreamStates[streamType]; + final VolumeStreamState streamState = getVssForStream(streamType); if (streamState == null) { continue; } @@ -2083,7 +2104,10 @@ public class AudioService extends IAudioService.Stub // keep track of any error during stream volume initialization int status = AudioSystem.AUDIO_STATUS_OK; for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - VolumeStreamState streamState = mStreamStates[streamType]; + VolumeStreamState streamState = getVssForStream(streamType); + if (streamState == null) { + continue; + } final int res = AudioSystem.initStreamVolume( streamType, MIN_STREAM_VOLUME[streamType], MAX_STREAM_VOLUME[streamType]); if (res != AudioSystem.AUDIO_STATUS_OK) { @@ -2243,12 +2267,13 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { - if (mStreamVolumeAlias[streamType] >= 0) { - mStreamStates[streamType] - .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG); + int streamAlias = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1); + final VolumeStreamState streamState = getVssForStream(streamType); + if (streamAlias != -1 && streamState != null) { + streamState.setAllIndexes(getVssForStream(streamAlias), TAG); // apply stream volume - if (!mStreamStates[streamType].mIsMuted) { - mStreamStates[streamType].applyAllVolumes(); + if (!streamState.mIsMuted) { + streamState.applyAllVolumes(); } } } @@ -2348,11 +2373,17 @@ public class AudioService extends IAudioService.Stub if (device == AudioSystem.DEVICE_OUT_SPEAKER_SAFE) { device = AudioSystem.DEVICE_OUT_SPEAKER; } - if (!mStreamStates[streamType].hasIndexForDevice(device)) { + + final VolumeStreamState streamState = getVssForStream(streamType); + if (streamState == null) { + // nothing to update + return; + } + + if (!streamState.hasIndexForDevice(device)) { // set the default value, if device is affected by a full/fix/abs volume rule, it // will taken into account in checkFixedVolumeDevices() - mStreamStates[streamType].setIndex( - mStreamStates[mStreamVolumeAlias[streamType]] + streamState.setIndex(getVssForStreamOrDefault(sStreamVolumeAlias.get(streamType)) .getIndex(AudioSystem.DEVICE_OUT_DEFAULT), device, caller, true /*hasModifyAudioSettings*/); } @@ -2365,11 +2396,11 @@ public class AudioService extends IAudioService.Stub for (AudioDeviceAttributes deviceAttributes : devicesForAttributes) { if (deviceAttributes.getType() == AudioDeviceInfo.convertInternalDeviceToDeviceType( device)) { - mStreamStates[streamType].checkFixedVolumeDevices(); + streamState.checkFixedVolumeDevices(); // Unmute streams if required and device is full volume if (isStreamMute(streamType) && mFullVolumeDevices.contains(device)) { - mStreamStates[streamType].mute(false, "updateVolumeStates(" + caller); + streamState.mute(false, "updateVolumeStates(" + caller); } } } @@ -2379,22 +2410,27 @@ public class AudioService extends IAudioService.Stub { int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { - if (mStreamStates[streamType] != null) { - mStreamStates[streamType].checkFixedVolumeDevices(); + final VolumeStreamState vss = getVssForStream(streamType); + if (vss != null) { + vss.checkFixedVolumeDevices(); } } } private void checkAllFixedVolumeDevices(int streamType) { - mStreamStates[streamType].checkFixedVolumeDevices(); + final VolumeStreamState vss = getVssForStream(streamType); + if (vss == null) { + return; + } + vss.checkFixedVolumeDevices(); } private void checkMuteAffectedStreams() { // any stream with a min level > 0 is not muteable by definition // STREAM_VOICE_CALL and STREAM_BLUETOOTH_SCO can be muted by applications // that has the the MODIFY_PHONE_STATE permission. - for (int i = 0; i < mStreamStates.length; i++) { - final VolumeStreamState vss = mStreamStates[i]; + for (int i = 0; i < mStreamStates.size(); i++) { + final VolumeStreamState vss = mStreamStates.valueAt(i); if (vss != null && vss.mIndexMin > 0 && (vss.mStreamType != AudioSystem.STREAM_VOICE_CALL && vss.mStreamType != AudioSystem.STREAM_BLUETOOTH_SCO)) { @@ -2406,13 +2442,14 @@ public class AudioService extends IAudioService.Stub private void createStreamStates() { int numStreamTypes = AudioSystem.getNumStreamTypes(); - VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; + mStreamStates = new SparseArray<>(numStreamTypes); for (int i = 0; i < numStreamTypes; 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); + final int streamAlias = sStreamVolumeAlias.get(i, /*valueIfKeyNotFound=*/-1); + // a negative sStreamVolumeAlias value means the stream state type is not supported + if (streamAlias >= 0) { + mStreamStates.set(i, + new VolumeStreamState(System.VOLUME_SETTINGS_INT[streamAlias], i)); } } @@ -2431,24 +2468,25 @@ public class AudioService extends IAudioService.Stub * For other volume groups not linked to any streams, default music stream index is considered. */ private void updateDefaultVolumes() { - for (int stream = 0; stream < mStreamStates.length; stream++) { - int streamVolumeAlias = mStreamVolumeAlias[stream]; + for (int stream = 0; stream < mStreamStates.size(); stream++) { + int streamType = mStreamStates.keyAt(stream); + int streamVolumeAlias = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1); if (mUseVolumeGroupAliases) { - if (AudioSystem.DEFAULT_STREAM_VOLUME[stream] != UNSET_INDEX) { + if (AudioSystem.DEFAULT_STREAM_VOLUME[streamType] != UNSET_INDEX) { // Already initialized through default property based mecanism. continue; } streamVolumeAlias = AudioSystem.STREAM_MUSIC; - int defaultAliasVolume = getUiDefaultRescaledIndex(streamVolumeAlias, stream); - if ((defaultAliasVolume >= MIN_STREAM_VOLUME[stream]) - && (defaultAliasVolume <= MAX_STREAM_VOLUME[stream])) { - AudioSystem.DEFAULT_STREAM_VOLUME[stream] = defaultAliasVolume; + int defaultAliasVolume = getUiDefaultRescaledIndex(streamVolumeAlias, streamType); + if ((defaultAliasVolume >= MIN_STREAM_VOLUME[streamType]) + && (defaultAliasVolume <= MAX_STREAM_VOLUME[streamType])) { + AudioSystem.DEFAULT_STREAM_VOLUME[streamType] = defaultAliasVolume; continue; } } - if (streamVolumeAlias >= 0 && stream != streamVolumeAlias) { - AudioSystem.DEFAULT_STREAM_VOLUME[stream] = - getUiDefaultRescaledIndex(streamVolumeAlias, stream); + if (streamVolumeAlias >= 0 && streamType != streamVolumeAlias) { + AudioSystem.DEFAULT_STREAM_VOLUME[streamType] = + getUiDefaultRescaledIndex(streamVolumeAlias, streamType); } } } @@ -2490,13 +2528,17 @@ public class AudioService extends IAudioService.Stub continue; } StringBuilder alias = new StringBuilder(); - if (mStreamVolumeAlias[i] != i) { + final int streamAlias = sStreamVolumeAlias.get(i, /*valueIfKeyNotFound*/-1); + if (streamAlias != i && streamAlias != -1) { alias.append(" (aliased to: ") - .append(AudioSystem.STREAM_NAMES[mStreamVolumeAlias[i]]) + .append(AudioSystem.STREAM_NAMES[streamAlias]) .append(")"); } pw.println("- " + AudioSystem.STREAM_NAMES[i] + alias + ":"); - mStreamStates[i].dump(pw); + final VolumeStreamState vss = getVssForStream(i); + if (vss != null) { + vss.dump(pw); + } pw.println(""); } pw.print("\n- mute affected streams = 0x"); @@ -2505,6 +2547,13 @@ public class AudioService extends IAudioService.Stub pw.println(Integer.toHexString(mUserMutableStreams)); } + private void initStreamVolumeAlias(int[] streamVolumeAlias) { + sStreamVolumeAlias = new SparseIntArray(streamVolumeAlias.length); + for (int i = 0; i < streamVolumeAlias.length; ++i) { + sStreamVolumeAlias.put(i, streamVolumeAlias[i]); + } + } + private void updateStreamVolumeAlias(boolean updateVolumes, String caller) { int dtmfStreamAlias; final int a11yStreamAlias = sIndependentA11yVolume ? @@ -2514,24 +2563,24 @@ public class AudioService extends IAudioService.Stub AudioSystem.STREAM_ASSISTANT : AudioSystem.STREAM_MUSIC; if (mIsSingleVolume) { - mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION.clone(); + initStreamVolumeAlias(STREAM_VOLUME_ALIAS_TELEVISION); dtmfStreamAlias = AudioSystem.STREAM_MUSIC; } else if (mUseVolumeGroupAliases) { - mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NONE.clone(); + initStreamVolumeAlias(STREAM_VOLUME_ALIAS_NONE); dtmfStreamAlias = AudioSystem.STREAM_DTMF; } else { switch (mPlatformType) { case AudioSystem.PLATFORM_VOICE: - mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE.clone(); + initStreamVolumeAlias(STREAM_VOLUME_ALIAS_VOICE); dtmfStreamAlias = AudioSystem.STREAM_RING; break; default: - mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT.clone(); + initStreamVolumeAlias(STREAM_VOLUME_ALIAS_DEFAULT); dtmfStreamAlias = AudioSystem.STREAM_MUSIC; } if (!mNotifAliasRing) { - mStreamVolumeAlias[AudioSystem.STREAM_NOTIFICATION] = - AudioSystem.STREAM_NOTIFICATION; + sStreamVolumeAlias.put(AudioSystem.STREAM_NOTIFICATION, + AudioSystem.STREAM_NOTIFICATION); } } @@ -2546,15 +2595,14 @@ public class AudioService extends IAudioService.Stub } } - mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; - mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias; - mStreamVolumeAlias[AudioSystem.STREAM_ASSISTANT] = assistantStreamAlias; + sStreamVolumeAlias.put(AudioSystem.STREAM_DTMF, dtmfStreamAlias); + sStreamVolumeAlias.put(AudioSystem.STREAM_ACCESSIBILITY, a11yStreamAlias); + sStreamVolumeAlias.put(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; + // mStreanStates.get(STREAM_BLUETOOTH_SCO) == null + sStreamVolumeAlias.delete(AudioSystem.STREAM_BLUETOOTH_SCO); } if (updateVolumes && mStreamStates != null) { @@ -2562,17 +2610,17 @@ public class AudioService extends IAudioService.Stub synchronized (mSettingsLock) { synchronized (VolumeStreamState.class) { - mStreamStates[AudioSystem.STREAM_DTMF] - .setAllIndexes(mStreamStates[dtmfStreamAlias], caller); - mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setSettingName( + getVssForStreamOrDefault(AudioSystem.STREAM_DTMF) + .setAllIndexes(getVssForStreamOrDefault(dtmfStreamAlias), caller); + getVssForStreamOrDefault(AudioSystem.STREAM_ACCESSIBILITY).setSettingName( System.VOLUME_SETTINGS_INT[a11yStreamAlias]); - mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes( - mStreamStates[a11yStreamAlias], caller); + getVssForStreamOrDefault(AudioSystem.STREAM_ACCESSIBILITY).setAllIndexes( + getVssForStreamOrDefault(a11yStreamAlias), caller); } } if (sIndependentA11yVolume) { // restore the a11y values from the settings - mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings(); + getVssForStreamOrDefault(AudioSystem.STREAM_ACCESSIBILITY).readSettings(); } // apply stream mute states according to new value of mRingerModeAffectedStreams @@ -2582,13 +2630,13 @@ public class AudioService extends IAudioService.Stub SENDMSG_QUEUE, 0, 0, - mStreamStates[AudioSystem.STREAM_DTMF], 0); + getVssForStreamOrDefault(AudioSystem.STREAM_DTMF), 0); sendMsg(mAudioHandler, MSG_SET_ALL_VOLUMES, SENDMSG_QUEUE, 0, 0, - mStreamStates[AudioSystem.STREAM_ACCESSIBILITY], 0); + getVssForStreamOrDefault(AudioSystem.STREAM_ACCESSIBILITY), 0); } dispatchStreamAliasingUpdate(); } @@ -3065,7 +3113,8 @@ public class AudioService extends IAudioService.Stub } private int getIndexRange(int streamType) { - return (mStreamStates[streamType].getMaxIndex() - mStreamStates[streamType].getMinIndex()); + return (getVssForStreamOrDefault(streamType).getMaxIndex() - getVssForStreamOrDefault( + streamType).getMinIndex()); } private int rescaleIndex(VolumeInfo volumeInfo, int dstStream) { @@ -3073,11 +3122,12 @@ public class AudioService extends IAudioService.Stub || volumeInfo.getMinVolumeIndex() == VolumeInfo.INDEX_NOT_SET || volumeInfo.getMaxVolumeIndex() == VolumeInfo.INDEX_NOT_SET) { Log.e(TAG, "rescaleIndex: volumeInfo has invalid index or range"); - return mStreamStates[dstStream].getMinIndex(); + return getVssForStreamOrDefault(dstStream).getMinIndex(); } return rescaleIndex(volumeInfo.getVolumeIndex(), volumeInfo.getMinVolumeIndex(), volumeInfo.getMaxVolumeIndex(), - mStreamStates[dstStream].getMinIndex(), mStreamStates[dstStream].getMaxIndex()); + getVssForStreamOrDefault(dstStream).getMinIndex(), + getVssForStreamOrDefault(dstStream).getMaxIndex()); } private int rescaleIndex(int index, int srcStream, VolumeInfo dstVolumeInfo) { @@ -3088,14 +3138,17 @@ public class AudioService extends IAudioService.Stub return index; } return rescaleIndex(index, - mStreamStates[srcStream].getMinIndex(), mStreamStates[srcStream].getMaxIndex(), + getVssForStreamOrDefault(srcStream).getMinIndex(), + getVssForStreamOrDefault(srcStream).getMaxIndex(), dstMin, dstMax); } private int rescaleIndex(int index, int srcStream, int dstStream) { return rescaleIndex(index, - mStreamStates[srcStream].getMinIndex(), mStreamStates[srcStream].getMaxIndex(), - mStreamStates[dstStream].getMinIndex(), mStreamStates[dstStream].getMaxIndex()); + getVssForStreamOrDefault(srcStream).getMinIndex(), + getVssForStreamOrDefault(srcStream).getMaxIndex(), + getVssForStreamOrDefault(dstStream).getMinIndex(), + getVssForStreamOrDefault(dstStream).getMaxIndex()); } private int rescaleIndex(int index, int srcMin, int srcMax, int dstMin, int dstMax) { @@ -3618,7 +3671,7 @@ public class AudioService extends IAudioService.Stub streamType = replaceBtScoStreamWithVoiceCall(streamType, "adjustSuggestedStreamVolume"); ensureValidStreamType(streamType); - final int resolvedStream = mStreamVolumeAlias[streamType]; + final int resolvedStream = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1); // Play sounds on STREAM_RING only. if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && @@ -3735,9 +3788,9 @@ public class AudioService extends IAudioService.Stub // use stream type alias here so that streams with same alias have the same behavior, // including with regard to silent mode control (e.g the use of STREAM_RING below and in // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) - int streamTypeAlias = mStreamVolumeAlias[streamType]; + int streamTypeAlias = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1); - VolumeStreamState streamState = mStreamStates[streamTypeAlias]; + VolumeStreamState streamState = getVssForStreamOrDefault(streamTypeAlias); final int device = getDeviceForStream(streamTypeAlias); @@ -3823,7 +3876,7 @@ public class AudioService extends IAudioService.Stub if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) { adjustVolume = false; } - int oldIndex = mStreamStates[streamType].getIndex(device); + int oldIndex = getVssForStreamOrDefault(streamType).getIndex(device); // Check if the volume adjustment should be handled by an absolute volume controller instead if (isAbsoluteVolumeDevice(device) && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { @@ -3879,7 +3932,7 @@ public class AudioService extends IAudioService.Stub 0); } - int newIndex = mStreamStates[streamType].getIndex(device); + int newIndex = getVssForStreamOrDefault(streamType).getIndex(device); int streamToDriveAbsVol = absVolumeIndexFix() ? getBluetoothContextualVolumeStream() : AudioSystem.STREAM_MUSIC; @@ -3906,7 +3959,7 @@ public class AudioService extends IAudioService.Stub + newIndex + " stream=" + streamType); } mDeviceBroker.postSetLeAudioVolumeIndex(newIndex, - mStreamStates[streamType].getMaxIndex(), streamType); + getVssForStreamOrDefault(streamType).getMaxIndex(), streamType); } // Check if volume update should be send to Hearing Aid. @@ -3922,7 +3975,7 @@ public class AudioService extends IAudioService.Stub } } - final int newIndex = mStreamStates[streamType].getIndex(device); + final int newIndex = getVssForStreamOrDefault(streamType).getIndex(device); if (adjustVolume) { synchronized (mHdmiClientLock) { if (mHdmiManager != null) { @@ -4004,22 +4057,22 @@ public class AudioService extends IAudioService.Stub synchronized (mSettingsLock) { synchronized (VolumeStreamState.class) { List<Integer> streamsToMute = new ArrayList<>(); - for (int stream = 0; stream < mStreamStates.length; stream++) { - VolumeStreamState vss = mStreamStates[stream]; - if (vss != null && streamAlias == mStreamVolumeAlias[stream] + for (int stream = 0; stream < mStreamStates.size(); stream++) { + final VolumeStreamState vss = mStreamStates.valueAt(stream); + if (vss != null && streamAlias == sStreamVolumeAlias.get(vss.getStreamType()) && vss.isMutable()) { if (!(mCameraSoundForced && (vss.getStreamType() == AudioSystem.STREAM_SYSTEM_ENFORCED))) { boolean changed = vss.mute(state, /* apply= */ false, "muteAliasStreams"); if (changed) { - streamsToMute.add(stream); + streamsToMute.add(vss.getStreamType()); } } } } streamsToMute.forEach(streamToMute -> { - mStreamStates[streamToMute].doMute(); + getVssForStreamOrDefault(streamToMute).doMute(); broadcastMuteSetting(streamToMute, state); }); } @@ -4047,7 +4100,7 @@ public class AudioService extends IAudioService.Stub // vss.updateVolumeGroupIndex synchronized (mSettingsLock) { synchronized (VolumeStreamState.class) { - final VolumeStreamState streamState = mStreamStates[streamAlias]; + final VolumeStreamState streamState = getVssForStreamOrDefault(streamAlias); // if unmuting causes a change, it was muted wasMuted = streamState.mute(false, "onUnmuteStreamOnSingleVolDevice"); if (wasMuted) { @@ -4145,7 +4198,7 @@ public class AudioService extends IAudioService.Stub */ /*package*/ void onSetStreamVolume(int streamType, int index, int flags, int device, String caller, boolean hasModifyAudioSettings, boolean canChangeMute) { - final int stream = mStreamVolumeAlias[streamType]; + final int stream = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1); // setting volume on ui sounds stream type also controls silent mode if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || (stream == getUiSoundsStreamType())) { @@ -4286,26 +4339,30 @@ public class AudioService extends IAudioService.Stub // that can interfere with the sending of the VOLUME_CHANGED_ACTION intent mAudioSystem.clearRoutingCache(); + int streamType = replaceBtScoStreamWithVoiceCall(vi.getStreamType(), "setDeviceVolume"); + + final VolumeStreamState vss = getVssForStream(streamType); + // log the current device that will be used when evaluating the sending of the // VOLUME_CHANGED_ACTION intent to see if the current device is the one being modified - final int currDev = getDeviceForStream(vi.getStreamType()); + final int currDev = getDeviceForStream(streamType); - final boolean skipping = (currDev == ada.getInternalType()); + final boolean skipping = (currDev == ada.getInternalType()) || (vss == null); - AudioService.sVolumeLogger.enqueue(new DeviceVolumeEvent(vi.getStreamType(), index, ada, + AudioService.sVolumeLogger.enqueue(new DeviceVolumeEvent(streamType, index, ada, currDev, callingPackage, skipping)); if (skipping) { - // setDeviceVolume was called on a device currently being used + // setDeviceVolume was called on a device currently being used or stream state is null return; } // TODO handle unmuting of current audio device // if a stream is not muted but the VolumeInfo is for muting, set the volume index // for the device to min volume - if (vi.hasMuteCommand() && vi.isMuted() && !isStreamMute(vi.getStreamType())) { - setStreamVolumeWithAttributionInt(vi.getStreamType(), - mStreamStates[vi.getStreamType()].getMinIndex(), + if (vi.hasMuteCommand() && vi.isMuted() && !isStreamMute(streamType)) { + setStreamVolumeWithAttributionInt(streamType, + vss.getMinIndex(), /*flags*/ 0, ada, callingPackage, null, //TODO handle unmuting of current audio device @@ -4319,22 +4376,22 @@ public class AudioService extends IAudioService.Stub if (vi.getMinVolumeIndex() == VolumeInfo.INDEX_NOT_SET || vi.getMaxVolumeIndex() == VolumeInfo.INDEX_NOT_SET) { // assume index meant to be in stream type range, validate - if ((index * 10) < mStreamStates[vi.getStreamType()].getMinIndex() - || (index * 10) > mStreamStates[vi.getStreamType()].getMaxIndex()) { + if ((index * 10) < vss.getMinIndex() + || (index * 10) > vss.getMaxIndex()) { throw new IllegalArgumentException("invalid volume index " + index + " not between min/max for stream " + vi.getStreamType()); } } else { // check if index needs to be rescaled - final int min = (mStreamStates[vi.getStreamType()].getMinIndex() + 5) / 10; - final int max = (mStreamStates[vi.getStreamType()].getMaxIndex() + 5) / 10; + final int min = (vss.getMinIndex() + 5) / 10; + final int max = (vss.getMaxIndex() + 5) / 10; if (vi.getMinVolumeIndex() != min || vi.getMaxVolumeIndex() != max) { index = rescaleIndex(index, /*srcMin*/ vi.getMinVolumeIndex(), /*srcMax*/ vi.getMaxVolumeIndex(), /*dstMin*/ min, /*dstMax*/ max); } } - setStreamVolumeWithAttributionInt(vi.getStreamType(), index, /*flags*/ 0, + setStreamVolumeWithAttributionInt(streamType, index, /*flags*/ 0, ada, callingPackage, null, false /*canChangeMuteAndUpdateController*/); } @@ -4762,7 +4819,7 @@ public class AudioService extends IAudioService.Stub if (AudioSystem.isLeAudioDeviceType(device)) { mDeviceBroker.postSetLeAudioVolumeIndex(index * 10, - mStreamStates[streamType].getMaxIndex(), streamType); + getVssForStreamOrDefault(streamType).getMaxIndex(), streamType); } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) { mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType); } else { @@ -4790,8 +4847,8 @@ public class AudioService extends IAudioService.Stub streamType = replaceBtScoStreamWithVoiceCall(streamType, "setStreamVolume"); ensureValidStreamType(streamType); - int streamTypeAlias = mStreamVolumeAlias[streamType]; - VolumeStreamState streamState = mStreamStates[streamTypeAlias]; + int streamTypeAlias = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound*/-1); + final VolumeStreamState streamState = getVssForStreamOrDefault(streamTypeAlias); if (!replaceStreamBtSco() && (streamType == AudioManager.STREAM_VOICE_CALL) && isInCommunication() && mDeviceBroker.isBluetoothScoActive()) { @@ -4857,7 +4914,7 @@ public class AudioService extends IAudioService.Stub // ada is non-null when called from setDeviceVolume, // which shouldn't update the mute state canChangeMuteAndUpdateController /*canChangeMute*/); - index = mStreamStates[streamType].getIndex(device); + index = getVssForStreamOrDefault(streamType).getIndex(device); } } @@ -4885,8 +4942,8 @@ public class AudioService extends IAudioService.Stub Log.d(TAG, "setStreamVolume postSetLeAudioVolumeIndex index=" + index + " stream=" + streamType); } - mDeviceBroker.postSetLeAudioVolumeIndex(index, mStreamStates[streamType].getMaxIndex(), - streamType); + mDeviceBroker.postSetLeAudioVolumeIndex(index, + getVssForStreamOrDefault(streamType).getMaxIndex(), streamType); } if (device == AudioSystem.DEVICE_OUT_HEARING_AID @@ -4916,7 +4973,7 @@ public class AudioService extends IAudioService.Stub // ada is non-null when called from setDeviceVolume, // which shouldn't update the mute state canChangeMuteAndUpdateController /*canChangeMute*/); - index = mStreamStates[streamType].getIndex(device); + index = getVssForStreamOrDefault(streamType).getIndex(device); } } @@ -5099,7 +5156,7 @@ public class AudioService extends IAudioService.Stub // UI update and Broadcast Intent protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags, int device) { - streamType = mStreamVolumeAlias[streamType]; + streamType = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1); if (streamType == AudioSystem.STREAM_MUSIC && isFullVolumeDevice(device)) { flags &= ~AudioManager.FLAG_SHOW_UI; @@ -5147,7 +5204,7 @@ public class AudioService extends IAudioService.Stub if (isFullVolumeDevice(device)) { return; } - VolumeStreamState streamState = mStreamStates[streamType]; + final VolumeStreamState streamState = getVssForStreamOrDefault(streamType); if (streamState.setIndex(index, device, caller, hasModifyAudioSettings) || force) { // Post message to set system volume (it in turn will post a message @@ -5171,7 +5228,7 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { ensureValidStreamType(streamType); - return mStreamStates[streamType].mIsMuted; + return getVssForStreamOrDefault(streamType).mIsMuted; } } @@ -5270,7 +5327,7 @@ public class AudioService extends IAudioService.Stub if (applyRequired) { // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC); - mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes(); + getVssForStreamOrDefault(AudioSystem.STREAM_MUSIC).applyAllVolumes(); } } } @@ -5351,15 +5408,16 @@ public class AudioService extends IAudioService.Stub private int getStreamVolume(int streamType, int device) { synchronized (VolumeStreamState.class) { - int index = mStreamStates[streamType].getIndex(device); + final VolumeStreamState vss = getVssForStreamOrDefault(streamType); + int index = vss.getIndex(device); // by convention getStreamVolume() returns 0 when a stream is muted. - if (mStreamStates[streamType].mIsMuted) { + if (vss.mIsMuted) { index = 0; } - if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) && - isFixedVolumeDevice(device)) { - index = mStreamStates[streamType].getMaxIndex(); + if (index != 0 && (sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_MUSIC) + && isFixedVolumeDevice(device)) { + index = vss.getMaxIndex(); } return (index + 5) / 10; } @@ -5382,20 +5440,27 @@ public class AudioService extends IAudioService.Stub return getDefaultVolumeInfo(); } - int streamType = vi.getStreamType(); + int streamType = replaceBtScoStreamWithVoiceCall(vi.getStreamType(), "getStreamMaxVolume"); final VolumeInfo.Builder vib = new VolumeInfo.Builder(vi); - vib.setMinVolumeIndex((mStreamStates[streamType].mIndexMin + 5) / 10); - vib.setMaxVolumeIndex((mStreamStates[streamType].mIndexMax + 5) / 10); + final VolumeStreamState vss = getVssForStream(streamType); + if (vss == null) { + Log.w(TAG, + "getDeviceVolume unsupported stream type " + streamType + ". Return default"); + return getDefaultVolumeInfo(); + } + + vib.setMinVolumeIndex((vss.mIndexMin + 5) / 10); + vib.setMaxVolumeIndex((vss.mIndexMax + 5) / 10); synchronized (VolumeStreamState.class) { final int index; if (isFixedVolumeDevice(ada.getInternalType())) { - index = (mStreamStates[streamType].mIndexMax + 5) / 10; + index = (vss.mIndexMax + 5) / 10; } else { - index = (mStreamStates[streamType].getIndex(ada.getInternalType()) + 5) / 10; + index = (vss.getIndex(ada.getInternalType()) + 5) / 10; } vib.setVolumeIndex(index); // only set as a mute command if stream muted - if (mStreamStates[streamType].mIsMuted) { + if (vss.mIsMuted) { vib.setMuted(true); } return vib.build(); @@ -5406,7 +5471,7 @@ public class AudioService extends IAudioService.Stub public int getStreamMaxVolume(int streamType) { streamType = replaceBtScoStreamWithVoiceCall(streamType, "getStreamMaxVolume"); ensureValidStreamType(streamType); - return (mStreamStates[streamType].getMaxIndex() + 5) / 10; + return (getVssForStreamOrDefault(streamType).getMaxIndex() + 5) / 10; } /** @see AudioManager#getStreamMinVolumeInt(int) @@ -5419,7 +5484,7 @@ public class AudioService extends IAudioService.Stub || callingHasAudioSettingsPermission() || (mContext.checkCallingPermission(MODIFY_AUDIO_ROUTING) == PackageManager.PERMISSION_GRANTED); - return (mStreamStates[streamType].getMinIndex(isPrivileged) + 5) / 10; + return (getVssForStreamOrDefault(streamType).getMinIndex(isPrivileged) + 5) / 10; } @android.annotation.EnforcePermission(QUERY_AUDIO_STATE) @@ -5432,7 +5497,7 @@ public class AudioService extends IAudioService.Stub ensureValidStreamType(streamType); int device = getDeviceForStream(streamType); - return (mStreamStates[streamType].getIndex(device) + 5) / 10; + return (getVssForStreamOrDefault(streamType).getIndex(device) + 5) / 10; } /** @@ -5502,9 +5567,10 @@ public class AudioService extends IAudioService.Stub .boxed().toList()); } ArrayList<Integer> res = new ArrayList(1); - for (int stream : mStreamVolumeAlias) { - if (stream >= 0 && !res.contains(stream)) { - res.add(stream); + for (int stream = 0; stream < sStreamVolumeAlias.size(); ++stream) { + final int streamAlias = sStreamVolumeAlias.valueAt(stream); + if (!res.contains(streamAlias)) { + res.add(streamAlias); } } return res; @@ -5525,7 +5591,7 @@ public class AudioService extends IAudioService.Stub // verify parameters ensureValidStreamType(sourceStreamType); - return mStreamVolumeAlias[sourceStreamType]; + return sStreamVolumeAlias.get(sourceStreamType, /*valueIfKeyNotFound=*/-1); } /** @@ -5547,7 +5613,7 @@ public class AudioService extends IAudioService.Stub */ public int getUiSoundsStreamType() { return mUseVolumeGroupAliases ? STREAM_VOLUME_ALIAS_VOICE[AudioSystem.STREAM_SYSTEM] - : mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM]; + : sStreamVolumeAlias.get(AudioSystem.STREAM_SYSTEM); } /** @@ -5559,7 +5625,7 @@ public class AudioService extends IAudioService.Stub return mUseVolumeGroupAliases ? STREAM_VOLUME_ALIAS_VOICE[aliasStreamType] == STREAM_VOLUME_ALIAS_VOICE[AudioSystem.STREAM_SYSTEM] - : aliasStreamType == mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM]; + : aliasStreamType == sStreamVolumeAlias.get(AudioSystem.STREAM_SYSTEM); } /** @see AudioManager#setMicrophoneMute(boolean) */ @@ -5853,6 +5919,10 @@ public class AudioService extends IAudioService.Stub forceUse, eventSource, 0); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { + final VolumeStreamState vss = getVssForStream(streamType); + if (vss == null) { + continue; + } final boolean isMuted = isStreamMutedByRingerOrZenMode(streamType); final boolean muteAllowedBySco = !((shouldRingSco || shouldRingBle) && streamType == AudioSystem.STREAM_RING); @@ -5863,10 +5933,9 @@ public class AudioService extends IAudioService.Stub if (!shouldMute) { // unmute // ring and notifications volume should never be 0 when not silenced - if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING - || mStreamVolumeAlias[streamType] == AudioSystem.STREAM_NOTIFICATION) { + if (sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_RING + || sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_NOTIFICATION) { synchronized (VolumeStreamState.class) { - final VolumeStreamState vss = mStreamStates[streamType]; for (int i = 0; i < vss.mIndexMap.size(); i++) { int device = vss.mIndexMap.keyAt(i); int value = vss.mIndexMap.valueAt(i); @@ -5881,20 +5950,20 @@ public class AudioService extends IAudioService.Stub SENDMSG_QUEUE, device, 0, - mStreamStates[streamType], + vss, PERSIST_DELAY); } } sRingerAndZenModeMutedStreams &= ~(1 << streamType); sMuteLogger.enqueue(new AudioServiceEvents.RingerZenMutedStreamsEvent( sRingerAndZenModeMutedStreams, "muteRingerModeStreams")); - mStreamStates[streamType].mute(false, "muteRingerModeStreams"); + vss.mute(false, "muteRingerModeStreams"); } else { // mute sRingerAndZenModeMutedStreams |= (1 << streamType); sMuteLogger.enqueue(new AudioServiceEvents.RingerZenMutedStreamsEvent( sRingerAndZenModeMutedStreams, "muteRingerModeStreams")); - mStreamStates[streamType].mute(true, "muteRingerModeStreams"); + vss.mute(true, "muteRingerModeStreams"); } } } @@ -6317,15 +6386,15 @@ public class AudioService extends IAudioService.Stub final int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); final int device = getDeviceForStream(streamType); - final int streamAlias = mStreamVolumeAlias[streamType]; + final int streamAlias = sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/ + -1); if (DEBUG_MODE) { Log.v(TAG, "onUpdateAudioMode: streamType=" + streamType + ", streamAlias=" + streamAlias); } - final int index = mStreamStates[streamAlias].getIndex(device); - final int maxIndex = mStreamStates[streamAlias].getMaxIndex(); + final int index = getVssForStreamOrDefault(streamAlias).getIndex(device); setStreamVolumeInt(streamAlias, index, device, true, requesterPackage, true /*hasModifyAudioSettings*/); @@ -6630,13 +6699,13 @@ public class AudioService extends IAudioService.Stub // restore volume settings int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = 0; streamType < numStreamTypes; streamType++) { - VolumeStreamState streamState = mStreamStates[streamType]; + final VolumeStreamState streamState = getVssForStream(streamType); if (streamState == null) { continue; } - if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) { + if (userSwitch && sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_MUSIC) { continue; } @@ -7204,7 +7273,7 @@ public class AudioService extends IAudioService.Stub } else { ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); } - if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) { + if (sStreamVolumeAlias.get(AudioSystem.STREAM_DTMF) == AudioSystem.STREAM_RING) { ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF); } else { ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF); @@ -7260,7 +7329,7 @@ public class AudioService extends IAudioService.Stub } private void ensureValidStreamType(int streamType) { - if (streamType < 0 || streamType >= mStreamStates.length) { + if (streamType < 0 || streamType >= AudioSystem.getNumStreamTypes()) { throw new IllegalArgumentException("Bad stream type " + streamType); } } @@ -7525,9 +7594,10 @@ public class AudioService extends IAudioService.Stub ? MIN_STREAM_VOLUME[AudioSystem.STREAM_ALARM] : Math.min(idx + 1, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]); // update the VolumeStreamState for STREAM_ALARM and its aliases - for (int stream : mStreamVolumeAlias) { - if (stream >= 0 && mStreamVolumeAlias[stream] == AudioSystem.STREAM_ALARM) { - mStreamStates[stream].updateNoPermMinIndex(safeIndex); + for (int stream = 0; stream < sStreamVolumeAlias.size(); ++stream) { + final int streamAlias = sStreamVolumeAlias.valueAt(stream); + if (streamAlias == AudioSystem.STREAM_ALARM) { + getVssForStreamOrDefault(streamAlias).updateNoPermMinIndex(safeIndex); } } } @@ -7642,21 +7712,21 @@ public class AudioService extends IAudioService.Stub stream = replaceBtScoStreamWithVoiceCall(stream, "getDeviceSetForStream"); ensureValidStreamType(stream); synchronized (VolumeStreamState.class) { - return mStreamStates[stream].observeDevicesForStream_syncVSS(true); + return getVssForStreamOrDefault(stream).observeDevicesForStream_syncVSS(true); } } private void onObserveDevicesForAllStreams(int skipStream) { synchronized (mSettingsLock) { synchronized (VolumeStreamState.class) { - for (int stream = 0; stream < mStreamStates.length; stream++) { - if (stream != skipStream && mStreamStates[stream] != null) { + for (int stream = 0; stream < mStreamStates.size(); stream++) { + final VolumeStreamState vss = mStreamStates.valueAt(stream); + if (vss != null && vss.getStreamType() != skipStream) { Set<Integer> deviceSet = - mStreamStates[stream].observeDevicesForStream_syncVSS( - false /*checkOthers*/); + vss.observeDevicesForStream_syncVSS(false /*checkOthers*/); for (Integer device : deviceSet) { // Update volume states for devices routed for the stream - updateVolumeStates(device, stream, + updateVolumeStates(device, vss.getStreamType(), "AudioService#onObserveDevicesForAllStreams"); } } @@ -7689,7 +7759,7 @@ public class AudioService extends IAudioService.Stub private void onUpdateScoDeviceActive(boolean scoDeviceActive) { if (mScoDeviceActive.compareAndSet(!scoDeviceActive, scoDeviceActive)) { - getVssVolumeForStream(AudioSystem.STREAM_VOICE_CALL).updateIndexFactors(); + getVssForStreamOrDefault(AudioSystem.STREAM_VOICE_CALL).updateIndexFactors(); } } @@ -8084,7 +8154,7 @@ public class AudioService extends IAudioService.Stub /** only public for mocking/spying, do not call outside of AudioService */ @VisibleForTesting public void setMusicMute(boolean mute) { - mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); + getVssForStreamOrDefault(AudioSystem.STREAM_MUSIC).muteInternally(mute); } private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET; @@ -8115,8 +8185,8 @@ public class AudioService extends IAudioService.Stub if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS && !isStreamMutedByRingerOrZenMode(AudioSystem.STREAM_MUSIC) && DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice) - && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted - && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0 + && getVssForStreamOrDefault(AudioSystem.STREAM_MUSIC).mIsMuted + && getVssForStreamOrDefault(AudioSystem.STREAM_MUSIC).getIndex(newDevice) != 0 && getDeviceSetForStreamDirect(AudioSystem.STREAM_MUSIC).contains(newDevice)) { if (DEBUG_VOL) { Log.i(TAG, String.format("onAccessoryPlugMediaUnmute unmuting device=%d [%s]", @@ -8125,7 +8195,8 @@ public class AudioService extends IAudioService.Stub // Locking mSettingsLock to avoid inversion when calling vss.mute -> vss.doMute -> // vss.updateVolumeGroupIndex synchronized (mSettingsLock) { - mStreamStates[AudioSystem.STREAM_MUSIC].mute(false, "onAccessoryPlugMediaUnmute"); + getVssForStreamOrDefault(AudioSystem.STREAM_MUSIC).mute(false, + "onAccessoryPlugMediaUnmute"); } } } @@ -8296,8 +8367,8 @@ public class AudioService extends IAudioService.Stub } if (replaceStreamBtSco()) { - mIndexMin = mStreamStates[mPublicStreamType].getMinIndex() / 10; - mIndexMax = mStreamStates[mPublicStreamType].getMaxIndex() / 10; + mIndexMin = getVssForStreamOrDefault(mPublicStreamType).getMinIndex() / 10; + mIndexMax = getVssForStreamOrDefault(mPublicStreamType).getMaxIndex() / 10; } else { mIndexMin = MIN_STREAM_VOLUME[mPublicStreamType]; mIndexMax = MAX_STREAM_VOLUME[mPublicStreamType]; @@ -8334,7 +8405,7 @@ public class AudioService extends IAudioService.Stub */ private boolean isVssMuteBijective(int stream) { return isStreamAffectedByMute(stream) - && (getMinIndex() == (mStreamStates[stream].getMinIndex() + 5) / 10) + && (getMinIndex() == (getVssForStreamOrDefault(stream).getMinIndex() + 5) / 10) && (getMinIndex() == 0 || isCallStream(stream)); } @@ -8380,7 +8451,8 @@ public class AudioService extends IAudioService.Stub return; } - float stepFactor = mStreamStates[mPublicStreamType].getIndexStepFactor(); + float stepFactor = getVssForStreamOrDefault( + mPublicStreamType).getIndexStepFactor(); switch (direction) { case AudioManager.ADJUST_TOGGLE_MUTE: { // Note: If muted by volume 0, unmute will restore volume 0. @@ -8476,7 +8548,7 @@ public class AudioService extends IAudioService.Stub // 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 (mHasValidStreamType && isVssMuteBijective(mPublicStreamType) - && mStreamStates[mPublicStreamType].isFullyMuted()) { + && getVssForStreamOrDefault(mPublicStreamType).isFullyMuted()) { index = 0; } else if (isStreamBluetoothSco(mPublicStreamType) && index == 0) { index = 1; @@ -8484,7 +8556,7 @@ public class AudioService extends IAudioService.Stub if (replaceStreamBtSco()) { index = (int) (mIndexMin + (index - mIndexMin) - / mStreamStates[mPublicStreamType].getIndexStepFactor()); + / getVssForStreamOrDefault(mPublicStreamType).getIndexStepFactor()); } if (DEBUG_VOL) { @@ -8517,7 +8589,7 @@ public class AudioService extends IAudioService.Stub } private boolean isValidStream(int stream) { - return (stream != AudioSystem.STREAM_DEFAULT) && (stream < mStreamStates.length); + return (stream != AudioSystem.STREAM_DEFAULT) && getVssForStream(stream) != null; } public boolean isMusic() { @@ -8535,10 +8607,10 @@ public class AudioService extends IAudioService.Stub if (device != AudioSystem.DEVICE_OUT_DEFAULT) { for (int stream : getLegacyStreamTypes()) { if (isValidStream(stream)) { - boolean streamMuted = mStreamStates[stream].mIsMuted; + final VolumeStreamState vss = getVssForStreamOrDefault(stream); + boolean streamMuted = vss.mIsMuted; int deviceForStream = getDeviceForStream(stream); - int indexForStream = - (mStreamStates[stream].getIndex(deviceForStream) + 5) / 10; + int indexForStream = (vss.getIndex(deviceForStream) + 5) / 10; if (device == deviceForStream) { if (indexForStream == index && (isMuted() == streamMuted) && isVssMuteBijective(stream)) { @@ -8548,19 +8620,17 @@ public class AudioService extends IAudioService.Stub if (vgsVssSyncMuteOrder()) { if ((isMuted() != streamMuted) && isVssMuteBijective( stream)) { - mStreamStates[stream].mute(isMuted(), - "VGS.applyAllVolumes#1"); + vss.mute(isMuted(), "VGS.applyAllVolumes#1"); } } if (indexForStream != index) { - mStreamStates[stream].setIndex(index * 10, device, caller, - true /*hasModifyAudioSettings*/); + vss.setIndex(index * 10, device, + caller, true /*hasModifyAudioSettings*/); } if (!vgsVssSyncMuteOrder()) { if ((isMuted() != streamMuted) && isVssMuteBijective( stream)) { - mStreamStates[stream].mute(isMuted(), - "VGS.applyAllVolumes#1"); + vss.mute(isMuted(), "VGS.applyAllVolumes#1"); } } } @@ -8584,11 +8654,12 @@ public class AudioService extends IAudioService.Stub boolean forceDeviceSync = userSwitch && (mIndexMap.indexOfKey(deviceForVolume) < 0); for (int stream : getLegacyStreamTypes()) { if (isValidStream(stream)) { - boolean streamMuted = mStreamStates[stream].mIsMuted; - int defaultStreamIndex = (mStreamStates[stream].getIndex( - AudioSystem.DEVICE_OUT_DEFAULT) + 5) / 10; + final VolumeStreamState vss = getVssForStreamOrDefault(stream); + boolean streamMuted = vss.mIsMuted; + int defaultStreamIndex = (vss.getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5) + / 10; if (forceDeviceSync) { - mStreamStates[stream].setIndex(index * 10, deviceForVolume, caller, + vss.setIndex(index * 10, deviceForVolume, caller, true /*hasModifyAudioSettings*/); } if (defaultStreamIndex == index && (isMuted() == streamMuted) @@ -8597,12 +8668,11 @@ public class AudioService extends IAudioService.Stub continue; } if (defaultStreamIndex != index) { - mStreamStates[stream].setIndex( - index * 10, AudioSystem.DEVICE_OUT_DEFAULT, caller, + vss.setIndex(index * 10, AudioSystem.DEVICE_OUT_DEFAULT, caller, true /*hasModifyAudioSettings*/); } if ((isMuted() != streamMuted) && isVssMuteBijective(stream)) { - mStreamStates[stream].mute(isMuted(), "VGS.applyAllVolumes#2"); + vss.mute(isMuted(), "VGS.applyAllVolumes#2"); } } } @@ -8950,7 +9020,7 @@ public class AudioService extends IAudioService.Stub postObserveDevicesForAllStreams(mStreamType); } // log base stream changes to the event log - if (mStreamVolumeAlias[mStreamType] == mStreamType) { + if (sStreamVolumeAlias.get(mStreamType, /*valueIfKeyNotFound=*/-1) == mStreamType) { EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices); } // send STREAM_DEVICES_CHANGED_ACTION on the message handler so it is scheduled after @@ -9202,10 +9272,11 @@ public class AudioService extends IAudioService.Stub isCurrentDevice = (device == getDeviceForStream(mStreamType)); final int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - final VolumeStreamState aliasStreamState = mStreamStates[streamType]; - if (streamType != mStreamType && - mStreamVolumeAlias[streamType] == mStreamType && - (changed || !aliasStreamState.hasIndexForDevice(device))) { + final VolumeStreamState aliasStreamState = getVssForStream(streamType); + if (aliasStreamState != null && streamType != mStreamType + && sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound*/-1) + == mStreamType && (changed || !aliasStreamState.hasIndexForDevice( + device))) { final int scaledIndex = rescaleIndex(aliasIndex, mStreamType, streamType); boolean changedAlias = aliasStreamState.setIndex(scaledIndex, device, @@ -9240,7 +9311,7 @@ public class AudioService extends IAudioService.Stub oldIndex = (oldIndex + 5) / 10; index = (index + 5) / 10; // log base stream changes to the event log - if (mStreamVolumeAlias[mStreamType] == mStreamType) { + if (sStreamVolumeAlias.get(mStreamType, /*valueIfKeyNotFound=*/-1) == mStreamType) { if (caller == null) { Log.w(TAG, "No caller for volume_changed event", new Throwable()); } @@ -9252,7 +9323,9 @@ public class AudioService extends IAudioService.Stub if ((index != oldIndex) && isCurrentDevice) { // for single volume devices, only send the volume change broadcast // on the alias stream - if (!mIsSingleVolume || (mStreamVolumeAlias[mStreamType] == mStreamType)) { + final int streamAlias = sStreamVolumeAlias.get( + mStreamType, /*valueIfKeyNotFound=*/-1); + if (!mIsSingleVolume || streamAlias == mStreamType) { mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); @@ -9267,9 +9340,9 @@ public class AudioService extends IAudioService.Stub mStreamType); } mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS, - mStreamVolumeAlias[mStreamType]); + streamAlias); - if (mStreamType == mStreamVolumeAlias[mStreamType]) { + if (mStreamType == streamAlias) { String aliasStreamIndexesString = ""; if (!aliasStreamIndexes.isEmpty()) { aliasStreamIndexesString = @@ -9527,7 +9600,7 @@ public class AudioService extends IAudioService.Stub public void checkFixedVolumeDevices() { synchronized (VolumeStreamState.class) { // ignore settings for fixed volume devices: volume should always be at max or 0 - if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) { + if (sStreamVolumeAlias.get(mStreamType) == AudioSystem.STREAM_MUSIC) { for (int i = 0; i < mIndexMap.size(); i++) { int device = mIndexMap.keyAt(i); int index = mIndexMap.valueAt(i); @@ -9673,7 +9746,11 @@ public class AudioService extends IAudioService.Stub } private void onSetVolumeIndexOnDevice(@NonNull DeviceVolumeUpdate update) { - final VolumeStreamState streamState = mStreamStates[update.mStreamType]; + final VolumeStreamState streamState = getVssForStream(update.mStreamType); + if (streamState == null) { + Log.w(TAG, "Invalid onSetVolumeIndexOnDevice for stream type " + update.mStreamType); + return; + } if (update.hasVolumeIndex()) { int index = update.getVolumeIndex(); if (mSoundDoseHelper.checkSafeMediaVolume(update.mStreamType, index, update.mDevice)) { @@ -9704,8 +9781,10 @@ public class AudioService extends IAudioService.Stub // Apply change to all streams using this one as alias int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - if (streamType != streamState.mStreamType && - mStreamVolumeAlias[streamType] == streamState.mStreamType) { + final VolumeStreamState vss = getVssForStream(streamType); + if (vss != null && streamType != streamState.mStreamType + && sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1) + == streamState.mStreamType) { // Make sure volume is also maxed out on A2DP device for aliased stream // that may have a different device selected int streamDevice = getDeviceForStream(streamType); @@ -9713,9 +9792,9 @@ public class AudioService extends IAudioService.Stub && (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device) || AudioSystem.isLeAudioDeviceType(device))) { - mStreamStates[streamType].applyDeviceVolume_syncVSS(device); + vss.applyDeviceVolume_syncVSS(device); } - mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice); + vss.applyDeviceVolume_syncVSS(streamDevice); } } } @@ -9749,9 +9828,11 @@ public class AudioService extends IAudioService.Stub // Apply change to all streams using this one as alias int numStreamTypes = AudioSystem.getNumStreamTypes(); for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { - if (streamType != streamState.mStreamType && - mStreamVolumeAlias[streamType] == streamState.mStreamType) { - mStreamStates[streamType].applyAllVolumes(); + final VolumeStreamState vss = getVssForStream(streamType); + if (vss != null && streamType != streamState.mStreamType + && sStreamVolumeAlias.get(streamType, /*valueIfKeyNotFound=*/-1) + == streamState.mStreamType) { + vss.applyAllVolumes(); } } } @@ -10201,7 +10282,7 @@ public class AudioService extends IAudioService.Stub } sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, - mStreamStates[AudioSystem.STREAM_MUSIC], 0); + getVssForStreamOrDefault(AudioSystem.STREAM_MUSIC), 0); } /** @@ -10321,7 +10402,7 @@ public class AudioService extends IAudioService.Stub SENDMSG_QUEUE, 0, 0, - mStreamStates[AudioSystem.STREAM_MUSIC], 0); + getVssForStreamOrDefault(AudioSystem.STREAM_MUSIC), 0); } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) { // Disable audio recording for the background user/profile int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); @@ -11488,13 +11569,15 @@ public class AudioService extends IAudioService.Stub if (cameraSoundForcedChanged) { if (!mIsSingleVolume) { synchronized (VolumeStreamState.class) { - VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED]; + final VolumeStreamState s = getVssForStreamOrDefault( + AudioSystem.STREAM_SYSTEM_ENFORCED); if (cameraSoundForced) { s.setAllIndexesToMax(); mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED); } else { - s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG); + s.setAllIndexes(getVssForStreamOrDefault(AudioSystem.STREAM_SYSTEM), + TAG); mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED); } @@ -11511,7 +11594,7 @@ public class AudioService extends IAudioService.Stub SENDMSG_QUEUE, 0, 0, - mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0); + getVssForStreamOrDefault(AudioSystem.STREAM_SYSTEM_ENFORCED), 0); } } diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java index ded93e60cd6f..dc79ab26d3b8 100644 --- a/services/core/java/com/android/server/audio/SoundDoseHelper.java +++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java @@ -633,7 +633,7 @@ public class SoundDoseHelper { } /*package*/ void enforceSafeMediaVolume(String caller) { - AudioService.VolumeStreamState streamState = mAudioService.getVssVolumeForStream( + AudioService.VolumeStreamState streamState = mAudioService.getVssForStreamOrDefault( AudioSystem.STREAM_MUSIC); for (int i = 0; i < mSafeMediaVolumeDevices.size(); ++i) { @@ -665,7 +665,7 @@ public class SoundDoseHelper { @GuardedBy("mSafeMediaVolumeStateLock") private boolean checkSafeMediaVolume_l(int streamType, int index, int device) { return (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) - && (AudioService.mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) + && (AudioService.sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_MUSIC) && safeDevicesContains(device) && (index > safeMediaVolumeIndex(device)); } @@ -908,7 +908,7 @@ public class SoundDoseHelper { return; } - if (AudioService.mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC + if (AudioService.sStreamVolumeAlias.get(streamType) == AudioSystem.STREAM_MUSIC && safeDevicesContains(device)) { float attenuationDb = -AudioSystem.getStreamVolumeDB(AudioSystem.STREAM_MUSIC, (newIndex + 5) / 10, device); |