Tungstenite: Is it possible I'm loosing messages when polling a socket in a loop?

Hey folks!

Sorry in advance, this question needs some more background than usually probably.
I'm building a little something to connect a MIDI DAW controller (Korg nanoKontrol 2) to a mixer console with a browser interface (Soundcraft UI12, see the interface in a demo here), doing the communication through websockets.

So far, everything works somewhat fine, but I struggle to synchronise the state of the mixer back to my MIDI controller, in particular the lighting of the buttons for muting etc., correctly. It works on startup, e.g. the mute status of all channels gets synced down to my controller, and when I hit a button in the web interface, then the correct LED on the board is turned on/off. That does not happen though when I press the corresponding button on the nanoKontrol.

For explanation: I read & send MIDI signals from/to the controller on a different thread and pass them over via an mpsc::channel, its receiving end going by the name ui_command_receiver in this respective function. I also built a data type around the command, giving me a string the mixer understands on a websocket when calling ui12_control_string(). The update_sender obviously sends the updates back to the thread doing the MIDI work. So here is my function:

const SETTER_PREFIX: &str = "SETD";
const ALIVE: &str = "3:::ALIVE";
const PING: u8 = 0x9;

pub fn connect_to_ui(url: String, 
  ui_command_receiver: Receiver<Ui12Command>, 
  update_sender: Sender<StatusUpdate>) {

  let (mut socket, response) =
        connect(Url::parse(&url).unwrap()).expect("Can't connect");

  loop {
          let msg = socket.read_message().expect("Error reading message from UI12");
          let str = msg.to_string();
          let lines = str.lines().collect::<Vec<&str>>();
          for line in lines {
              if line.to_string().contains(SETTER_PREFIX) {
                  // gets triggered fine on startup and when pressing a button in the web interface
                  debug!("Received UI12 message: {}", line);
                  let raw_update = StatusUpdate::from_string(&line.to_string());
                  if let Ok(update) = raw_update {
                      debug!("Read update {:?}", update);
                      update_sender.send(update)
                          .unwrap_or_else(|e| error!("{e}"));
                  }
              }
  
              if line.to_string().contains(&PING.to_string()) {
                  // necessary because the UI12 apparently meddles with the PING somehow, see:
                  // https://proforums.harman.com/soundcraft/discussion/comment/198832#Comment_198832
                  socket.write_message(Text(ALIVE.into())).unwrap();
              }
          }
  
          // this probably doesn't work too well in conjunction with the polling approach?
          if let Ok(msg) = ui_command_receiver.try_recv() {
              socket
                  .write_message(Text(msg.ui12_control_string()))
                  .unwrap();
              debug!("Message written to socket: {:?}", msg.ui12_control_string());
          }
    }
}

So I observe the following: When I press a mute button in the web interface (looking at the AUX 1 section which I'm trying to control here), I see a log message "Received UI12 message: SETD^i.7.aux.0.mute^1" which is exactly what I expect. Hitting the associated button on the controller correctly mutes the channel on the mixer, but I don't see the log line and hence don't receive an update for the lights on the nanoKontrol.

Now I ask myself: Is there is the possibility that I'm missing messages/data frames/whatever you call a unit of communication over websockets when I poll the socket in this loop?
Sending out the command from a received MIDI message is the last thing the loop does, apart from logging. I could imagine that an immediately sent response from the mixer might go unnoticed in the time until the socket is read again, but I surely don't know that. It also could be that messages cue up on the socket perfectly alright, and it's just the mixer that doesn't reply to a state change - which is not what you see when you observe the web socket connection in the browser though. When crafting a similar mute message by hand and sending it out, the behaviour is just the same by the way: The web interface correctly shows the changed state, but the MIDI controller doesn't receive it.

Maybe sending & receiving from the same thread is just not a good idea in general? I wouldn't know how to do differently though, because I need a mutual reference to the socket in order to write to it which can't be shared without headaches. Also, I'd rather occupy as little threads as I can because those are a resource as well.

My dependencies are these btw.:

[dependencies]
approx = "0.5.1"
dns-lookup = "1.0.8"
env_logger = "0.9.0"
log = "0.4.17"
midir = "0.8.0"
tungstenite = "0.17.3"
url = "2.2.2"

Update: I read up a little more, and it looks like I ran into the problem of full duplex communication with tungstenite like described e.g. here.

I'll dig a little deeper and probably go async, even if that means I'll have to restructure basically everything. :neutral_face:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.