use std::net::{IpAddr, UdpSocket};
use rosc::{OscError, OscMessage, OscPacket, OscType};
use snafu::{ResultExt, Snafu};
pub struct OscSender {
target: (IpAddr, u16),
socket: UdpSocket,
}
#[derive(Debug, Snafu)]
pub enum OscSenderError {
#[snafu(display("failed to bind UDP socket to {to:#?}"))]
UDPBind {
source: std::io::Error,
to: (IpAddr, u16),
},
#[snafu(display("failed to encode OSC packet with destination {address}"))]
OSCPacketEncoding { source: OscError, address: String },
#[snafu(display("failed to send UDP packet with data: {data:#?} to {to:#?}"))]
UDPSend {
source: std::io::Error,
data: Vec<u8>,
to: (IpAddr, u16),
},
}
impl OscSender {
pub fn new(bind: (IpAddr, u16), target: (IpAddr, u16)) -> Result<Self, OscSenderError> {
let socket = UdpSocket::bind(bind).context(UDPBindSnafu { to: bind })?;
Ok(Self { target, socket })
}
pub fn send_osc(&self, address: String, args: Vec<OscType>) -> Result<(), OscSenderError> {
let packet = OscPacket::Message(OscMessage {
addr: address.clone(),
args,
});
let data = rosc::encoder::encode(&packet).context(OSCPacketEncodingSnafu {
address: address.to_string(),
})?;
self.socket
.send_to(data.as_slice(), self.target)
.context(UDPSendSnafu {
data,
to: self.target,
})?;
Ok(())
}
}