vmc/lib.rs
1//! An asynchronous implementation of the [Virtual Motion Capture Protocol](https://protocol.vmc.info/) in Rust.
2//!
3//! ### Performer
4//! ```no_run
5//! use vmc::{ApplyBlendShapes, BlendShape, ModelState, StandardVRMBlendShape, State, Time};
6//!
7//! #[tokio::main]
8//! async fn main() -> vmc::Result<()> {
9//! let socket = vmc::performer!("127.0.0.1:39539").await?;
10//! loop {
11//! socket.send(BlendShape::new(StandardVRMBlendShape::Joy, 1.0)).await?;
12//! socket.send(ApplyBlendShapes).await?;
13//! socket.send(State::new(ModelState::Loaded)).await?;
14//! socket.send(Time::elapsed()).await?;
15//! }
16//! }
17//! ```
18//!
19//! ### Marionette
20//! ```no_run
21//! use futures_util::StreamExt;
22//! use vmc::Message;
23//!
24//! #[tokio::main]
25//! async fn main() -> vmc::Result<()> {
26//! let mut socket = vmc::marionette!("127.0.0.1:39539").await?;
27//! while let Some(packet) = socket.next().await {
28//! let (packet, _) = packet?;
29//! for message in vmc::parse(packet)? {
30//! match message {
31//! Message::BoneTransform(transform) => {
32//! println!(
33//! "\tTransform bone: {} (pos {:?}; rot {:?})",
34//! transform.bone, transform.position, transform.rotation
35//! )
36//! }
37//! _ => {}
38//! }
39//! }
40//! }
41//!
42//! Ok(())
43//! }
44//! ```
45
46#![allow(clippy::tabs_in_doc_comments)]
47
48use std::{
49 io,
50 net::SocketAddr,
51 pin::Pin,
52 sync::Arc,
53 task::{Context, Poll}
54};
55
56use futures_core::Stream;
57use rosc::OscPacket;
58use tokio::net::{ToSocketAddrs, UdpSocket};
59
60mod definitions;
61mod error;
62pub mod message;
63pub extern crate rosc;
64mod udp;
65
66use self::udp::UDPSocketStream;
67pub use self::{
68 definitions::*,
69 error::{Error, Result},
70 message::{ApplyBlendShapes, BlendShape, BoneTransform, DeviceTransform, Message, RootTransform, State, Time, parse}
71};
72
73pub(crate) trait IntoOSCMessage {
74 fn into_osc_message(self) -> rosc::OscMessage;
75}
76
77pub trait IntoOSCPacket {
78 fn into_osc_packet(self) -> rosc::OscPacket;
79}
80
81impl<T> IntoOSCPacket for T
82where
83 T: IntoOSCMessage
84{
85 fn into_osc_packet(self) -> rosc::OscPacket {
86 rosc::OscPacket::Message(self.into_osc_message())
87 }
88}
89
90impl IntoOSCPacket for rosc::OscBundle {
91 fn into_osc_packet(self) -> rosc::OscPacket {
92 rosc::OscPacket::Bundle(self)
93 }
94}
95
96/// A UDP socket to send and receive VMC messages.
97#[derive(Debug)]
98pub struct VMCSocket {
99 socket: UDPSocketStream
100}
101
102impl VMCSocket {
103 /// Creates a new OSC socket from a [`tokio::net::UdpSocket`].
104 pub fn new(socket: UdpSocket) -> Self {
105 let socket = UDPSocketStream::new(socket);
106 Self { socket }
107 }
108
109 /// Creates an VMC socket from the given address.
110 ///
111 /// Binding with a port number of 0 will request that the OS assigns a port to this socket.
112 /// The port allocated can be queried via [`local_addr`] method.
113 ///
114 /// [`local_addr`]: #method.local_addr
115 pub async fn bind<A: ToSocketAddrs>(addr: A) -> Result<Self> {
116 let socket = UdpSocket::bind(addr).await?;
117 Ok(Self::new(socket))
118 }
119
120 /// Connects the UDP socket to a remote address.
121 ///
122 /// When connected, only messages from this address will be received and the [`send`] method
123 /// will use the specified address for sending.
124 ///
125 /// [`send`]: #method.send
126 ///
127 /// # Examples
128 ///
129 /// ```no_run
130 /// # fn main() -> vmc::Result<()> { tokio_test::block_on(async {
131 /// use vmc::VMCSocket;
132 ///
133 /// let socket = VMCSocket::bind("127.0.0.1:0").await?;
134 /// socket.connect("127.0.0.1:8080").await?;
135 /// # Ok(()) }) }
136 /// ```
137 pub async fn connect<A: ToSocketAddrs>(&self, addrs: A) -> Result<()> {
138 self.socket().connect(addrs).await?;
139 Ok(())
140 }
141
142 /// Sends an OSC packet on the socket to the given address.
143 ///
144 /// # Examples
145 ///
146 /// ```no_run
147 /// # fn main() -> vmc::Result<()> { tokio_test::block_on(async {
148 /// use vmc::{BlendShape, StandardVRMBlendShape, VMCSocket};
149 ///
150 /// let socket = VMCSocket::bind("127.0.0.1:0").await?;
151 /// let addr = "127.0.0.1:39539";
152 /// let message = BlendShape::new(StandardVRMBlendShape::Joy, 1.0);
153 /// socket.send_to(message, &addr).await?;
154 /// # Ok(()) }) }
155 /// ```
156 pub async fn send_to<A: ToSocketAddrs, P: IntoOSCPacket>(&self, packet: P, addrs: A) -> Result<()> {
157 let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
158 let n = self.socket().send_to(&buf[..], addrs).await?;
159 check_len(&buf[..], n)
160 }
161
162 /// Sends a packet on the socket to the remote address to which it is connected.
163 ///
164 /// The [`connect`] method will connect this socket to a remote address.
165 /// This method will fail if the socket is not connected.
166 ///
167 /// [`connect`]: #method.connect
168 ///
169 /// # Examples
170 ///
171 /// ```no_run
172 /// # fn main() -> vmc::Result<()> { tokio_test::block_on(async {
173 /// use vmc::{BlendShape, StandardVRMBlendShape, VMCSocket};
174 ///
175 /// let socket = VMCSocket::bind("127.0.0.1:2434").await?;
176 /// socket.connect("127.0.0.1:39539").await?;
177 /// socket.send(BlendShape::new(StandardVRMBlendShape::Joy, 1.0)).await?;
178 /// #
179 /// # Ok(()) }) }
180 /// ```
181 pub async fn send<P: IntoOSCPacket>(&self, packet: P) -> Result<()> {
182 let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
183 let n = self.socket().send(&buf[..]).await?;
184 check_len(&buf[..], n)
185 }
186
187 /// Create a standalone sender for this socket.
188 ///
189 /// The sender can be moved to other threads or tasks.
190 pub fn sender(&self) -> VMCSender {
191 VMCSender::new(self.socket.clone_inner())
192 }
193
194 /// Get a reference to the underling [`UdpSocket`].
195 pub fn socket(&self) -> &UdpSocket {
196 self.socket.get_ref()
197 }
198
199 /// Returns the local address that this socket is bound to.
200 ///
201 /// This can be useful, for example, when binding to port 0 to figure out which port was
202 /// actually bound.
203 pub fn local_addr(&self) -> Result<SocketAddr> {
204 let addr = self.socket().local_addr()?;
205 Ok(addr)
206 }
207}
208
209impl Stream for VMCSocket {
210 type Item = Result<(OscPacket, SocketAddr)>;
211 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
212 let packet = match Pin::new(&mut self.socket).poll_next(cx) {
213 Poll::Ready(packet) => packet,
214 Poll::Pending => return Poll::Pending
215 };
216 let message = packet.map(|packet| match packet {
217 Err(err) => Err(err.into()),
218 Ok((buf, peer_addr)) => rosc::decoder::decode_udp(&buf[..]).map_err(|e| e.into()).map(|p| (p.1, peer_addr))
219 });
220 Poll::Ready(message)
221 }
222}
223
224/// A sender to send messages over a VMC socket.
225///
226/// See [`VMCSocket::sender`].
227#[derive(Clone, Debug)]
228pub struct VMCSender {
229 socket: Arc<UdpSocket>
230}
231
232impl VMCSender {
233 fn new(socket: Arc<UdpSocket>) -> Self {
234 Self { socket }
235 }
236
237 /// Sends a VMC packet on the socket to the given address.
238 ///
239 /// See [`VMCSocket::send_to`].
240 pub async fn send_to<A: ToSocketAddrs, P: IntoOSCPacket>(&self, packet: P, addrs: A) -> Result<()> {
241 let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
242 let n = self.socket().send_to(&buf[..], addrs).await?;
243 check_len(&buf[..], n)
244 }
245
246 /// Sends a VMC packet on the connected socket.
247 ///
248 /// See [`VMCSocket::send`].
249 pub async fn send<P: IntoOSCPacket>(&self, packet: P) -> Result<()> {
250 let buf = rosc::encoder::encode(&packet.into_osc_packet())?;
251 let n = self.socket().send(&buf[..]).await?;
252 check_len(&buf[..], n)
253 }
254
255 /// Get a reference to the underling [`UdpSocket`].
256 pub fn socket(&self) -> &UdpSocket {
257 &self.socket
258 }
259}
260
261/// Creates a new VMC Performer. Performers process tracking, motion, and IK, and send bone transforms and other
262/// information to a [`marionette`].
263///
264/// The default usage of this usage will automatically select a free port to bind to, and send information to port 39539
265/// (default VMC receiver port) on the local machine.
266///
267/// The behavior of both binding and sending can be customized:
268/// ```no_run
269/// # fn main() -> vmc::Result<()> { tokio_test::block_on(async {
270/// // default; binds to random port, sends to 127.0.0.1:39539
271/// let performer = vmc::performer!().await?;
272/// // customize bound port
273/// let performer = vmc::performer!(bind_port = 39540).await?;
274/// // customize bind address
275/// let performer = vmc::performer!(bind = "192.168.1.182:39539").await?;
276/// // customize send address & port
277/// let performer = vmc::performer!("127.13.72.16:2434").await?;
278/// // customize send address and bound port
279/// let performer = vmc::performer!("127.13.72.16:2434", bind_port = 39540).await?;
280/// # Ok(()) }) }
281/// ```
282#[macro_export]
283macro_rules! performer {
284 () => {
285 $crate::_create_performer("127.0.0.1:0", "127.0.0.1:39539")
286 };
287 (bind = $bind:expr) => {
288 $crate::_create_performer($bind, "127.0.0.1:39539")
289 };
290 (bind_port = $bind_port:expr) => {
291 $crate::_create_performer(format!("127.0.0.1:{}", $bind_port), "127.0.0.1:39539")
292 };
293 ($addr:expr) => {
294 $crate::_create_performer("127.0.0.1:0", $addr)
295 };
296 ($addr:expr, bind = $bind:expr) => {
297 $crate::_create_performer($bind, $addr)
298 };
299 ($addr:expr, bind_port = $bind_port:expr) => {
300 $crate::_create_performer(format!("127.0.0.1:{}", $bind_port), $addr)
301 };
302}
303
304#[doc(hidden)]
305pub async fn _create_performer(bind: impl ToSocketAddrs, addr: impl ToSocketAddrs) -> Result<VMCSocket> {
306 let socket = VMCSocket::bind(bind).await?;
307 socket.connect(addr).await?;
308 Ok(socket)
309}
310
311/// Creates a new VMC Marionette. Marionettes receive motion data from a [`performer`] and render the avatar to a
312/// screen.
313///
314/// The default usage of this usage will automatically bind to port 39539, the default VMC port.
315///
316/// The binding address can also be customized:
317/// ```no_run
318/// # fn main() -> vmc::Result<()> { tokio_test::block_on(async {
319/// // default; binds to 127.0.0.1:39539
320/// let marionette = vmc::marionette!().await?;
321/// // customize bind address/port
322/// let marionette = vmc::marionette!("192.168.1.193:2434").await?;
323/// # Ok(()) }) }
324/// ```
325#[macro_export]
326macro_rules! marionette {
327 () => {
328 $crate::_create_marionette("127.0.0.1:39539")
329 };
330 ($addr:expr) => {
331 $crate::_create_marionette($addr)
332 };
333}
334
335#[doc(hidden)]
336pub async fn _create_marionette(addr: impl ToSocketAddrs) -> Result<VMCSocket> {
337 let socket = VMCSocket::bind(addr).await?;
338 Ok(socket)
339}
340
341fn check_len(buf: &[u8], len: usize) -> Result<()> {
342 if len != buf.len() {
343 Err(io::Error::new(io::ErrorKind::Interrupted, "UDP packet not fully sent").into())
344 } else {
345 Ok(())
346 }
347}