summaryrefslogtreecommitdiffstats
path: root/src/osc.rs
blob: 6288e2facef07220d48c0b87cd966e59c74f8579 (plain)
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
use std::{error::Error, net::UdpSocket};

use rosc::{OscMessage, OscPacket};

pub struct OscServer {
    socket: UdpSocket,
    buf: Vec<u8>,
}

impl OscServer {
    pub fn new(addr: &str) -> std::io::Result<Self> {
        let socket = UdpSocket::bind(addr)?;
        socket.set_nonblocking(true)?;
        log::info!("listening for OSC on {}", addr);
        Ok(Self {
            socket,
            buf: vec![0u8; 0x10000],
        })
    }

    /// Drains all pending OSC messages, calling `on_message` for each.
    /// Returns `true` if any messages were dispatched.
    pub fn poll(
        &mut self,
        mut on_message: impl FnMut(OscMessage) -> Result<(), Box<dyn Error>>,
    ) -> bool {
        let mut received = false;
        loop {
            match self.socket.recv_from(&mut self.buf) {
                Ok((size, _addr)) => {
                    let data = &self.buf[..size];
                    let res = rosc::decoder::decode_udp(data)
                        .map_err(Box::from)
                        .and_then(|(_, packet)| dispatch(packet, &mut on_message));
                    if let Err(e) = res {
                        log::error!("{}", e);
                    };

                    received = true;
                }
                Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break,
                Err(e) => {
                    log::error!("OSC recv error: {}", e);
                    break;
                }
            }
        }
        received
    }

    /// Blocks until at least one OSC message arrives, then drains all pending.
    pub fn recv(
        &mut self,
        mut on_message: impl FnMut(OscMessage) -> Result<(), Box<dyn Error>>,
    ) -> bool {
        self.socket.set_nonblocking(false).expect("set blocking");
        match self.socket.recv_from(&mut self.buf) {
            Ok((size, _addr)) => {
                let data = &self.buf[..size];
                let res = rosc::decoder::decode_udp(data)
                    .map_err(Box::from)
                    .and_then(|(_, packet)| dispatch(packet, &mut on_message));
                if let Err(e) = res {
                    log::error!("{}", e);
                };
            }
            Err(e) => {
                log::error!("OSC recv error: {}", e);
            }
        }
        self.socket.set_nonblocking(true).expect("set nonblocking");
        self.poll(on_message);
        true
    }
}

fn dispatch<E>(
    packet: OscPacket,
    on_message: &mut impl FnMut(OscMessage) -> Result<(), E>,
) -> Result<(), E> {
    match packet {
        OscPacket::Message(msg) => on_message(msg)?,
        OscPacket::Bundle(bundle) => {
            for p in bundle.content {
                dispatch(p, on_message)?;
            }
        }
    }
    Ok(())
}