1 // Copyright 2024, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 use bluetooth_offload_hci as hci; 16 17 use crate::arbiter::Arbiter; 18 use crate::service::{Service, StreamConfiguration}; 19 use hci::{ 20 Command, CommandToBytes, Event, EventToBytes, IsoData, Module, ModuleBuilder, ReturnParameters, 21 Status, 22 }; 23 use std::collections::HashMap; 24 use std::sync::{Arc, Mutex}; 25 26 const DATA_PATH_ID_SOFTWARE: u8 = 0x19; // TODO 27 28 /// LE Audio HCI-Proxy module builder 29 pub struct LeAudioModuleBuilder {} 30 31 pub(crate) struct LeAudioModule { 32 next_module: Arc<dyn Module>, 33 state: Mutex<State>, 34 } 35 36 #[derive(Default)] 37 struct State { 38 big: HashMap<u8, BigParameters>, 39 cig: HashMap<u8, CigParameters>, 40 stream: HashMap<u16, Stream>, 41 arbiter: Option<Arc<Arbiter>>, 42 } 43 44 struct BigParameters { 45 sdu_interval: u32, 46 max_sdu_size: u16, 47 bis_handles: Vec<u16>, 48 } 49 50 struct CigParameters { 51 sdu_interval_c_to_p: u32, 52 sdu_interval_p_to_c: u32, 53 cis: Vec<CisParameters>, 54 } 55 56 struct CisParameters { 57 handle: u16, 58 max_sdu_size_c_to_p: u16, 59 max_sdu_size_p_to_c: u16, 60 } 61 62 #[derive(Debug, Clone)] 63 struct Stream { 64 state: StreamState, 65 iso_type: IsoType, 66 iso_interval_us: u32, 67 } 68 69 #[derive(Debug, PartialEq, Clone)] 70 enum StreamState { 71 Disabled, 72 Enabling, 73 Enabled, 74 } 75 76 #[derive(Debug, Clone)] 77 enum IsoType { 78 Cis { c_to_p: IsoInDirection, _p_to_c: IsoInDirection }, 79 Bis { c_to_p: IsoInDirection }, 80 } 81 82 #[derive(Debug, Clone)] 83 struct IsoInDirection { 84 sdu_interval_us: u32, 85 max_sdu_size: u16, 86 flush_timeout: u8, 87 } 88 89 impl Stream { new_cis(cig: &CigParameters, e: &hci::LeCisEstablished) -> Self90 fn new_cis(cig: &CigParameters, e: &hci::LeCisEstablished) -> Self { 91 let cis = cig.cis.iter().find(|&s| s.handle == e.connection_handle).unwrap(); 92 let iso_interval_us = (e.iso_interval as u32) * 1250; 93 94 assert!( 95 cig.sdu_interval_c_to_p == 0 || (iso_interval_us % cig.sdu_interval_c_to_p) == 0, 96 "Framing mode not supported" 97 ); 98 assert!( 99 cig.sdu_interval_p_to_c == 0 || (iso_interval_us % cig.sdu_interval_p_to_c) == 0, 100 "Framing mode not supported" 101 ); 102 103 Self { 104 state: StreamState::Disabled, 105 iso_interval_us, 106 iso_type: IsoType::Cis { 107 c_to_p: IsoInDirection { 108 sdu_interval_us: cig.sdu_interval_c_to_p, 109 max_sdu_size: cis.max_sdu_size_c_to_p, 110 flush_timeout: e.ft_c_to_p, 111 }, 112 _p_to_c: IsoInDirection { 113 sdu_interval_us: cig.sdu_interval_p_to_c, 114 max_sdu_size: cis.max_sdu_size_p_to_c, 115 flush_timeout: e.ft_p_to_c, 116 }, 117 }, 118 } 119 } 120 new_bis(big: &BigParameters, e: &hci::LeCreateBigComplete) -> Self121 fn new_bis(big: &BigParameters, e: &hci::LeCreateBigComplete) -> Self { 122 let iso_interval_us = (e.iso_interval as u32) * 1250; 123 assert_eq!(iso_interval_us % big.sdu_interval, 0, "Framing mode not supported"); 124 125 Self { 126 state: StreamState::Disabled, 127 iso_interval_us, 128 iso_type: IsoType::Bis { 129 c_to_p: IsoInDirection { 130 sdu_interval_us: big.sdu_interval, 131 max_sdu_size: big.max_sdu_size, 132 flush_timeout: e.irc, 133 }, 134 }, 135 } 136 } 137 } 138 139 impl ModuleBuilder for LeAudioModuleBuilder { 140 /// Build the HCI-Proxy module from the next module in the chain build(&self, next_module: Arc<dyn Module>) -> Arc<dyn Module>141 fn build(&self, next_module: Arc<dyn Module>) -> Arc<dyn Module> { 142 Service::register(); 143 Arc::new(LeAudioModule::new(next_module)) 144 } 145 } 146 147 impl LeAudioModule { new(next_module: Arc<dyn Module>) -> Self148 pub(crate) fn new(next_module: Arc<dyn Module>) -> Self { 149 Self { next_module, state: Mutex::new(Default::default()) } 150 } 151 152 #[cfg(test)] arbiter(&self) -> Option<Arc<Arbiter>>153 pub(crate) fn arbiter(&self) -> Option<Arc<Arbiter>> { 154 let state = self.state.lock().unwrap(); 155 state.arbiter.clone() 156 } 157 } 158 159 impl Module for LeAudioModule { next(&self) -> &dyn Module160 fn next(&self) -> &dyn Module { 161 &*self.next_module 162 } 163 out_cmd(&self, data: &[u8])164 fn out_cmd(&self, data: &[u8]) { 165 match Command::from_bytes(data) { 166 Ok(Command::LeSetCigParameters(ref c)) => { 167 let mut state = self.state.lock().unwrap(); 168 state.cig.insert( 169 c.cig_id, 170 CigParameters { 171 sdu_interval_c_to_p: c.sdu_interval_c_to_p, 172 sdu_interval_p_to_c: c.sdu_interval_p_to_c, 173 cis: c 174 .cis 175 .iter() 176 .map(|c| CisParameters { 177 handle: 0, 178 max_sdu_size_c_to_p: c.max_sdu_c_to_p, 179 max_sdu_size_p_to_c: c.max_sdu_p_to_c, 180 }) 181 .collect(), 182 }, 183 ); 184 } 185 186 Ok(Command::LeCreateBig(ref c)) => { 187 let mut state = self.state.lock().unwrap(); 188 state.big.insert( 189 c.big_handle, 190 BigParameters { 191 sdu_interval: c.sdu_interval, 192 max_sdu_size: c.max_sdu, 193 bis_handles: vec![], 194 }, 195 ); 196 } 197 198 Ok(Command::LeSetupIsoDataPath(ref c)) if c.data_path_id == DATA_PATH_ID_SOFTWARE => 'command: { 199 assert_eq!(c.data_path_direction, hci::LeDataPathDirection::Input); 200 let mut state = self.state.lock().unwrap(); 201 let Some(stream) = state.stream.get_mut(&c.connection_handle) else { 202 log::warn!( 203 "Setup ISO Data Path on non existing BIS/CIS handle: 0x{:03x}", 204 c.connection_handle 205 ); 206 break 'command; 207 }; 208 stream.state = StreamState::Enabling; 209 210 // Phase 1 limitation: The controller does not implement HCI Link Feedback event, 211 // and not implement the `DATA_PATH_ID_SOTWARE` to enable it. 212 // Fix the data_path_id to 0 (HCI) waiting for controller implementation. 213 self.next() 214 .out_cmd(&hci::LeSetupIsoDataPath { data_path_id: 0, ..c.clone() }.to_bytes()); 215 return; 216 } 217 218 Ok(Command::LeRemoveIsoDataPath(ref c)) => { 219 let mut state = self.state.lock().unwrap(); 220 if state.stream.get_mut(&c.connection_handle).is_none() { 221 log::warn!( 222 "Remove ISO Data Path on non existing BIS/CIS handle: 0x{:03x}", 223 c.connection_handle 224 ); 225 } 226 } 227 228 _ => (), 229 } 230 231 self.next().out_cmd(data); 232 } 233 in_evt(&self, data: &[u8])234 fn in_evt(&self, data: &[u8]) { 235 match Event::from_bytes(data) { 236 Ok(Event::CommandComplete(ref e)) => match e.return_parameters { 237 ReturnParameters::Reset(ref ret) if ret.status == Status::Success => { 238 let mut state = self.state.lock().unwrap(); 239 *state = Default::default(); 240 } 241 242 ReturnParameters::LeReadBufferSizeV2(ref ret) if ret.status == Status::Success => { 243 let mut state = self.state.lock().unwrap(); 244 state.arbiter = Some(Arc::new(Arbiter::new( 245 self.next_module.clone(), 246 ret.iso_data_packet_length.into(), 247 ret.total_num_iso_data_packets.into(), 248 ))); 249 Service::reset(Arc::downgrade(state.arbiter.as_ref().unwrap())); 250 } 251 252 ReturnParameters::LeSetCigParameters(ref ret) if ret.status == Status::Success => { 253 let mut state = self.state.lock().unwrap(); 254 let cig = state.cig.get_mut(&ret.cig_id).unwrap(); 255 256 assert!(cig.cis.len() == ret.connection_handles.len()); 257 for (cis, &handle) in cig.cis.iter_mut().zip(ret.connection_handles.iter()) { 258 cis.handle = handle; 259 } 260 } 261 262 ReturnParameters::LeRemoveCig(ref ret) if ret.status == Status::Success => { 263 let mut state = self.state.lock().unwrap(); 264 state.cig.remove(&ret.cig_id); 265 } 266 267 ReturnParameters::LeSetupIsoDataPath(ref ret) => 'event: { 268 let mut state = self.state.lock().unwrap(); 269 let Some(stream) = state.stream.get_mut(&ret.connection_handle) else { 270 break 'event; 271 }; 272 stream.state = 273 if stream.state == StreamState::Enabling && ret.status == Status::Success { 274 StreamState::Enabled 275 } else { 276 StreamState::Disabled 277 }; 278 279 if stream.state != StreamState::Enabled { 280 break 'event; 281 } 282 283 let c_to_p = match stream.iso_type { 284 IsoType::Cis { ref c_to_p, .. } => c_to_p, 285 IsoType::Bis { ref c_to_p } => c_to_p, 286 }; 287 288 Service::start_stream( 289 ret.connection_handle, 290 StreamConfiguration { 291 isoIntervalUs: stream.iso_interval_us as i32, 292 sduIntervalUs: c_to_p.sdu_interval_us as i32, 293 maxSduSize: c_to_p.max_sdu_size as i32, 294 flushTimeout: c_to_p.flush_timeout as i32, 295 }, 296 ); 297 } 298 299 ReturnParameters::LeRemoveIsoDataPath(ref ret) if ret.status == Status::Success => 'event: { 300 let mut state = self.state.lock().unwrap(); 301 let Some(stream) = state.stream.get_mut(&ret.connection_handle) else { 302 break 'event; 303 }; 304 if stream.state == StreamState::Enabled { 305 Service::stop_stream(ret.connection_handle); 306 } 307 stream.state = StreamState::Disabled; 308 } 309 310 _ => (), 311 }, 312 313 Ok(Event::LeCisEstablished(ref e)) if e.status == Status::Success => { 314 let mut state = self.state.lock().unwrap(); 315 let mut cig_values = state.cig.values(); 316 let Some(cig) = 317 cig_values.find(|&g| g.cis.iter().any(|s| s.handle == e.connection_handle)) 318 else { 319 panic!("CIG not set-up for CIS 0x{:03x}", e.connection_handle); 320 }; 321 322 let cis = Stream::new_cis(cig, e); 323 if state.stream.insert(e.connection_handle, cis).is_some() { 324 log::error!("CIS already established"); 325 } else { 326 let arbiter = state.arbiter.as_ref().unwrap(); 327 arbiter.add_connection(e.connection_handle); 328 } 329 } 330 331 Ok(Event::DisconnectionComplete(ref e)) if e.status == Status::Success => { 332 let mut state = self.state.lock().unwrap(); 333 if state.stream.remove(&e.connection_handle).is_some() { 334 let arbiter = state.arbiter.as_ref().unwrap(); 335 arbiter.remove_connection(e.connection_handle); 336 } 337 } 338 339 Ok(Event::LeCreateBigComplete(ref e)) if e.status == Status::Success => { 340 let mut state_guard = self.state.lock().unwrap(); 341 let state = &mut *state_guard; 342 343 let big = state.big.get_mut(&e.big_handle).unwrap(); 344 big.bis_handles = e.bis_handles.clone(); 345 346 let bis = Stream::new_bis(big, e); 347 for h in &big.bis_handles { 348 if state.stream.insert(*h, bis.clone()).is_some() { 349 log::error!("BIS already established"); 350 } else { 351 let arbiter = state.arbiter.as_ref().unwrap(); 352 arbiter.add_connection(*h); 353 } 354 } 355 } 356 357 Ok(Event::LeTerminateBigComplete(ref e)) => { 358 let mut state = self.state.lock().unwrap(); 359 let big = state.big.remove(&e.big_handle).unwrap(); 360 for h in big.bis_handles { 361 state.stream.remove(&h); 362 363 let arbiter = state.arbiter.as_ref().unwrap(); 364 arbiter.remove_connection(h); 365 } 366 } 367 368 Ok(Event::NumberOfCompletedPackets(ref e)) => 'event: { 369 let state = self.state.lock().unwrap(); 370 let Some(arbiter) = state.arbiter.as_ref() else { 371 break 'event; 372 }; 373 374 let (stack_event, _) = { 375 let mut stack_event = hci::NumberOfCompletedPackets { 376 handles: Vec::with_capacity(e.handles.len()), 377 }; 378 let mut audio_event = hci::NumberOfCompletedPackets { 379 handles: Vec::with_capacity(e.handles.len()), 380 }; 381 for item in &e.handles { 382 let handle = item.connection_handle; 383 arbiter.set_completed(handle, item.num_completed_packets.into()); 384 385 if match state.stream.get(&handle) { 386 Some(stream) => stream.state == StreamState::Enabled, 387 None => false, 388 } { 389 audio_event.handles.push(*item); 390 } else { 391 stack_event.handles.push(*item); 392 } 393 } 394 (stack_event, audio_event) 395 }; 396 397 if !stack_event.handles.is_empty() { 398 self.next().in_evt(&stack_event.to_bytes()); 399 } 400 return; 401 } 402 403 Ok(..) => (), 404 405 Err(code) => { 406 log::error!("Malformed event with code: {:?}", code); 407 } 408 } 409 410 self.next().in_evt(data); 411 } 412 out_iso(&self, data: &[u8])413 fn out_iso(&self, data: &[u8]) { 414 let state = self.state.lock().unwrap(); 415 let arbiter = state.arbiter.as_ref().unwrap(); 416 arbiter.push_incoming(&IsoData::from_bytes(data).unwrap()); 417 } 418 } 419