blob: 160363e88a95ed172c06f4fae77fc1006ff01ef3 [file] [log] [blame]
//! Fluoride/GD Bluetooth stack.
//!
//! This crate provides the API implementation of the Fluoride/GD Bluetooth stack, independent of
//! any RPC projection.
#[macro_use]
extern crate num_derive;
pub mod bluetooth;
pub mod bluetooth_gatt;
pub mod bluetooth_media;
pub mod uuid;
use log::debug;
use std::sync::{Arc, Mutex};
use tokio::sync::mpsc::channel;
use tokio::sync::mpsc::{Receiver, Sender};
use crate::bluetooth::Bluetooth;
use crate::bluetooth_gatt::BluetoothGatt;
use crate::bluetooth_media::{BluetoothMedia, MediaActions};
use bt_topshim::{
btif::BaseCallbacks,
profiles::{
a2dp::A2dpCallbacks, avrcp::AvrcpCallbacks, gatt::GattClientCallbacks,
gatt::GattServerCallbacks, hfp::HfpCallbacks, hid_host::HHCallbacks, sdp::SdpCallbacks,
},
};
/// Represents a Bluetooth address.
// TODO: Add support for LE random addresses.
#[derive(Clone, Debug)]
pub enum BluetoothCallbackType {
Adapter,
Connection,
}
/// Message types that are sent to the stack main dispatch loop.
pub enum Message {
// Callbacks from libbluetooth
A2dp(A2dpCallbacks),
Avrcp(AvrcpCallbacks),
Base(BaseCallbacks),
GattClient(GattClientCallbacks),
GattServer(GattServerCallbacks),
HidHost(HHCallbacks),
Hfp(HfpCallbacks),
Sdp(SdpCallbacks),
// Actions within the stack
Media(MediaActions),
// Client callback disconnections
BluetoothCallbackDisconnected(u32, BluetoothCallbackType),
}
/// Umbrella class for the Bluetooth stack.
pub struct Stack {}
impl Stack {
/// Creates an mpsc channel for passing messages to the main dispatch loop.
pub fn create_channel() -> (Sender<Message>, Receiver<Message>) {
channel::<Message>(1)
}
/// Runs the main dispatch loop.
pub async fn dispatch(
mut rx: Receiver<Message>,
bluetooth: Arc<Mutex<Box<Bluetooth>>>,
bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>,
bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>,
) {
loop {
let m = rx.recv().await;
if m.is_none() {
eprintln!("Message dispatch loop quit");
break;
}
match m.unwrap() {
Message::A2dp(a) => {
bluetooth_media.lock().unwrap().dispatch_a2dp_callbacks(a);
}
Message::Avrcp(av) => {
bluetooth_media.lock().unwrap().dispatch_avrcp_callbacks(av);
}
Message::Base(b) => {
bluetooth.lock().unwrap().dispatch_base_callbacks(b);
}
Message::GattClient(m) => {
bluetooth_gatt.lock().unwrap().dispatch_gatt_client_callbacks(m);
}
Message::GattServer(m) => {
// TODO(b/193685149): dispatch GATT server callbacks.
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");
}
Message::Sdp(s) => {
bluetooth.lock().unwrap().dispatch_sdp_callbacks(s);
}
Message::Media(action) => {
bluetooth_media.lock().unwrap().dispatch_media_actions(action);
}
Message::BluetoothCallbackDisconnected(id, cb_type) => {
bluetooth.lock().unwrap().callback_disconnected(id, cb_type);
}
}
}
}
}
/// Signifies that the object may be a proxy to a remote RPC object.
///
/// An object that implements RPCProxy trait signifies that the object may be a proxy to a remote
/// RPC object. Therefore the object may be disconnected and thus should implement
/// `register_disconnect` to let others observe the disconnection event.
pub trait RPCProxy {
/// Registers disconnect observer that will be notified when the remote object is disconnected.
fn register_disconnect(&mut self, f: Box<dyn Fn(u32) + Send>) -> u32;
/// Returns the ID of the object. For example this would be an object path in D-Bus RPC.
fn get_object_id(&self) -> String;
/// Unregisters callback with this id.
fn unregister(&mut self, id: u32) -> bool;
}