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

Commit 311b3bdc authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "vc: Fix handling volume setup after reconnect" into main am: d2dd97a5 am: 7259a9c8

parents 32f3284b 7259a9c8
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ public:
                                 addr.get());
  }

  void OnVolumeStateChanged(const RawAddress& bd_addr, uint8_t volume, bool mute,
  void OnVolumeStateChanged(const RawAddress& bd_addr, uint8_t volume, bool mute, uint8_t flags,
                            bool isAutonomous) override {
    log::info("");

@@ -86,7 +86,7 @@ public:

    sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress), (jbyte*)&bd_addr);
    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onVolumeStateChanged, (jint)volume,
                                 (jboolean)mute, addr.get(), (jboolean)isAutonomous);
                                 (jboolean)mute, (jint)flags, addr.get(), (jboolean)isAutonomous);
  }

  void OnGroupVolumeStateChanged(int group_id, uint8_t volume, bool mute,
@@ -533,7 +533,7 @@ int register_com_android_bluetooth_vc(JNIEnv* env) {

  const JNIJavaMethod javaMethods[] = {
          {"onConnectionStateChanged", "(I[B)V", &method_onConnectionStateChanged},
          {"onVolumeStateChanged", "(IZ[BZ)V", &method_onVolumeStateChanged},
          {"onVolumeStateChanged", "(IZI[BZ)V", &method_onVolumeStateChanged},
          {"onGroupVolumeStateChanged", "(IZIZ)V", &method_onGroupVolumeStateChanged},
          {"onDeviceAvailable", "(I[B)V", &method_onDeviceAvailable},
          {"onExtAudioOutVolumeOffsetChanged", "(II[B)V", &method_onExtAudioOutVolumeOffsetChanged},
+3 −1
Original line number Diff line number Diff line
@@ -251,13 +251,15 @@ public class VolumeControlNativeInterface {
    }

    @VisibleForTesting
    void onVolumeStateChanged(int volume, boolean mute, byte[] address, boolean isAutonomous) {
    void onVolumeStateChanged(
            int volume, boolean mute, int flags, byte[] address, boolean isAutonomous) {
        VolumeControlStackEvent event =
                new VolumeControlStackEvent(
                        VolumeControlStackEvent.EVENT_TYPE_VOLUME_STATE_CHANGED);
        event.device = getDevice(address);
        event.valueInt1 = -1;
        event.valueInt2 = volume;
        event.valueInt3 = flags;
        event.valueBool1 = mute;
        event.valueBool2 = isAutonomous;

+48 −16
Original line number Diff line number Diff line
@@ -200,6 +200,11 @@ public class VolumeControlService extends ProfileService {
    private final Map<Integer, Boolean> mGroupMuteCache = new HashMap<>();
    private final Map<BluetoothDevice, Integer> mDeviceVolumeCache = new HashMap<>();

    /* As defined by Volume Control Service 1.0.1, 3.3.1. Volume Flags behavior.
     * User Set Volume Setting means that remote keeps volume in its cache.
     */
    @VisibleForTesting static final int VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK = 0x01;

    @VisibleForTesting ServiceFactory mFactory = new ServiceFactory();

    public VolumeControlService(Context ctx) {
@@ -862,14 +867,22 @@ public class VolumeControlService extends ProfileService {
        }
    }

    void handleVolumeControlChanged(
            BluetoothDevice device, int groupId, int volume, boolean mute, boolean isAutonomous) {
    int getBleVolumeFromCurrentStream() {
        int streamType = getBluetoothContextualVolumeStream();
        int streamVolume = mAudioManager.getStreamVolume(streamType);
        int streamMaxVolume = mAudioManager.getStreamMaxVolume(streamType);

        if (isAutonomous && device != null) {
            Log.e(TAG, "We expect only group notification for autonomous updates");
            return;
        /* leaudio expect volume value in range 0 to 255 */
        return (int) Math.round((double) streamVolume * LE_AUDIO_MAX_VOL / streamMaxVolume);
    }

    void handleVolumeControlChanged(
            BluetoothDevice device,
            int groupId,
            int volume,
            int flags,
            boolean mute,
            boolean isAutonomous) {
        if (groupId == IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID) {
            LeAudioService leAudioService = mFactory.getLeAudioService();
            if (leAudioService == null) {
@@ -887,6 +900,34 @@ public class VolumeControlService extends ProfileService {
        int groupVolume = getGroupVolume(groupId);
        Boolean groupMute = getGroupMute(groupId);

        if (isAutonomous && device != null) {
            Log.i(
                    TAG,
                    ("Initial volume set after connect, volume: " + volume)
                            + (", mute: " + mute)
                            + (", flags: " + flags));
            /* We are here, because system has just started and LeAudio device is connected. If
             * remote device has User Persistent flag set or the volume != 0, Android sets the
             * volume to local cache and to the audio system. If Reset Flag is set and remote has
             * volume set to 0, then Android sets to remote devices either cached volume volume
             * taken from audio manager. Note, to match BR/EDR behavior, don't show volume change in
             * UI here
             */
            if ((flags & VOLUME_FLAGS_PERSISTED_USER_SET_VOLUME_MASK) == 0x01 || (volume != 0)) {
                updateGroupCacheAndAudioSystem(groupId, volume, mute, false);
            } else {
                if (groupVolume != IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
                    Log.i(TAG, "Setting volume: " + groupVolume + " to the group: " + groupId);
                    setGroupVolume(groupId, groupVolume);
                } else {
                    int vol = getBleVolumeFromCurrentStream();
                    Log.i(TAG, "Setting system volume: " + vol + " to the group: " + groupId);
                    setGroupVolume(groupId, getBleVolumeFromCurrentStream());
                }
            }
            return;
        }

        if (Flags.leaudioBroadcastVolumeControlForConnectedDevices()) {
            Log.i(TAG, "handleVolumeControlChanged: " + device + "; volume: " + volume);
            if (device == null) {
@@ -906,16 +947,6 @@ public class VolumeControlService extends ProfileService {
            }
        }

        if (groupVolume == IBluetoothVolumeControl.VOLUME_CONTROL_UNKNOWN_VOLUME) {
            /* We are here, because system was just started and LeAudio device just connected.
             * In such case, we take Volume stored on remote device and apply it to our cache and
             * audio system.
             * Note, to match BR/EDR behavior, don't show volume change in UI here
             */
            updateGroupCacheAndAudioSystem(groupId, volume, mute, false);
            return;
        }

        if (!isAutonomous) {
            /* If the change is triggered by Android device, the stream is already changed.
             * However it might be called with isAutonomous, one the first read of after
@@ -1119,6 +1150,7 @@ public class VolumeControlService extends ProfileService {
                    stackEvent.device,
                    stackEvent.valueInt1,
                    stackEvent.valueInt2,
                    stackEvent.valueInt3,
                    stackEvent.valueBool1,
                    stackEvent.valueBool2);
            return;
+12 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ public class VolumeControlStackEvent {
    public BluetoothDevice device;
    public int valueInt1;
    public int valueInt2;
    public int valueInt3;
    public boolean valueBool1;
    public boolean valueBool2;
    public String valueString1;
@@ -58,6 +59,7 @@ public class VolumeControlStackEvent {
        result.append(", device:").append(device);
        result.append(", valueInt1:").append(eventTypeValue1ToString(type, valueInt1));
        result.append(", valueInt2:").append(eventTypeValue2ToString(type, valueInt2));
        result.append(", valueInt3:").append(eventTypeValue3ToString(type, valueInt3));
        result.append(", valueBool1:").append(eventTypeValueBool1ToString(type, valueBool1));
        result.append(", valueBool2:").append(eventTypeValueBool2ToString(type, valueBool2));
        result.append(", valueString1:").append(eventTypeString1ToString(type, valueString1));
@@ -138,6 +140,16 @@ public class VolumeControlStackEvent {
        return Integer.toString(value);
    }

    private static String eventTypeValue3ToString(int type, int value) {
        switch (type) {
            case EVENT_TYPE_VOLUME_STATE_CHANGED:
                return "{flags:" + value + "}";
            default:
                break;
        }
        return Integer.toString(value);
    }

    private static String eventTypeValueBool1ToString(int type, boolean value) {
        switch (type) {
            case EVENT_TYPE_VOLUME_STATE_CHANGED:
+2 −1
Original line number Diff line number Diff line
@@ -71,10 +71,11 @@ public class VolumeControlNativeInterfaceTest {
    public void onVolumeStateChanged() {
        int volume = 3;
        boolean mute = false;
        int flags = 1;
        byte[] address = new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
        boolean isAutonomous = false;

        mNativeInterface.onVolumeStateChanged(volume, mute, address, isAutonomous);
        mNativeInterface.onVolumeStateChanged(volume, mute, flags, address, isAutonomous);

        ArgumentCaptor<VolumeControlStackEvent> event =
                ArgumentCaptor.forClass(VolumeControlStackEvent.class);
Loading