| 1 | //! The RFCOMM control link: a byte stream to one channel on the buds. |
| 2 | |
| 3 | use std::os::fd::OwnedFd; |
| 4 | use std::time::{Duration, Instant}; |
| 5 | |
| 6 | use super::{Transport, classify, socket}; |
| 7 | use crate::bt::BdAddr; |
| 8 | use crate::error::{Error, Result}; |
| 9 | |
| 10 | /// Upper bound for the connect and for each send. The audio link is already up, so a healthy |
| 11 | /// connect takes well under a second. |
| 12 | const TIMEOUT: Duration = Duration::from_secs(8); |
| 13 | |
| 14 | pub struct Rfcomm { |
| 15 | fd: OwnedFd, |
| 16 | } |
| 17 | |
| 18 | impl Rfcomm { |
| 19 | pub fn connect(address: BdAddr, channel: u8) -> Result<Self> { |
| 20 | let fd = socket::connect(address, socket::Target::Rfcomm { channel }, TIMEOUT) |
| 21 | .map_err(|e| classify(e, "connecting to the control channel", true))?; |
| 22 | Ok(Self { fd }) |
| 23 | } |
| 24 | } |
| 25 | |
| 26 | impl Transport for Rfcomm { |
| 27 | fn send(&mut self, bytes: &[u8]) -> Result<()> { |
| 28 | socket::write_all(&self.fd, bytes).map_err(|e| classify(e, "sending to the buds", false)) |
| 29 | } |
| 30 | |
| 31 | fn recv(&mut self, deadline: Instant) -> Result<Option<Vec<u8>>> { |
| 32 | let readable = |
| 33 | socket::wait_readable(&self.fd, deadline).map_err(|e| classify(e, "waiting for the buds", false))?; |
| 34 | if !readable { |
| 35 | return Ok(None); |
| 36 | } |
| 37 | let mut buffer = vec![0u8; 1024]; |
| 38 | let n = socket::read(&self.fd, &mut buffer).map_err(|e| classify(e, "reading from the buds", false))?; |
| 39 | if n == 0 { |
| 40 | return Err(Error::NotConnected( |
| 41 | "the buds closed the control link (case lid closed?)".to_owned(), |
| 42 | )); |
| 43 | } |
| 44 | buffer.truncate(n); |
| 45 | Ok(Some(buffer)) |
| 46 | } |
| 47 | } |