• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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