diff --git a/manager-app/src/async_bridge/bridge.rs b/manager-app/src/async_bridge/bridge.rs index d63b1f1..9ebd7d3 100644 --- a/manager-app/src/async_bridge/bridge.rs +++ b/manager-app/src/async_bridge/bridge.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use log::debug; +use log::{debug, info, trace}; use tauri::AppHandle; use tokio::sync::{mpsc, Mutex}; @@ -10,7 +10,7 @@ use soundcore_lib::{ device_manager::{create_device_manager, DeviceManager}, }; -use super::{BridgeCommand, BridgeResponse, NewStateResponse}; +use super::{BridgeCommand, BridgeResponse, TaggedStateResponse}; struct CommandLoopState { manager: DeviceManager, @@ -18,9 +18,7 @@ struct CommandLoopState { impl CommandLoopState { fn new(manager: DeviceManager) -> Self { - Self { - manager, - } + Self { manager } } } @@ -29,8 +27,7 @@ pub async fn async_bridge( output_tx: mpsc::Sender, ) { tokio::spawn(async move { - let manager = - create_device_manager().await; + let manager = create_device_manager().await; // Adapter events let mut manager_event_channel = manager.get_event_channel().await.unwrap(); @@ -82,6 +79,14 @@ async fn handle_command( .await .map(|_| BridgeResponse::Disconnected(addr_clone)) } + BridgeCommand::DisconnectAll => { + command_loop_state + .lock() + .await + .manager + .disconnect_all() + .await.map(|_| BridgeResponse::DisconnectedAll) + } BridgeCommand::Connect(d) => { let addr = d.clone().descriptor.addr; let device = command_loop_state.lock().await.manager.connect(d).await; @@ -89,20 +94,32 @@ async fn handle_command( if let Ok(device) = device { // Get the state channel and listen for changes in the background let mut state_channel = device.state_channel().await; - tokio::task::spawn(async move { + let _ = tokio::task::spawn(async move { + info!("Listening for state changes for {:?}", addr_clone); while let Ok(()) = state_channel.changed().await { let state = state_channel.borrow().clone(); - // TODO: Add logging - let new_state_response = NewStateResponse { - addr: addr_clone.clone(), + trace!( + "Got new state {:?} for {:?}, sending event...", state, - }; - output_tx - .send(BridgeResponse::NewState(new_state_response)) + addr_clone + ); + let res = output_tx + .send(BridgeResponse::NewState(TaggedStateResponse { + addr: addr_clone.clone(), + state, + })) .await; + + if let Err(e) = res { + debug!("Failed to send new state event: {:?}", e); + } } + trace!("State channel for {:?} closed", addr_clone); }); - Ok(BridgeResponse::ConnectionEstablished(addr)) + Ok(BridgeResponse::ConnectionEstablished(TaggedStateResponse { + addr, + state: device.latest_state().await, + })) } else { Err(device.err().unwrap()) } diff --git a/manager-app/src/async_bridge/command.rs b/manager-app/src/async_bridge/command.rs index 8305030..44b8bf6 100644 --- a/manager-app/src/async_bridge/command.rs +++ b/manager-app/src/async_bridge/command.rs @@ -11,4 +11,5 @@ pub enum BridgeCommand { Scan, Connect(DiscoveredDevice), Disconnect(BluetoothAdrr), + DisconnectAll, } diff --git a/manager-app/src/async_bridge/response.rs b/manager-app/src/async_bridge/response.rs index e63b42a..1f3a1ac 100644 --- a/manager-app/src/async_bridge/response.rs +++ b/manager-app/src/async_bridge/response.rs @@ -11,9 +11,10 @@ use typeshare::typeshare; #[typeshare] pub enum BridgeResponse { ScanResult(Vec), - ConnectionEstablished(BluetoothAdrr), - NewState(NewStateResponse), + ConnectionEstablished(TaggedStateResponse), + NewState(TaggedStateResponse), Disconnected(BluetoothAdrr), + DisconnectedAll, AdapterEvent(BLEAdapterEvent), Error(String), } @@ -21,7 +22,7 @@ pub enum BridgeResponse { #[derive(Debug, Serialize, Clone)] #[serde(rename_all = "camelCase")] #[typeshare] -pub struct NewStateResponse { +pub struct TaggedStateResponse { pub addr: BluetoothAdrr, pub state: SoundcoreDeviceState, } \ No newline at end of file diff --git a/manager-ui/src/types/tauri-backend.d.ts b/manager-ui/src/types/tauri-backend.d.ts index 29fb588..54a4a61 100644 --- a/manager-ui/src/types/tauri-backend.d.ts +++ b/manager-ui/src/types/tauri-backend.d.ts @@ -2,7 +2,7 @@ Generated by typeshare 1.7.0 */ -export interface NewStateResponse { +export interface TaggedStateResponse { addr: BluetoothAdrr; state: SoundcoreDeviceState; } @@ -46,12 +46,14 @@ export interface DeviceFeatures { export type BridgeCommand = | { command: 'scan'; payload?: undefined } | { command: 'connect'; payload: DiscoveredDevice } - | { command: 'disconnect'; payload: BluetoothAdrr }; + | { command: 'disconnect'; payload: BluetoothAdrr } + | { command: 'disconnectAll'; payload?: undefined }; export type BridgeResponse = | { kind: 'scanResult'; payload: DiscoveredDevice[] } - | { kind: 'connectionEstablished'; payload: BluetoothAdrr } - | { kind: 'newState'; payload: NewStateResponse } + | { kind: 'connectionEstablished'; payload: TaggedStateResponse } + | { kind: 'newState'; payload: TaggedStateResponse } | { kind: 'disconnected'; payload: BluetoothAdrr } + | { kind: 'disconnectedAll'; payload?: undefined } | { kind: 'adapterEvent'; payload: BLEAdapterEvent } | { kind: 'error'; payload: string }; diff --git a/soundcore-lib/src/device_manager.rs b/soundcore-lib/src/device_manager.rs index 99ce504..9b0d1d4 100644 --- a/soundcore-lib/src/device_manager.rs +++ b/soundcore-lib/src/device_manager.rs @@ -80,10 +80,18 @@ where .collect::>()) } - pub async fn get_event_channel(&self) -> SoundcoreLibResult> { + pub async fn get_event_channel( + &self, + ) -> SoundcoreLibResult> { self.ble_manager.adapter_events().await } + pub async fn disconnect_all(&self) -> SoundcoreLibResult<()> { + let mut devices = self.ble_devices.write().await; + devices.clear(); + Ok(()) + } + fn map_descriptor_to_discovered_device(descriptor: &BLEDeviceDescriptor) -> DiscoveredDevice { DiscoveredDevice { descriptor: descriptor.to_owned(), @@ -103,7 +111,6 @@ where None => discovered_device, } } - } /// A discovered BLE device. The DiscoveredDevice can be upgraded to a SoundcoreBLEDevice.