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

Commit b97b3980 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

AudioService: hearing aid volume updates for voice vs media

Fix interactions between hearing aid volume control and Sound
Settings and Slice UIs with the following changes:

  When receiving volume change, only change the hearing aid volume
if the device is hearing aid and the stream type to change matches
the stream type returned by AudioService.getHearingAidStreamType().

  Modify AudioService.getHearingAidStreamType() to rely on the
audio mode OR the activity of the VOICE_COMMUNICATION* usage.

  Add a listener of audio playback activity to monitor the start
and end of the use of VOICE_COMMUNICATION* to reset the hearing
aid volume to that of media.
Do this only when HEARING_AID device is connected: register/unregister
callback for playback activity according to hearing aid connections.

Bug: 129163231
Test: use Sound Settings UI to control voice vol outside of call, verify
volume is unchanged when listening to media later.

Change-Id: I7af9554d04139e1a3929efa53cdcb04e37878571
parent e50aa221
Loading
Loading
Loading
Loading
+68 −8
Original line number Original line Diff line number Diff line
@@ -162,6 +162,7 @@ import java.util.List;
import java.util.NoSuchElementException;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;


/**
/**
 * The implementation of the volume manager service.
 * The implementation of the volume manager service.
@@ -265,6 +266,7 @@ public class AudioService extends IAudioService.Stub
    private static final int MSG_SET_DEVICE_STREAM_VOLUME = 26;
    private static final int MSG_SET_DEVICE_STREAM_VOLUME = 26;
    private static final int MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS = 27;
    private static final int MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS = 27;
    private static final int MSG_HDMI_VOLUME_CHECK = 28;
    private static final int MSG_HDMI_VOLUME_CHECK = 28;
    private static final int MSG_PLAYBACK_CONFIG_CHANGE = 29;
    // start of messages handled under wakelock
    // start of messages handled under wakelock
    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -1870,10 +1872,16 @@ public class AudioService extends IAudioService.Stub


            // Check if volume update should be send to Hearing Aid
            // Check if volume update should be send to Hearing Aid
            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
                Log.i(TAG, "adjustSreamVolume postSetHearingAidVolumeIndex index=" + newIndex
                // only modify the hearing aid attenuation when the stream to modify matches
                        + " stream=" + streamType);
                // the one expected by the hearing aid
                if (streamType == getHearingAidStreamType()) {
                    if (DEBUG_VOL) {
                        Log.d(TAG, "adjustSreamVolume postSetHearingAidVolumeIndex index="
                                + newIndex + " stream=" + streamType);
                    }
                    mDeviceBroker.postSetHearingAidVolumeIndex(newIndex, streamType);
                    mDeviceBroker.postSetHearingAidVolumeIndex(newIndex, streamType);
                }
                }
            }


            // Check if volume update should be sent to Hdmi system audio.
            // Check if volume update should be sent to Hdmi system audio.
            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
@@ -2164,11 +2172,53 @@ public class AudioService extends IAudioService.Stub
                return AudioSystem.STREAM_VOICE_CALL;
                return AudioSystem.STREAM_VOICE_CALL;
            case AudioSystem.MODE_NORMAL:
            case AudioSystem.MODE_NORMAL:
            default:
            default:
                // other conditions will influence the stream type choice, read on...
                break;
                break;
        }
        }
        if (mVoiceActive.get()) {
            return AudioSystem.STREAM_VOICE_CALL;
        }
        return AudioSystem.STREAM_MUSIC;
        return AudioSystem.STREAM_MUSIC;
    }
    }


    private AtomicBoolean mVoiceActive = new AtomicBoolean(false);

    private final IPlaybackConfigDispatcher mVoiceActivityMonitor =
            new IPlaybackConfigDispatcher.Stub() {
        @Override
        public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
                                                 boolean flush) {
            sendMsg(mAudioHandler, MSG_PLAYBACK_CONFIG_CHANGE, SENDMSG_REPLACE,
                    0 /*arg1 ignored*/, 0 /*arg2 ignored*/,
                    configs /*obj*/, 0 /*delay*/);
        }
    };

    private void onPlaybackConfigChange(List<AudioPlaybackConfiguration> configs) {
        boolean voiceActive = false;
        for (AudioPlaybackConfiguration config : configs) {
            final int usage = config.getAudioAttributes().getUsage();
            if ((usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
                    || usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
                    && config.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
                voiceActive = true;
                break;
            }
        }
        if (mVoiceActive.getAndSet(voiceActive) != voiceActive) {
            updateHearingAidVolumeOnVoiceActivityUpdate();
        }
    }

    private void updateHearingAidVolumeOnVoiceActivityUpdate() {
        final int streamType = getHearingAidStreamType();
        final int index = getStreamVolume(streamType);
        sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID,
                mVoiceActive.get(), streamType, index));
        mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);

    }

    /**
    /**
     * Manage an audio mode change for audio devices that use an "absolute volume" model,
     * Manage an audio mode change for audio devices that use an "absolute volume" model,
     * i.e. the framework sends the full scale signal, and the actual volume for the use case
     * i.e. the framework sends the full scale signal, and the actual volume for the use case
@@ -2203,10 +2253,8 @@ public class AudioService extends IAudioService.Stub
        // handling of specific interfaces goes here:
        // handling of specific interfaces goes here:
        if ((device & mAbsVolumeMultiModeCaseDevices) == AudioSystem.DEVICE_OUT_HEARING_AID) {
        if ((device & mAbsVolumeMultiModeCaseDevices) == AudioSystem.DEVICE_OUT_HEARING_AID) {
            final int index = getStreamVolume(streamType);
            final int index = getStreamVolume(streamType);
            mModeLogger.log(new AudioEventLogger.StringEvent("setMode to "
            sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_MODE_CHANGE_HEARING_AID,
                    + AudioSystem.modeToString(newMode)
                    newMode, streamType, index));
                    + " causes setting HEARING_AID volume to idx:" + index
                    + " stream:" + AudioSystem.streamToString(streamType)));
            mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
            mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
        }
        }
    }
    }
@@ -2272,7 +2320,8 @@ public class AudioService extends IAudioService.Stub
                mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
                mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10);
            }
            }


            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
            if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0
                    && streamType == getHearingAidStreamType()) {
                Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
                Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index
                        + " stream=" + streamType);
                        + " stream=" + streamType);
                mDeviceBroker.postSetHearingAidVolumeIndex(index, streamType);
                mDeviceBroker.postSetHearingAidVolumeIndex(index, streamType);
@@ -4348,6 +4397,11 @@ public class AudioService extends IAudioService.Stub
            throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
            throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
                    + " (dis)connection, got " + state);
                    + " (dis)connection, got " + state);
        }
        }
        if (state == BluetoothProfile.STATE_CONNECTED) {
            mPlaybackMonitor.registerPlaybackCallback(mVoiceActivityMonitor, true);
        } else {
            mPlaybackMonitor.unregisterPlaybackCallback(mVoiceActivityMonitor);
        }
        mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
        mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
                device, state, suppressNoisyIntent, musicDevice, "AudioService");
                device, state, suppressNoisyIntent, musicDevice, "AudioService");
    }
    }
@@ -4853,6 +4907,7 @@ public class AudioService extends IAudioService.Stub
            pw.println((mIndexMin + 5) / 10);
            pw.println((mIndexMin + 5) / 10);
            pw.print("   Max: ");
            pw.print("   Max: ");
            pw.println((mIndexMax + 5) / 10);
            pw.println((mIndexMax + 5) / 10);
            pw.print("   streamVolume:"); pw.println(getStreamVolume(mStreamType));
            pw.print("   Current: ");
            pw.print("   Current: ");
            for (int i = 0; i < mIndexMap.size(); i++) {
            for (int i = 0; i < mIndexMap.size(); i++) {
                if (i > 0) {
                if (i > 0) {
@@ -5429,6 +5484,11 @@ public class AudioService extends IAudioService.Stub


                case MSG_HDMI_VOLUME_CHECK:
                case MSG_HDMI_VOLUME_CHECK:
                    onCheckVolumeCecOnHdmiConnection(msg.arg1, (String) msg.obj);
                    onCheckVolumeCecOnHdmiConnection(msg.arg1, (String) msg.obj);
                    break;

                case MSG_PLAYBACK_CONFIG_CHANGE:
                    onPlaybackConfigChange((List<AudioPlaybackConfiguration>) msg.obj);
                    break;
            }
            }
        }
        }
    }
    }
+43 −3
Original line number Original line Diff line number Diff line
@@ -95,6 +95,8 @@ public class AudioServiceEvents {
        static final int VOL_SET_HEARING_AID_VOL = 3;
        static final int VOL_SET_HEARING_AID_VOL = 3;
        static final int VOL_SET_AVRCP_VOL = 4;
        static final int VOL_SET_AVRCP_VOL = 4;
        static final int VOL_ADJUST_VOL_UID = 5;
        static final int VOL_ADJUST_VOL_UID = 5;
        static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6;
        static final int VOL_MODE_CHANGE_HEARING_AID = 7;


        final int mOp;
        final int mOp;
        final int mStream;
        final int mStream;
@@ -102,6 +104,10 @@ public class AudioServiceEvents {
        final int mVal2;
        final int mVal2;
        final String mCaller;
        final String mCaller;


        /** used for VOL_ADJUST_VOL_UID,
         *           VOL_ADJUST_SUGG_VOL,
         *           VOL_ADJUST_STREAM_VOL,
         *           VOL_SET_STREAM_VOL */
        VolumeEvent(int op, int stream, int val1, int val2, String caller) {
        VolumeEvent(int op, int stream, int val1, int val2, String caller) {
            mOp = op;
            mOp = op;
            mStream = stream;
            mStream = stream;
@@ -110,6 +116,7 @@ public class AudioServiceEvents {
            mCaller = caller;
            mCaller = caller;
        }
        }


        /** used for VOL_SET_HEARING_AID_VOL*/
        VolumeEvent(int op, int index, int gainDb) {
        VolumeEvent(int op, int index, int gainDb) {
            mOp = op;
            mOp = op;
            mVal1 = index;
            mVal1 = index;
@@ -119,6 +126,7 @@ public class AudioServiceEvents {
            mCaller = null;
            mCaller = null;
        }
        }


        /** used for VOL_SET_AVRCP_VOL */
        VolumeEvent(int op, int index) {
        VolumeEvent(int op, int index) {
            mOp = op;
            mOp = op;
            mVal1 = index;
            mVal1 = index;
@@ -128,6 +136,26 @@ public class AudioServiceEvents {
            mCaller = null;
            mCaller = null;
        }
        }


        /** used for VOL_VOICE_ACTIVITY_HEARING_AID */
        VolumeEvent(int op, boolean voiceActive, int stream, int index) {
            mOp = op;
            mStream = stream;
            mVal1 = index;
            mVal2 = voiceActive ? 1 : 0;
            // unused
            mCaller = null;
        }

        /** used for VOL_MODE_CHANGE_HEARING_AID */
        VolumeEvent(int op, int mode, int stream, int index) {
            mOp = op;
            mStream = stream;
            mVal1 = index;
            mVal2 = mode;
            // unused
            mCaller = null;
        }

        @Override
        @Override
        public String eventToString() {
        public String eventToString() {
            switch (mOp) {
            switch (mOp) {
@@ -168,6 +196,18 @@ public class AudioServiceEvents {
                            .append(" flags:0x").append(Integer.toHexString(mVal2))
                            .append(" flags:0x").append(Integer.toHexString(mVal2))
                            .append(") from ").append(mCaller)
                            .append(") from ").append(mCaller)
                            .toString();
                            .toString();
                case VOL_VOICE_ACTIVITY_HEARING_AID:
                    return new StringBuilder("Voice activity change (")
                            .append(mVal2 == 1 ? "active" : "inactive")
                            .append(") causes setting HEARING_AID volume to idx:").append(mVal1)
                            .append(" stream:").append(AudioSystem.streamToString(mStream))
                            .toString();
                case VOL_MODE_CHANGE_HEARING_AID:
                    return new StringBuilder("setMode(")
                            .append(AudioSystem.modeToString(mVal2))
                            .append(") causes setting HEARING_AID volume to idx:").append(mVal1)
                            .append(" stream:").append(AudioSystem.streamToString(mStream))
                            .toString();
                default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
                default: return new StringBuilder("FIXME invalid op:").append(mOp).toString();
            }
            }
        }
        }