bt_avctp/avc/
mod.rs

1// Copyright 2019 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 fuchsia_async::{MonotonicInstant, TimeoutExt};
6use fuchsia_bluetooth::types::Channel;
7use futures::future::Ready;
8use futures::stream::FilterMap;
9use futures::{future, Stream, StreamExt};
10use log::{info, trace};
11use packet_encoding::{Decodable, Encodable};
12use zx::MonotonicDuration;
13
14#[cfg(test)]
15mod tests;
16
17mod types;
18
19use crate::avctp::{
20    Command as AvctpCommand, CommandStream as AvctpCommandStream, Header as AvctpHeader,
21    Packet as AvctpPacket, Peer as AvctpPeer,
22};
23use crate::{Error, Result};
24
25use self::types::BT_SIG_COMPANY_ID;
26
27pub use self::types::{CommandType, Header, OpCode, PacketType, ResponseType, SubunitType};
28
29pub type CommandStream = FilterMap<
30    AvctpCommandStream,
31    Ready<Option<Result<Command>>>,
32    fn(Result<AvctpCommand>) -> Ready<Option<Result<Command>>>,
33>;
34
35/// Represents a received AVC Command from a `Peer`.
36#[derive(Debug)]
37pub struct Command {
38    inner: AvctpCommand,
39    avc_header: Header,
40}
41
42impl Command {
43    pub fn avctp_header(&self) -> &AvctpHeader {
44        self.inner.header()
45    }
46
47    pub fn avc_header(&self) -> &Header {
48        &self.avc_header
49    }
50
51    pub fn body(&self) -> &[u8] {
52        &self.inner.body()[self.avc_header.encoded_len()..]
53    }
54
55    pub fn send_response(&self, response_type: ResponseType, body: &[u8]) -> Result<()> {
56        let response_header = self.avc_header.create_response(response_type)?;
57        let mut rbuf = vec![0 as u8; response_header.encoded_len()];
58        response_header.encode(&mut rbuf[..])?;
59        if body.len() > 0 {
60            rbuf.extend_from_slice(body);
61        }
62        self.inner.send_response(rbuf.as_slice())
63    }
64
65    pub fn is_vendor_dependent(&self) -> bool {
66        self.avc_header.op_code() == &OpCode::VendorDependent
67    }
68}
69
70impl TryFrom<Result<AvctpCommand>> for Command {
71    type Error = Error;
72
73    fn try_from(value: Result<AvctpCommand>) -> Result<Command> {
74        let inner = match value {
75            Err(e) => return Err(e),
76            Ok(inner) => inner,
77        };
78        let avc_header = match Header::decode(inner.body()) {
79            Err(e) => return Err(e),
80            Ok(head) => head,
81        };
82        Ok(Command { inner, avc_header })
83    }
84}
85
86#[derive(Debug, Clone, PartialEq)]
87pub struct CommandResponse(pub ResponseType, pub Vec<u8>);
88
89impl CommandResponse {
90    pub fn response_type(&self) -> ResponseType {
91        return self.0;
92    }
93
94    pub fn response(&self) -> &[u8] {
95        return self.1.as_slice();
96    }
97}
98
99impl TryFrom<AvctpPacket> for CommandResponse {
100    type Error = Error;
101
102    fn try_from(value: AvctpPacket) -> Result<CommandResponse> {
103        let buf = value.body();
104        let avc_header = Header::decode(buf)?;
105        let body = buf[avc_header.encoded_len()..].to_vec();
106        if let PacketType::Response(response_type) = avc_header.packet_type() {
107            Ok(CommandResponse(response_type, body))
108        } else {
109            Err(Error::InvalidHeader)
110        }
111    }
112}
113
114/// Represents a peer connection to a remote device that uses the AV\C protocol over AVCTP encoded
115/// L2CAP socket. Primarily used for the the control channel in AVRCP.
116#[derive(Debug)]
117pub struct Peer {
118    /// The encapsulated AVCTP peer connection to the remote peer.
119    inner: AvctpPeer,
120}
121
122impl Peer {
123    /// Create a new peer object from a established L2CAP socket with the peer.
124    pub fn new(channel: Channel) -> Self {
125        Self { inner: AvctpPeer::new(channel) }
126    }
127
128    /// Decodes AV\C commands received over encapsulated AVCTP socket. Invalid AV|C commands are
129    /// converted to errors.
130    /// Note: Unit info and subunit info are responded to directly and swallowed since they return a
131    /// static response.
132    fn filter_internal_responses(
133        avct_command_result: Result<AvctpCommand>,
134    ) -> Option<Result<Command>> {
135        let cmd = match Command::try_from(avct_command_result) {
136            Ok(cmd) => cmd,
137            Err(e) => return Some(Err(e)),
138        };
139
140        // Handle some early return short cutting logic.
141        let avcth = cmd.avctp_header();
142        let avch = cmd.avc_header();
143
144        match (avcth.is_single(), avch.subunit_type(), avch.op_code()) {
145            // The only type of subunit we support other than panel is unit subunit when a
146            // unit info or sub unit info command is sent.
147            (true, Some(SubunitType::Unit), &OpCode::UnitInfo) => {
148                trace!("received UNITINFO command");
149                // The packet needs to be 8 bytes long according to spec. First three bytes are
150                // handled in the response header. Remaining buf is initialized to 0xff.
151                let mut pbuf: [u8; 5] = [0xff; 5];
152                // This constant is unexplained in the AVC spec but must always be 7.
153                pbuf[0] = 0x07;
154                // Set unit_type (bits 7-3) set to panel (0x09), and unit (bits 2-0) to 0.
155                pbuf[1] = u8::from(&SubunitType::Panel) << 3;
156                // Explicitly set company_id to 0xfffff for a generic company.
157                pbuf[2] = 0xff;
158                pbuf[3] = 0xff;
159                pbuf[4] = 0xff;
160                match cmd.send_response(ResponseType::ImplementedStable, &pbuf) {
161                    Err(e) => Some(Err(e)),
162                    Ok(_) => None,
163                }
164            }
165            (true, Some(SubunitType::Unit), &OpCode::SubUnitInfo) => {
166                trace!("received SUBUNITINFO command");
167                // The packet needs to be 8 bytes long according to spec. First three bytes are
168                // handled in the response header. Remaining buf is initialized to 0xff.
169                let mut pbuf: [u8; 5] = [0xff; 5];
170                // Set page (bits 6-4) to 0, and set all extension_code (bits 2-0) on.
171                pbuf[0] = 0b111;
172                // Set subunit_type (bits 7-3) to panel (0x09), and max_subunit_ID (bits 2-0) to 0.
173                pbuf[1] = u8::from(&SubunitType::Panel) << 3;
174                match cmd.send_response(ResponseType::ImplementedStable, &pbuf) {
175                    Err(e) => Some(Err(e)),
176                    Ok(_) => None,
177                }
178            }
179            (_, Some(SubunitType::Panel), &OpCode::Passthrough)
180            | (_, Some(SubunitType::Panel), &OpCode::VendorDependent) => Some(Ok(cmd)),
181            _ => {
182                info!("received invalid command");
183                match cmd.send_response(ResponseType::NotImplemented, &[]) {
184                    Err(e) => Some(Err(e)),
185                    Ok(_) => None,
186                }
187            }
188        }
189    }
190
191    /// Takes the command stream for incoming commands from the remote peer.
192    pub fn take_command_stream(&self) -> CommandStream {
193        self.inner
194            .take_command_stream()
195            .filter_map(|avct_command| future::ready(Self::filter_internal_responses(avct_command)))
196    }
197
198    /// The maximum amount of time we will wait for a response to a command packet.
199    fn passthrough_command_timeout() -> MonotonicDuration {
200        const CMD_TIMER_MS: i64 = 1000;
201        MonotonicDuration::from_millis(CMD_TIMER_MS)
202    }
203
204    /// Sends a vendor specific command to the remote peer. Returns a CommandResponseStream to poll
205    /// for the responses to the sent command. Returns error if the underlying socket is closed.
206    pub fn send_vendor_dependent_command<'a>(
207        &'a self,
208        command_type: CommandType,
209        payload: &'a [u8],
210    ) -> Result<impl Stream<Item = Result<CommandResponse>>> {
211        let avc_header = Header::new(
212            command_type,
213            u8::from(&SubunitType::Panel),
214            0,
215            OpCode::VendorDependent,
216            Some(BT_SIG_COMPANY_ID),
217        );
218
219        let avc_h_len = avc_header.encoded_len();
220        let mut buf = vec![0; avc_h_len];
221        avc_header.encode(&mut buf[..])?;
222        buf.extend_from_slice(payload);
223
224        let stream = self.inner.send_command(buf.as_slice())?;
225        let stream = stream.map(|resp| CommandResponse::try_from(resp?));
226        Ok(stream)
227    }
228
229    /// Sends an AVC passthrough command to the remote peer. Returns the command response ignoring
230    /// any interim responses. Returns error if the underlying socket is closed or the command isn't
231    /// acknowledged with an interim response after 1000 ms.
232    pub async fn send_avc_passthrough_command<'a>(
233        &'a self,
234        payload: &'a [u8],
235    ) -> Result<CommandResponse> {
236        let avc_header = Header::new(
237            CommandType::Control,
238            u8::from(&SubunitType::Panel),
239            0,
240            OpCode::Passthrough,
241            Some(BT_SIG_COMPANY_ID),
242        );
243
244        let avc_h_len = avc_header.encoded_len();
245        let mut buf = vec![0; avc_h_len];
246        avc_header.encode(&mut buf[..])?;
247        buf.extend_from_slice(payload);
248
249        let mut response_stream = self.inner.send_command(buf.as_slice())?;
250
251        let timeout = MonotonicInstant::after(Peer::passthrough_command_timeout());
252        loop {
253            if let Some(resp) = response_stream
254                .next()
255                .on_timeout(timeout, || return Some(Err(Error::Timeout)))
256                .await
257            {
258                let value = CommandResponse::try_from(resp?)?;
259                if value.0 == ResponseType::Interim {
260                    continue;
261                }
262                return Ok(value);
263            } else {
264                return Err(Error::PeerDisconnected);
265            }
266        }
267    }
268}