-
-
Notifications
You must be signed in to change notification settings - Fork 20
/
osc.rs
114 lines (102 loc) · 3.22 KB
/
osc.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use derive_more::Display;
use rosc::OscPacket;
use serde::{Deserialize, Serialize};
use serde_with::DeserializeFromStr;
use slog::warn;
use smallvec::SmallVec;
use std::error::Error;
use std::io;
use std::net::{Ipv4Addr, SocketAddrV4, ToSocketAddrs, UdpSocket};
use std::str::FromStr;
use uuid::Uuid;
const OSC_BUFFER_SIZE: usize = 10_000;
#[derive(Debug)]
pub struct OscInputDevice {
id: OscDeviceId,
socket: UdpSocket,
logger: slog::Logger,
osc_buffer: [u8; OSC_BUFFER_SIZE],
}
impl OscInputDevice {
pub fn bind(
id: OscDeviceId,
addr: impl ToSocketAddrs,
logger: slog::Logger,
) -> Result<OscInputDevice, Box<dyn Error>> {
let socket = UdpSocket::bind(addr)?;
socket.set_nonblocking(true)?;
let dev = OscInputDevice {
id,
socket,
logger,
osc_buffer: [0; OSC_BUFFER_SIZE],
};
Ok(dev)
}
pub fn id(&self) -> &OscDeviceId {
&self.id
}
pub fn poll(&mut self) -> Result<Option<OscPacket>, &'static str> {
match self.socket.recv(&mut self.osc_buffer) {
Ok(num_bytes) => match rosc::decoder::decode(&self.osc_buffer[..num_bytes]) {
Ok(packet) => Ok(Some(packet)),
Err(err) => {
warn!(self.logger, "Error trying to decode OSC packet: {:?}", err);
Err("error trying to decode OSC messages")
}
},
Err(ref err) if err.kind() != io::ErrorKind::WouldBlock => {
warn!(self.logger, "Error trying to receive OSC packet: {}", err);
Err("error trying to receive OSC message")
}
// We don't need to handle "would block" because we are running in a loop anyway.
_ => Ok(None),
}
}
pub fn poll_multiple(&mut self, n: usize) -> impl Iterator<Item = OscPacket> + '_ {
(0..n).flat_map(move |_| self.poll().ok().flatten())
}
}
#[derive(Debug)]
pub struct OscOutputDevice {
id: OscDeviceId,
socket: UdpSocket,
logger: slog::Logger,
}
impl OscOutputDevice {
pub fn connect(
id: OscDeviceId,
addr: impl ToSocketAddrs,
logger: slog::Logger,
) -> Result<OscOutputDevice, Box<dyn Error>> {
let socket = UdpSocket::bind(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0))?;
socket.set_nonblocking(true)?;
socket.connect(addr)?;
let dev = OscOutputDevice { id, socket, logger };
Ok(dev)
}
pub fn id(&self) -> &OscDeviceId {
&self.id
}
pub fn send(&self, packet: &OscPacket) -> Result<(), &'static str> {
let bytes =
rosc::encoder::encode(packet).map_err(|_| "error trying to encode OSC packet")?;
self.socket
.send(&bytes)
.map_err(|_| "error trying to send OSC packet");
Ok(())
}
}
/// An OSC device ID.
///
/// This uniquely identifies an OSC device according to ReaLearn's device configuration.
#[derive(
Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Display, Serialize, Deserialize,
)]
#[serde(transparent)]
pub struct OscDeviceId(uuid::Uuid);
impl OscDeviceId {
pub fn random() -> OscDeviceId {
OscDeviceId(Uuid::new_v4())
}
}