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