async_osc/
osc.rs

1use async_std::net::{ToSocketAddrs, UdpSocket};
2use async_std::stream::Stream;
3use futures_lite::ready;
4use rosc::OscPacket;
5use std::io;
6use std::net::SocketAddr;
7use std::pin::Pin;
8use std::sync::Arc;
9use std::task::{Context, Poll};
10
11use crate::error::Error;
12use crate::prelude::IntoOscPacket;
13use crate::udp::UdpSocketStream;
14
15/// A UDP socket to send and receive OSC messages.
16#[derive(Debug)]
17pub struct OscSocket {
18    socket: UdpSocketStream,
19}
20
21impl OscSocket {
22    /// Creates a new OSC socket from a [`async_std::net::UdpSocket`].
23    pub fn new(socket: UdpSocket) -> Self {
24        let socket = UdpSocketStream::new(socket);
25        Self { socket }
26    }
27
28    /// Creates an OSC socket from the given address.
29    ///
30    /// Binding with a port number of 0 will request that the OS assigns a port to this socket.
31    /// The port allocated can be queried via [`local_addr`] method.
32    ///
33    /// [`local_addr`]: #method.local_addr
34    pub async fn bind<A: ToSocketAddrs>(addr: A) -> Result<Self, Error> {
35        let socket = UdpSocket::bind(addr).await?;
36        Ok(Self::new(socket))
37    }
38
39    /// Connects the UDP socket to a remote address.
40    ///
41    /// When connected, only messages from this address will be received and the [`send`] method
42    /// will use the specified address for sending.
43    ///
44    /// [`send`]: #method.send
45    ///
46    /// # Examples
47    ///
48    /// ```no_run
49    /// # fn main() -> async_osc::Result<()> { async_std::task::block_on(async {
50    /// #
51    /// use async_osc::{prelude::*, OscSocket, OscMessage};
52    ///
53    /// let socket = OscSocket::bind("127.0.0.1:0").await?;
54    /// socket.connect("127.0.0.1:8080").await?;
55    /// #
56    /// # Ok(()) }) }
57    /// ```
58    pub async fn connect<A: ToSocketAddrs>(&self, addrs: A) -> Result<(), Error> {
59        self.socket().connect(addrs).await?;
60        Ok(())
61    }
62
63    /// Sends an OSC packet on the socket to the given address.
64    ///
65    /// # Examples
66    ///
67    /// ```no_run
68    /// # fn main() -> async_osc::Result<()> { async_std::task::block_on(async {
69    /// #
70    /// use async_osc::{prelude::*, OscSocket, OscMessage};
71    ///
72    /// let socket = OscSocket::bind("127.0.0.1:0").await?;
73    /// let addr = "127.0.0.1:5010";
74    /// let message = OscMessage::new("/volume", (0.8,));
75    /// socket.send_to(message, &addr).await?;
76    /// #
77    /// # Ok(()) }) }
78    /// ```
79    pub async fn send_to<A: ToSocketAddrs, P: IntoOscPacket>(
80        &self,
81        packet: P,
82        addrs: A,
83    ) -> Result<(), Error> {
84        let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
85        let n = self.socket().send_to(&buf[..], addrs).await?;
86        check_len(&buf[..], n)
87    }
88
89    /// Sends a packet on the socket to the remote address to which it is connected.
90    ///
91    /// The [`connect`] method will connect this socket to a remote address.
92    /// This method will fail if the socket is not connected.
93    ///
94    /// [`connect`]: #method.connect
95    ///
96    /// # Examples
97    ///
98    /// ```no_run
99    /// # fn main() -> async_osc::Result<()> { async_std::task::block_on(async {
100    /// #
101    /// use async_osc::{prelude::*, OscSocket, OscMessage};
102    ///
103    /// let socket = OscSocket::bind("127.0.0.1:34254").await?;
104    /// socket.connect("127.0.0.1:8080").await?;
105    /// socket.send(("/volume", (1.0f32,))).await?;
106    /// #
107    /// # Ok(()) }) }
108    /// ```
109    pub async fn send<P: IntoOscPacket>(&self, packet: P) -> Result<(), Error> {
110        let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
111        let n = self.socket().send(&buf[..]).await?;
112        check_len(&buf[..], n)
113    }
114
115    /// Create a standalone sender for this socket.
116    ///
117    /// The sender can be moved to other threads or tasks.
118    pub fn sender(&self) -> OscSender {
119        OscSender::new(self.socket.clone_inner())
120    }
121
122    /// Get a reference to the underling [`UdpSocket`].
123    pub fn socket(&self) -> &UdpSocket {
124        self.socket.get_ref()
125    }
126
127    /// Returns the local address that this socket is bound to.
128    ///
129    /// This can be useful, for example, when binding to port 0 to figure out which port was
130    /// actually bound.
131    pub fn local_addr(&self) -> Result<SocketAddr, Error> {
132        let addr = self.socket().local_addr()?;
133        Ok(addr)
134    }
135}
136
137impl Stream for OscSocket {
138    type Item = Result<(OscPacket, SocketAddr), Error>;
139    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
140        let packet = ready!(Pin::new(&mut self.socket).poll_next(cx));
141        let message = match packet {
142            None => None,
143            Some(packet) => Some(match packet {
144                Err(err) => Err(err.into()),
145                Ok((buf, peer_addr)) => rosc::decoder::decode(&buf[..])
146                    .map_err(|e| e.into())
147                    .map(|p| (p, peer_addr)),
148            }),
149        };
150        Poll::Ready(message)
151    }
152}
153
154/// A sender to send messages over an OSC socket.
155///
156/// See [`OscSocket::sender`].
157#[derive(Clone, Debug)]
158pub struct OscSender {
159    socket: Arc<UdpSocket>,
160}
161
162impl OscSender {
163    fn new(socket: Arc<UdpSocket>) -> Self {
164        Self { socket }
165    }
166
167    /// Sends an OSC packet on the socket to the given address.
168    ///
169    /// See [`OscSocket::send_to`].
170    pub async fn send_to<A: ToSocketAddrs, P: IntoOscPacket>(
171        &self,
172        packet: P,
173        addrs: A,
174    ) -> Result<(), Error> {
175        let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
176        let n = self.socket().send_to(&buf[..], addrs).await?;
177        check_len(&buf[..], n)
178    }
179
180    /// Sends an OSC packet on the connected socket.
181    ///
182    /// See [`OscSocket::send`].
183    pub async fn send<P: IntoOscPacket>(&self, packet: P) -> Result<(), Error> {
184        let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
185        let n = self.socket().send(&buf[..]).await?;
186        check_len(&buf[..], n)
187    }
188
189    /// Get a reference to the underling [`UdpSocket`].
190    pub fn socket(&self) -> &UdpSocket {
191        &*self.socket
192    }
193}
194
195fn check_len(buf: &[u8], len: usize) -> Result<(), Error> {
196    if len != buf.len() {
197        Err(io::Error::new(io::ErrorKind::Interrupted, "UDP packet not fully sent").into())
198    } else {
199        Ok(())
200    }
201}