diff --git a/manager-app/src/async_bridge/bridge.rs b/manager-app/src/async_bridge/bridge.rs index 8ff2f06..d63b1f1 100644 --- a/manager-app/src/async_bridge/bridge.rs +++ b/manager-app/src/async_bridge/bridge.rs @@ -1,5 +1,6 @@ use std::sync::Arc; +use log::debug; use tauri::AppHandle; use tokio::sync::{mpsc, Mutex}; @@ -13,16 +14,12 @@ use super::{BridgeCommand, BridgeResponse, NewStateResponse}; struct CommandLoopState { manager: DeviceManager, - app_handle: AppHandle, - devices: Vec>>, } impl CommandLoopState { - fn new(manager: DeviceManager, app_handle: AppHandle) -> Self { + fn new(manager: DeviceManager) -> Self { Self { manager, - app_handle, - devices: Vec::new(), } } } @@ -30,11 +27,25 @@ impl CommandLoopState { pub async fn async_bridge( mut input_rx: mpsc::Receiver, output_tx: mpsc::Sender, - app_handle: AppHandle, ) { - let command_loop = tokio::spawn(async move { - let manager = create_device_manager().await; - let command_loop_state = Arc::new(Mutex::new(CommandLoopState::new(manager, app_handle))); + tokio::spawn(async move { + let manager = + create_device_manager().await; + + // Adapter events + let mut manager_event_channel = manager.get_event_channel().await.unwrap(); + let adapter_tx = output_tx.clone(); + tokio::task::spawn(async move { + while let Some(event) = manager_event_channel.recv().await { + adapter_tx + .send(BridgeResponse::AdapterEvent(event)) + .await + .expect("Failed to send adapter event"); + } + }); + + // Main command loop + let command_loop_state = Arc::new(Mutex::new(CommandLoopState::new(manager))); loop { while let Some(command) = input_rx.recv().await { let command_loop_state = command_loop_state.clone(); diff --git a/manager-app/src/async_bridge/response.rs b/manager-app/src/async_bridge/response.rs index fe77d6f..e63b42a 100644 --- a/manager-app/src/async_bridge/response.rs +++ b/manager-app/src/async_bridge/response.rs @@ -1,6 +1,7 @@ use serde::Serialize; use soundcore_lib::api::SoundcoreDeviceState; +use soundcore_lib::ble::BLEAdapterEvent; use soundcore_lib::btaddr::BluetoothAdrr; use soundcore_lib::device_manager::DiscoveredDevice; use typeshare::typeshare; @@ -13,6 +14,7 @@ pub enum BridgeResponse { ConnectionEstablished(BluetoothAdrr), NewState(NewStateResponse), Disconnected(BluetoothAdrr), + AdapterEvent(BLEAdapterEvent), Error(String), } diff --git a/manager-app/src/main.rs b/manager-app/src/main.rs index 5cc84bb..b000267 100644 --- a/manager-app/src/main.rs +++ b/manager-app/src/main.rs @@ -59,21 +59,18 @@ async fn main() { #[cfg(target_os = "macos")] server::launch_server(); - // Bring up bridge - // builder() // .filter(None, log::LevelFilter::Debug) // .filter_module("h2", log::LevelFilter::Off) // .filter_module("hyper", log::LevelFilter::Off) // .filter_module("tower", log::LevelFilter::Off) // .init(); - let (input_tx, input_rx) = channel(1); - let (output_tx, mut output_rx) = channel(1); + let (input_tx, input_rx) = channel(255); + let (output_tx, mut output_rx) = channel(255); tauri::Builder::default() .setup(|app| { - let bridge_app_handle = app.handle(); - tokio::spawn(async_bridge(input_rx, output_tx, bridge_app_handle)); + tokio::spawn(async_bridge(input_rx, output_tx)); let app_handle = app.handle(); tokio::spawn(async move { diff --git a/soundcore-lib/Cargo.toml b/soundcore-lib/Cargo.toml index 0a7c779..e00f3cc 100644 --- a/soundcore-lib/Cargo.toml +++ b/soundcore-lib/Cargo.toml @@ -18,7 +18,12 @@ log = { workspace = true } env_logger = { workspace = true } thiserror = { workspace = true } serde = { workspace = true, features = ["derive", "rc"] } -tokio = { workspace = true, features = ["time", "macros", "rt-multi-thread", "sync"] } +tokio = { workspace = true, features = [ + "time", + "macros", + "rt-multi-thread", + "sync", +] } async-trait = { workspace = true } futures = { workspace = true } strum = { version = "0.26", features = ["derive"] } @@ -34,7 +39,6 @@ btleplug = { version = "0.11", features = ["serde"], optional = true } test_data = { path = "../test_data" } - [target.'cfg(target_os = "windows")'.dependencies] windows = { version = "0.52", features = [ "Storage_Streams", @@ -44,5 +48,5 @@ windows = { version = "0.52", features = [ "Devices_Enumeration", "Devices_Bluetooth", "Devices_Bluetooth_GenericAttributeProfile", - "Devices_Bluetooth_Advertisement" -], optional = true } \ No newline at end of file + "Devices_Bluetooth_Advertisement", +], optional = true } diff --git a/soundcore-lib/src/ble/btleplug/btaddr.rs b/soundcore-lib/src/ble/btleplug/btaddr.rs index 294072b..9d9679b 100644 --- a/soundcore-lib/src/ble/btleplug/btaddr.rs +++ b/soundcore-lib/src/ble/btleplug/btaddr.rs @@ -24,6 +24,12 @@ impl From for PeripheralId { } } +impl From for BluetoothAdrr { + fn from(val: PeripheralId) -> Self { + BluetoothAdrr::from_str(&val.to_string()).unwrap() + } +} + impl From for btleplug::api::WriteType { fn from(value: WriteType) -> Self { match value { diff --git a/soundcore-lib/src/ble/btleplug/manager.rs b/soundcore-lib/src/ble/btleplug/manager.rs index 4209f05..b269aa1 100644 --- a/soundcore-lib/src/ble/btleplug/manager.rs +++ b/soundcore-lib/src/ble/btleplug/manager.rs @@ -2,16 +2,22 @@ use std::sync::{Arc, Weak}; use std::time::Duration; use async_trait::async_trait; +use btleplug::api::{Central as _, CentralEvent}; use btleplug::{ api::Manager as _, platform::{Adapter, Manager}, }; +use futures::StreamExt; +use log::warn; use tokio::sync::RwLock; use weak_table::weak_value_hash_map::Entry; use weak_table::WeakValueHashMap; -use crate::ble::{BLEConnectionFactory, BLEConnectionUuidSet, BLEDeviceDescriptor, BLEConnectionManager, BLEDeviceScanner}; use crate::ble::btleplug::connection::BtlePlugConnection; +use crate::ble::{ + BLEConnectionFactory, BLEConnectionManager, BLEConnectionUuidSet, BLEDeviceDescriptor, + BLEAdapterEvent, BLEDeviceScanner, +}; use crate::btaddr::BluetoothAdrr; use crate::error::SoundcoreLibResult; @@ -72,10 +78,13 @@ impl BLEConnectionManager for BtlePlugBLEManager { descriptor: BLEDeviceDescriptor, uuid_set: Option, ) -> SoundcoreLibResult> { - match self.open_connections.write().await.entry(descriptor.addr.to_owned()) { - Entry::Occupied(e) => { - Ok(e.get().to_owned()) - } + match self + .open_connections + .write() + .await + .entry(descriptor.addr.to_owned()) + { + Entry::Occupied(e) => Ok(e.get().to_owned()), Entry::Vacant(e) => { let connection = self .connection_factory @@ -87,4 +96,40 @@ impl BLEConnectionManager for BtlePlugBLEManager { } } } + + async fn adapter_events( + &self, + ) -> SoundcoreLibResult> { + let (tx, rx) = tokio::sync::mpsc::channel::(255); + + for adapter in self.adapters.clone() { + let tx_clone = tx.clone(); + let mut adapter_events = adapter.events().await.unwrap(); + tokio::spawn(async move { + while let Some(evt) = adapter_events.next().await { + let event: Option = evt.try_into().ok(); + if let Some(event) = event { + tx_clone.send(event).await.unwrap(); + } + } + }); + } + Ok(rx) + } } + + +impl TryInto for CentralEvent { + type Error = (); + + fn try_into(self) -> Result { + match self { + CentralEvent::DeviceDisconnected(id) => Ok(BLEAdapterEvent::DeviceDisconnected(id.into())), + CentralEvent::DeviceConnected(id) => Ok(BLEAdapterEvent::DeviceConnected(id.into())), + _ => { + warn!("Unhandled CentralEvent: {:?}", self); + Err(()) + } + } + } +} \ No newline at end of file diff --git a/soundcore-lib/src/device_manager.rs b/soundcore-lib/src/device_manager.rs index 6aebc01..99ce504 100644 --- a/soundcore-lib/src/device_manager.rs +++ b/soundcore-lib/src/device_manager.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use std::{sync::Arc, time::Duration}; use crate::ble::btleplug::manager::BtlePlugBLEManager; +use crate::ble::BLEAdapterEvent; #[cfg(any(test, feature = "mock-ble"))] use crate::mocks::*; use crate::{ @@ -79,6 +80,10 @@ where .collect::>()) } + pub async fn get_event_channel(&self) -> SoundcoreLibResult> { + self.ble_manager.adapter_events().await + } + fn map_descriptor_to_discovered_device(descriptor: &BLEDeviceDescriptor) -> DiscoveredDevice { DiscoveredDevice { descriptor: descriptor.to_owned(), @@ -98,6 +103,7 @@ where None => discovered_device, } } + } /// A discovered BLE device. The DiscoveredDevice can be upgraded to a SoundcoreBLEDevice. diff --git a/soundcore-lib/src/mocks/connection_manager.rs b/soundcore-lib/src/mocks/connection_manager.rs index 8948572..2f12c5a 100644 --- a/soundcore-lib/src/mocks/connection_manager.rs +++ b/soundcore-lib/src/mocks/connection_manager.rs @@ -42,4 +42,8 @@ impl BLEConnectionManager for MockBLEConnectionManager { let conn = MockBLEConnection::new_with_empty_channel(); Ok(Arc::new(conn)) } + + async fn adapter_events(&self) -> SoundcoreLibResult> { + unimplemented!() + } }