1use fidl_fuchsia_bluetooth_bredr::AudioOffloadExtProxy;
6use fuchsia_async::{DurationExt, Task, TimeoutExt};
7use fuchsia_bluetooth::types::{A2dpDirection, Channel};
8use fuchsia_sync::{Mutex, RwLock};
9use futures::stream::{FusedStream, Stream};
10use futures::{FutureExt, Sink};
11use log::warn;
12use std::pin::Pin;
13use std::sync::{Arc, Weak};
14use std::task::{Context, Poll};
15use std::{fmt, io};
16use zx::{MonotonicDuration, Status};
17
18use crate::types::{
19 EndpointType, Error, ErrorCode, MediaCodecType, MediaType, Result as AvdtpResult,
20 ServiceCapability, ServiceCategory, StreamEndpointId, StreamInformation,
21};
22use crate::{Peer, SimpleResponder};
23
24pub type StreamEndpointUpdateCallback = Box<dyn Fn(&StreamEndpoint) -> () + Sync + Send>;
25
26#[derive(PartialEq, Debug, Default, Clone, Copy)]
28pub enum StreamState {
29 #[default]
30 Idle,
31 Configured,
32 Opening,
34 Open,
35 Streaming,
36 Closing,
37 Aborting,
38}
39
40pub struct StreamEndpoint {
45 id: StreamEndpointId,
47 endpoint_type: EndpointType,
49 media_type: MediaType,
51 state: Arc<Mutex<StreamState>>,
53 transport: Option<Arc<RwLock<Channel>>>,
56 stream_held: Arc<Mutex<bool>>,
59 capabilities: Vec<ServiceCapability>,
61 remote_id: Option<StreamEndpointId>,
63 configuration: Vec<ServiceCapability>,
65 update_callback: Option<StreamEndpointUpdateCallback>,
67 in_progress: Option<Task<()>>,
70}
71
72impl fmt::Debug for StreamEndpoint {
73 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74 f.debug_struct("StreamEndpoint")
75 .field("id", &self.id.0)
76 .field("endpoint_type", &self.endpoint_type)
77 .field("media_type", &self.media_type)
78 .field("state", &self.state)
79 .field("capabilities", &self.capabilities)
80 .field("remote_id", &self.remote_id.as_ref().map(|id| id.to_string()))
81 .field("configuration", &self.configuration)
82 .finish()
83 }
84}
85
86impl StreamEndpoint {
87 pub fn new(
91 id: u8,
92 media_type: MediaType,
93 endpoint_type: EndpointType,
94 capabilities: Vec<ServiceCapability>,
95 ) -> AvdtpResult<StreamEndpoint> {
96 let seid = StreamEndpointId::try_from(id)?;
97 Ok(StreamEndpoint {
98 id: seid,
99 capabilities,
100 media_type,
101 endpoint_type,
102 state: Default::default(),
103 transport: None,
104 stream_held: Arc::new(Mutex::new(false)),
105 remote_id: None,
106 configuration: vec![],
107 update_callback: None,
108 in_progress: None,
109 })
110 }
111
112 pub fn as_new(&self) -> Self {
113 StreamEndpoint::new(
114 self.id.0,
115 self.media_type.clone(),
116 self.endpoint_type.clone(),
117 self.capabilities.clone(),
118 )
119 .expect("as_new")
120 }
121
122 fn set_state(&mut self, state: StreamState) {
124 *self.state.lock() = state;
125 self.update_callback();
126 }
127
128 pub fn set_update_callback(&mut self, callback: Option<StreamEndpointUpdateCallback>) {
131 self.update_callback = callback;
132 }
133
134 fn update_callback(&self) {
135 if let Some(cb) = self.update_callback.as_ref() {
136 cb(self);
137 }
138 }
139
140 pub fn from_info(
144 info: &StreamInformation,
145 capabilities: Vec<ServiceCapability>,
146 ) -> StreamEndpoint {
147 StreamEndpoint {
148 id: info.id().clone(),
149 capabilities,
150 media_type: info.media_type().clone(),
151 endpoint_type: info.endpoint_type().clone(),
152 state: Default::default(),
153 transport: None,
154 stream_held: Arc::new(Mutex::new(false)),
155 remote_id: None,
156 configuration: vec![],
157 update_callback: None,
158 in_progress: None,
159 }
160 }
161
162 fn state_is(&self, state: StreamState) -> Result<(), ErrorCode> {
165 (*self.state.lock() == state).then_some(()).ok_or(ErrorCode::BadState)
166 }
167
168 pub fn configure(
172 &mut self,
173 remote_id: &StreamEndpointId,
174 capabilities: Vec<ServiceCapability>,
175 ) -> Result<(), (ServiceCategory, ErrorCode)> {
176 self.state_is(StreamState::Idle)
177 .map_err(|_| (ServiceCategory::None, ErrorCode::SepInUse))?;
178 self.remote_id = Some(remote_id.clone());
179 for cap in &capabilities {
180 if !self
181 .capabilities
182 .iter()
183 .any(|y| std::mem::discriminant(cap) == std::mem::discriminant(y))
184 {
185 return Err((cap.category(), ErrorCode::UnsupportedConfiguration));
186 }
187 }
188 self.configuration = capabilities;
189 self.set_state(StreamState::Configured);
190 Ok(())
191 }
192
193 pub fn reconfigure(
198 &mut self,
199 mut capabilities: Vec<ServiceCapability>,
200 ) -> Result<(), (ServiceCategory, ErrorCode)> {
201 self.state_is(StreamState::Open).map_err(|e| (ServiceCategory::None, e))?;
202 if let Some(cap) = capabilities.iter().find(|x| !x.is_application()) {
204 return Err((cap.category(), ErrorCode::InvalidCapabilities));
205 }
206 let to_replace: std::vec::Vec<_> =
208 capabilities.iter().map(|x| std::mem::discriminant(x)).collect();
209 self.configuration.retain(|x| {
210 let disc = std::mem::discriminant(x);
211 !to_replace.contains(&disc)
212 });
213 self.configuration.append(&mut capabilities);
214 self.update_callback();
215 Ok(())
216 }
217
218 pub fn get_configuration(&self) -> Option<&Vec<ServiceCapability>> {
222 if self.configuration.is_empty() {
223 return None;
224 }
225 Some(&self.configuration)
226 }
227
228 const SRC_FLUSH_TIMEOUT: MonotonicDuration = MonotonicDuration::from_millis(100);
231
232 pub fn receive_channel(&mut self, c: Channel) -> AvdtpResult<bool> {
239 if self.state_is(StreamState::Opening).is_err() || self.transport.is_some() {
240 return Err(Error::InvalidState);
241 }
242 self.transport = Some(Arc::new(RwLock::new(c)));
243 self.try_flush_timeout(Self::SRC_FLUSH_TIMEOUT);
244 self.stream_held = Arc::new(Mutex::new(false));
245 self.set_state(StreamState::Open);
247 Ok(false)
248 }
249
250 pub fn establish(&mut self) -> Result<(), ErrorCode> {
253 if self.state_is(StreamState::Configured).is_err() || self.transport.is_some() {
254 return Err(ErrorCode::BadState);
255 }
256 self.set_state(StreamState::Opening);
257 Ok(())
258 }
259
260 pub fn try_priority(&self, active: bool) {
264 let priority = match (active, &self.endpoint_type) {
265 (false, _) => A2dpDirection::Normal,
266 (true, EndpointType::Source) => A2dpDirection::Source,
267 (true, EndpointType::Sink) => A2dpDirection::Sink,
268 };
269 let fut = match self.transport.as_ref().unwrap().try_read() {
270 None => return,
271 Some(channel) => channel.set_audio_priority(priority).map(|_| ()),
272 };
273 Task::spawn(fut).detach();
275 }
276
277 pub fn try_flush_timeout(&self, timeout: MonotonicDuration) {
279 if self.endpoint_type != EndpointType::Source {
280 return;
281 }
282 let fut = match self.transport.as_ref().unwrap().try_write() {
283 None => return,
284 Some(channel) => channel.set_flush_timeout(Some(timeout)).map(|_| ()),
285 };
286 Task::spawn(fut).detach();
288 }
289
290 pub fn release(&mut self, responder: SimpleResponder, peer: &Peer) -> AvdtpResult<()> {
294 {
295 let lock = self.state.lock();
296 if *lock != StreamState::Open && *lock != StreamState::Streaming {
297 return responder.reject(ErrorCode::BadState);
298 }
299 }
300 self.set_state(StreamState::Closing);
301 responder.send()?;
302 let release_wait_fut = {
303 let seid = self.remote_id.take().unwrap();
306 let transport = self.transport.take().unwrap();
307 let peer = peer.clone();
308 let state = self.state.clone();
309 async move {
310 let closed_fut = {
311 let Some(channel) = transport.try_read() else {
312 warn!("unable to lock transport channel, dropping and assuming closed");
313 *state.lock() = StreamState::Idle;
314 return;
315 };
316 channel.closed()
317 };
318
319 let closed_fut = closed_fut
320 .on_timeout(MonotonicDuration::from_seconds(3).after_now(), || {
321 Err(Status::TIMED_OUT)
322 });
323
324 if let Err(Status::TIMED_OUT) = closed_fut.await {
325 let _ = peer.abort(&seid).await;
326 *state.lock() = StreamState::Aborting;
327 }
328 drop(transport);
330 *state.lock() = StreamState::Idle;
331 }
332 };
333 self.in_progress = Some(Task::local(release_wait_fut));
334 self.configuration.clear();
337 self.update_callback();
338 Ok(())
339 }
340
341 pub fn state(&self) -> StreamState {
343 *self.state.lock()
344 }
345
346 pub fn start(&mut self) -> Result<(), ErrorCode> {
349 self.state_is(StreamState::Open)?;
350 self.try_priority(true);
351 self.set_state(StreamState::Streaming);
352 Ok(())
353 }
354
355 pub fn suspend(&mut self) -> Result<(), ErrorCode> {
358 self.state_is(StreamState::Streaming)?;
359 self.set_state(StreamState::Open);
360 self.try_priority(false);
361 Ok(())
362 }
363
364 pub async fn initiate_abort<'a>(&'a mut self, peer: &'a Peer) {
368 if let Some(seid) = self.remote_id.take() {
369 let _ = peer.abort(&seid).await;
370 self.set_state(StreamState::Aborting);
371 }
372 self.abort()
373 }
374
375 pub fn abort(&mut self) {
378 self.set_state(StreamState::Aborting);
379 self.configuration.clear();
380 self.remote_id = None;
381 self.transport = None;
382 self.set_state(StreamState::Idle);
383 }
384
385 pub fn capabilities(&self) -> &Vec<ServiceCapability> {
389 &self.capabilities
390 }
391
392 pub fn codec_type(&self) -> Option<&MediaCodecType> {
396 self.capabilities.iter().find_map(|cap| match cap {
397 ServiceCapability::MediaCodec { codec_type, .. } => Some(codec_type),
398 _ => None,
399 })
400 }
401
402 pub fn local_id(&self) -> &StreamEndpointId {
404 &self.id
405 }
406
407 pub fn remote_id(&self) -> Option<&StreamEndpointId> {
409 self.remote_id.as_ref()
410 }
411
412 pub fn endpoint_type(&self) -> &EndpointType {
414 &self.endpoint_type
415 }
416
417 pub fn information(&self) -> StreamInformation {
419 let in_use = self.state_is(StreamState::Idle).is_err();
420 StreamInformation::new(
421 self.id.clone(),
422 in_use,
423 self.media_type.clone(),
424 self.endpoint_type.clone(),
425 )
426 }
427
428 pub fn take_transport(&mut self) -> Option<MediaStream> {
432 let mut stream_held = self.stream_held.lock();
433 if *stream_held || self.transport.is_none() {
434 return None;
435 }
436
437 *stream_held = true;
438
439 Some(MediaStream::new(
440 self.stream_held.clone(),
441 Arc::downgrade(self.transport.as_ref().unwrap()),
442 ))
443 }
444
445 pub fn audio_offload(&self) -> Option<AudioOffloadExtProxy> {
447 self.transport.as_ref().and_then(|c| c.read().audio_offload())
448 }
449}
450
451pub struct MediaStream {
455 in_use: Arc<Mutex<bool>>,
456 channel: Weak<RwLock<Channel>>,
457 terminated: bool,
458}
459
460impl MediaStream {
461 pub fn new(in_use: Arc<Mutex<bool>>, channel: Weak<RwLock<Channel>>) -> Self {
462 Self { in_use, channel, terminated: false }
463 }
464
465 fn try_upgrade(&self) -> Result<Arc<RwLock<Channel>>, io::Error> {
466 self.channel
467 .upgrade()
468 .ok_or_else(|| io::Error::new(io::ErrorKind::ConnectionAborted, "lost connection"))
469 }
470
471 pub fn max_tx_size(&self) -> Result<usize, io::Error> {
472 match self.try_upgrade()?.try_read() {
473 None => return Err(io::Error::new(io::ErrorKind::WouldBlock, "couldn't lock")),
474 Some(lock) => Ok(lock.max_tx_size()),
475 }
476 }
477}
478
479impl Drop for MediaStream {
480 fn drop(&mut self) {
481 let mut l = self.in_use.lock();
482 *l = false;
483 }
484}
485
486impl Stream for MediaStream {
487 type Item = AvdtpResult<Vec<u8>>;
488
489 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
490 let Ok(arc_chan) = self.try_upgrade() else {
491 self.terminated = true;
492 return Poll::Ready(None);
493 };
494 let Some(lock) = arc_chan.try_write() else {
495 self.terminated = true;
496 return Poll::Ready(None);
497 };
498 let mut pin_chan = Pin::new(lock);
499 match pin_chan.as_mut().poll_next(cx) {
500 Poll::Ready(Some(Ok(res))) => Poll::Ready(Some(Ok(res))),
501 Poll::Ready(Some(Err(e))) => Poll::Ready(Some(Err(Error::PeerRead(e)))),
502 Poll::Ready(None) => {
503 self.terminated = true;
504 Poll::Ready(None)
505 }
506 Poll::Pending => Poll::Pending,
507 }
508 }
509}
510
511impl FusedStream for MediaStream {
512 fn is_terminated(&self) -> bool {
513 self.terminated
514 }
515}
516
517impl Sink<Vec<u8>> for MediaStream {
518 type Error = io::Error;
519
520 fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
521 let arc_chan = self.try_upgrade()?;
522 let mut lock = arc_chan
523 .try_write()
524 .ok_or_else(|| io::Error::new(io::ErrorKind::WouldBlock, "couldn't lock"))?;
525 Pin::new(&mut *lock).poll_ready(cx).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
526 }
527
528 fn start_send(self: Pin<&mut Self>, item: Vec<u8>) -> Result<(), Self::Error> {
529 let arc_chan = self.try_upgrade()?;
530 let mut lock = arc_chan
531 .try_write()
532 .ok_or_else(|| io::Error::new(io::ErrorKind::WouldBlock, "couldn't lock"))?;
533 Pin::new(&mut *lock).start_send(item).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
534 }
535
536 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
537 let arc_chan = self.try_upgrade()?;
538 let mut lock = arc_chan
539 .try_write()
540 .ok_or_else(|| io::Error::new(io::ErrorKind::WouldBlock, "couldn't lock"))?;
541 Pin::new(&mut *lock).poll_flush(cx).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
542 }
543
544 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
545 let arc_chan = self.try_upgrade()?;
546 let mut lock = arc_chan
547 .try_write()
548 .ok_or_else(|| io::Error::new(io::ErrorKind::WouldBlock, "couldn't lock"))?;
549 Pin::new(&mut *lock).poll_close(cx).map_err(|e| io::Error::new(io::ErrorKind::Other, e))
550 }
551}
552
553#[cfg(test)]
554mod tests {
555 use super::*;
556 use crate::Request;
557 use crate::tests::{expect_remote_recv, setup_peer};
558 use bt_channel_test_support::{Transport, create_test_channels};
559 use test_case::test_case;
560
561 use assert_matches::assert_matches;
562 use async_utils::PollExt;
563 use fidl::endpoints::create_request_stream;
564 use fidl_fuchsia_bluetooth as fidl_bt;
565 use fidl_fuchsia_bluetooth_bredr as bredr;
566 use fuchsia_async as fasync;
567 use futures::SinkExt;
568 use futures::stream::StreamExt;
569
570 const REMOTE_ID_VAL: u8 = 1;
571 const REMOTE_ID: StreamEndpointId = StreamEndpointId(REMOTE_ID_VAL);
572
573 #[test]
574 fn make() {
575 let s = StreamEndpoint::new(
576 REMOTE_ID_VAL,
577 MediaType::Audio,
578 EndpointType::Sink,
579 vec![ServiceCapability::MediaTransport],
580 );
581 assert!(s.is_ok());
582 let s = s.unwrap();
583 assert_eq!(&StreamEndpointId(1), s.local_id());
584
585 let info = s.information();
586 assert!(!info.in_use());
587
588 let no = StreamEndpoint::new(
589 0,
590 MediaType::Audio,
591 EndpointType::Sink,
592 vec![ServiceCapability::MediaTransport],
593 );
594 assert!(no.is_err());
595 }
596
597 fn establish_stream(s: &mut StreamEndpoint, transport: Transport) -> Channel {
598 assert_matches!(s.establish(), Ok(()));
599 let (chan, remote) = create_test_channels(transport);
600 assert_matches!(s.receive_channel(chan), Ok(false));
601 remote
602 }
603
604 #[test]
605 fn from_info() {
606 let seid = StreamEndpointId::try_from(5).unwrap();
607 let info =
608 StreamInformation::new(seid.clone(), false, MediaType::Audio, EndpointType::Sink);
609 let capabilities = vec![ServiceCapability::MediaTransport];
610
611 let endpoint = StreamEndpoint::from_info(&info, capabilities);
612
613 assert_eq!(&seid, endpoint.local_id());
614 assert_eq!(&false, endpoint.information().in_use());
615 assert_eq!(1, endpoint.capabilities().len());
616 }
617
618 #[test]
619 fn codec_type() {
620 let s = StreamEndpoint::new(
621 REMOTE_ID_VAL,
622 MediaType::Audio,
623 EndpointType::Sink,
624 vec![
625 ServiceCapability::MediaTransport,
626 ServiceCapability::MediaCodec {
627 media_type: MediaType::Audio,
628 codec_type: MediaCodecType::new(0x40),
629 codec_extra: vec![0xDE, 0xAD, 0xBE, 0xEF], },
631 ],
632 )
633 .unwrap();
634
635 assert_eq!(Some(&MediaCodecType::new(0x40)), s.codec_type());
636
637 let s = StreamEndpoint::new(
638 REMOTE_ID_VAL,
639 MediaType::Audio,
640 EndpointType::Sink,
641 vec![ServiceCapability::MediaTransport],
642 )
643 .unwrap();
644
645 assert_eq!(None, s.codec_type());
646 }
647
648 fn test_endpoint(r#type: EndpointType) -> StreamEndpoint {
649 StreamEndpoint::new(
650 REMOTE_ID_VAL,
651 MediaType::Audio,
652 r#type,
653 vec![
654 ServiceCapability::MediaTransport,
655 ServiceCapability::MediaCodec {
656 media_type: MediaType::Audio,
657 codec_type: MediaCodecType::new(0x40),
658 codec_extra: vec![0xDE, 0xAD, 0xBE, 0xEF], },
660 ],
661 )
662 .unwrap()
663 }
664
665 #[test_case(Transport::Socket ; "socket")]
666 #[test_case(Transport::Fidl ; "fidl")]
667 #[fuchsia::test]
668 fn stream_configure_reconfigure(transport: Transport) {
669 let _exec = fasync::TestExecutor::new();
670 let mut s = test_endpoint(EndpointType::Sink);
671
672 assert_matches!(
674 s.configure(&REMOTE_ID, vec![ServiceCapability::Reporting]),
675 Err((ServiceCategory::Reporting, ErrorCode::UnsupportedConfiguration))
676 );
677
678 assert_matches!(
679 s.configure(
680 &REMOTE_ID,
681 vec![
682 ServiceCapability::MediaTransport,
683 ServiceCapability::MediaCodec {
684 media_type: MediaType::Audio,
685 codec_type: MediaCodecType::new(0x40),
686 codec_extra: vec![0x0C, 0x0D, 0x02, 0x51],
688 }
689 ]
690 ),
691 Ok(())
692 );
693
694 assert_matches!(
696 s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]),
697 Err((_, ErrorCode::SepInUse))
698 );
699
700 let _channel = establish_stream(&mut s, transport);
702
703 assert_matches!(
704 s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]),
705 Err((_, ErrorCode::SepInUse))
706 );
707
708 let reconfiguration = vec![ServiceCapability::MediaCodec {
709 media_type: MediaType::Audio,
710 codec_type: MediaCodecType::new(0x40),
711 codec_extra: vec![0x0C, 0x0D, 0x0E, 0x0F],
713 }];
714
715 let new_configuration = vec![ServiceCapability::MediaTransport, reconfiguration[0].clone()];
718
719 assert_matches!(s.reconfigure(reconfiguration.clone()), Ok(()));
721
722 assert_eq!(Some(&new_configuration), s.get_configuration());
723
724 assert_matches!(
726 s.reconfigure(vec![ServiceCapability::MediaTransport]),
727 Err((ServiceCategory::MediaTransport, ErrorCode::InvalidCapabilities))
728 );
729
730 assert_matches!(s.start(), Ok(()));
732
733 assert_matches!(
734 s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]),
735 Err((_, ErrorCode::SepInUse))
736 );
737
738 assert_matches!(s.reconfigure(reconfiguration.clone()), Err((_, ErrorCode::BadState)));
739
740 assert_matches!(s.suspend(), Ok(()));
741
742 assert_matches!(s.reconfigure(reconfiguration.clone()), Ok(()));
744
745 assert_matches!(
747 s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]),
748 Err((_, ErrorCode::SepInUse))
749 );
750 }
751
752 #[test_case(Transport::Socket ; "socket")]
753 #[test_case(Transport::Fidl ; "fidl")]
754 #[fuchsia::test]
755 fn stream_establishment(transport: Transport) {
756 let mut exec = fasync::TestExecutor::new();
757 let mut s = test_endpoint(EndpointType::Sink);
758
759 let (transport_chan, mut remote) = create_test_channels(transport);
760
761 assert_matches!(s.establish(), Err(ErrorCode::BadState));
763
764 assert_matches!(s.receive_channel(transport_chan), Err(Error::InvalidState));
766
767 let mut read_fut = remote.next();
768 let res = exec.run_until_stalled(&mut read_fut).expect("should be ready");
769 assert_matches!(res, None);
771
772 assert_matches!(s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]), Ok(()));
773
774 assert_matches!(s.establish(), Ok(()));
775
776 let (transport_chan, _remote) = create_test_channels(transport);
778 assert_matches!(s.receive_channel(transport_chan), Ok(false));
779 }
780
781 fn setup_peer_for_release(
782 exec: &mut fasync::TestExecutor,
783 transport: Transport,
784 ) -> (Peer, Channel, SimpleResponder) {
785 let (peer, mut signaling) = setup_peer(transport);
786 exec.run_until_stalled(&mut signaling.send(vec![0x40, 0x08, 0x04]))
788 .expect("signaling write")
789 .expect("write successful");
790 let mut req_stream = peer.take_request_stream();
791 let mut req_fut = req_stream.next();
792 let complete = exec.run_until_stalled(&mut req_fut);
793 let responder = match complete {
794 Poll::Ready(Some(Ok(Request::Close { responder, .. }))) => responder,
795 _ => panic!("Expected a close request"),
796 };
797 (peer, signaling, responder)
798 }
799
800 #[test_case(Transport::Socket ; "socket")]
801 #[test_case(Transport::Fidl ; "fidl")]
802 #[fuchsia::test]
803 fn stream_release_without_abort(transport: Transport) {
804 let mut exec = fasync::TestExecutor::new();
805 let mut s = test_endpoint(EndpointType::Sink);
806
807 assert_matches!(s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]), Ok(()));
808
809 let remote_transport = establish_stream(&mut s, transport);
810
811 let (peer, mut signaling, responder) = setup_peer_for_release(&mut exec, transport);
812
813 s.release(responder, &peer).unwrap();
815 expect_remote_recv(&mut exec, &[0x42, 0x08], &mut signaling);
817
818 drop(remote_transport);
820
821 let _ = exec.run_until_stalled(&mut futures::future::pending::<()>());
823 assert_eq!(s.state(), StreamState::Idle);
824 }
825
826 #[test_case(Transport::Socket ; "socket")]
827 #[test_case(Transport::Fidl ; "fidl")]
828 #[fuchsia::test]
829 fn test_mediastream(transport: Transport) {
830 let mut exec = fasync::TestExecutor::new();
831 let mut s = test_endpoint(EndpointType::Sink);
832
833 assert_matches!(s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]), Ok(()));
834
835 assert!(s.take_transport().is_none());
837
838 let mut remote_transport = establish_stream(&mut s, transport);
839
840 let temp_stream = s.take_transport();
842 assert!(temp_stream.is_some());
843
844 assert!(s.take_transport().is_none());
846
847 drop(temp_stream);
849
850 let media_stream = s.take_transport();
851 assert!(media_stream.is_some());
852 let mut media_stream = media_stream.unwrap();
853
854 assert_matches!(media_stream.max_tx_size(), Ok(Channel::DEFAULT_MAX_TX));
856
857 let hearts = vec![0xF0, 0x9F, 0x92, 0x96, 0xF0, 0x9F, 0x92, 0x96];
859 let mut write_fut = media_stream.send(hearts.clone());
860
861 assert_matches!(exec.run_until_stalled(&mut write_fut), Poll::Ready(Ok(())));
862
863 expect_remote_recv(&mut exec, &hearts, &mut remote_transport);
864
865 let mut close_fut = media_stream.close();
867 assert_matches!(exec.run_until_stalled(&mut close_fut), Poll::Ready(Ok(())));
868 drop(s);
872
873 let mut read_fut = remote_transport.next();
875 let res = exec.run_until_stalled(&mut read_fut).expect("should be ready");
876 assert_matches!(res, None);
878
879 let mut write_fut = media_stream.send(vec![0xDE, 0xAD]);
881 assert_matches!(exec.run_until_stalled(&mut write_fut), Poll::Ready(Err(_)));
882
883 let mut next_fut = media_stream.next();
885 assert_matches!(exec.run_until_stalled(&mut next_fut), Poll::Ready(None));
886
887 assert!(media_stream.is_terminated(), "should be terminated");
888
889 assert_matches!(media_stream.max_tx_size(), Err(_));
891 }
892
893 #[test_case(Transport::Socket ; "socket")]
894 #[test_case(Transport::Fidl ; "fidl")]
895 #[fuchsia::test]
896 fn stream_release_with_abort(transport: Transport) {
897 let mut exec = fasync::TestExecutor::new();
898 let mut s = test_endpoint(EndpointType::Sink);
899
900 assert_matches!(s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]), Ok(()));
901 let remote_transport = establish_stream(&mut s, transport);
902 let (peer, mut signaling, responder) = setup_peer_for_release(&mut exec, transport);
903
904 s.release(responder, &peer).unwrap();
906 expect_remote_recv(&mut exec, &[0x42, 0x08], &mut signaling);
908
909 let next = std::pin::pin!(signaling.next());
911 let received =
912 exec.run_singlethreaded(next).expect("channel not closed").expect("successful read");
913 assert_eq!(0x0A, received[1]);
914 let txlabel = received[0] & 0xF0;
915 exec.run_until_stalled(&mut signaling.send(vec![txlabel | 0x02, 0x0A]))
917 .expect("signaling write")
918 .expect("write successful");
919
920 let _ = exec.run_singlethreaded(&mut std::pin::pin!(remote_transport.closed()));
921
922 while s.state() != StreamState::Idle {
924 let _ = exec.run_until_stalled(&mut futures::future::pending::<()>());
925 }
926 }
927
928 fn create_channel_for_start_test(
929 transport: Transport,
930 ) -> (Channel, Channel, Option<bredr::AudioDirectionExtRequestStream>) {
931 match transport {
932 Transport::Socket => {
933 let (remote, local) = zx::Socket::create_datagram();
934 let (client_end, direction_request_stream) =
935 create_request_stream::<bredr::AudioDirectionExtMarker>();
936 let ext = bredr::Channel {
937 socket: Some(local),
938 channel_mode: Some(fidl_bt::ChannelMode::Basic),
939 max_tx_sdu_size: Some(1004),
940 ext_direction: Some(client_end),
941 ..Default::default()
942 };
943 let channel = Channel::try_from(ext).unwrap();
944 let remote_chan = Channel::from_socket_infallible(remote, Channel::DEFAULT_MAX_TX);
945 (channel, remote_chan, Some(direction_request_stream))
946 }
947 Transport::Fidl => {
948 let (client, server) = create_test_channels(Transport::Fidl);
949 (client, server, None)
950 }
951 }
952 }
953
954 #[test_case(Transport::Socket ; "socket")]
955 #[test_case(Transport::Fidl ; "fidl")]
956 #[fuchsia::test]
957 fn start_and_suspend(transport: Transport) {
958 let mut exec = fasync::TestExecutor::new();
959 let mut s = test_endpoint(EndpointType::Sink);
960
961 assert_matches!(s.start(), Err(ErrorCode::BadState));
963 assert_matches!(s.suspend(), Err(ErrorCode::BadState));
964
965 assert_matches!(s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]), Ok(()));
966
967 assert_matches!(s.start(), Err(ErrorCode::BadState));
968 assert_matches!(s.suspend(), Err(ErrorCode::BadState));
969
970 assert_matches!(s.establish(), Ok(()));
971
972 assert_matches!(s.start(), Err(ErrorCode::BadState));
973 assert_matches!(s.suspend(), Err(ErrorCode::BadState));
974
975 let (transport_chan, remote, mut direction_request_stream) =
976 create_channel_for_start_test(transport);
977 assert_matches!(s.receive_channel(transport_chan), Ok(false));
978
979 assert_matches!(s.suspend(), Err(ErrorCode::BadState));
981 assert_matches!(s.start(), Ok(()));
982
983 if let Some(ref mut stream) = direction_request_stream {
984 match exec.run_until_stalled(&mut stream.next()) {
985 Poll::Ready(Some(Ok(bredr::AudioDirectionExtRequest::SetPriority {
986 priority,
987 responder,
988 }))) => {
989 assert_eq!(bredr::A2dpDirectionPriority::Sink, priority);
990 responder.send(Ok(())).expect("response to send cleanly");
991 }
992 x => panic!("Expected a item to be ready on the request stream, got {:?}", x),
993 }
994 }
995
996 assert_matches!(s.start(), Err(ErrorCode::BadState));
998 assert_matches!(s.suspend(), Ok(()));
999
1000 if let Some(ref mut stream) = direction_request_stream {
1001 match exec.run_until_stalled(&mut stream.next()) {
1002 Poll::Ready(Some(Ok(bredr::AudioDirectionExtRequest::SetPriority {
1003 priority,
1004 responder,
1005 }))) => {
1006 assert_eq!(bredr::A2dpDirectionPriority::Normal, priority);
1007 responder.send(Ok(())).expect("response to send cleanly");
1008 }
1009 x => panic!("Expected a item to be ready on the request stream, got {:?}", x),
1010 }
1011 }
1012
1013 assert_matches!(s.start(), Ok(()));
1015 assert_matches!(s.suspend(), Ok(()));
1016
1017 let (peer, mut signaling, responder) = setup_peer_for_release(&mut exec, transport);
1019
1020 {
1021 s.release(responder, &peer).unwrap();
1022 expect_remote_recv(&mut exec, &[0x42, 0x08], &mut signaling);
1024 drop(remote);
1026 while s.state() != StreamState::Idle {
1027 let _ = exec.run_until_stalled(&mut futures::future::pending::<()>());
1028 }
1029 }
1030
1031 assert_matches!(s.start(), Err(ErrorCode::BadState));
1033 assert_matches!(s.suspend(), Err(ErrorCode::BadState));
1034 }
1035
1036 fn receive_l2cap_params_channel(
1037 s: &mut StreamEndpoint,
1038 transport: Transport,
1039 ) -> (Channel, Option<bredr::L2capParametersExtRequestStream>) {
1040 assert_matches!(s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport]), Ok(()));
1041 assert_matches!(s.establish(), Ok(()));
1042
1043 match transport {
1044 Transport::Socket => {
1045 let (remote, local) = zx::Socket::create_datagram();
1046 let (client_end, l2cap_params_requests) =
1047 create_request_stream::<bredr::L2capParametersExtMarker>();
1048 let ext = bredr::Channel {
1049 socket: Some(local),
1050 channel_mode: Some(fidl_bt::ChannelMode::Basic),
1051 max_tx_sdu_size: Some(1004),
1052 ext_l2cap: Some(client_end),
1053 ..Default::default()
1054 };
1055 let transport_chan = Channel::try_from(ext).unwrap();
1056 assert_matches!(s.receive_channel(transport_chan), Ok(false));
1057 let remote_chan = Channel::from_socket_infallible(remote, Channel::DEFAULT_MAX_TX);
1058 (remote_chan, Some(l2cap_params_requests))
1059 }
1060 Transport::Fidl => {
1061 let (client, server) = create_test_channels(Transport::Fidl);
1062 assert_matches!(s.receive_channel(client), Ok(false));
1063 (server, None)
1064 }
1065 }
1066 }
1067
1068 #[test_case(Transport::Socket ; "socket")]
1069 #[test_case(Transport::Fidl ; "fidl")]
1070 #[fuchsia::test]
1071 fn sets_flush_timeout_for_source_transports(transport: Transport) {
1072 let mut exec = fasync::TestExecutor::new();
1073 let mut s = test_endpoint(EndpointType::Source);
1074 let (_remote, mut l2cap_params_requests) = receive_l2cap_params_channel(&mut s, transport);
1075
1076 if let Some(ref mut stream) = l2cap_params_requests {
1077 match exec.run_until_stalled(&mut stream.next()) {
1078 Poll::Ready(Some(Ok(bredr::L2capParametersExtRequest::RequestParameters {
1079 request,
1080 responder,
1081 }))) => {
1082 assert_eq!(
1083 Some(StreamEndpoint::SRC_FLUSH_TIMEOUT.into_nanos()),
1084 request.flush_timeout
1085 );
1086 responder.send(&request).expect("response to send cleanly");
1087 }
1088 x => panic!("Expected a item to be ready on the request stream, got {:?}", x),
1089 };
1090 }
1091 }
1092
1093 #[test_case(Transport::Socket ; "socket")]
1094 #[test_case(Transport::Fidl ; "fidl")]
1095 #[fuchsia::test]
1096 fn no_flush_timeout_for_sink_transports(transport: Transport) {
1097 let mut exec = fasync::TestExecutor::new();
1098 let mut s = test_endpoint(EndpointType::Sink);
1099 let (_remote, mut l2cap_params_requests) = receive_l2cap_params_channel(&mut s, transport);
1100
1101 if let Some(ref mut stream) = l2cap_params_requests {
1102 match exec.run_until_stalled(&mut stream.next()) {
1104 Poll::Pending => {}
1105 x => panic!("Expected no request to set flush timeout, got {:?}", x),
1106 };
1107 }
1108 }
1109
1110 #[test]
1111 fn get_configuration() {
1112 let mut s = test_endpoint(EndpointType::Sink);
1113
1114 assert!(s.get_configuration().is_none());
1116
1117 let config = vec![
1118 ServiceCapability::MediaTransport,
1119 ServiceCapability::MediaCodec {
1120 media_type: MediaType::Audio,
1121 codec_type: MediaCodecType::new(0),
1122 codec_extra: vec![0x60, 0x0D, 0x02, 0x55],
1124 },
1125 ];
1126
1127 assert_matches!(s.configure(&REMOTE_ID, config.clone()), Ok(()));
1128
1129 match s.get_configuration() {
1130 Some(c) => assert_eq!(&config, c),
1131 x => panic!("Expected Ok from get_configuration but got {:?}", x),
1132 };
1133
1134 s.abort();
1136
1137 assert!(s.get_configuration().is_none());
1138 }
1139
1140 use std::sync::atomic::{AtomicUsize, Ordering};
1141
1142 fn call_count_callback() -> (Option<StreamEndpointUpdateCallback>, Arc<AtomicUsize>) {
1144 let call_count = Arc::new(AtomicUsize::new(0));
1145 let call_count_reader = call_count.clone();
1146 let count_cb: StreamEndpointUpdateCallback = Box::new(move |_stream: &StreamEndpoint| {
1147 let _ = call_count.fetch_add(1, Ordering::SeqCst);
1148 });
1149 (Some(count_cb), call_count_reader)
1150 }
1151
1152 #[test_case(Transport::Socket ; "socket")]
1159 #[test_case(Transport::Fidl ; "fidl")]
1160 #[fuchsia::test]
1161 fn update_callback(transport: Transport) {
1162 let _exec = fasync::TestExecutor::new();
1164 let mut s = test_endpoint(EndpointType::Sink);
1165 let (cb, call_count) = call_count_callback();
1166 s.set_update_callback(cb);
1167
1168 s.configure(&REMOTE_ID, vec![ServiceCapability::MediaTransport])
1169 .expect("Configure to succeed in test");
1170 assert!(call_count.load(Ordering::SeqCst) > 0, "Update callback called at least once");
1171 call_count.store(0, Ordering::SeqCst); s.establish().expect("Establish to succeed in test");
1174 assert!(call_count.load(Ordering::SeqCst) > 0, "Update callback called at least once");
1175 call_count.store(0, Ordering::SeqCst); let (transport_chan, _remote) = create_test_channels(transport);
1178 assert_eq!(
1179 s.receive_channel(transport_chan).expect("Receive channel to succeed in test"),
1180 false
1181 );
1182 assert!(call_count.load(Ordering::SeqCst) > 0, "Update callback called at least once");
1183 call_count.store(0, Ordering::SeqCst); s.start().expect("Start to succeed in test");
1186 assert!(call_count.load(Ordering::SeqCst) > 0, "Update callback called at least once");
1187 call_count.store(0, Ordering::SeqCst); s.suspend().expect("Suspend to succeed in test");
1190 assert!(call_count.load(Ordering::SeqCst) > 0, "Update callback called at least once");
1191 call_count.store(0, Ordering::SeqCst); s.reconfigure(vec![]).expect("Reconfigure to succeed in test");
1194 assert!(call_count.load(Ordering::SeqCst) > 0, "Update callback called at least once");
1195 call_count.store(0, Ordering::SeqCst); s.abort();
1199 }
1200}