Start rtpMIDI if it is not running; it also restarts itself if it crashes

- Hold MIDI on "LIGHT PC MIDI GONE" starts the rtpMIDI service, then its tray
  app, only if they are not running (a restart drops every session).
- The Lighting PC's rtpMIDI service now has Windows recovery actions
  (restart after 5 s, 5 s, 30 s); windows-setup.ps1 sets the same.
- coremidi.disconnect_peer (Disconnect in Audio MIDI Setup), used to test the
  alarms: all six links dropped and came back (four by themselves, two by
  the hold).
- Audio MIDI Setup need not be open: quitting it on NA Ingest left the
  session connected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 16:16:31 -04:00
co-authored by Claude Opus 5.5
parent 1d05412359
commit 288c1e6e1a
5 changed files with 47 additions and 8 deletions
+9 -2
View File
@@ -529,8 +529,12 @@ class TestFixes(unittest.TestCase):
self.assertEqual(self.plan("arena"), [("fix", "arena")])
self.assertEqual(self.plan("apps"), [("fix", "vista")])
# Restarting rtpMIDI drops every session and does not rejoin them (2026-10-08): the hold
# reconnects the peer from the Mac's side instead, like Connect in Audio MIDI Setup.
self.assertEqual(self.plan("midi"), [("fix", "midi_reconnect")])
# starts rtpMIDI only if it is not running, and reconnects the peer from the Mac's side.
self.assertEqual(sorted(self.plan("midi")), [("fix", "midi_reconnect"), ("fix", "rtpmidi_start")])
run = CONFIG["fixes"]["rtpmidi_start"]["run"]
self.assertTrue(run.startswith("(sc query rtpMIDIService | find"), run)
self.assertNotIn("Restart-Service", run)
self.assertNotIn("net stop", run)
for fix_id in ("obs", "arena", "vista"): # never closes a running app
self.assertTrue(CONFIG["fixes"][fix_id]["run"].startswith("tasklist "), fix_id)
@@ -575,6 +579,9 @@ class TestFixes(unittest.TestCase):
self.assertEqual(new["peers"][2], {"address": "10.1.10.206:5004", "name": "Lighting PC"})
self.assertEqual({k: v for k, v in new.items() if k != "peers"}, {k: v for k, v in sess.items() if k != "peers"})
self.assertIsNone(coremidi.with_peer(new, "Lighting PC", "10.1.10.206:5004")) # already there
back = coremidi.without_peer(new, "Lighting PC")
self.assertEqual(back, sess)
self.assertIsNone(coremidi.without_peer(sess, "Lighting PC")) # not there
def test_an_off_pc_is_woken(self):
from unittest import mock