Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 56dbf7ef authored by Vlad Popa's avatar Vlad Popa Committed by Automerger Merge Worker
Browse files

Merge "CSD: Implement support for absolute volume" into udc-dev am: 052bd448

parents d1038687 052bd448
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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);
+126 −44
Original line number Diff line number Diff line
@@ -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,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) {
@@ -620,7 +707,6 @@ public class SoundDoseHelper {

        reset();
    }
    }

    private void onConfigureSafeMedia(boolean force, String caller) {
        synchronized (mSafeMediaVolumeStateLock) {
@@ -668,10 +754,6 @@ public class SoundDoseHelper {
                                /*obj=*/null), /*delay=*/0);
            }
        }

        if (mEnableCsd) {
            initCsd();
        }
    }

    private int getTimeoutMsForWarning(@AudioManager.CsdWarning int csdWarning) {