diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2021-11-02 08:14:41 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-11-02 08:14:41 +0000 |
commit | 7c43e37aa8957602c9f220cd520770501f414a7c (patch) | |
tree | 9b3f26eb913476ba3ea486e7dd5be48f5cd99e95 | |
parent | 8b91b04a5485ee927338e34cf1338608fd4e2d6d (diff) | |
parent | e9ec027fdc04137915af90a8703310618984f0ec (diff) | |
download | bt-7c43e37aa8957602c9f220cd520770501f414a7c.tar.gz |
Merge "floss: Fill in topshim for headset interface"
-rw-r--r-- | gd/rust/linux/stack/src/bluetooth_media.rs | 62 | ||||
-rw-r--r-- | gd/rust/linux/stack/src/lib.rs | 7 | ||||
-rw-r--r-- | gd/rust/topshim/Android.bp | 2 | ||||
-rw-r--r-- | gd/rust/topshim/BUILD.gn | 3 | ||||
-rw-r--r-- | gd/rust/topshim/Cargo.toml | 1 | ||||
-rw-r--r-- | gd/rust/topshim/hfp/hfp_shim.cc | 40 | ||||
-rw-r--r-- | gd/rust/topshim/hfp/hfp_shim.h | 5 | ||||
-rw-r--r-- | gd/rust/topshim/src/btif.rs | 2 | ||||
-rw-r--r-- | gd/rust/topshim/src/profiles/hfp.rs | 117 | ||||
-rw-r--r-- | gd/rust/topshim/src/profiles/mod.rs | 1 |
10 files changed, 237 insertions, 3 deletions
diff --git a/gd/rust/linux/stack/src/bluetooth_media.rs b/gd/rust/linux/stack/src/bluetooth_media.rs index c645f081e..6b3f17874 100644 --- a/gd/rust/linux/stack/src/bluetooth_media.rs +++ b/gd/rust/linux/stack/src/bluetooth_media.rs @@ -7,8 +7,12 @@ use bt_topshim::profiles::a2dp::{ PresentationPosition, }; use bt_topshim::profiles::avrcp::{Avrcp, AvrcpCallbacks, AvrcpCallbacksDispatcher}; +use bt_topshim::profiles::hfp::{BthfConnectionState, Hfp, HfpCallbacks, HfpCallbacksDispatcher}; + use bt_topshim::topstack; +use log::warn; + use std::collections::HashMap; use std::convert::TryFrom; use std::sync::Arc; @@ -28,6 +32,7 @@ pub trait IBluetoothMedia { /// clean up media stack fn cleanup(&mut self) -> bool; + // TODO (b/204488289): Accept and validate RawAddress instead. fn connect(&mut self, device: String); fn set_active_device(&mut self, device: String); fn disconnect(&mut self, device: String); @@ -78,6 +83,8 @@ pub struct BluetoothMedia { a2dp: Option<A2dp>, avrcp: Option<Avrcp>, a2dp_states: HashMap<RawAddress, BtavConnectionState>, + hfp: Option<Hfp>, + hfp_states: HashMap<RawAddress, BthfConnectionState>, selectable_caps: HashMap<RawAddress, Vec<A2dpCodecConfig>>, } @@ -92,6 +99,8 @@ impl BluetoothMedia { a2dp: None, avrcp: None, a2dp_states: HashMap::new(), + hfp: None, + hfp_states: HashMap::new(), selectable_caps: HashMap::new(), } } @@ -165,6 +174,28 @@ impl BluetoothMedia { } } + pub fn dispatch_hfp_callbacks(&mut self, cb: HfpCallbacks) { + match cb { + HfpCallbacks::ConnectionState(state, addr) => { + if !self.hfp_states.get(&addr).is_none() + && state == *self.hfp_states.get(&addr).unwrap() + { + return; + } + match state { + BthfConnectionState::Connected => { + // TODO: Integrate with A2dp + } + BthfConnectionState::Connecting => {} + BthfConnectionState::Disconnected => {} + BthfConnectionState::Disconnecting => { + // TODO: Integrate with A2dp + } + } + } + } + } + fn for_all_callbacks<F: Fn(&Box<dyn IBluetoothMediaCallback + Send>)>(&self, f: F) { for callback in &self.callbacks { f(&callback.1); @@ -194,6 +225,17 @@ fn get_avrcp_dispatcher(tx: Sender<Message>) -> AvrcpCallbacksDispatcher { } } +fn get_hfp_dispatcher(tx: Sender<Message>) -> HfpCallbacksDispatcher { + HfpCallbacksDispatcher { + dispatch: Box::new(move |cb| { + let txl = tx.clone(); + topstack::get_runtime().spawn(async move { + let _ = txl.send(Message::Hfp(cb)).await; + }); + }), + } +} + impl IBluetoothMedia for BluetoothMedia { fn register_callback(&mut self, callback: Box<dyn IBluetoothMediaCallback + Send>) -> bool { self.callback_last_id += 1; @@ -216,11 +258,24 @@ impl IBluetoothMedia for BluetoothMedia { let avrcp_dispatcher = get_avrcp_dispatcher(self.tx.clone()); self.avrcp = Some(Avrcp::new(&self.intf.lock().unwrap())); self.avrcp.as_mut().unwrap().initialize(avrcp_dispatcher); + + // HFP + let hfp_dispatcher = get_hfp_dispatcher(self.tx.clone()); + self.hfp = Some(Hfp::new(&self.intf.lock().unwrap())); + self.hfp.as_mut().unwrap().initialize(hfp_dispatcher); + true } fn connect(&mut self, device: String) { + let addr = RawAddress::from_string(device.clone()); + if addr.is_none() { + warn!("Invalid device string {}", device); + return; + } + self.a2dp.as_mut().unwrap().connect(device); + self.hfp.as_mut().unwrap().connect(addr.unwrap()); } fn cleanup(&mut self) -> bool { @@ -232,7 +287,14 @@ impl IBluetoothMedia for BluetoothMedia { } fn disconnect(&mut self, device: String) { + let addr = RawAddress::from_string(device.clone()); + if addr.is_none() { + warn!("Invalid device string {}", device); + return; + } + self.a2dp.as_mut().unwrap().disconnect(device); + self.hfp.as_mut().unwrap().disconnect(addr.unwrap()); } fn set_audio_config( diff --git a/gd/rust/linux/stack/src/lib.rs b/gd/rust/linux/stack/src/lib.rs index 498b56023..160363e88 100644 --- a/gd/rust/linux/stack/src/lib.rs +++ b/gd/rust/linux/stack/src/lib.rs @@ -23,7 +23,7 @@ use bt_topshim::{ btif::BaseCallbacks, profiles::{ a2dp::A2dpCallbacks, avrcp::AvrcpCallbacks, gatt::GattClientCallbacks, - gatt::GattServerCallbacks, hid_host::HHCallbacks, sdp::SdpCallbacks, + gatt::GattServerCallbacks, hfp::HfpCallbacks, hid_host::HHCallbacks, sdp::SdpCallbacks, }, }; @@ -45,6 +45,7 @@ pub enum Message { GattClient(GattClientCallbacks), GattServer(GattServerCallbacks), HidHost(HHCallbacks), + Hfp(HfpCallbacks), Sdp(SdpCallbacks), // Actions within the stack @@ -100,6 +101,10 @@ impl Stack { debug!("Unhandled Message::GattServer: {:?}", m); } + Message::Hfp(hf) => { + bluetooth_media.lock().unwrap().dispatch_hfp_callbacks(hf); + } + Message::HidHost(_h) => { // TODO(abps) - Handle hid host callbacks debug!("Received HH callback"); diff --git a/gd/rust/topshim/Android.bp b/gd/rust/topshim/Android.bp index dd77ec064..95326a631 100644 --- a/gd/rust/topshim/Android.bp +++ b/gd/rust/topshim/Android.bp @@ -74,6 +74,7 @@ gensrcs { "src/btif.rs", "src/profiles/a2dp.rs", "src/profiles/avrcp.rs", + "src/profiles/hfp.rs", "src/profiles/gatt.rs", ], output_extension: "rs.h", @@ -88,6 +89,7 @@ gensrcs { "src/btif.rs", "src/profiles/a2dp.rs", "src/profiles/avrcp.rs", + "src/profiles/hfp.rs", "src/profiles/gatt.rs", ], output_extension: "cc", diff --git a/gd/rust/topshim/BUILD.gn b/gd/rust/topshim/BUILD.gn index 26f18e0c2..d6e225296 100644 --- a/gd/rust/topshim/BUILD.gn +++ b/gd/rust/topshim/BUILD.gn @@ -27,6 +27,7 @@ cxxbridge_header("btif_bridge_header") { "src/btif.rs", "src/profiles/a2dp.rs", "src/profiles/avrcp.rs", + "src/profiles/hfp.rs", "src/profiles/gatt.rs", ] all_dependent_configs = [ ":rust_topshim_config" ] @@ -38,6 +39,7 @@ cxxbridge_cc("btif_bridge_code") { "src/btif.rs", "src/profiles/a2dp.rs", "src/profiles/avrcp.rs", + "src/profiles/hfp.rs", "src/profiles/gatt.rs", ] deps = [":btif_bridge_header"] @@ -49,6 +51,7 @@ source_set("btif_cxx_bridge_code") { "btif/btif_shim.cc", "btav/btav_shim.cc", "btav_sink/btav_sink_shim.cc", + "hfp/hfp_shim.cc", "gatt/gatt_shim.cc", ] diff --git a/gd/rust/topshim/Cargo.toml b/gd/rust/topshim/Cargo.toml index 2a46144e0..f9e405264 100644 --- a/gd/rust/topshim/Cargo.toml +++ b/gd/rust/topshim/Cargo.toml @@ -27,6 +27,7 @@ topshim_macros = { path = "macros" } cxx = "*" lazy_static = "*" +log = "*" proc-macro2 = "*" num-derive = "*" num-traits = "*" diff --git a/gd/rust/topshim/hfp/hfp_shim.cc b/gd/rust/topshim/hfp/hfp_shim.cc index 363c2c328..d7e1d9987 100644 --- a/gd/rust/topshim/hfp/hfp_shim.cc +++ b/gd/rust/topshim/hfp/hfp_shim.cc @@ -17,8 +17,15 @@ #include "gd/rust/topshim/hfp/hfp_shim.h" #include "btif/include/btif_hf.h" +#include "include/hardware/bt_hf.h" +#include "src/profiles/hfp.rs.h" #include "types/raw_address.h" +namespace rusty = ::bluetooth::topshim::rust; +namespace bluetooth::topshim::rust::internal { +static void connection_state_cb(bluetooth::headset::bthf_connection_state_t state, RawAddress* addr); +} // namespace bluetooth::topshim::rust::internal + namespace bluetooth::headset { class DBusHeadsetCallbacks : public Callbacks { public: @@ -27,8 +34,9 @@ class DBusHeadsetCallbacks : public Callbacks { return instance; } - void ConnectionStateCallback( - [[maybe_unused]] bthf_connection_state_t state, [[maybe_unused]] RawAddress* bd_addr) override {} + void ConnectionStateCallback(bthf_connection_state_t state, RawAddress* bd_addr) override { + topshim::rust::internal::connection_state_cb(state, bd_addr); + } void AudioStateCallback([[maybe_unused]] bthf_audio_state_t state, [[maybe_unused]] RawAddress* bd_addr) override {} @@ -88,12 +96,40 @@ namespace rust { namespace internal { static HfpIntf* g_hfpif; +// TODO (b/204488136): Refactor to have a2dp, gatt and hfp share these helpers. +static RustRawAddress to_rust_address(const RawAddress& addr) { + RustRawAddress raddr; + std::copy(std::begin(addr.address), std::end(addr.address), std::begin(raddr.address)); + return raddr; +} + +static RawAddress from_rust_address(const RustRawAddress& raddr) { + RawAddress addr; + addr.FromOctets(raddr.address.data()); + return addr; +} + +static void connection_state_cb(bluetooth::headset::bthf_connection_state_t state, RawAddress* addr) { + RustRawAddress raddr = to_rust_address(*addr); + rusty::hfp_connection_state_callback(state, raddr); +} + } // namespace internal int HfpIntf::init() { return intf_->Init(headset::DBusHeadsetCallbacks::GetInstance(), 1, false); } +int HfpIntf::connect(RustRawAddress bt_addr) { + RawAddress addr = internal::from_rust_address(bt_addr); + return intf_->Connect(&addr); +} + +int HfpIntf::disconnect(RustRawAddress bt_addr) { + RawAddress addr = internal::from_rust_address(bt_addr); + return intf_->Disconnect(&addr); +} + void HfpIntf::cleanup() {} std::unique_ptr<HfpIntf> GetHfpProfile(const unsigned char* btif) { diff --git a/gd/rust/topshim/hfp/hfp_shim.h b/gd/rust/topshim/hfp/hfp_shim.h index a924fdaf0..e8a962242 100644 --- a/gd/rust/topshim/hfp/hfp_shim.h +++ b/gd/rust/topshim/hfp/hfp_shim.h @@ -18,16 +18,21 @@ #include "btif/include/btif_hf.h" #include "include/hardware/bluetooth_headset_callbacks.h" +#include "types/raw_address.h" namespace bluetooth { namespace topshim { namespace rust { +struct RustRawAddress; + class HfpIntf { public: HfpIntf(headset::Interface* intf) : intf_(intf){}; int init(); + int connect(RustRawAddress bt_addr); + int disconnect(RustRawAddress bt_addr); void cleanup(); private: diff --git a/gd/rust/topshim/src/btif.rs b/gd/rust/topshim/src/btif.rs index c74fc31e9..91cf7d721 100644 --- a/gd/rust/topshim/src/btif.rs +++ b/gd/rust/topshim/src/btif.rs @@ -543,6 +543,7 @@ impl From<BluetoothProperty> for (Box<[u8]>, bindings::bt_property_t) { pub enum SupportedProfiles { HidHost, + Hfp, A2dp, Gatt, Sdp, @@ -552,6 +553,7 @@ impl From<SupportedProfiles> for Vec<u8> { fn from(item: SupportedProfiles) -> Self { match item { SupportedProfiles::HidHost => "hidhost", + SupportedProfiles::Hfp => "hfp", SupportedProfiles::A2dp => "a2dp", SupportedProfiles::Gatt => "gatt", SupportedProfiles::Sdp => "sdp", diff --git a/gd/rust/topshim/src/profiles/hfp.rs b/gd/rust/topshim/src/profiles/hfp.rs new file mode 100644 index 000000000..10d3c8d26 --- /dev/null +++ b/gd/rust/topshim/src/profiles/hfp.rs @@ -0,0 +1,117 @@ +use crate::btif::{BluetoothInterface, RawAddress}; +use crate::topstack::get_dispatchers; + +use num_traits::cast::FromPrimitive; +use std::sync::{Arc, Mutex}; +use topshim_macros::cb_variant; + +#[derive(Debug, FromPrimitive, PartialEq, PartialOrd)] +#[repr(u32)] +pub enum BthfConnectionState { + Disconnected = 0, + Connecting, + Connected, + Disconnecting, +} + +impl From<u32> for BthfConnectionState { + fn from(item: u32) -> Self { + BthfConnectionState::from_u32(item).unwrap() + } +} + +#[cxx::bridge(namespace = bluetooth::topshim::rust)] +pub mod ffi { + #[derive(Debug, Copy, Clone)] + pub struct RustRawAddress { + address: [u8; 6], + } + + unsafe extern "C++" { + include!("hfp/hfp_shim.h"); + + type HfpIntf; + + unsafe fn GetHfpProfile(btif: *const u8) -> UniquePtr<HfpIntf>; + + fn init(self: Pin<&mut HfpIntf>) -> i32; + fn connect(self: Pin<&mut HfpIntf>, bt_addr: RustRawAddress) -> i32; + fn disconnect(self: Pin<&mut HfpIntf>, bt_addr: RustRawAddress) -> i32; + fn cleanup(self: Pin<&mut HfpIntf>); + + } + extern "Rust" { + fn hfp_connection_state_callback(state: u32, addr: RustRawAddress); + } +} + +impl From<RawAddress> for ffi::RustRawAddress { + fn from(addr: RawAddress) -> Self { + ffi::RustRawAddress { address: addr.val } + } +} + +impl Into<RawAddress> for ffi::RustRawAddress { + fn into(self) -> RawAddress { + RawAddress { val: self.address } + } +} + +#[derive(Debug)] +pub enum HfpCallbacks { + ConnectionState(BthfConnectionState, RawAddress), +} + +pub struct HfpCallbacksDispatcher { + pub dispatch: Box<dyn Fn(HfpCallbacks) + Send>, +} + +type HfpCb = Arc<Mutex<HfpCallbacksDispatcher>>; + +cb_variant!( + HfpCb, + hfp_connection_state_callback -> HfpCallbacks::ConnectionState, + u32 -> BthfConnectionState, ffi::RustRawAddress -> RawAddress, { + let _1 = _1.into(); + } +); + +pub struct Hfp { + internal: cxx::UniquePtr<ffi::HfpIntf>, + _is_init: bool, +} + +// For *const u8 opaque btif +unsafe impl Send for Hfp {} + +impl Hfp { + pub fn new(intf: &BluetoothInterface) -> Hfp { + let hfpif: cxx::UniquePtr<ffi::HfpIntf>; + unsafe { + hfpif = ffi::GetHfpProfile(intf.as_raw_ptr()); + } + + Hfp { internal: hfpif, _is_init: false } + } + + pub fn initialize(&mut self, callbacks: HfpCallbacksDispatcher) -> bool { + if get_dispatchers().lock().unwrap().set::<HfpCb>(Arc::new(Mutex::new(callbacks))) { + panic!("Tried to set dispatcher for HFP callbacks while it already exists"); + } + self.internal.pin_mut().init(); + true + } + + pub fn connect(&mut self, addr: RawAddress) { + self.internal.pin_mut().connect(addr.into()); + } + + pub fn disconnect(&mut self, addr: RawAddress) { + self.internal.pin_mut().disconnect(addr.into()); + } + + pub fn cleanup(&mut self) -> bool { + self.internal.pin_mut().cleanup(); + true + } +} diff --git a/gd/rust/topshim/src/profiles/mod.rs b/gd/rust/topshim/src/profiles/mod.rs index ea2f671fe..a12e7c504 100644 --- a/gd/rust/topshim/src/profiles/mod.rs +++ b/gd/rust/topshim/src/profiles/mod.rs @@ -1,5 +1,6 @@ pub mod a2dp; pub mod avrcp; pub mod gatt; +pub mod hfp; pub mod hid_host; pub mod sdp; |