bt_avdtp/
types.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use packet_encoding::{decodable_enum, Decodable, Encodable};
6use std::io::{Cursor, Write};
7use std::{fmt, result};
8use thiserror::Error;
9
10/// Result type for AVDTP, using avdtp::Error
11pub type Result<T> = result::Result<T, Error>;
12
13/// The error type of the AVDTP library.
14#[derive(Error, Debug)]
15#[non_exhaustive]
16pub enum Error {
17    /// The value that was sent on the wire was out of range.
18    #[error("Value was out of range")]
19    OutOfRange,
20
21    /// The signal identifier was invalid when parsing a message.
22    #[error("Invalid signal id for {:?}: {:X?}", _0, _1)]
23    InvalidSignalId(TxLabel, u8),
24
25    /// The header was invalid when parsing a message from the peer.
26    #[error("Invalid Header for a AVDTP message")]
27    InvalidHeader,
28
29    /// The body format was invalid when parsing a message from the peer.
30    #[error("Failed to parse AVDTP message contents")]
31    InvalidMessage,
32
33    /// The remote end failed to respond to this command in time.
34    #[error("Command timed out")]
35    Timeout,
36
37    /// The Remote end rejected a command we sent (with this error code)
38    #[error("Remote end rejected the command ({:})", _0)]
39    RemoteRejected(#[from] RemoteReject),
40
41    /// When a message hasn't been implemented yet, the parser will return this.
42    #[error("Message has not been implemented yet")]
43    UnimplementedMessage,
44
45    /// The distant peer has disconnected.
46    #[error("Peer has disconnected")]
47    PeerDisconnected,
48
49    /// Sent if a Command Future is polled after it's already completed
50    #[error("Command Response has already been received")]
51    AlreadyReceived,
52
53    /// Encountered an IO error setting up the channel
54    #[error("Encountered an IO error reading from the peer: {}", _0)]
55    ChannelSetup(zx::Status),
56
57    /// Encountered an IO error reading from the peer.
58    #[error("Encountered an IO error reading from the peer: {}", _0)]
59    PeerRead(zx::Status),
60
61    /// Encountered an IO error reading from the peer.
62    #[error("Encountered an IO error writing to the peer: {}", _0)]
63    PeerWrite(zx::Status),
64
65    /// A message couldn't be encoded.
66    #[error("Encountered an error encoding a message")]
67    Encoding,
68
69    /// An error has been detected, and the request that is being handled
70    /// should be rejected with the error code given.
71    #[error("Invalid request detected: {:?}", _0)]
72    RequestInvalid(ErrorCode),
73
74    /// Same as RequestInvalid, but an extra byte is included, which is used
75    /// in Stream and Configure responses
76    #[error("Invalid request detected: {:?} (extra: {:?})", _0, _1)]
77    RequestInvalidExtra(ErrorCode, u8),
78
79    /// An operation was attempted in an Invalid State
80    #[error("Invalid State")]
81    InvalidState,
82
83    /// An error from another source
84    #[error(transparent)]
85    Other(#[from] anyhow::Error),
86}
87
88/// Errors that can be returned by the remote peer in response to a message
89#[derive(Error, Debug)]
90#[cfg_attr(test, derive(PartialEq))]
91pub struct RemoteReject {
92    /// The signal identifier in this rejection.
93    /// This is the only field populated for a General Rejection, which only occurs when the remote
94    /// end does not understand the SignalIdentifier (but we do, or we would return a
95    /// `Error::InvalidHeader`)
96    signal_id: SignalIdentifier,
97    /// Error code reported for this error.
98    error_code: Option<u8>,
99    /// The service category reported that applies to this error.  Only set when `signal_id` is
100    /// SetConfiguration or Reconfigure.
101    service_category: Option<u8>,
102    /// The StreamEndpointId reported that applies for this rejection.
103    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            // General Reject
110            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                // The Stream ID here is in the top 6 bits, with the bottom 2 bits RFA.
123                (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    /// Retrieve the error code returned by the remote end.
131    /// Returns Some(Err(u8)) if the code isn't recognized, or None if it wasn't included
132    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    /// Retrieve the ServiceCategory returned by the remote end.
137    /// Returns Err(u8) if the category wasn't recognized, or None if it wasn't included
138    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    /// Retrieve the stream identifier returned from the remote end.
143    /// Returns None if it wasn't included.
144    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    /// Error Codes that can be returned as part of a reject message.
201    /// See Section 8.20.6
202    pub enum ErrorCode<u8, Error, OutOfRange> {
203        // Header Error Codes
204        BadHeaderFormat = 0x01,
205
206        // Payload Format Error Codes
207        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        // Transport Service Capabilities Error Codes
217        BadRecoveryType = 0x22,
218        BadMediaTransportFormat = 0x23,
219        BadRecoveryFormat = 0x25,
220        BadRohcFormat = 0x26,
221        BadCpFormat = 0x27,
222        BadMultiplexingFormat = 0x28,
223        UnsupportedConfiguration = 0x29,
224
225        // Procedure Error Codes
226        BadState = 0x31,
227    }
228}
229
230/// An AVDTP Transaction Label
231/// Not used outside the library.  Public as part of some internal Error variants.
232/// See Section 8.4.1
233#[derive(Debug, Clone, Copy, PartialEq)]
234pub struct TxLabel(u8);
235
236// Transaction labels are only 4 bits.
237const 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    /// Type of media
265    /// USed to specify the type of media on a stream endpoint.
266    /// Part of the StreamInformation in Discovery Response.
267    /// Defined in the Bluetooth Assigned Numbers
268    /// https://www.bluetooth.com/specifications/assigned-numbers/audio-video
269    pub enum MediaType<u8, Error, OutOfRange> {
270        Audio = 0x00,
271        Video = 0x01,
272        Multimedia = 0x02,
273    }
274}
275
276decodable_enum! {
277    /// Type of endpoint (source or sync)
278    /// Part of the StreamInformation in Discovery Response.
279    /// See Section 8.20.3
280    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    /// Indicated whether this packet is part of a fragmented packet set.
297    /// See Section 8.4.2
298    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    /// Specifies the command type of each signaling command or the response
308    /// type of each response packet.
309    /// See Section 8.4.3
310    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    /// Indicates the signaling command on a command packet.  The same identifier is used on the
320    /// response to that command packet.
321    /// See Section 8.4.4
322    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/// A Stream Endpoint Identifier, aka SEID, INT SEID, ACP SEID - Sec 8.20.1
436/// Valid values are 0x01 - 0x3E
437#[derive(Debug, PartialEq, Eq, Clone, Hash)]
438pub struct StreamEndpointId(pub(crate) u8);
439
440impl StreamEndpointId {
441    /// Interpret a StreamEndpointId from the upper six bits of a byte, which
442    /// is often how it's transmitted in a message.
443    pub(crate) fn from_msg(byte: &u8) -> Self {
444        StreamEndpointId(byte >> 2)
445    }
446
447    /// Produce a byte where the SEID value is placed in the upper six bits,
448    /// which is often how it is placed in a message.
449    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/// The type of the codec in the MediaCodec Service Capability
473/// Valid values are defined in the Bluetooth Assigned Numbers and are
474/// interpreted differently for different Media Types, so we do not interpret
475/// them here.
476/// Associated constants are provided that specify the value of `MediaCodecType`
477/// for different codecs given the `MediaType::Audio`.
478/// See https://www.bluetooth.com/specifications/assigned-numbers/audio-video
479#[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/// The type of content protection used in the Content Protection Service Capability.
508/// Defined in the Bluetooth Assigned Numbers
509/// https://www.bluetooth.com/specifications/assigned-numbers/audio-video
510#[derive(Debug, PartialEq, Clone)]
511pub enum ContentProtectionType {
512    DigitalTransmissionContentProtection, // DTCP, 0x0001
513    SerialCopyManagementSystem,           // SCMS-T, 0x0002
514}
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    /// Indicates the signaling command on a command packet.  The same identifier is used on the
539    /// response to that command packet.
540    /// See Section 8.4.4
541    #[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/// Service Capabilities indicate possible services that can be provided by
556/// each stream endpoint.  See AVDTP Spec section 8.21.
557#[derive(Debug, PartialEq, Clone)]
558pub enum ServiceCapability {
559    /// Indicates that the end point can provide at least basic media transport
560    /// service as defined by RFC 3550 and outlined in section 7.2.
561    /// Defined in section 8.21.2
562    MediaTransport,
563    /// Indicates that the end point can provide reporting service as outlined in section 7.3
564    /// Defined in section 8.21.3
565    Reporting,
566    /// Indicates the end point can provide recovery service as outlined in section 7.4
567    /// Defined in section 8.21.4
568    Recovery { recovery_type: u8, max_recovery_window_size: u8, max_number_media_packets: u8 },
569    /// Indicates the codec which is supported by this end point. |codec_extra| is defined within
570    /// the relevant profiles (A2DP for Audio, etc).
571    /// Defined in section 8.21.5
572    MediaCodec {
573        media_type: MediaType,
574        codec_type: MediaCodecType,
575        codec_extra: Vec<u8>, // TODO: Media codec specific information elements
576    },
577    /// Present when the device has content protection capability.
578    /// |extra| is defined elsewhere.
579    /// Defined in section 8.21.6
580    ContentProtection {
581        protection_type: ContentProtectionType,
582        extra: Vec<u8>, // Protection specific parameters
583    },
584    /// Indicates that header compression capabilities is offered  by this end point.
585    /// Defined in section 8.21.7
586    /// TODO(https://fxbug.dev/42114013): Implement header compression specific fields to use the payload.
587    HeaderCompression { payload_len: u8 },
588    /// Indicates that multiplexing service is offered by this end point.
589    /// Defined in section 8.21.8
590    /// TODO(https://fxbug.dev/42114015): Implement multiplexing specific fields to use the payload.
591    Multiplexing { payload_len: u8 },
592    /// Indicates that delay reporting is offered by this end point.
593    /// Defined in section 8.21.9
594    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    /// True when this ServiceCapability is a "basic" capability.
625    /// See Table 8.47 in Section 8.21.1
626    pub(crate) fn is_basic(&self) -> bool {
627        match self {
628            ServiceCapability::DelayReporting => false,
629            _ => true,
630        }
631    }
632
633    /// True when this capability should be included in the response to a |sig| command.
634    pub(crate) fn in_response(&self, sig: SignalIdentifier) -> bool {
635        sig != SignalIdentifier::GetCapabilities || self.is_basic()
636    }
637
638    /// True when this capability is classified as an "Application Service Capability"
639    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                // Check format of parameters. See Section 8.21.4, Table 8.51
688                // The only recovery type is RFC2733 (0x01)
689                if recovery_type != 0x01 {
690                    return Err(Error::RequestInvalid(ErrorCode::BadRecoveryType));
691                }
692                // The MRWS and MNMP must be 0x01 - 0x18
693                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/// All information related to a stream. Part of the Discovery Response.
798/// See Sec 8.6.2
799#[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    /// Create a new StreamInformation from an ID.
809    /// This will only fail if the ID given is out of the range of valid SEIDs (0x01 - 0x3E)
810    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}