Hundemeier / sacn

A simple ANSI E1.31 (aka sACN) module for python.
MIT License
47 stars 21 forks source link

manual_flush not working #33

Open garethnunns opened 3 years ago

garethnunns commented 3 years ago

Thanks for creating a great library, alas I'm having issues getting the manual flush to work as described in the readme.

Unfortunately, my receiver does not support E1.31 sync and when receiving from my code there is very noticable tearing across universes, however, when receiving from MadMapper or Resolume it is stable.

When sender.manual_flush is enabled, are the packets only sent when sender.flush() is called? Or does flush only send the sync packet?

When I monitor the output in sACNView, it reports that they have sync and are outputting at the desired FPS, however they are not in time.

My sender initialisation looks like this:

self.server = sacn.sACNsender(self.IP, 5568, self.sourceName, tuple(self.CID), 25, True)
self.server.manual_flush = True

And then to send each frame:

for uni in self.recording['frames'][frame]['dmx']:
  self.server[uni].dmx_data = self.recording['frames'][frame]['dmx'][uni]

self.server.flush()

For reference this is the full code block: https://github.com/garethnunns/PixelPlayback/blob/master/PixelPlayback/Playback.py#L146

Am I better off double buffering and updating the buffer instead of writing directly to the sender[uni].dmx_data?

Any advice would be great appreciated and thanks again!

Hundemeier commented 3 years ago

When sender.manual_flush is enabled, are the packets only sent when sender.flush() is called? Or does flush only send the sync packet?

When sender.flush() is called, there is a for loop specifically for sending out all currently active universes at roughly the same time, see code. When sender.manual_flush is enabled, no packets are send out automatically. This also means that the packets per second (or fps) that are specified in the constructor are not enforced any more.

Your code for sending each frame (i.e. multiple universes "at once") looks good to me. I don't think double buffering would make any difference, as your call to self.server[uni].dmx_data buffers the data and the call to self.server.flush() should then send out all the active universes right after another.

The LedFx project uses a somewhat similar setup and they have done some profiling recently (see #25) to catch performance regressions. So if in doubt, profile yourself with your specific setup and see how long the call to sender.flush() takes. It would be nive to have some quantitative data (i.e. how much milliseconds are we talking about).


Minor nitpick: Don't specify the port number manually. I would suggest rewriting it to

self.server = sacn.sACNsender(bind_address=self.IP, source_name=self.sourceName, cid=tuple(self.CID), fps=25, universeDiscovery=True)