Loading services/core/java/com/android/server/audio/AudioService.java +11 −0 Original line number Diff line number Diff line Loading @@ -8358,6 +8358,7 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { // apply device specific volumes first int index; boolean isAbsoluteVolume = false; for (int i = 0; i < mIndexMap.size(); i++) { final int device = mIndexMap.keyAt(i); if (device != AudioSystem.DEVICE_OUT_DEFAULT) { Loading @@ -8366,6 +8367,7 @@ public class AudioService extends IAudioService.Stub } else if (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device) || AudioSystem.isLeAudioDeviceType(device)) { isAbsoluteVolume = true; index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); } else if (isFullVolumeDevice(device)) { index = (mIndexMax + 5)/10; Loading @@ -8374,6 +8376,11 @@ public class AudioService extends IAudioService.Stub } else { index = (mIndexMap.valueAt(i) + 5)/10; } sendMsg(mAudioHandler, SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION, SENDMSG_REPLACE, device, isAbsoluteVolume ? 1 : 0, this, /*delay=*/0); setStreamVolumeIndex(index, device); } } Loading Loading @@ -8848,6 +8855,10 @@ public class AudioService extends IAudioService.Stub /*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) { synchronized (VolumeStreamState.class) { sendMsg(mAudioHandler, SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION, SENDMSG_REPLACE, device, (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device) || AudioSystem.isLeAudioDeviceType(device) ? 1 : 0), streamState, /*delay=*/0); // Apply volume streamState.applyDeviceVolume_syncVSS(device); Loading services/core/java/com/android/server/audio/SoundDoseHelper.java +126 −44 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; /** Loading Loading @@ -89,6 +90,7 @@ public class SoundDoseHelper { private static final int MSG_PERSIST_SAFE_VOLUME_STATE = SAFE_MEDIA_VOLUME_MSG_START + 2; private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = SAFE_MEDIA_VOLUME_MSG_START + 3; private static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 4; /*package*/ static final int MSG_CSD_UPDATE_ATTENUATION = SAFE_MEDIA_VOLUME_MSG_START + 5; private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours Loading Loading @@ -142,6 +144,13 @@ public class SoundDoseHelper { Arrays.asList(AudioSystem.DEVICE_OUT_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, AudioSystem.DEVICE_OUT_USB_HEADSET)); private final Set<Integer> mSafeMediaCsdDevices = new HashSet<>( Arrays.asList(AudioSystem.DEVICE_OUT_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, AudioSystem.DEVICE_OUT_USB_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_BROADCAST, AudioSystem.DEVICE_OUT_HEARING_AID, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled. // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled Loading @@ -158,10 +167,10 @@ public class SoundDoseHelper { private final boolean mEnableCsd; private ISoundDose mSoundDose; private final Object mCsdStateLock = new Object(); private final AtomicReference<ISoundDose> mSoundDose = new AtomicReference<>(); @GuardedBy("mCsdStateLock") private float mCurrentCsd = 0.f; // dose at which the next dose reached warning occurs Loading Loading @@ -245,9 +254,11 @@ public class SoundDoseHelper { mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED; } else { mSafeMediaVolumeState = mSettings.getGlobalInt(audioService.getContentResolver(), Settings.Global.AUDIO_SAFE_VOLUME_STATE, 0); Settings.Global.AUDIO_SAFE_VOLUME_STATE, SAFE_MEDIA_VOLUME_NOT_CONFIGURED); } initCsd(); // The default safe volume index read here will be replaced by the actual value when // the mcc is read by onConfigureSafeMedia() // For now we use the same index for RS2 initial warning with CSD Loading @@ -263,9 +274,14 @@ public class SoundDoseHelper { return 0.f; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return 0.f; } try { return mSoundDose.getOutputRs2(); return soundDose.getOutputRs2(); } catch (RemoteException e) { Log.e(TAG, "Exception while getting the RS2 exposure value", e); return 0.f; Loading @@ -277,9 +293,14 @@ public class SoundDoseHelper { return; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return; } try { mSoundDose.setOutputRs2(rs2Value); soundDose.setOutputRs2(rs2Value); } catch (RemoteException e) { Log.e(TAG, "Exception while setting the RS2 exposure value", e); } Loading @@ -290,9 +311,14 @@ public class SoundDoseHelper { return -1.f; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return -1.f; } try { return mSoundDose.getCsd(); return soundDose.getCsd(); } catch (RemoteException e) { Log.e(TAG, "Exception while getting the CSD value", e); return -1.f; Loading @@ -304,13 +330,18 @@ public class SoundDoseHelper { return; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return; } try { final SoundDoseRecord record = new SoundDoseRecord(); record.timestamp = System.currentTimeMillis(); record.value = csd; final SoundDoseRecord[] recordArray = new SoundDoseRecord[] { record }; mSoundDose.resetCsd(csd, recordArray); soundDose.resetCsd(csd, recordArray); } catch (RemoteException e) { Log.e(TAG, "Exception while setting the CSD value", e); } Loading @@ -321,9 +352,14 @@ public class SoundDoseHelper { return; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return; } try { mSoundDose.forceUseFrameworkMel(useFrameworkMel); soundDose.forceUseFrameworkMel(useFrameworkMel); } catch (RemoteException e) { Log.e(TAG, "Exception while forcing the internal MEL computation", e); } Loading @@ -334,9 +370,14 @@ public class SoundDoseHelper { return; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return; } try { mSoundDose.forceComputeCsdOnAllDevices(computeCsdOnAllDevices); soundDose.forceComputeCsdOnAllDevices(computeCsdOnAllDevices); } catch (RemoteException e) { Log.e(TAG, "Exception while forcing CSD computation on all devices", e); } Loading Loading @@ -551,6 +592,15 @@ public class SoundDoseHelper { case MSG_PERSIST_CSD_VALUES: onPersistSoundDoseRecords(); break; case MSG_CSD_UPDATE_ATTENUATION: final int device = msg.arg1; final boolean isAbsoluteVolume = (msg.arg2 == 1); final AudioService.VolumeStreamState streamState = (AudioService.VolumeStreamState) msg.obj; updateDoseAttenuation(streamState.getIndex(device), device, streamState.getStreamType(), isAbsoluteVolume); break; default: Log.e(TAG, "Unexpected msg to handle: " + msg.what); break; Loading @@ -574,16 +624,18 @@ public class SoundDoseHelper { /*package*/void reset() { Log.d(TAG, "Reset the sound dose helper"); mSoundDose = AudioSystem.getSoundDoseInterface(mSoundDoseCallback); mSoundDose.set(AudioSystem.getSoundDoseInterface(mSoundDoseCallback)); synchronized (mCsdStateLock) { try { if (mSoundDose != null && mSoundDose.asBinder().isBinderAlive()) { final ISoundDose soundDose = mSoundDose.get(); if (soundDose != null && soundDose.asBinder().isBinderAlive()) { if (mCurrentCsd != 0.f) { Log.d(TAG, "Resetting the saved sound dose value " + mCurrentCsd); SoundDoseRecord[] records = mDoseRecords.toArray( new SoundDoseRecord[0]); mSoundDose.resetCsd(mCurrentCsd, records); soundDose.resetCsd(mCurrentCsd, records); } } } catch (RemoteException e) { Loading @@ -592,8 +644,43 @@ public class SoundDoseHelper { } } private void updateDoseAttenuation(int newIndex, int device, int streamType, boolean isAbsoluteVolume) { if (!mEnableCsd) { return; } final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Can not apply attenuation. ISoundDose itf is null."); return; } try { if (!isAbsoluteVolume) { // remove any possible previous attenuation soundDose.updateAttenuation(/* attenuationDB= */0.f, device); return; } if (AudioService.mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC && mSafeMediaCsdDevices.contains(device)) { soundDose.updateAttenuation( AudioSystem.getStreamVolumeDB(AudioSystem.STREAM_MUSIC, (newIndex + 5) / 10, device), device); } } catch (RemoteException e) { Log.e(TAG, "Could not apply the attenuation for MEL calculation with volume index " + newIndex, e); } } private void initCsd() { if (mEnableCsd) { if (!mEnableCsd) { return; } Log.v(TAG, "Initializing sound dose"); synchronized (mCsdStateLock) { Loading @@ -620,7 +707,6 @@ public class SoundDoseHelper { reset(); } } private void onConfigureSafeMedia(boolean force, String caller) { synchronized (mSafeMediaVolumeStateLock) { Loading Loading @@ -668,10 +754,6 @@ public class SoundDoseHelper { /*obj=*/null), /*delay=*/0); } } if (mEnableCsd) { initCsd(); } } private int getTimeoutMsForWarning(@AudioManager.CsdWarning int csdWarning) { Loading Loading
services/core/java/com/android/server/audio/AudioService.java +11 −0 Original line number Diff line number Diff line Loading @@ -8358,6 +8358,7 @@ public class AudioService extends IAudioService.Stub synchronized (VolumeStreamState.class) { // apply device specific volumes first int index; boolean isAbsoluteVolume = false; for (int i = 0; i < mIndexMap.size(); i++) { final int device = mIndexMap.keyAt(i); if (device != AudioSystem.DEVICE_OUT_DEFAULT) { Loading @@ -8366,6 +8367,7 @@ public class AudioService extends IAudioService.Stub } else if (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device) || AudioSystem.isLeAudioDeviceType(device)) { isAbsoluteVolume = true; index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); } else if (isFullVolumeDevice(device)) { index = (mIndexMax + 5)/10; Loading @@ -8374,6 +8376,11 @@ public class AudioService extends IAudioService.Stub } else { index = (mIndexMap.valueAt(i) + 5)/10; } sendMsg(mAudioHandler, SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION, SENDMSG_REPLACE, device, isAbsoluteVolume ? 1 : 0, this, /*delay=*/0); setStreamVolumeIndex(index, device); } } Loading Loading @@ -8848,6 +8855,10 @@ public class AudioService extends IAudioService.Stub /*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) { synchronized (VolumeStreamState.class) { sendMsg(mAudioHandler, SoundDoseHelper.MSG_CSD_UPDATE_ATTENUATION, SENDMSG_REPLACE, device, (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device) || AudioSystem.isLeAudioDeviceType(device) ? 1 : 0), streamState, /*delay=*/0); // Apply volume streamState.applyDeviceVolume_syncVSS(device); Loading
services/core/java/com/android/server/audio/SoundDoseHelper.java +126 −44 Original line number Diff line number Diff line Loading @@ -56,6 +56,7 @@ import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; /** Loading Loading @@ -89,6 +90,7 @@ public class SoundDoseHelper { private static final int MSG_PERSIST_SAFE_VOLUME_STATE = SAFE_MEDIA_VOLUME_MSG_START + 2; private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = SAFE_MEDIA_VOLUME_MSG_START + 3; private static final int MSG_PERSIST_CSD_VALUES = SAFE_MEDIA_VOLUME_MSG_START + 4; /*package*/ static final int MSG_CSD_UPDATE_ATTENUATION = SAFE_MEDIA_VOLUME_MSG_START + 5; private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours Loading Loading @@ -142,6 +144,13 @@ public class SoundDoseHelper { Arrays.asList(AudioSystem.DEVICE_OUT_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, AudioSystem.DEVICE_OUT_USB_HEADSET)); private final Set<Integer> mSafeMediaCsdDevices = new HashSet<>( Arrays.asList(AudioSystem.DEVICE_OUT_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, AudioSystem.DEVICE_OUT_USB_HEADSET, AudioSystem.DEVICE_OUT_BLE_HEADSET, AudioSystem.DEVICE_OUT_BLE_BROADCAST, AudioSystem.DEVICE_OUT_HEARING_AID, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled. // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled Loading @@ -158,10 +167,10 @@ public class SoundDoseHelper { private final boolean mEnableCsd; private ISoundDose mSoundDose; private final Object mCsdStateLock = new Object(); private final AtomicReference<ISoundDose> mSoundDose = new AtomicReference<>(); @GuardedBy("mCsdStateLock") private float mCurrentCsd = 0.f; // dose at which the next dose reached warning occurs Loading Loading @@ -245,9 +254,11 @@ public class SoundDoseHelper { mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED; } else { mSafeMediaVolumeState = mSettings.getGlobalInt(audioService.getContentResolver(), Settings.Global.AUDIO_SAFE_VOLUME_STATE, 0); Settings.Global.AUDIO_SAFE_VOLUME_STATE, SAFE_MEDIA_VOLUME_NOT_CONFIGURED); } initCsd(); // The default safe volume index read here will be replaced by the actual value when // the mcc is read by onConfigureSafeMedia() // For now we use the same index for RS2 initial warning with CSD Loading @@ -263,9 +274,14 @@ public class SoundDoseHelper { return 0.f; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return 0.f; } try { return mSoundDose.getOutputRs2(); return soundDose.getOutputRs2(); } catch (RemoteException e) { Log.e(TAG, "Exception while getting the RS2 exposure value", e); return 0.f; Loading @@ -277,9 +293,14 @@ public class SoundDoseHelper { return; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return; } try { mSoundDose.setOutputRs2(rs2Value); soundDose.setOutputRs2(rs2Value); } catch (RemoteException e) { Log.e(TAG, "Exception while setting the RS2 exposure value", e); } Loading @@ -290,9 +311,14 @@ public class SoundDoseHelper { return -1.f; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return -1.f; } try { return mSoundDose.getCsd(); return soundDose.getCsd(); } catch (RemoteException e) { Log.e(TAG, "Exception while getting the CSD value", e); return -1.f; Loading @@ -304,13 +330,18 @@ public class SoundDoseHelper { return; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return; } try { final SoundDoseRecord record = new SoundDoseRecord(); record.timestamp = System.currentTimeMillis(); record.value = csd; final SoundDoseRecord[] recordArray = new SoundDoseRecord[] { record }; mSoundDose.resetCsd(csd, recordArray); soundDose.resetCsd(csd, recordArray); } catch (RemoteException e) { Log.e(TAG, "Exception while setting the CSD value", e); } Loading @@ -321,9 +352,14 @@ public class SoundDoseHelper { return; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return; } try { mSoundDose.forceUseFrameworkMel(useFrameworkMel); soundDose.forceUseFrameworkMel(useFrameworkMel); } catch (RemoteException e) { Log.e(TAG, "Exception while forcing the internal MEL computation", e); } Loading @@ -334,9 +370,14 @@ public class SoundDoseHelper { return; } Objects.requireNonNull(mSoundDose, "Sound dose interface not initialized"); final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Sound dose interface not initialized"); return; } try { mSoundDose.forceComputeCsdOnAllDevices(computeCsdOnAllDevices); soundDose.forceComputeCsdOnAllDevices(computeCsdOnAllDevices); } catch (RemoteException e) { Log.e(TAG, "Exception while forcing CSD computation on all devices", e); } Loading Loading @@ -551,6 +592,15 @@ public class SoundDoseHelper { case MSG_PERSIST_CSD_VALUES: onPersistSoundDoseRecords(); break; case MSG_CSD_UPDATE_ATTENUATION: final int device = msg.arg1; final boolean isAbsoluteVolume = (msg.arg2 == 1); final AudioService.VolumeStreamState streamState = (AudioService.VolumeStreamState) msg.obj; updateDoseAttenuation(streamState.getIndex(device), device, streamState.getStreamType(), isAbsoluteVolume); break; default: Log.e(TAG, "Unexpected msg to handle: " + msg.what); break; Loading @@ -574,16 +624,18 @@ public class SoundDoseHelper { /*package*/void reset() { Log.d(TAG, "Reset the sound dose helper"); mSoundDose = AudioSystem.getSoundDoseInterface(mSoundDoseCallback); mSoundDose.set(AudioSystem.getSoundDoseInterface(mSoundDoseCallback)); synchronized (mCsdStateLock) { try { if (mSoundDose != null && mSoundDose.asBinder().isBinderAlive()) { final ISoundDose soundDose = mSoundDose.get(); if (soundDose != null && soundDose.asBinder().isBinderAlive()) { if (mCurrentCsd != 0.f) { Log.d(TAG, "Resetting the saved sound dose value " + mCurrentCsd); SoundDoseRecord[] records = mDoseRecords.toArray( new SoundDoseRecord[0]); mSoundDose.resetCsd(mCurrentCsd, records); soundDose.resetCsd(mCurrentCsd, records); } } } catch (RemoteException e) { Loading @@ -592,8 +644,43 @@ public class SoundDoseHelper { } } private void updateDoseAttenuation(int newIndex, int device, int streamType, boolean isAbsoluteVolume) { if (!mEnableCsd) { return; } final ISoundDose soundDose = mSoundDose.get(); if (soundDose == null) { Log.w(TAG, "Can not apply attenuation. ISoundDose itf is null."); return; } try { if (!isAbsoluteVolume) { // remove any possible previous attenuation soundDose.updateAttenuation(/* attenuationDB= */0.f, device); return; } if (AudioService.mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC && mSafeMediaCsdDevices.contains(device)) { soundDose.updateAttenuation( AudioSystem.getStreamVolumeDB(AudioSystem.STREAM_MUSIC, (newIndex + 5) / 10, device), device); } } catch (RemoteException e) { Log.e(TAG, "Could not apply the attenuation for MEL calculation with volume index " + newIndex, e); } } private void initCsd() { if (mEnableCsd) { if (!mEnableCsd) { return; } Log.v(TAG, "Initializing sound dose"); synchronized (mCsdStateLock) { Loading @@ -620,7 +707,6 @@ public class SoundDoseHelper { reset(); } } private void onConfigureSafeMedia(boolean force, String caller) { synchronized (mSafeMediaVolumeStateLock) { Loading Loading @@ -668,10 +754,6 @@ public class SoundDoseHelper { /*obj=*/null), /*delay=*/0); } } if (mEnableCsd) { initCsd(); } } private int getTimeoutMsForWarning(@AudioManager.CsdWarning int csdWarning) { Loading