• 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::proxy::LeAudioModule;
18 use hci::{CommandToBytes, EventToBytes, IsoData, Module, ReturnParameters, Status};
19 use std::sync::{mpsc, Arc, Mutex};
20 use std::time::Duration;
21 
22 struct ModuleSinkState {
23     out_cmd: Vec<Vec<u8>>,
24     in_evt: Vec<Vec<u8>>,
25     out_iso: mpsc::Receiver<Vec<u8>>,
26 }
27 
28 struct ModuleSink {
29     state: Mutex<ModuleSinkState>,
30     out_iso: mpsc::Sender<Vec<u8>>,
31 }
32 
33 impl ModuleSink {
new() -> Self34     fn new() -> Self {
35         let (out_iso_tx, out_iso_rx) = mpsc::channel();
36         ModuleSink {
37             state: Mutex::new(ModuleSinkState {
38                 out_cmd: Default::default(),
39                 in_evt: Default::default(),
40                 out_iso: out_iso_rx,
41             }),
42             out_iso: out_iso_tx,
43         }
44     }
45 }
46 
47 impl Module for ModuleSink {
out_cmd(&self, data: &[u8])48     fn out_cmd(&self, data: &[u8]) {
49         self.state.lock().unwrap().out_cmd.push(data.to_vec());
50     }
in_evt(&self, data: &[u8])51     fn in_evt(&self, data: &[u8]) {
52         self.state.lock().unwrap().in_evt.push(data.to_vec());
53     }
out_iso(&self, data: &[u8])54     fn out_iso(&self, data: &[u8]) {
55         self.out_iso.send(data.to_vec()).expect("Sending ISO packet");
56     }
57 
next(&self) -> &dyn Module58     fn next(&self) -> &dyn Module {
59         panic!();
60     }
61 }
62 
63 #[test]
cig()64 fn cig() {
65     let sink: Arc<ModuleSink> = Arc::new(ModuleSink::new());
66     let m = LeAudioModule::new(sink.clone());
67 
68     m.in_evt(
69         &hci::CommandComplete {
70             num_hci_command_packets: 0,
71             return_parameters: ReturnParameters::Reset(hci::ResetComplete {
72                 status: Status::Success,
73             }),
74         }
75         .to_bytes(),
76     );
77 
78     m.in_evt(
79         &hci::CommandComplete {
80             num_hci_command_packets: 0,
81             return_parameters: ReturnParameters::LeReadBufferSizeV2(
82                 hci::LeReadBufferSizeV2Complete {
83                     status: Status::Success,
84                     le_acl_data_packet_length: 0,
85                     total_num_le_acl_data_packets: 0,
86                     iso_data_packet_length: 16,
87                     total_num_iso_data_packets: 2,
88                 },
89             ),
90         }
91         .to_bytes(),
92     );
93 
94     m.out_cmd(
95         &hci::LeSetCigParameters {
96             cig_id: 0x01,
97             sdu_interval_c_to_p: 10_000,
98             sdu_interval_p_to_c: 10_000,
99             worst_case_sca: 0,
100             packing: 0,
101             framing: 0,
102             max_transport_latency_c_to_p: 0,
103             max_transport_latency_p_to_c: 0,
104             cis: vec![
105                 hci::LeCisInCigParameters {
106                     cis_id: 0,
107                     max_sdu_c_to_p: 120,
108                     max_sdu_p_to_c: 120,
109                     phy_c_to_p: 0,
110                     phy_p_to_c: 0,
111                     rtn_c_to_p: 0,
112                     rtn_p_to_c: 0,
113                 },
114                 hci::LeCisInCigParameters {
115                     cis_id: 1,
116                     max_sdu_c_to_p: 150,
117                     max_sdu_p_to_c: 150,
118                     phy_c_to_p: 0,
119                     phy_p_to_c: 0,
120                     rtn_c_to_p: 0,
121                     rtn_p_to_c: 0,
122                 },
123             ],
124         }
125         .to_bytes(),
126     );
127 
128     m.in_evt(
129         &hci::CommandComplete {
130             num_hci_command_packets: 0,
131             return_parameters: ReturnParameters::LeSetCigParameters(
132                 hci::LeSetCigParametersComplete {
133                     status: Status::Success,
134                     cig_id: 0x01,
135                     connection_handles: vec![0x123, 0x456],
136                 },
137             ),
138         }
139         .to_bytes(),
140     );
141 
142     m.in_evt(
143         &hci::LeCisEstablished {
144             status: Status::Success,
145             connection_handle: 0x456,
146             cig_sync_delay: 0,
147             cis_sync_delay: 0,
148             transport_latency_c_to_p: 0,
149             transport_latency_p_to_c: 0,
150             phy_c_to_p: 0x02,
151             phy_p_to_c: 0x02,
152             nse: 0,
153             bn_c_to_p: 2,
154             bn_p_to_c: 2,
155             ft_c_to_p: 1,
156             ft_p_to_c: 1,
157             max_pdu_c_to_p: 10,
158             max_pdu_p_to_c: 0,
159             iso_interval: 20_000 / 1250,
160         }
161         .to_bytes(),
162     );
163 
164     m.out_cmd(
165         &hci::LeSetupIsoDataPath {
166             connection_handle: 0x456,
167             data_path_direction: hci::LeDataPathDirection::Input,
168             data_path_id: 0,
169             codec_id: hci::LeCodecId {
170                 coding_format: hci::CodingFormat::Transparent,
171                 company_id: 0,
172                 vendor_id: 0,
173             },
174             controller_delay: 0,
175             codec_configuration: vec![],
176         }
177         .to_bytes(),
178     );
179 
180     m.in_evt(
181         &hci::CommandComplete {
182             num_hci_command_packets: 0,
183             return_parameters: ReturnParameters::LeSetupIsoDataPath(hci::LeIsoDataPathComplete {
184                 status: Status::Success,
185                 connection_handle: 0x456,
186             }),
187         }
188         .to_bytes(),
189     );
190 
191     m.out_iso(&IsoData::new(0x456, 0, &[0x00, 0x11]).to_bytes());
192     m.out_iso(&IsoData::new(0x456, 1, &[]).to_bytes());
193     {
194         let state = sink.state.lock().unwrap();
195         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
196         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
197     }
198 
199     m.in_evt(
200         &hci::NumberOfCompletedPackets {
201             handles: vec![hci::NumberOfCompletedPacketsHandle {
202                 connection_handle: 0x456,
203                 num_completed_packets: 1,
204             }],
205         }
206         .to_bytes(),
207     );
208 
209     m.out_iso(&IsoData::new(0x456, 2, &[0x22]).to_bytes());
210     {
211         let state = sink.state.lock().unwrap();
212         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
213     }
214 
215     m.in_evt(
216         &hci::LeCisEstablished {
217             status: Status::Success,
218             connection_handle: 0x123,
219             cig_sync_delay: 0,
220             cis_sync_delay: 0,
221             transport_latency_c_to_p: 0,
222             transport_latency_p_to_c: 0,
223             phy_c_to_p: 0x02,
224             phy_p_to_c: 0x02,
225             nse: 0,
226             bn_c_to_p: 2,
227             bn_p_to_c: 2,
228             ft_c_to_p: 1,
229             ft_p_to_c: 1,
230             max_pdu_c_to_p: 10,
231             max_pdu_p_to_c: 0,
232             iso_interval: 20_000 / 1250,
233         }
234         .to_bytes(),
235     );
236 
237     m.in_evt(
238         &hci::NumberOfCompletedPackets {
239             handles: vec![hci::NumberOfCompletedPacketsHandle {
240                 connection_handle: 0x456,
241                 num_completed_packets: 1,
242             }],
243         }
244         .to_bytes(),
245     );
246 
247     m.out_iso(&IsoData::new(0x123, 0, &[]).to_bytes());
248     {
249         let state = sink.state.lock().unwrap();
250         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
251     }
252 
253     m.in_evt(
254         &hci::DisconnectionComplete {
255             status: Status::Success,
256             connection_handle: 0x456,
257             reason: 0,
258         }
259         .to_bytes(),
260     );
261 
262     m.out_iso(&IsoData::new(0x456, 3, &[0x33]).to_bytes());
263     m.out_iso(&IsoData::new(0x123, 1, &[0x11, 0x22]).to_bytes());
264     {
265         let state = sink.state.lock().unwrap();
266         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
267     }
268 
269     {
270         let state = sink.state.lock().unwrap();
271         assert_eq!(state.out_cmd.len(), 2);
272         assert_eq!(state.in_evt.len(), 9);
273     }
274 }
275 
276 #[test]
big()277 fn big() {
278     let sink: Arc<ModuleSink> = Arc::new(ModuleSink::new());
279     let m = LeAudioModule::new(sink.clone());
280 
281     m.in_evt(
282         &hci::CommandComplete {
283             num_hci_command_packets: 0,
284             return_parameters: ReturnParameters::Reset(hci::ResetComplete {
285                 status: Status::Success,
286             }),
287         }
288         .to_bytes(),
289     );
290 
291     m.in_evt(
292         &hci::CommandComplete {
293             num_hci_command_packets: 0,
294             return_parameters: ReturnParameters::LeReadBufferSizeV2(
295                 hci::LeReadBufferSizeV2Complete {
296                     status: Status::Success,
297                     le_acl_data_packet_length: 0,
298                     total_num_le_acl_data_packets: 0,
299                     iso_data_packet_length: 16,
300                     total_num_iso_data_packets: 2,
301                 },
302             ),
303         }
304         .to_bytes(),
305     );
306 
307     m.out_cmd(
308         &hci::LeCreateBig {
309             big_handle: 0x10,
310             advertising_handle: 0,
311             num_bis: 2,
312             sdu_interval: 10_000,
313             max_sdu: 120,
314             max_transport_latency: 0,
315             rtn: 5,
316             phy: 0x02,
317             packing: 0,
318             framing: 0,
319             encryption: 0,
320             broadcast_code: [0u8; 16],
321         }
322         .to_bytes(),
323     );
324 
325     m.in_evt(
326         &hci::LeCreateBigComplete {
327             status: Status::Success,
328             big_handle: 0x10,
329             big_sync_delay: 0,
330             big_transport_latency: 0,
331             phy: 0x02,
332             nse: 0,
333             bn: 2,
334             pto: 0,
335             irc: 0,
336             max_pdu: 10,
337             iso_interval: 20_000 / 1250,
338             bis_handles: vec![0x123, 0x456],
339         }
340         .to_bytes(),
341     );
342 
343     m.out_cmd(
344         &hci::LeSetupIsoDataPath {
345             connection_handle: 0x123,
346             data_path_direction: hci::LeDataPathDirection::Input,
347             data_path_id: 0,
348             codec_id: hci::LeCodecId {
349                 coding_format: hci::CodingFormat::Transparent,
350                 company_id: 0,
351                 vendor_id: 0,
352             },
353             controller_delay: 0,
354             codec_configuration: vec![],
355         }
356         .to_bytes(),
357     );
358 
359     m.in_evt(
360         &hci::CommandComplete {
361             num_hci_command_packets: 0,
362             return_parameters: ReturnParameters::LeSetupIsoDataPath(hci::LeIsoDataPathComplete {
363                 status: Status::Success,
364                 connection_handle: 0x123,
365             }),
366         }
367         .to_bytes(),
368     );
369 
370     m.out_cmd(
371         &hci::LeSetupIsoDataPath {
372             connection_handle: 0x456,
373             data_path_direction: hci::LeDataPathDirection::Input,
374             data_path_id: 0,
375             codec_id: hci::LeCodecId {
376                 coding_format: hci::CodingFormat::Transparent,
377                 company_id: 0,
378                 vendor_id: 0,
379             },
380             controller_delay: 0,
381             codec_configuration: vec![],
382         }
383         .to_bytes(),
384     );
385 
386     m.in_evt(
387         &hci::CommandComplete {
388             num_hci_command_packets: 0,
389             return_parameters: ReturnParameters::LeSetupIsoDataPath(hci::LeIsoDataPathComplete {
390                 status: Status::Success,
391                 connection_handle: 0x456,
392             }),
393         }
394         .to_bytes(),
395     );
396 
397     m.out_iso(&IsoData::new(0x456, 0, &[0x00, 0x11]).to_bytes());
398     m.out_iso(&IsoData::new(0x456, 1, &[]).to_bytes());
399     {
400         let state = sink.state.lock().unwrap();
401         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
402         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
403     }
404 
405     m.in_evt(
406         &hci::NumberOfCompletedPackets {
407             handles: vec![hci::NumberOfCompletedPacketsHandle {
408                 connection_handle: 0x456,
409                 num_completed_packets: 2,
410             }],
411         }
412         .to_bytes(),
413     );
414 
415     m.out_iso(&IsoData::new(0x123, 0, &[0x22, 0x33]).to_bytes());
416     m.out_iso(&IsoData::new(0x456, 2, &[]).to_bytes());
417     {
418         let state = sink.state.lock().unwrap();
419         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
420         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
421     }
422 
423     m.in_evt(
424         &hci::NumberOfCompletedPackets {
425             handles: vec![
426                 hci::NumberOfCompletedPacketsHandle {
427                     connection_handle: 0x456,
428                     num_completed_packets: 1,
429                 },
430                 hci::NumberOfCompletedPacketsHandle {
431                     connection_handle: 0x123,
432                     num_completed_packets: 1,
433                 },
434             ],
435         }
436         .to_bytes(),
437     );
438 
439     m.out_iso(&IsoData::new(0x123, 1, &[0x44]).to_bytes());
440     m.out_iso(&IsoData::new(0x123, 2, &[0x55, 0x66]).to_bytes());
441     {
442         let state = sink.state.lock().unwrap();
443         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
444         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
445     }
446 
447     m.in_evt(
448         &hci::NumberOfCompletedPackets {
449             handles: vec![hci::NumberOfCompletedPacketsHandle {
450                 connection_handle: 0x123,
451                 num_completed_packets: 2,
452             }],
453         }
454         .to_bytes(),
455     );
456 
457     m.out_iso(&IsoData::new(0x123, 3, &[]).to_bytes());
458     m.out_iso(&IsoData::new(0x123, 4, &[]).to_bytes());
459     {
460         let state = sink.state.lock().unwrap();
461         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
462         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
463     }
464 
465     {
466         let state = sink.state.lock().unwrap();
467         assert_eq!(state.out_cmd.len(), 3);
468         assert_eq!(state.in_evt.len(), 8);
469     }
470 }
471 
472 #[test]
merge()473 fn merge() {
474     let sink: Arc<ModuleSink> = Arc::new(ModuleSink::new());
475     let m = LeAudioModule::new(sink.clone());
476 
477     m.in_evt(
478         &hci::CommandComplete {
479             num_hci_command_packets: 0,
480             return_parameters: ReturnParameters::Reset(hci::ResetComplete {
481                 status: Status::Success,
482             }),
483         }
484         .to_bytes(),
485     );
486 
487     m.in_evt(
488         &hci::CommandComplete {
489             num_hci_command_packets: 0,
490             return_parameters: ReturnParameters::LeReadBufferSizeV2(
491                 hci::LeReadBufferSizeV2Complete {
492                     status: Status::Success,
493                     le_acl_data_packet_length: 0,
494                     total_num_le_acl_data_packets: 0,
495                     iso_data_packet_length: 16,
496                     total_num_iso_data_packets: 2,
497                 },
498             ),
499         }
500         .to_bytes(),
501     );
502 
503     m.out_cmd(
504         &hci::LeSetCigParameters {
505             cig_id: 0x01,
506             sdu_interval_c_to_p: 10_000,
507             sdu_interval_p_to_c: 10_000,
508             worst_case_sca: 0,
509             packing: 0,
510             framing: 0,
511             max_transport_latency_c_to_p: 0,
512             max_transport_latency_p_to_c: 0,
513             cis: vec![
514                 hci::LeCisInCigParameters {
515                     cis_id: 0,
516                     max_sdu_c_to_p: 120,
517                     max_sdu_p_to_c: 120,
518                     phy_c_to_p: 0,
519                     phy_p_to_c: 0,
520                     rtn_c_to_p: 0,
521                     rtn_p_to_c: 0,
522                 },
523                 hci::LeCisInCigParameters {
524                     cis_id: 1,
525                     max_sdu_c_to_p: 150,
526                     max_sdu_p_to_c: 150,
527                     phy_c_to_p: 0,
528                     phy_p_to_c: 0,
529                     rtn_c_to_p: 0,
530                     rtn_p_to_c: 0,
531                 },
532             ],
533         }
534         .to_bytes(),
535     );
536 
537     m.in_evt(
538         &hci::CommandComplete {
539             num_hci_command_packets: 0,
540             return_parameters: ReturnParameters::LeSetCigParameters(
541                 hci::LeSetCigParametersComplete {
542                     status: Status::Success,
543                     cig_id: 0x01,
544                     connection_handles: vec![0x123, 0x456],
545                 },
546             ),
547         }
548         .to_bytes(),
549     );
550 
551     // Establish CIS 0x123, using Software Offload path
552     // Establish CIS 0x456, using HCI (stack) path
553 
554     m.in_evt(
555         &hci::LeCisEstablished {
556             status: Status::Success,
557             connection_handle: 0x123,
558             cig_sync_delay: 0,
559             cis_sync_delay: 0,
560             transport_latency_c_to_p: 0,
561             transport_latency_p_to_c: 0,
562             phy_c_to_p: 0x02,
563             phy_p_to_c: 0x02,
564             nse: 0,
565             bn_c_to_p: 2,
566             bn_p_to_c: 2,
567             ft_c_to_p: 1,
568             ft_p_to_c: 1,
569             max_pdu_c_to_p: 10,
570             max_pdu_p_to_c: 0,
571             iso_interval: 20_000 / 1250,
572         }
573         .to_bytes(),
574     );
575 
576     m.in_evt(
577         &hci::LeCisEstablished {
578             status: Status::Success,
579             connection_handle: 0x456,
580             cig_sync_delay: 0,
581             cis_sync_delay: 0,
582             transport_latency_c_to_p: 0,
583             transport_latency_p_to_c: 0,
584             phy_c_to_p: 0x02,
585             phy_p_to_c: 0x02,
586             nse: 0,
587             bn_c_to_p: 2,
588             bn_p_to_c: 2,
589             ft_c_to_p: 1,
590             ft_p_to_c: 1,
591             max_pdu_c_to_p: 10,
592             max_pdu_p_to_c: 0,
593             iso_interval: 20_000 / 1250,
594         }
595         .to_bytes(),
596     );
597 
598     m.out_cmd(
599         &hci::LeSetupIsoDataPath {
600             connection_handle: 0x123,
601             data_path_direction: hci::LeDataPathDirection::Input,
602             data_path_id: 0x19,
603             codec_id: hci::LeCodecId {
604                 coding_format: hci::CodingFormat::Transparent,
605                 company_id: 0,
606                 vendor_id: 0,
607             },
608             controller_delay: 0,
609             codec_configuration: vec![],
610         }
611         .to_bytes(),
612     );
613 
614     m.in_evt(
615         &hci::CommandComplete {
616             num_hci_command_packets: 0,
617             return_parameters: ReturnParameters::LeSetupIsoDataPath(hci::LeIsoDataPathComplete {
618                 status: Status::Success,
619                 connection_handle: 0x123,
620             }),
621         }
622         .to_bytes(),
623     );
624 
625     m.out_cmd(
626         &hci::LeSetupIsoDataPath {
627             connection_handle: 0x456,
628             data_path_direction: hci::LeDataPathDirection::Input,
629             data_path_id: 0,
630             codec_id: hci::LeCodecId {
631                 coding_format: hci::CodingFormat::Transparent,
632                 company_id: 0,
633                 vendor_id: 0,
634             },
635             controller_delay: 0,
636             codec_configuration: vec![],
637         }
638         .to_bytes(),
639     );
640 
641     m.in_evt(
642         &hci::CommandComplete {
643             num_hci_command_packets: 0,
644             return_parameters: ReturnParameters::LeSetupIsoDataPath(hci::LeIsoDataPathComplete {
645                 status: Status::Success,
646                 connection_handle: 0x456,
647             }),
648         }
649         .to_bytes(),
650     );
651 
652     {
653         let mut state = sink.state.lock().unwrap();
654         assert_eq!(state.out_cmd.len(), 3);
655         assert_eq!(state.in_evt.len(), 7);
656         state.out_cmd.clear();
657         state.in_evt.clear();
658     }
659 
660     // Send 2 Packets on 0x123
661     // -> The packets are sent to the controller, and fulfill the FIFO
662 
663     m.arbiter().unwrap().push_audio(&IsoData::new(0x123, 1, &[0x44]));
664     m.arbiter().unwrap().push_audio(&IsoData::new(0x123, 2, &[0x55, 0x66]));
665     {
666         let state = sink.state.lock().unwrap();
667         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
668         state.out_iso.recv_timeout(Duration::from_millis(100)).expect("Receiving ISO Packet");
669     }
670 
671     // Send 2 packets on 0x456
672     // -> The packets are buffered, the controller FIFO is full
673 
674     m.out_iso(&IsoData::new(0x456, 1, &[0x11]).to_bytes());
675     m.out_iso(&IsoData::new(0x456, 2, &[0x22, 0x33]).to_bytes());
676     {
677         let state = sink.state.lock().unwrap();
678         assert_eq!(
679             state.out_iso.recv_timeout(Duration::from_millis(100)),
680             Err(mpsc::RecvTimeoutError::Timeout),
681         );
682     }
683 
684     // Acknowledge packet 1 on 0x123:
685     // -> The acknowledgment is filtered
686     // -> Packet 1 on 0x456 is tranmitted
687 
688     m.in_evt(
689         &hci::NumberOfCompletedPackets {
690             handles: vec![hci::NumberOfCompletedPacketsHandle {
691                 connection_handle: 0x123,
692                 num_completed_packets: 1,
693             }],
694         }
695         .to_bytes(),
696     );
697 
698     {
699         let mut state = sink.state.lock().unwrap();
700         assert_eq!(state.in_evt.pop(), None);
701         assert_eq!(
702             state.out_iso.recv_timeout(Duration::from_millis(100)),
703             Ok(IsoData::new(0x456, 1, &[0x11]).to_bytes())
704         );
705         assert_eq!(
706             state.out_iso.recv_timeout(Duration::from_millis(100)),
707             Err(mpsc::RecvTimeoutError::Timeout),
708         );
709     }
710 
711     // Link 0x123 disconnect (implicitly ack packet 2 on 0x123)
712     // -> Packet 2 on 0x456 is tranmitted
713 
714     m.in_evt(
715         &hci::DisconnectionComplete {
716             status: Status::Success,
717             connection_handle: 0x123,
718             reason: 0,
719         }
720         .to_bytes(),
721     );
722 
723     {
724         let state = sink.state.lock().unwrap();
725         assert_eq!(
726             state.out_iso.recv_timeout(Duration::from_millis(100)),
727             Ok(IsoData::new(0x456, 2, &[0x22, 0x33]).to_bytes())
728         );
729     }
730 
731     // Send packets and ack packets 1 and 2 on 0x456.
732     // -> Connection 0x123 is disconnected, ignored
733     // -> Packets 3, and 4 on 0x456 are sent
734     // -> Packet 5 on 0x456 is buffered
735 
736     m.out_iso(&IsoData::new(0x456, 3, &[0x33]).to_bytes());
737     m.arbiter().unwrap().push_audio(&IsoData::new(0x123, 3, &[0x33]));
738     m.arbiter().unwrap().push_audio(&IsoData::new(0x123, 4, &[0x44, 0x55]));
739     m.out_iso(&IsoData::new(0x456, 4, &[0x44, 0x55]).to_bytes());
740     m.out_iso(&IsoData::new(0x456, 5, &[0x55, 0x66]).to_bytes());
741     {
742         let state = sink.state.lock().unwrap();
743         assert_eq!(
744             state.out_iso.recv_timeout(Duration::from_millis(100)),
745             Err(mpsc::RecvTimeoutError::Timeout),
746         );
747     }
748 
749     m.in_evt(
750         &hci::NumberOfCompletedPackets {
751             handles: vec![hci::NumberOfCompletedPacketsHandle {
752                 connection_handle: 0x456,
753                 num_completed_packets: 2,
754             }],
755         }
756         .to_bytes(),
757     );
758 
759     {
760         let mut state = sink.state.lock().unwrap();
761         assert_eq!(
762             state.in_evt.pop(),
763             Some(
764                 hci::NumberOfCompletedPackets {
765                     handles: vec![hci::NumberOfCompletedPacketsHandle {
766                         connection_handle: 0x456,
767                         num_completed_packets: 2,
768                     }],
769                 }
770                 .to_bytes(),
771             )
772         );
773         assert_eq!(state.in_evt.len(), 1);
774         assert_eq!(
775             state.out_iso.recv_timeout(Duration::from_millis(100)),
776             Ok(IsoData::new(0x456, 3, &[0x33]).to_bytes())
777         );
778         assert_eq!(
779             state.out_iso.recv_timeout(Duration::from_millis(100)),
780             Ok(IsoData::new(0x456, 4, &[0x44, 0x55]).to_bytes())
781         );
782         state.in_evt.clear();
783     }
784 
785     // Re-establish CIS 0x123, using Software Offload path
786 
787     m.in_evt(
788         &hci::LeCisEstablished {
789             status: Status::Success,
790             connection_handle: 0x123,
791             cig_sync_delay: 0,
792             cis_sync_delay: 0,
793             transport_latency_c_to_p: 0,
794             transport_latency_p_to_c: 0,
795             phy_c_to_p: 0x02,
796             phy_p_to_c: 0x02,
797             nse: 0,
798             bn_c_to_p: 2,
799             bn_p_to_c: 2,
800             ft_c_to_p: 1,
801             ft_p_to_c: 1,
802             max_pdu_c_to_p: 10,
803             max_pdu_p_to_c: 0,
804             iso_interval: 20_000 / 1250,
805         }
806         .to_bytes(),
807     );
808 
809     m.out_cmd(
810         &hci::LeSetupIsoDataPath {
811             connection_handle: 0x123,
812             data_path_direction: hci::LeDataPathDirection::Input,
813             data_path_id: 0x19,
814             codec_id: hci::LeCodecId {
815                 coding_format: hci::CodingFormat::Transparent,
816                 company_id: 0,
817                 vendor_id: 0,
818             },
819             controller_delay: 0,
820             codec_configuration: vec![],
821         }
822         .to_bytes(),
823     );
824 
825     m.in_evt(
826         &hci::CommandComplete {
827             num_hci_command_packets: 0,
828             return_parameters: ReturnParameters::LeSetupIsoDataPath(hci::LeIsoDataPathComplete {
829                 status: Status::Success,
830                 connection_handle: 0x123,
831             }),
832         }
833         .to_bytes(),
834     );
835 
836     // Acknowledge packets 3 and 4 on 0x456
837     // -> Packet 5 on 0x456 is sent
838 
839     m.in_evt(
840         &hci::NumberOfCompletedPackets {
841             handles: vec![hci::NumberOfCompletedPacketsHandle {
842                 connection_handle: 0x456,
843                 num_completed_packets: 2,
844             }],
845         }
846         .to_bytes(),
847     );
848 
849     {
850         let mut state = sink.state.lock().unwrap();
851         assert_eq!(
852             state.in_evt.pop(),
853             Some(
854                 hci::NumberOfCompletedPackets {
855                     handles: vec![hci::NumberOfCompletedPacketsHandle {
856                         connection_handle: 0x456,
857                         num_completed_packets: 2,
858                     }],
859                 }
860                 .to_bytes(),
861             )
862         );
863         assert_eq!(
864             state.out_iso.recv_timeout(Duration::from_millis(100)),
865             Ok(IsoData::new(0x456, 5, &[0x55, 0x66]).to_bytes())
866         );
867         assert_eq!(
868             state.out_iso.recv_timeout(Duration::from_millis(100)),
869             Err(mpsc::RecvTimeoutError::Timeout),
870         );
871         state.out_cmd.clear();
872         state.in_evt.clear();
873     }
874 
875     // Acknowledge packet 5 on 0x456
876     // -> Controller FIFO is now empty
877 
878     m.in_evt(
879         &hci::NumberOfCompletedPackets {
880             handles: vec![hci::NumberOfCompletedPacketsHandle {
881                 connection_handle: 0x456,
882                 num_completed_packets: 1,
883             }],
884         }
885         .to_bytes(),
886     );
887 
888     {
889         let mut state = sink.state.lock().unwrap();
890         assert_eq!(
891             state.in_evt.pop(),
892             Some(
893                 hci::NumberOfCompletedPackets {
894                     handles: vec![hci::NumberOfCompletedPacketsHandle {
895                         connection_handle: 0x456,
896                         num_completed_packets: 1,
897                     }],
898                 }
899                 .to_bytes(),
900             )
901         );
902     }
903 
904     // Send 1 packet on each CIS, and acknowledge them
905     // -> The CIS 0x123 is removed from "NumberOfCompletedPackets" event
906 
907     m.out_iso(&IsoData::new(0x123, 0, &[]).to_bytes());
908     m.arbiter().unwrap().push_audio(&IsoData::new(0x456, 6, &[0x66, 0x77]));
909 
910     {
911         let state = sink.state.lock().unwrap();
912         for _ in 0..2 {
913             let pkt = state.out_iso.recv_timeout(Duration::from_millis(100));
914             assert!(
915                 pkt == Ok(IsoData::new(0x123, 0, &[]).to_bytes())
916                     || pkt == Ok(IsoData::new(0x456, 6, &[0x66, 0x77]).to_bytes())
917             );
918         }
919     }
920 
921     m.in_evt(
922         &hci::NumberOfCompletedPackets {
923             handles: vec![
924                 hci::NumberOfCompletedPacketsHandle {
925                     connection_handle: 0x456,
926                     num_completed_packets: 1,
927                 },
928                 hci::NumberOfCompletedPacketsHandle {
929                     connection_handle: 0x123,
930                     num_completed_packets: 1,
931                 },
932             ],
933         }
934         .to_bytes(),
935     );
936 
937     {
938         let mut state = sink.state.lock().unwrap();
939         assert_eq!(
940             state.in_evt.pop(),
941             Some(
942                 hci::NumberOfCompletedPackets {
943                     handles: vec![hci::NumberOfCompletedPacketsHandle {
944                         connection_handle: 0x456,
945                         num_completed_packets: 1,
946                     }],
947                 }
948                 .to_bytes(),
949             )
950         );
951     }
952 }
953