aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2021-11-02 08:14:41 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2021-11-02 08:14:41 +0000
commit7c43e37aa8957602c9f220cd520770501f414a7c (patch)
tree9b3f26eb913476ba3ea486e7dd5be48f5cd99e95
parent8b91b04a5485ee927338e34cf1338608fd4e2d6d (diff)
parente9ec027fdc04137915af90a8703310618984f0ec (diff)
downloadbt-7c43e37aa8957602c9f220cd520770501f414a7c.tar.gz
Merge "floss: Fill in topshim for headset interface"
-rw-r--r--gd/rust/linux/stack/src/bluetooth_media.rs62
-rw-r--r--gd/rust/linux/stack/src/lib.rs7
-rw-r--r--gd/rust/topshim/Android.bp2
-rw-r--r--gd/rust/topshim/BUILD.gn3
-rw-r--r--gd/rust/topshim/Cargo.toml1
-rw-r--r--gd/rust/topshim/hfp/hfp_shim.cc40
-rw-r--r--gd/rust/topshim/hfp/hfp_shim.h5
-rw-r--r--gd/rust/topshim/src/btif.rs2
-rw-r--r--gd/rust/topshim/src/profiles/hfp.rs117
-rw-r--r--gd/rust/topshim/src/profiles/mod.rs1
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;