rust/bt-ascs: CIS establish/release handling Change-Id: Ia57027b152a515f2bf7567791ffbf40d3a7f2785 Reviewed-on: https://bluetooth-review.googlesource.com/c/bluetooth/+/1900
diff --git a/rust/bt-ascs/src/server.rs b/rust/bt-ascs/src/server.rs index 982968f..9a329fa 100644 --- a/rust/bt-ascs/src/server.rs +++ b/rust/bt-ascs/src/server.rs
@@ -300,8 +300,41 @@ Ok(()) } - pub fn release(&mut self, _id: AseId) -> Result<(), Error> { - unimplemented!() + pub fn cis_established( + &mut self, + peer_id: PeerId, + ase_id: AseId, + cis: (CigId, CisId), + ) -> Result<(), Error> { + let endpoints = + self.client_endpoints.get_mut(&peer_id).ok_or(Error::UnknownPeer(peer_id))?; + endpoints.established_cis(ase_id, cis); + for operation in endpoints.autonomous_operations() { + self.queue_operation_unpin(peer_id, operation); + } + Ok(()) + } + + pub fn cis_released( + &mut self, + peer_id: PeerId, + ase_id: AseId, + cis: (CigId, CisId), + ) -> Result<(), Error> { + let endpoints = + self.client_endpoints.get_mut(&peer_id).ok_or(Error::UnknownPeer(peer_id))?; + endpoints.released_cis(ase_id, cis); + for operation in endpoints.autonomous_operations() { + self.queue_operation_unpin(peer_id, operation); + } + Ok(()) + } + + fn queue_operation_unpin(&mut self, peer_id: PeerId, op: AseControlOperation) { + let (events, fut) = + op.apply(peer_id, self.client_endpoints.get(&peer_id).unwrap().endpoints.clone()); + self.outgoing_events.extend(events); + self.responses.push(fut); } fn queue_operation(self: std::pin::Pin<&mut Self>, peer_id: PeerId, op: AseControlOperation) { @@ -521,6 +554,7 @@ struct ClientEndpoints { endpoints: HashMap<AseId, AudioStreamEndpoint>, handles: HashMap<Handle, AseId>, + established: HashMap<AseId, Vec<(CigId, CisId)>>, } impl ClientEndpoints { @@ -549,12 +583,46 @@ ) }) .unzip(); - Self { endpoints, handles } + Self { endpoints, handles, established: Default::default() } } fn clone_for_peer(&self, _peer_id: PeerId) -> Self { // TODO: Randomize the ASE_IDs. Handles need to stay the same. - Self { endpoints: self.endpoints.clone(), handles: self.handles.clone() } + Self { + endpoints: self.endpoints.clone(), + handles: self.handles.clone(), + established: Default::default(), + } + } + + fn established_cis(&mut self, ase_id: AseId, cis: (CigId, CisId)) { + self.established.entry(ase_id).or_default().push(cis); + } + + fn released_cis(&mut self, ase_id: AseId, cis: (CigId, CisId)) { + self.established.get_mut(&ase_id).map(|established| established.retain(|i| i != &cis)); + } + + fn autonomous_operations(&self) -> Vec<AseControlOperation> { + let mut operations = Vec::new(); + for endpoint in self.endpoints.values() { + match endpoint.state { + AseState::Enabling + if self.established.get(&endpoint.ase_id).is_some_and(|e| !e.is_empty()) => + { + operations.push(AseControlOperation::ReceiverStartReady { + ases: vec![endpoint.ase_id], + }); + } + AseState::Releasing + if self.established.get(&endpoint.ase_id).is_some_and(|e| e.is_empty()) => + { + operations.push(AseControlOperation::Released { ase_id: endpoint.ase_id }); + } + _ => continue, + } + } + operations } }
diff --git a/rust/bt-ascs/src/types.rs b/rust/bt-ascs/src/types.rs index 6eb27c9..1ca6f3f 100644 --- a/rust/bt-ascs/src/types.rs +++ b/rust/bt-ascs/src/types.rs
@@ -22,6 +22,8 @@ PublishError(bt_gatt::types::Error), #[error("Unsupported configuration: {0}")] Unsupported(String), + #[error("Unknown Peer: {0}")] + UnknownPeer(bt_common::PeerId), } #[non_exhaustive] @@ -714,7 +716,7 @@ return (Err(Self::Error::BufferTooSmall), buf.len()); } let val = u32::from_le_bytes([buf[0], buf[1], buf[2], 0]); - if val < 0xFF || val > 0x0FFFFF { + if (val < 0xFF) || (val > 0x0FFFFF) { return (Err(Self::Error::OutOfRange), Self::BYTE_SIZE); } (Ok(SduInterval(val)), Self::BYTE_SIZE) @@ -1087,6 +1089,26 @@ assert_eq!(codec_config.target_phy, TargetPhy::Le2MPhy); assert_eq!(codec_config.codec_id, CodecId::Assigned(bt_common::core::CodingFormat::Lc3)); assert_eq!(codec_config.codec_specific_configuration.len(), 0x10); + + #[rustfmt::skip] + let encoded_qos = &[ + 0x02, 0x01, // Qos OpCode, 1 number_of_ases + 0x03, // ASE_ID, + 0x00, // CIG_ID, + 0x00, // CIS_ID, + 0x10, 0x27, 0x00, // SduInterval + 0x01, 0x02, 0x28, 0x00, 0x02, 0xf4, + 0x01, 0x18, 0x00, 0x80, + ]; + assert_eq!(QosConfiguration::BYTE_SIZE, encoded_qos.len() - 2); + let (qos_config, consumed) = QosConfiguration::decode(&encoded_qos[2..]); + assert!(qos_config.is_ok()); + assert_eq!(consumed, encoded_qos.len() - 2); + let encoded_qos: Vec<u8> = encoded_qos.into_iter().copied().collect(); + let operation = AseControlOperation::try_from(encoded_qos); + let Ok(_operation) = operation else { + panic!("Expected decode to work correctly, for {operation:?}"); + }; } #[test]