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

Commit 56edb4f1 authored by Frédéric Danis's avatar Frédéric Danis
Browse files

Floss: Add CallSource to CallInfo

In order to maintain call list status correctly, this design choose to
separate the call source from CRAS and HID device.
It won’t affect the call list status of CRAS, and it only maintains call
source from HID device in this feature.

Bug: 277693919
Test: Conduct the following manual tests.
  pair Bluetooth Headset
  load https://google.git.io/libhidtelephoony/ with Chrome
  click on "Start", select the headset then "Connect"
  "Inputs Reports" and "Output Reports" are correct
  "Hook Switch" and "Ring" test cases are passed
  used https://online-voice-recorer.com during "Hook Switch" test to check
    audio input
  Google Meet: headset is able to hang-up the call
Test: atest bluetooth_test_gd

Change-Id: I7270de77884630b74a41a990b658988204565c9e
parent a100356e
Loading
Loading
Loading
Loading
+163 −78
Original line number Diff line number Diff line
@@ -13,8 +13,9 @@ use bt_topshim::profiles::avrcp::{
    Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher, PlayerMetadata,
};
use bt_topshim::profiles::hfp::{
    BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallState, Hfp, HfpCallbacks,
    HfpCallbacksDispatcher, HfpCodecCapability, HfpCodecId, PhoneState, TelephonyDeviceStatus,
    BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallSource, CallState, Hfp,
    HfpCallbacks, HfpCallbacksDispatcher, HfpCodecCapability, HfpCodecId, PhoneState,
    TelephonyDeviceStatus,
};
use bt_topshim::profiles::ProfileConnectionState;
use bt_topshim::{metrics, topstack};
@@ -733,20 +734,19 @@ impl BluetoothMedia {

                        self.hfp_audio_state.insert(addr, state);

                        // Change the phone state only when it's currently managed by media stack
                        // (I.e., phone operations are not enabled).
                        if !(self.phone_ops_enabled || self.mps_qualification_enabled)
                            && self.phone_state.num_active != 1
                        if !self.mps_qualification_enabled
                            && self.call_list.iter().all(|c| c.source != CallSource::CRAS)
                        {
                            // This triggers a +CIEV command to set the call status for HFP devices.
                            // It is required for some devices to provide sound.
                            self.phone_state.num_active = 1;
                            self.call_list = vec![CallInfo {
                                index: 1,
                            self.phone_state.num_active += 1;
                            self.call_list.push(CallInfo {
                                index: self.new_call_index(),
                                dir_incoming: false,
                                source: CallSource::CRAS,
                                state: CallState::Active,
                                number: "".into(),
                            }];
                            });
                            self.phone_state_change("".into());
                        }
                    }
@@ -762,13 +762,19 @@ impl BluetoothMedia {
                            });
                        }

                        // Change the phone state only when it's currently managed by media stack
                        // (I.e., phone operations are not enabled).
                        if !(self.phone_ops_enabled || self.mps_qualification_enabled)
                            && self.phone_state.num_active != 0
                        if !self.mps_qualification_enabled
                            && self.call_list.iter().any(|c| c.source == CallSource::CRAS)
                        {
                            self.phone_state.num_active = 0;
                            self.call_list = vec![];
                            for c in self.call_list.iter_mut() {
                                if c.source == CallSource::CRAS {
                                    self.phone_state.num_active -= 1;
                                }
                            }

                            self.call_list.retain(|x| match x.source {
                                CallSource::CRAS => false,
                                _ => true,
                            });
                            self.phone_state_change("".into());
                        }

@@ -1147,7 +1153,7 @@ impl BluetoothMedia {
            } else if data == UHID_OUTPUT_RING {
                self.incoming_call("".into());
            } else if data == UHID_OUTPUT_OFF_HOOK {
                if self.phone_state.num_active > 0 {
                if self.call_list.iter().any(|c| c.source == CallSource::HID) {
                    return;
                }
                self.dialing_call("".into());
@@ -1716,9 +1722,8 @@ impl BluetoothMedia {
    }

    fn answer_call_impl(&mut self) -> bool {
        if !(self.phone_ops_enabled || self.mps_qualification_enabled)
            || self.phone_state.state == CallState::Idle
        {
        if self.mps_qualification_enabled {
            if self.phone_state.state == CallState::Idle {
                return false;
            }
            // There must be exactly one incoming/dialing call in the list.
@@ -1733,13 +1738,34 @@ impl BluetoothMedia {
            }
            self.phone_state.state = CallState::Idle;
            self.phone_state.num_active += 1;
        true
            return true;
        } else if self.phone_ops_enabled {
            if self.phone_state.state == CallState::Idle {
                return false;
            }
            // There must be exactly one incoming/dialing call in the list.
            for c in self.call_list.iter_mut() {
                if c.source == CallSource::CRAS {
                    continue;
                }

                match c.state {
                    CallState::Incoming | CallState::Dialing | CallState::Alerting => {
                        c.state = CallState::Active;
                        self.phone_state.state = CallState::Idle;
                        self.phone_state.num_active += 1;
                        return true;
                    }
                    _ => {}
                }
            }
        }

    fn hangup_call_impl(&mut self) -> bool {
        if !(self.phone_ops_enabled || self.mps_qualification_enabled) {
        return false;
    }

    fn hangup_call_impl(&mut self) -> bool {
        if self.mps_qualification_enabled {
            match self.phone_state.state {
                CallState::Idle if self.phone_state.num_active > 0 => {
                    self.phone_state.num_active -= 1;
@@ -1747,34 +1773,77 @@ impl BluetoothMedia {
                CallState::Incoming | CallState::Dialing | CallState::Alerting => {
                    self.phone_state.state = CallState::Idle;
                }
            _ => {
                return false;
            }
                _ => return false,
            }
            // At this point, there must be exactly one incoming/dialing/alerting/active call to be
            // removed.
            self.call_list.retain(|x| match x.state {
            CallState::Active | CallState::Incoming | CallState::Dialing | CallState::Alerting => {
                false
                CallState::Active
                | CallState::Incoming
                | CallState::Dialing
                | CallState::Alerting => false,
                _ => true,
            });
            return true;
        } else if self.phone_ops_enabled {
            let mut ret = false;
            for c in self.call_list.iter_mut() {
                if c.source == CallSource::CRAS {
                    continue;
                }

                match c.state {
                    CallState::Incoming | CallState::Dialing | CallState::Alerting => {
                        ret = true;
                    }
                    CallState::Active => {
                        self.phone_state.num_active -= 1;
                        ret = true;
                    }
                    _ => {}
                }
            }

            self.call_list.retain(|x| match x.source {
                CallSource::HID => false,
                _ => true,
            });
        true
            self.phone_state.state = CallState::Idle;
            return ret;
        }

        return false;
    }

    fn dialing_call_impl(&mut self, number: String) -> bool {
        if !(self.phone_ops_enabled || self.mps_qualification_enabled)
            || self.phone_state.state != CallState::Idle
            || self.phone_state.num_active > 0
        {
            return false;
        }
        if self.mps_qualification_enabled {
            if self.phone_state.num_active > 0 {
                return false;
            }
            self.call_list.push(CallInfo {
                index: self.new_call_index(),
                dir_incoming: false,
                source: CallSource::CRAS,
                state: CallState::Dialing,
                number: number.clone(),
            });
        } else if self.phone_ops_enabled {
            if self.call_list.iter().any(|c| c.source == CallSource::HID) {
                return false;
            }
            self.call_list.push(CallInfo {
                index: self.new_call_index(),
                dir_incoming: false,
                source: CallSource::HID,
                state: CallState::Dialing,
                number: number.clone(),
            });
        }
        self.phone_state.state = CallState::Dialing;
        true
    }
@@ -2621,17 +2690,16 @@ impl IBluetoothTelephony for BluetoothMedia {
        self.last_dialing_number = None;
        self.a2dp_has_interrupted_stream = false;

        if !enable {
            if self.hfp_states.values().any(|x| x == &BthfConnectionState::SlcConnected) {
        if self.hfp_audio_state.values().any(|x| x == &BthfAudioState::Connected) {
            self.call_list.push(CallInfo {
                index: 1,
                dir_incoming: false,
                source: CallSource::CRAS,
                state: CallState::Active,
                number: "".into(),
            });
            self.phone_state.num_active = 1;
        }
        }

        self.phone_ops_enabled = enable;
        self.phone_state_change("".into());
@@ -2652,10 +2720,11 @@ impl IBluetoothTelephony for BluetoothMedia {
        self.a2dp_has_interrupted_stream = false;

        if !enable {
            if self.hfp_states.values().any(|x| x == &BthfConnectionState::SlcConnected) {
            if self.hfp_audio_state.values().any(|x| x == &BthfAudioState::Connected) {
                self.call_list.push(CallInfo {
                    index: 1,
                    dir_incoming: false,
                    source: CallSource::CRAS,
                    state: CallState::Active,
                    number: "".into(),
                });
@@ -2670,16 +2739,32 @@ impl IBluetoothTelephony for BluetoothMedia {
    fn incoming_call(&mut self, number: String) -> bool {
        if !(self.phone_ops_enabled || self.mps_qualification_enabled)
            || self.phone_state.state != CallState::Idle
            || self.phone_state.num_active > 0
        {
            return false;
        }
        if self.mps_qualification_enabled {
            if self.phone_state.num_active > 0 {
                return false;
            }
            self.call_list.push(CallInfo {
                index: self.new_call_index(),
                dir_incoming: true,
                source: CallSource::CRAS,
                state: CallState::Incoming,
                number: number.clone(),
            });
        } else if self.phone_ops_enabled {
            if self.call_list.iter().any(|c| c.source == CallSource::HID) {
                return false;
            }
            self.call_list.push(CallInfo {
                index: self.new_call_index(),
                dir_incoming: true,
                source: CallSource::HID,
                state: CallState::Incoming,
                number: number.clone(),
            });
        }
        self.phone_state.state = CallState::Incoming;
        self.phone_state_change(number);
        self.try_a2dp_suspend();
+15 −0
Original line number Diff line number Diff line
@@ -98,10 +98,24 @@ pub mod ffi {
        Held,   // Only used by CLCC response
    }

    #[derive(Debug, Copy, Clone)]
    /*
    When a SCO is created, it is necessary to have at least one call in the call list.
    Otherwise, some headsets may not be able to output sound.

    Therefore, we need to separate the call for CRAS from the call for the application so that
    we can have a correct life cycle for the call list status.
    */
    pub enum CallSource {
        CRAS,
        HID,
    }

    #[derive(Debug, Clone)]
    pub struct CallInfo {
        index: i32,
        dir_incoming: bool,
        source: CallSource,
        state: CallState,
        number: String,
    }
@@ -210,6 +224,7 @@ impl TelephonyDeviceStatus {
}

pub type CallState = ffi::CallState;
pub type CallSource = ffi::CallSource;
pub type CallInfo = ffi::CallInfo;
pub type PhoneState = ffi::PhoneState;
pub type CallHoldCommand = ffi::CallHoldCommand;