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

Commit 049596db authored by WhaleChang's avatar WhaleChang Committed by Whale Chang
Browse files

Floss: Fix headset that requires +CIEV command to work and cannot provide...

Floss: Fix headset that requires +CIEV command to work and cannot provide sound when Bluetooth Telephony is enabled

Some Bluetooth headsets require placing an active call to trigger +CIEV
to enable sound through HFP. However, the +CIEV workaround conflicts
with the initial state needed for Bluetooth Telephony, which requires
no call.

Originally, we removed the +CIEV workaround when the Bluetooth Telephony
feature flag was enabled. However, this could potentially cause a
regression for headsets requiring the +CIEV command when launching the
feature.

To avoid breaking the original use case for users who don't need
telephony, we restrict the +CIEV workaround removal to only when a user
explicitly enables UHID, which means the user intents to use Bluetooth
Telephony.

Bug: 340375662
Test: Conduct the following manual tests
  - enable bluetooth telephony
  - pair Bluetooth Headset need +CIEV command to work(Parrot Zik 2.0)
  - playback with youtube and online voice recorder and make sure hfp
  audio work
  - enable uhid and observe the hfp audio will not work
Test: atest bluetooth_test_gd
Tag: #floss
Flag: EXEMPT, no behavior change on Android; Floss-only changes

Change-Id: I41ea0d3ae61ec928bb099c5b6053c65f473bb764
parent d6e7e4ed
Loading
Loading
Loading
Loading
+45 −8
Original line number Diff line number Diff line
@@ -283,6 +283,7 @@ struct UHid {
    pub handle: UHidHfp,
    pub volume: u8,
    pub muted: bool,
    pub is_open: bool,
}

pub struct BluetoothMedia {
@@ -1180,6 +1181,7 @@ impl BluetoothMedia {
                ),
                volume: 15, // By default use maximum volume in case microphone gain has not been received
                muted: false,
                is_open: false,
            },
        );
    }
@@ -1340,15 +1342,28 @@ impl BluetoothMedia {
            }
            Some(addr) => addr,
        };
        let uhid = match self.uhid.get_mut(&addr) {
            Some(uhid) => uhid,
            None => {
                warn!("[{}]: UHID: No valid UHID", DisplayAddress(&addr));
                return;
            }
        };

        debug!("[{}]: UHID: Telephony use: {}", DisplayAddress(&addr), state);
        if state == false {
            // As there's a HID call for each WebHID call, even if it has been answered in the app
            // or pre-exists, and that an app which disconnects from WebHID may not have trigger
            // the UHID_OUTPUT_NONE, we need to remove all pending HID calls on telephony use
            // release to keep lower HF layer in sync and not prevent A2DP streaming
        uhid.is_open = state;

        info!("[{}]: UHID: floss telephony device is open: {}", DisplayAddress(&addr), state);
        // A hangup call is necessary both when opening and closing the UHID device,
        // although for different reasons:
        //  - On open: To prevent conflicts with existing SCO calls in CRAS and establish
        //             a clean environment for Bluetooth Telephony operations.
        //  - On close: As there's a HID call for each WebHID call, even if it has been
        //              answered in the app or pre-exists, and that an app which disconnects
        //              from WebHID may not have trigger the UHID_OUTPUT_NONE, we need to
        //              remove all pending HID calls on telephony use release to keep lower
        //              HF layer in sync and not prevent A2DP streaming.
        self.hangup_call_impl();
        }

        self.telephony_callbacks.lock().unwrap().for_all_callbacks(|callback| {
            callback.on_telephony_use(address.to_string(), state);
        });
@@ -2227,6 +2242,16 @@ impl BluetoothMedia {
        self.avrcp.as_mut().unwrap().add_player(&name, browsing_supported);
    }

    // This function determines if it's safe to send a +CIEV command to an HFP device when SCO starts.

    // The +CIEV command should NOT be sent if:
    //  - MPS qualification mode is enabled, as it may cause qualification failures.
    //  - Uhid device is open, as it may conflict with ongoing telephony operations.

    // The +CIEV command is safe to send if:
    //  - Both MPS qualification and Bluetooth telephony are disabled.
    //  - Uhid device is closed, preventing any telephony conflicts.
    //  - The headset is listed in interop_database.conf, indicating it requires +CIEV for audio.
    fn should_insert_call_when_sco_start(&self, address: RawAddress) -> bool {
        if self.mps_qualification_enabled {
            return false;
@@ -2234,6 +2259,18 @@ impl BluetoothMedia {
        if !self.phone_ops_enabled {
            return true;
        }

        match self.uhid.get(&address) {
            Some(uhid) => {
                if !uhid.is_open {
                    return true;
                }
            }
            None => {
                return true;
            }
        };

        return interop_insert_call_when_sco_start(address);
    }
    // Places an active call into the call list and triggers a headset update (+CIEV).