Merge "CSD: Implement support for absolute volume" into udc-dev
This commit is contained in:
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
@@ -592,36 +644,70 @@ public class SoundDoseHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private void initCsd() {
|
||||
if (mEnableCsd) {
|
||||
Log.v(TAG, "Initializing sound dose");
|
||||
private void updateDoseAttenuation(int newIndex, int device, int streamType,
|
||||
boolean isAbsoluteVolume) {
|
||||
if (!mEnableCsd) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (mCsdStateLock) {
|
||||
if (mGlobalTimeOffsetInSecs == GLOBAL_TIME_OFFSET_UNINITIALIZED) {
|
||||
mGlobalTimeOffsetInSecs = System.currentTimeMillis() / 1000L;
|
||||
}
|
||||
final ISoundDose soundDose = mSoundDose.get();
|
||||
if (soundDose == null) {
|
||||
Log.w(TAG, "Can not apply attenuation. ISoundDose itf is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
float prevCsd = mCurrentCsd;
|
||||
// Restore persisted values
|
||||
mCurrentCsd = parseGlobalSettingFloat(
|
||||
Settings.Global.AUDIO_SAFE_CSD_CURRENT_VALUE, /* defaultValue= */0.f);
|
||||
if (mCurrentCsd != prevCsd) {
|
||||
mNextCsdWarning = parseGlobalSettingFloat(
|
||||
Settings.Global.AUDIO_SAFE_CSD_NEXT_WARNING, /* defaultValue= */1.f);
|
||||
final List<SoundDoseRecord> records = persistedStringToRecordList(
|
||||
mSettings.getGlobalString(mAudioService.getContentResolver(),
|
||||
Settings.Global.AUDIO_SAFE_CSD_DOSE_RECORDS),
|
||||
mGlobalTimeOffsetInSecs);
|
||||
if (records != null) {
|
||||
mDoseRecords.addAll(records);
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (!isAbsoluteVolume) {
|
||||
// remove any possible previous attenuation
|
||||
soundDose.updateAttenuation(/* attenuationDB= */0.f, device);
|
||||
return;
|
||||
}
|
||||
|
||||
reset();
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.v(TAG, "Initializing sound dose");
|
||||
|
||||
synchronized (mCsdStateLock) {
|
||||
if (mGlobalTimeOffsetInSecs == GLOBAL_TIME_OFFSET_UNINITIALIZED) {
|
||||
mGlobalTimeOffsetInSecs = System.currentTimeMillis() / 1000L;
|
||||
}
|
||||
|
||||
float prevCsd = mCurrentCsd;
|
||||
// Restore persisted values
|
||||
mCurrentCsd = parseGlobalSettingFloat(
|
||||
Settings.Global.AUDIO_SAFE_CSD_CURRENT_VALUE, /* defaultValue= */0.f);
|
||||
if (mCurrentCsd != prevCsd) {
|
||||
mNextCsdWarning = parseGlobalSettingFloat(
|
||||
Settings.Global.AUDIO_SAFE_CSD_NEXT_WARNING, /* defaultValue= */1.f);
|
||||
final List<SoundDoseRecord> records = persistedStringToRecordList(
|
||||
mSettings.getGlobalString(mAudioService.getContentResolver(),
|
||||
Settings.Global.AUDIO_SAFE_CSD_DOSE_RECORDS),
|
||||
mGlobalTimeOffsetInSecs);
|
||||
if (records != null) {
|
||||
mDoseRecords.addAll(records);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
private void onConfigureSafeMedia(boolean force, String caller) {
|
||||
synchronized (mSafeMediaVolumeStateLock) {
|
||||
int mcc = mContext.getResources().getConfiguration().mcc;
|
||||
@@ -668,10 +754,6 @@ public class SoundDoseHelper {
|
||||
/*obj=*/null), /*delay=*/0);
|
||||
}
|
||||
}
|
||||
|
||||
if (mEnableCsd) {
|
||||
initCsd();
|
||||
}
|
||||
}
|
||||
|
||||
private int getTimeoutMsForWarning(@AudioManager.CsdWarning int csdWarning) {
|
||||
|
||||
Reference in New Issue
Block a user