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

Commit b14a0592 authored by Hsin-chen Chuang's avatar Hsin-chen Chuang
Browse files

floss: telephony: Support hold call operations

Implemented the following functions and wired to btclient:
- ReleaseHeld
- ReleaseActiveAcceptHeld
- HoldActiveAcceptHeld

Also handled the above commands sent from HF.

Bug: 214149380
Tag: #floss
Test: HFP/AG/ECS/BV-01-I, HFP/AG/ECS/BV-02-I
Change-Id: Iae8e068981a601d23a1bcf1a5457b2d59318662e
parent 75ea431c
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -284,6 +284,9 @@ fn build_commands() -> HashMap<String, CommandOption> {
                String::from("telephony <incoming-call|dialing-call> <number>"),
                String::from("telephony <answer-call|hangup-call>"),
                String::from("telephony <set-memory-call|set-last-call> [<number>]"),
                String::from(
                    "telephony <release-held|release-active-accept-held|hold-active-accept-held>",
                ),
            ],
            description: String::from("Set device telephony status."),
            function_pointer: CommandHandler::cmd_telephony,
@@ -1658,6 +1661,39 @@ impl CommandHandler {
                    return Err("SetLastCall failed".into());
                }
            }
            "release-held" => {
                let success =
                    self.context.lock().unwrap().telephony_dbus.as_mut().unwrap().release_held();
                if !success {
                    return Err("ReleaseHeld failed".into());
                }
            }
            "release-active-accept-held" => {
                let success = self
                    .context
                    .lock()
                    .unwrap()
                    .telephony_dbus
                    .as_mut()
                    .unwrap()
                    .release_active_accept_held();
                if !success {
                    return Err("ReleaseActiveAcceptHeld failed".into());
                }
            }
            "hold-active-accept-held" => {
                let success = self
                    .context
                    .lock()
                    .unwrap()
                    .telephony_dbus
                    .as_mut()
                    .unwrap()
                    .hold_active_accept_held();
                if !success {
                    return Err("HoldActiveAcceptHeld failed".into());
                }
            }
            other => {
                return Err(format!("Invalid argument '{}'", other).into());
            }
+12 −0
Original line number Diff line number Diff line
@@ -1882,4 +1882,16 @@ impl IBluetoothTelephony for BluetoothTelephonyDBus {
    fn set_last_call(&mut self, number: Option<String>) -> bool {
        dbus_generated!()
    }
    #[dbus_method("ReleaseHeld")]
    fn release_held(&mut self) -> bool {
        dbus_generated!()
    }
    #[dbus_method("ReleaseActiveAcceptHeld")]
    fn release_active_accept_held(&mut self) -> bool {
        dbus_generated!()
    }
    #[dbus_method("HoldActiveAcceptHeld")]
    fn hold_active_accept_held(&mut self) -> bool {
        dbus_generated!()
    }
}
+12 −0
Original line number Diff line number Diff line
@@ -58,4 +58,16 @@ impl IBluetoothTelephony for IBluetoothTelephonyDBus {
    fn set_last_call(&mut self, number: Option<String>) -> bool {
        dbus_generated!()
    }
    #[dbus_method("ReleaseHeld")]
    fn release_held(&mut self) -> bool {
        dbus_generated!()
    }
    #[dbus_method("ReleaseActiveAcceptHeld")]
    fn release_active_accept_held(&mut self) -> bool {
        dbus_generated!()
    }
    #[dbus_method("HoldActiveAcceptHeld")]
    fn hold_active_accept_held(&mut self) -> bool {
        dbus_generated!()
    }
}
+106 −1
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@ use bt_topshim::profiles::avrcp::{
    Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher, PlayerMetadata,
};
use bt_topshim::profiles::hfp::{
    BthfAudioState, BthfConnectionState, CallInfo, CallState, Hfp, HfpCallbacks,
    BthfAudioState, BthfConnectionState, CallHoldCommand, CallInfo, CallState, Hfp, HfpCallbacks,
    HfpCallbacksDispatcher, HfpCodecCapability, PhoneState, TelephonyDeviceStatus,
};
use bt_topshim::profiles::ProfileConnectionState;
@@ -170,6 +170,12 @@ pub trait IBluetoothTelephony {
    fn set_memory_call(&mut self, number: Option<String>) -> bool;
    /// Sets/unsets the last call.
    fn set_last_call(&mut self, number: Option<String>) -> bool;
    /// Releases all of the held calls.
    fn release_held(&mut self) -> bool;
    /// Releases the active call and accepts a held call.
    fn release_active_accept_held(&mut self) -> bool;
    /// Holds the active call and accepts a held call.
    fn hold_active_accept_held(&mut self) -> bool;
}

/// Serializable device used in.
@@ -769,6 +775,29 @@ impl BluetoothMedia {
                    warn!("[{}]: Unexpected dialing command from HF", addr.to_string());
                }
            }
            HfpCallbacks::CallHold(command, addr) => {
                let success = match command {
                    CallHoldCommand::ReleaseHeld => self.release_held_impl(),
                    CallHoldCommand::ReleaseActiveAcceptHeld => {
                        self.release_active_accept_held_impl()
                    }
                    CallHoldCommand::HoldActiveAcceptHeld => self.hold_active_accept_held_impl(),
                    _ => false, // We only support the 3 operations above.
                };
                // Respond OK/ERROR to the HF which sent the command.
                // This should be called before calling phone_state_change.
                self.simple_at_response(success, addr.clone());
                if success {
                    // Success means the call state has changed. Inform the LibBluetooth stack.
                    self.phone_state_change("".into());
                } else {
                    warn!(
                        "[{}]: Unexpected or unsupported CHLD command {:?} from HF",
                        addr.to_string(),
                        command
                    );
                }
            }
        }
    }

@@ -1212,6 +1241,58 @@ impl BluetoothMedia {
        self.phone_state.state = CallState::Dialing;
        true
    }

    fn release_held_impl(&mut self) -> bool {
        if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle {
            return false;
        }
        self.call_list.retain(|x| x.state != CallState::Held);
        self.phone_state.num_held = 0;
        true
    }

    fn release_active_accept_held_impl(&mut self) -> bool {
        if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle {
            return false;
        }
        self.call_list.retain(|x| x.state != CallState::Active);
        self.phone_state.num_active = 0;
        // Activate the first held call
        for c in self.call_list.iter_mut() {
            if c.state == CallState::Held {
                c.state = CallState::Active;
                self.phone_state.num_held -= 1;
                self.phone_state.num_active += 1;
                break;
            }
        }
        true
    }

    fn hold_active_accept_held_impl(&mut self) -> bool {
        if !self.phone_ops_enabled || self.phone_state.state != CallState::Idle {
            return false;
        }

        self.phone_state.num_held += self.phone_state.num_active;
        self.phone_state.num_active = 0;

        for c in self.call_list.iter_mut() {
            match c.state {
                // Activate at most one held call
                CallState::Held if self.phone_state.num_active == 0 => {
                    c.state = CallState::Active;
                    self.phone_state.num_held -= 1;
                    self.phone_state.num_active = 1;
                }
                CallState::Active => {
                    c.state = CallState::Held;
                }
                _ => {}
            }
        }
        true
    }
}

fn get_a2dp_dispatcher(tx: Sender<Message>) -> A2dpCallbacksDispatcher {
@@ -1936,6 +2017,30 @@ impl IBluetoothTelephony for BluetoothMedia {
        self.last_dialing_number = number;
        true
    }

    fn release_held(&mut self) -> bool {
        if !self.release_held_impl() {
            return false;
        }
        self.phone_state_change("".into());
        true
    }

    fn release_active_accept_held(&mut self) -> bool {
        if !self.release_active_accept_held_impl() {
            return false;
        }
        self.phone_state_change("".into());
        true
    }

    fn hold_active_accept_held(&mut self) -> bool {
        if !self.hold_active_accept_held_impl() {
            return false;
        }
        self.phone_state_change("".into());
        true
    }
}

struct BatteryProviderCallback {}
+24 −1
Original line number Diff line number Diff line
@@ -66,6 +66,27 @@ static void dial_call_cb(char* number, RawAddress* addr) {
  rusty::hfp_dial_call_callback(::rust::String{number}, *addr);
}

static void call_hold_cb(bluetooth::headset::bthf_chld_type_t chld, RawAddress* addr) {
  rusty::CallHoldCommand chld_rs;
  switch (chld) {
    case bluetooth::headset::BTHF_CHLD_TYPE_RELEASEHELD:
      chld_rs = rusty::CallHoldCommand::ReleaseHeld;
      break;
    case bluetooth::headset::BTHF_CHLD_TYPE_RELEASEACTIVE_ACCEPTHELD:
      chld_rs = rusty::CallHoldCommand::ReleaseActiveAcceptHeld;
      break;
    case bluetooth::headset::BTHF_CHLD_TYPE_HOLDACTIVE_ACCEPTHELD:
      chld_rs = rusty::CallHoldCommand::HoldActiveAcceptHeld;
      break;
    case bluetooth::headset::BTHF_CHLD_TYPE_ADDHELDTOCONF:
      chld_rs = rusty::CallHoldCommand::AddHeldToConf;
      break;
    default:
      ASSERT_LOG(false, "Unhandled enum value from C++");
  }
  rusty::hfp_call_hold_callback(chld_rs, *addr);
}

static headset::bthf_call_state_t from_rust_call_state(rusty::CallState state) {
  switch (state) {
    case rusty::CallState::Idle:
@@ -136,7 +157,9 @@ class DBusHeadsetCallbacks : public headset::Callbacks {
    rusty::hfp_caps_update_callback(wbs == headset::BTHF_WBS_YES, *addr);
  }

  void AtChldCallback([[maybe_unused]] headset::bthf_chld_type_t chld, [[maybe_unused]] RawAddress* bd_addr) override {}
  void AtChldCallback(headset::bthf_chld_type_t chld, RawAddress* bd_addr) override {
    topshim::rust::internal::call_hold_cb(chld, bd_addr);
  }

  void AtCnumCallback(RawAddress* bd_addr) override {
    // Send an OK response to HF to indicate that we have no subscriber info.
Loading