1use packet_encoding::{decodable_enum, Decodable, Encodable};
6use std::io::{Cursor, Write};
7use std::{fmt, result};
8use thiserror::Error;
9
10pub type Result<T> = result::Result<T, Error>;
12
13#[derive(Error, Debug)]
15#[non_exhaustive]
16pub enum Error {
17 #[error("Value was out of range")]
19 OutOfRange,
20
21 #[error("Invalid signal id for {:?}: {:X?}", _0, _1)]
23 InvalidSignalId(TxLabel, u8),
24
25 #[error("Invalid Header for a AVDTP message")]
27 InvalidHeader,
28
29 #[error("Failed to parse AVDTP message contents")]
31 InvalidMessage,
32
33 #[error("Command timed out")]
35 Timeout,
36
37 #[error("Remote end rejected the command ({:})", _0)]
39 RemoteRejected(#[from] RemoteReject),
40
41 #[error("Message has not been implemented yet")]
43 UnimplementedMessage,
44
45 #[error("Peer has disconnected")]
47 PeerDisconnected,
48
49 #[error("Command Response has already been received")]
51 AlreadyReceived,
52
53 #[error("Encountered an IO error reading from the peer: {}", _0)]
55 ChannelSetup(zx::Status),
56
57 #[error("Encountered an IO error reading from the peer: {}", _0)]
59 PeerRead(zx::Status),
60
61 #[error("Encountered an IO error writing to the peer: {}", _0)]
63 PeerWrite(zx::Status),
64
65 #[error("Encountered an error encoding a message")]
67 Encoding,
68
69 #[error("Invalid request detected: {:?}", _0)]
72 RequestInvalid(ErrorCode),
73
74 #[error("Invalid request detected: {:?} (extra: {:?})", _0, _1)]
77 RequestInvalidExtra(ErrorCode, u8),
78
79 #[error("Invalid State")]
81 InvalidState,
82
83 #[error(transparent)]
85 Other(#[from] anyhow::Error),
86}
87
88#[derive(Error, Debug)]
90#[cfg_attr(test, derive(PartialEq))]
91pub struct RemoteReject {
92 signal_id: SignalIdentifier,
97 error_code: Option<u8>,
99 service_category: Option<u8>,
102 stream_endpoint_id: Option<StreamEndpointId>,
104}
105
106impl RemoteReject {
107 pub(crate) fn from_params(signal_id: SignalIdentifier, params: &[u8]) -> Self {
108 if params.len() == 0 {
109 return Self {
111 signal_id,
112 error_code: None,
113 service_category: None,
114 stream_endpoint_id: None,
115 };
116 }
117 let (error_code, service_category, stream_endpoint_id) = match signal_id {
118 SignalIdentifier::SetConfiguration | SignalIdentifier::Reconfigure => {
119 (params.get(1).copied(), params.get(0).copied(), None)
120 }
121 SignalIdentifier::Start | SignalIdentifier::Suspend => {
122 (params.get(1).copied(), None, params.get(0).map(StreamEndpointId::from_msg))
124 }
125 _ => (params.get(0).copied(), None, None),
126 };
127 Self { signal_id, error_code, service_category, stream_endpoint_id }
128 }
129
130 pub fn error_code(&self) -> Option<std::result::Result<ErrorCode, u8>> {
133 self.error_code.map(|e| ErrorCode::try_from(e).map_err(|_| e))
134 }
135
136 pub fn service_category(&self) -> Option<std::result::Result<ServiceCategory, u8>> {
139 self.service_category.map(|e| ServiceCategory::try_from(e).map_err(|_| e))
140 }
141
142 pub fn stream_id(&self) -> Option<StreamEndpointId> {
145 self.stream_endpoint_id.clone()
146 }
147
148 #[cfg(test)]
149 pub fn general(signal_id: SignalIdentifier) -> Self {
150 Self { signal_id, error_code: None, service_category: None, stream_endpoint_id: None }
151 }
152
153 #[cfg(test)]
154 pub fn rejected(signal_id: SignalIdentifier, code: u8) -> Self {
155 Self { signal_id, error_code: Some(code), service_category: None, stream_endpoint_id: None }
156 }
157
158 #[cfg(test)]
159 pub fn config(signal_id: SignalIdentifier, cat: u8, code: u8) -> Self {
160 Self {
161 signal_id,
162 error_code: Some(code),
163 service_category: Some(cat),
164 stream_endpoint_id: None,
165 }
166 }
167
168 #[cfg(test)]
169 pub fn stream(signal_id: SignalIdentifier, stream: u8, code: u8) -> Self {
170 Self {
171 signal_id,
172 error_code: Some(code),
173 service_category: None,
174 stream_endpoint_id: stream.try_into().ok(),
175 }
176 }
177}
178
179impl std::fmt::Display for RemoteReject {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
181 let Some(error_code) = self.error_code else {
182 return write!(f, "did not recognize {:?}", self.signal_id);
183 };
184
185 write!(f, "{:?}, ", self.signal_id)?;
186 match self.signal_id {
187 SignalIdentifier::SetConfiguration | SignalIdentifier::Reconfigure => {
188 write!(f, "category {:?}, ", self.service_category)?;
189 }
190 SignalIdentifier::Start | SignalIdentifier::Suspend => {
191 write!(f, "stream id {:?}, ", self.stream_endpoint_id)?;
192 }
193 _ => {}
194 };
195 write!(f, "{:x}", error_code)
196 }
197}
198
199decodable_enum! {
200 pub enum ErrorCode<u8, Error, OutOfRange> {
203 BadHeaderFormat = 0x01,
205
206 BadLength = 0x11,
208 BadAcpSeid = 0x12,
209 SepInUse = 0x13,
210 SepNotInUse = 0x14,
211 BadServiceCategory = 0x17,
212 BadPayloadFormat = 0x18,
213 NotSupportedCommand = 0x19,
214 InvalidCapabilities = 0x1A,
215
216 BadRecoveryType = 0x22,
218 BadMediaTransportFormat = 0x23,
219 BadRecoveryFormat = 0x25,
220 BadRohcFormat = 0x26,
221 BadCpFormat = 0x27,
222 BadMultiplexingFormat = 0x28,
223 UnsupportedConfiguration = 0x29,
224
225 BadState = 0x31,
227 }
228}
229
230#[derive(Debug, Clone, Copy, PartialEq)]
234pub struct TxLabel(u8);
235
236const MAX_TX_LABEL: u8 = 0xF;
238
239impl TryFrom<u8> for TxLabel {
240 type Error = Error;
241
242 fn try_from(value: u8) -> Result<Self> {
243 if value > MAX_TX_LABEL {
244 Err(Error::OutOfRange)
245 } else {
246 Ok(TxLabel(value))
247 }
248 }
249}
250
251impl From<&TxLabel> for u8 {
252 fn from(v: &TxLabel) -> u8 {
253 v.0
254 }
255}
256
257impl From<&TxLabel> for usize {
258 fn from(v: &TxLabel) -> usize {
259 v.0 as usize
260 }
261}
262
263decodable_enum! {
264 pub enum MediaType<u8, Error, OutOfRange> {
270 Audio = 0x00,
271 Video = 0x01,
272 Multimedia = 0x02,
273 }
274}
275
276decodable_enum! {
277 pub enum EndpointType<u8, Error, OutOfRange> {
281 Source = 0x00,
282 Sink = 0x01,
283 }
284}
285
286impl EndpointType {
287 pub fn opposite(&self) -> Self {
288 match self {
289 Self::Source => Self::Sink,
290 Self::Sink => Self::Source,
291 }
292 }
293}
294
295decodable_enum! {
296 pub(crate) enum SignalingPacketType<u8, Error, OutOfRange> {
299 Single = 0x00,
300 Start = 0x01,
301 Continue = 0x02,
302 End = 0x03,
303 }
304}
305
306decodable_enum! {
307 pub(crate) enum SignalingMessageType<u8, Error, OutOfRange> {
311 Command = 0x00,
312 GeneralReject = 0x01,
313 ResponseAccept = 0x02,
314 ResponseReject = 0x03,
315 }
316}
317
318decodable_enum! {
319 pub enum SignalIdentifier<u8, Error, OutOfRange> {
323 Discover = 0x01,
324 GetCapabilities = 0x02,
325 SetConfiguration = 0x03,
326 GetConfiguration = 0x04,
327 Reconfigure = 0x05,
328 Open = 0x06,
329 Start = 0x07,
330 Close = 0x08,
331 Suspend = 0x09,
332 Abort = 0x0A,
333 SecurityControl = 0x0B,
334 GetAllCapabilities = 0x0C,
335 DelayReport = 0x0D,
336 }
337}
338
339#[derive(Debug)]
340pub(crate) struct SignalingHeader {
341 pub label: TxLabel,
342 packet_type: SignalingPacketType,
343 pub(crate) message_type: SignalingMessageType,
344 num_packets: u8,
345 pub signal: SignalIdentifier,
346}
347
348impl SignalingHeader {
349 pub fn new(
350 label: TxLabel,
351 signal: SignalIdentifier,
352 message_type: SignalingMessageType,
353 ) -> SignalingHeader {
354 SignalingHeader {
355 label,
356 signal,
357 message_type,
358 packet_type: SignalingPacketType::Single,
359 num_packets: 1,
360 }
361 }
362
363 pub fn label(&self) -> TxLabel {
364 self.label
365 }
366
367 pub fn signal(&self) -> SignalIdentifier {
368 self.signal
369 }
370
371 pub fn is_type(&self, other: SignalingMessageType) -> bool {
372 self.message_type == other
373 }
374
375 pub fn is_command(&self) -> bool {
376 self.is_type(SignalingMessageType::Command)
377 }
378}
379
380impl Decodable for SignalingHeader {
381 type Error = Error;
382
383 fn decode(bytes: &[u8]) -> Result<SignalingHeader> {
384 if bytes.len() < 2 {
385 return Err(Error::OutOfRange);
386 }
387 let label = TxLabel::try_from(bytes[0] >> 4)?;
388 let packet_type = SignalingPacketType::try_from((bytes[0] >> 2) & 0x3)?;
389 let (id_offset, num_packets) = match packet_type {
390 SignalingPacketType::Start => {
391 if bytes.len() < 3 {
392 return Err(Error::OutOfRange);
393 }
394 (2, bytes[1])
395 }
396 _ => (1, 1),
397 };
398 let signal_id_val = bytes[id_offset] & 0x3F;
399 let id = SignalIdentifier::try_from(signal_id_val)
400 .map_err(|_| Error::InvalidSignalId(label, signal_id_val))?;
401 let header = SignalingHeader {
402 label,
403 packet_type,
404 message_type: SignalingMessageType::try_from(bytes[0] & 0x3)?,
405 signal: id,
406 num_packets,
407 };
408 Ok(header)
409 }
410}
411
412impl Encodable for SignalingHeader {
413 type Error = Error;
414
415 fn encoded_len(&self) -> usize {
416 if self.num_packets > 1 {
417 3
418 } else {
419 2
420 }
421 }
422
423 fn encode(&self, buf: &mut [u8]) -> Result<()> {
424 if buf.len() < self.encoded_len() {
425 return Err(Error::Encoding);
426 }
427 buf[0] = u8::from(&self.label) << 4
428 | u8::from(&self.packet_type) << 2
429 | u8::from(&self.message_type);
430 buf[1] = u8::from(&self.signal);
431 Ok(())
432 }
433}
434
435#[derive(Debug, PartialEq, Eq, Clone, Hash)]
438pub struct StreamEndpointId(pub(crate) u8);
439
440impl StreamEndpointId {
441 pub(crate) fn from_msg(byte: &u8) -> Self {
444 StreamEndpointId(byte >> 2)
445 }
446
447 pub(crate) fn to_msg(&self) -> u8 {
450 self.0 << 2
451 }
452}
453
454impl TryFrom<u8> for StreamEndpointId {
455 type Error = Error;
456
457 fn try_from(value: u8) -> Result<Self> {
458 if value == 0 || value > 0x3E {
459 Err(Error::OutOfRange)
460 } else {
461 Ok(StreamEndpointId(value))
462 }
463 }
464}
465
466impl fmt::Display for StreamEndpointId {
467 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
468 write!(fmt, "{}", self.0)
469 }
470}
471
472#[derive(PartialEq, Eq, Clone)]
480pub struct MediaCodecType(u8);
481
482impl MediaCodecType {
483 pub const AUDIO_SBC: Self = MediaCodecType(0b0);
484 pub const AUDIO_MPEG12: Self = MediaCodecType(0b1);
485 pub const AUDIO_AAC: Self = MediaCodecType(0b10);
486 pub const AUDIO_ATRAC: Self = MediaCodecType(0b100);
487 pub const AUDIO_NON_A2DP: Self = MediaCodecType(0b1111_1111);
488
489 pub fn new(num: u8) -> MediaCodecType {
490 MediaCodecType(num)
491 }
492}
493
494impl fmt::Debug for MediaCodecType {
495 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
496 match self {
497 &Self::AUDIO_SBC => write!(f, "MediaCodecType::AUDIO_SBC"),
498 &Self::AUDIO_MPEG12 => write!(f, "MediaCodecType::AUDIO_MPEG12"),
499 &Self::AUDIO_AAC => write!(f, "MediaCodecType::AUDIO_AAC"),
500 &Self::AUDIO_ATRAC => write!(f, "MediaCodecType::AUDIO_ATRAC"),
501 &Self::AUDIO_NON_A2DP => write!(f, "MediaCodecType::AUDIO_NON_A2DP"),
502 _ => f.debug_tuple("MediaCodecType").field(&self.0).finish(),
503 }
504 }
505}
506
507#[derive(Debug, PartialEq, Clone)]
511pub enum ContentProtectionType {
512 DigitalTransmissionContentProtection, SerialCopyManagementSystem, }
515
516impl ContentProtectionType {
517 fn to_le_bytes(&self) -> [u8; 2] {
518 match self {
519 ContentProtectionType::DigitalTransmissionContentProtection => [0x01, 0x00],
520 ContentProtectionType::SerialCopyManagementSystem => [0x02, 0x00],
521 }
522 }
523}
524
525impl TryFrom<u16> for ContentProtectionType {
526 type Error = Error;
527
528 fn try_from(val: u16) -> Result<Self> {
529 match val {
530 1 => Ok(ContentProtectionType::DigitalTransmissionContentProtection),
531 2 => Ok(ContentProtectionType::SerialCopyManagementSystem),
532 _ => Err(Error::OutOfRange),
533 }
534 }
535}
536
537decodable_enum! {
538 #[derive(PartialOrd, Ord)]
542 pub enum ServiceCategory<u8, Error, OutOfRange> {
543 None = 0x00,
544 MediaTransport = 0x01,
545 Reporting = 0x02,
546 Recovery = 0x03,
547 ContentProtection = 0x04,
548 HeaderCompression = 0x05,
549 Multiplexing = 0x06,
550 MediaCodec = 0x07,
551 DelayReporting = 0x08,
552 }
553}
554
555#[derive(Debug, PartialEq, Clone)]
558pub enum ServiceCapability {
559 MediaTransport,
563 Reporting,
566 Recovery { recovery_type: u8, max_recovery_window_size: u8, max_number_media_packets: u8 },
569 MediaCodec {
573 media_type: MediaType,
574 codec_type: MediaCodecType,
575 codec_extra: Vec<u8>, },
577 ContentProtection {
581 protection_type: ContentProtectionType,
582 extra: Vec<u8>, },
584 HeaderCompression { payload_len: u8 },
588 Multiplexing { payload_len: u8 },
592 DelayReporting,
595}
596
597impl ServiceCapability {
598 pub fn category(&self) -> ServiceCategory {
599 match self {
600 ServiceCapability::MediaTransport => ServiceCategory::MediaTransport,
601 ServiceCapability::Reporting => ServiceCategory::Reporting,
602 ServiceCapability::Recovery { .. } => ServiceCategory::Recovery,
603 ServiceCapability::ContentProtection { .. } => ServiceCategory::ContentProtection,
604 ServiceCapability::MediaCodec { .. } => ServiceCategory::MediaCodec,
605 ServiceCapability::DelayReporting => ServiceCategory::DelayReporting,
606 ServiceCapability::HeaderCompression { .. } => ServiceCategory::HeaderCompression,
607 ServiceCapability::Multiplexing { .. } => ServiceCategory::Multiplexing,
608 }
609 }
610
611 pub(crate) fn length_of_service_capabilities(&self) -> u8 {
612 match self {
613 ServiceCapability::MediaTransport => 0,
614 ServiceCapability::Reporting => 0,
615 ServiceCapability::Recovery { .. } => 3,
616 ServiceCapability::MediaCodec { codec_extra, .. } => 2 + codec_extra.len() as u8,
617 ServiceCapability::ContentProtection { extra, .. } => 2 + extra.len() as u8,
618 ServiceCapability::DelayReporting => 0,
619 ServiceCapability::HeaderCompression { payload_len } => *payload_len,
620 ServiceCapability::Multiplexing { payload_len } => *payload_len,
621 }
622 }
623
624 pub(crate) fn is_basic(&self) -> bool {
627 match self {
628 ServiceCapability::DelayReporting => false,
629 _ => true,
630 }
631 }
632
633 pub(crate) fn in_response(&self, sig: SignalIdentifier) -> bool {
635 sig != SignalIdentifier::GetCapabilities || self.is_basic()
636 }
637
638 pub(crate) fn is_application(&self) -> bool {
640 match self {
641 ServiceCapability::MediaCodec { .. } | ServiceCapability::ContentProtection { .. } => {
642 true
643 }
644 _ => false,
645 }
646 }
647
648 pub fn is_codec(&self) -> bool {
649 match self {
650 ServiceCapability::MediaCodec { .. } => true,
651 _ => false,
652 }
653 }
654
655 pub fn codec_type(&self) -> Option<&MediaCodecType> {
656 match self {
657 ServiceCapability::MediaCodec { codec_type, .. } => Some(codec_type),
658 _ => None,
659 }
660 }
661}
662
663impl Decodable for ServiceCapability {
664 type Error = Error;
665
666 fn decode(from: &[u8]) -> Result<Self> {
667 if from.len() < 2 {
668 return Err(Error::Encoding);
669 }
670 let length_of_capability = from[1] as usize;
671 let d = match ServiceCategory::try_from(from[0]) {
672 Ok(ServiceCategory::MediaTransport) => match length_of_capability {
673 0 => ServiceCapability::MediaTransport,
674 _ => return Err(Error::RequestInvalid(ErrorCode::BadMediaTransportFormat)),
675 },
676 Ok(ServiceCategory::Reporting) => match length_of_capability {
677 0 => ServiceCapability::Reporting,
678 _ => return Err(Error::RequestInvalid(ErrorCode::BadPayloadFormat)),
679 },
680 Ok(ServiceCategory::Recovery) => {
681 if from.len() < 5 || length_of_capability != 3 {
682 return Err(Error::RequestInvalid(ErrorCode::BadRecoveryFormat));
683 }
684 let recovery_type = from[2];
685 let mrws = from[3];
686 let mnmp = from[4];
687 if recovery_type != 0x01 {
690 return Err(Error::RequestInvalid(ErrorCode::BadRecoveryType));
691 }
692 if mrws < 0x01 || mrws > 0x18 || mnmp < 0x01 || mnmp > 0x18 {
694 return Err(Error::RequestInvalid(ErrorCode::BadRecoveryFormat));
695 }
696 ServiceCapability::Recovery {
697 recovery_type,
698 max_recovery_window_size: mrws,
699 max_number_media_packets: mnmp,
700 }
701 }
702 Ok(ServiceCategory::ContentProtection) => {
703 let cp_err = Err(Error::RequestInvalid(ErrorCode::BadCpFormat));
704 if from.len() < 4
705 || length_of_capability < 2
706 || from.len() < length_of_capability + 2
707 {
708 return cp_err;
709 }
710 let cp_type: u16 = ((from[3] as u16) << 8) + from[2] as u16;
711 let protection_type = match ContentProtectionType::try_from(cp_type) {
712 Ok(val) => val,
713 Err(_) => return cp_err,
714 };
715 let extra_len = length_of_capability - 2;
716 let mut extra = vec![0; extra_len];
717 extra.copy_from_slice(&from[4..4 + extra_len]);
718 ServiceCapability::ContentProtection { protection_type, extra }
719 }
720 Ok(ServiceCategory::MediaCodec) => {
721 let err = Err(Error::RequestInvalid(ErrorCode::BadPayloadFormat));
722 if from.len() < 4
723 || length_of_capability < 2
724 || from.len() < length_of_capability + 2
725 {
726 return err;
727 }
728 let media_type = match MediaType::try_from(from[2] >> 4) {
729 Ok(media) => media,
730 Err(_) => return err,
731 };
732 let codec_type = MediaCodecType::new(from[3]);
733 let extra_len = length_of_capability - 2;
734 let mut codec_extra = vec![0; extra_len];
735 codec_extra.copy_from_slice(&from[4..4 + extra_len]);
736 ServiceCapability::MediaCodec { media_type, codec_type, codec_extra }
737 }
738 Ok(ServiceCategory::DelayReporting) => match length_of_capability {
739 0 => ServiceCapability::DelayReporting,
740 _ => return Err(Error::RequestInvalid(ErrorCode::BadPayloadFormat)),
741 },
742 Ok(ServiceCategory::Multiplexing) => {
743 ServiceCapability::Multiplexing { payload_len: length_of_capability as u8 }
744 }
745 Ok(ServiceCategory::HeaderCompression) => {
746 ServiceCapability::HeaderCompression { payload_len: length_of_capability as u8 }
747 }
748 _ => {
749 return Err(Error::RequestInvalid(ErrorCode::BadServiceCategory));
750 }
751 };
752 Ok(d)
753 }
754}
755
756impl Encodable for ServiceCapability {
757 type Error = Error;
758
759 fn encoded_len(&self) -> usize {
760 2 + self.length_of_service_capabilities() as usize
761 }
762
763 fn encode(&self, buf: &mut [u8]) -> Result<()> {
764 if buf.len() < self.encoded_len() {
765 return Err(Error::Encoding);
766 }
767 let mut cursor = Cursor::new(buf);
768 let _ = cursor
769 .write(&[u8::from(&self.category()), self.length_of_service_capabilities()])
770 .map_err(|_| Error::Encoding)?;
771 match self {
772 ServiceCapability::Recovery {
773 recovery_type: t,
774 max_recovery_window_size: max_size,
775 max_number_media_packets: max_packets,
776 } => {
777 let _ =
778 cursor.write(&[*t, *max_size, *max_packets]).map_err(|_| Error::Encoding)?;
779 }
780 ServiceCapability::MediaCodec { media_type, codec_type, codec_extra } => {
781 let _ = cursor
782 .write(&[u8::from(media_type) << 4, codec_type.0])
783 .map_err(|_| Error::Encoding)?;
784 let _ = cursor.write(codec_extra.as_slice()).map_err(|_| Error::Encoding)?;
785 }
786 ServiceCapability::ContentProtection { protection_type, extra } => {
787 let _ =
788 cursor.write(&protection_type.to_le_bytes()).map_err(|_| Error::Encoding)?;
789 let _ = cursor.write(extra.as_slice()).map_err(|_| Error::Encoding)?;
790 }
791 _ => {}
792 }
793 Ok(())
794 }
795}
796
797#[derive(Debug, PartialEq)]
800pub struct StreamInformation {
801 id: StreamEndpointId,
802 in_use: bool,
803 media_type: MediaType,
804 endpoint_type: EndpointType,
805}
806
807impl StreamInformation {
808 pub fn new(
811 id: StreamEndpointId,
812 in_use: bool,
813 media_type: MediaType,
814 endpoint_type: EndpointType,
815 ) -> StreamInformation {
816 StreamInformation { id, in_use, media_type, endpoint_type }
817 }
818
819 pub fn id(&self) -> &StreamEndpointId {
820 &self.id
821 }
822
823 pub fn media_type(&self) -> &MediaType {
824 &self.media_type
825 }
826
827 pub fn endpoint_type(&self) -> &EndpointType {
828 &self.endpoint_type
829 }
830
831 pub fn in_use(&self) -> &bool {
832 &self.in_use
833 }
834}
835
836impl Decodable for StreamInformation {
837 type Error = Error;
838
839 fn decode(from: &[u8]) -> Result<Self> {
840 if from.len() < 2 {
841 return Err(Error::InvalidMessage);
842 }
843 let id = StreamEndpointId::from_msg(&from[0]);
844 let in_use: bool = from[0] & 0x02 != 0;
845 let media_type = MediaType::try_from(from[1] >> 4)?;
846 let endpoint_type = EndpointType::try_from((from[1] >> 3) & 0x1)?;
847 Ok(StreamInformation { id, in_use, media_type, endpoint_type })
848 }
849}
850
851impl Encodable for StreamInformation {
852 type Error = Error;
853
854 fn encoded_len(&self) -> usize {
855 2
856 }
857
858 fn encode(&self, into: &mut [u8]) -> Result<()> {
859 if into.len() < self.encoded_len() {
860 return Err(Error::Encoding);
861 }
862 into[0] = self.id.to_msg() | if self.in_use { 0x02 } else { 0x00 };
863 into[1] = u8::from(&self.media_type) << 4 | u8::from(&self.endpoint_type) << 3;
864 Ok(())
865 }
866}
867
868#[cfg(test)]
869mod test {
870 use super::*;
871 use assert_matches::assert_matches;
872
873 #[test]
874 fn remote_reject_from_params_short() {
875 let r = RemoteReject::from_params(SignalIdentifier::Discover, &[]);
876 assert_eq!(None, r.error_code());
877 assert_eq!(None, r.service_category());
878 assert_eq!(None, r.stream_id());
879
880 let r = RemoteReject::from_params(SignalIdentifier::Start, &[0x12]);
881 assert_eq!(None, r.error_code());
882 assert_eq!(None, r.service_category());
883 assert_eq!(Some(StreamEndpointId(4)), r.stream_id());
884
885 let r = RemoteReject::from_params(SignalIdentifier::SetConfiguration, &[0x02]);
886 assert_eq!(None, r.error_code());
887 assert_eq!(Some(Ok(ServiceCategory::Reporting)), r.service_category());
888 assert_eq!(None, r.stream_id());
889 }
890
891 #[test]
892 fn remote_reject_ignores_unexpected_params() {
893 let r: RemoteReject =
894 RemoteReject::from_params(SignalIdentifier::Open, &[0x01, 0x02, 0x03, 0x04]);
895 assert_eq!(Some(Ok(ErrorCode::BadHeaderFormat)), r.error_code());
896 assert_eq!(None, r.service_category());
897 assert_eq!(None, r.stream_id());
898
899 let r: RemoteReject = RemoteReject::from_params(
900 SignalIdentifier::SetConfiguration,
901 &[0x02, 0x12, 0x03, 0x04],
902 );
903 assert_eq!(Some(Ok(ErrorCode::BadAcpSeid)), r.error_code());
904 assert_eq!(Some(Ok(ServiceCategory::Reporting)), r.service_category());
905 assert_eq!(None, r.stream_id());
906
907 let r: RemoteReject =
908 RemoteReject::from_params(SignalIdentifier::Start, &[0x04, 0x01, 0x03, 0x04]);
909 assert_eq!(Some(Ok(ErrorCode::BadHeaderFormat)), r.error_code());
910 assert_eq!(None, r.service_category());
911 assert_eq!(Some(StreamEndpointId(1)), r.stream_id());
912 }
913
914 #[test]
915 fn remote_reject_unrecognized_category() {
916 let r: RemoteReject =
917 RemoteReject::from_params(SignalIdentifier::SetConfiguration, &[0xF0, 0x01]);
918 assert_eq!(Some(Ok(ErrorCode::BadHeaderFormat)), r.error_code());
919 assert_eq!(Some(Err(0xF0)), r.service_category());
920 assert_eq!(None, r.stream_id());
921 }
922
923 #[test]
924 fn remote_reject_unrecognized_errorcode() {
925 let r: RemoteReject = RemoteReject::from_params(SignalIdentifier::Discover, &[0xF1]);
926 assert_eq!(Some(Err(0xF1)), r.error_code());
927 assert_eq!(None, r.service_category());
928 assert_eq!(None, r.stream_id());
929 }
930
931 #[test]
932 fn txlabel_tofrom_u8() {
933 let mut label: Result<TxLabel> = TxLabel::try_from(15);
934 assert!(label.is_ok());
935 assert_eq!(15, u8::from(&label.unwrap()));
936 label = TxLabel::try_from(16);
937 assert_matches!(label, Err(Error::OutOfRange));
938 }
939
940 #[test]
941 fn txlabel_to_usize() {
942 let label = TxLabel::try_from(1).unwrap();
943 assert_eq!(1, usize::from(&label));
944 }
945
946 #[test]
947 fn test_capability_inspection() {
948 let sbc_codec = ServiceCapability::MediaCodec {
949 media_type: MediaType::Audio,
950 codec_type: MediaCodecType::AUDIO_SBC.clone(),
951 codec_extra: vec![0x01],
952 };
953 let transport = ServiceCapability::MediaTransport;
954
955 assert!(sbc_codec.is_application());
956 assert!(!transport.is_application());
957
958 assert!(sbc_codec.is_codec());
959 assert!(!transport.is_codec());
960
961 assert_eq!(Some(&MediaCodecType::AUDIO_SBC), sbc_codec.codec_type());
962 assert_eq!(None, transport.codec_type());
963 }
964}