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}