Skip to content

Log debug messages when the number of connections to output changes#1402

Merged
Trouffman merged 11 commits into
DistroAV:masterfrom
BitRate27:outputinfoconnect
Mar 30, 2026
Merged

Log debug messages when the number of connections to output changes#1402
Trouffman merged 11 commits into
DistroAV:masterfrom
BitRate27:outputinfoconnect

Conversation

@BitRate27

Copy link
Copy Markdown
Contributor

When there are no receivers for a DistroAV output, whether it be Main/Preview/Filter, we still call the NDI send API. This causes CPU overhead which can be significant. Testing a 30 fps media source at full HD (1920x1024):

Filter output off: -10% CPU
Preview output off: -5% CPU
Main output off: < -3% CPU

Here are the pertinent log messages with normal logging (no -verbose) showing when output is paused and started based on connections.

09:00:13.793: [distroav] NDI Filter Updated: 'DistroAV NDI Output'
09:00:13.794: [distroav] NDI Filter Created: 'DistroAV NDI Filter Output'
09:00:13.912: [distroav] Dedicated NDI Output video 'BILLSLENOVO (DistroAV NDI Filter Output)' has no connections, sender paused.
09:00:15.192: [distroav] NDI Output Updated. 'OBS'
09:00:15.207: [distroav] NDI Main Output started
09:00:15.208: [distroav] NDI Output started successfully. 'OBS'
09:00:15.212: [distroav] NDI Output Updated. 'OBS Preview'
09:00:15.288: [distroav] NDI Output Updated. 'OBS Preview'
09:00:15.329: [distroav] NDI Output started successfully. 'OBS Preview'
09:00:15.353: [distroav] NDI Output video 'BILLSLENOVO (OBS Preview)' has no connections, sender paused.
09:00:15.366: [distroav] NDI Output video 'BILLSLENOVO (OBS)' has no connections, sender paused.
09:00:30.479: [distroav] NDI Output audio 'BILLSLENOVO (OBS)' has connections, sender started.
09:00:38.554: [distroav] NDI Output audio 'BILLSLENOVO (OBS)' has no connections, sender paused.
09:00:38.790: [distroav] NDI Output video 'BILLSLENOVO (OBS Preview)' has connections, sender started.
09:00:47.055: [distroav] Dedicated NDI Output video 'BILLSLENOVO (DistroAV NDI Filter Output)' has connections, sender started.
09:00:47.969: [distroav] NDI Output video 'BILLSLENOVO (OBS Preview)' has no connections, sender paused.
09:00:55.297: [distroav] Dedicated NDI Output video 'BILLSLENOVO (DistroAV NDI Filter Output)' has no connections, sender paused.

This was tested by starting OBS, then selecting OBS, then OBS Preview, then DistroAV NDI Filter Output as sources in a single instance of NDI Studio Monitor.

The output thread will check the number of connections once a second, and will wait at most 10ms to return the no of connections.

@BitRate27
BitRate27 requested a review from Trouffman February 16, 2026 09:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Reduces unnecessary NDI send workload by pausing video/audio frame submission when there are no active NDI receivers, aiming to lower CPU usage for Main/Preview/Filter outputs.

Changes:

  • Adds receiver-connection checks and early-returns to skip NDI send calls when no receivers are connected.
  • Introduces throttling (once per second) for connection checks in ndi-output.cpp.
  • Adds connection-aware logging for sender pause/resume events.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.

File Description
src/ndi-output.cpp Adds mutex-protected sender access plus throttled connection checks to skip sending when no receivers exist.
src/ndi-filter.cpp Adds connection checks and pause/resume logging to dedicated filter sender paths.
Comments suppressed due to low confidence (1)

src/ndi-filter.cpp:305

  • NDIlib_send_create_t send_desc is not zero-initialized; if the SDK struct gains fields, they will be indeterminate and can break sender creation. Initialize the struct (e.g., NDIlib_send_create_t send_desc{};) before populating fields.
	NDIlib_send_create_t send_desc;

	send_desc.p_ndi_name = name;

	if (groups && groups[0])
		send_desc.p_groups = groups;
	else
		send_desc.p_groups = nullptr;
	send_desc.clock_video = false;
	send_desc.clock_audio = false;


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/ndi-output.cpp Outdated
Comment thread src/ndi-output.cpp
Comment thread src/ndi-filter.cpp
Comment thread src/ndi-filter.cpp
Comment thread src/ndi-filter.cpp
Comment thread src/ndi-output.cpp
Comment thread src/ndi-output.cpp Outdated
Comment thread src/ndi-output.cpp Outdated
Comment thread src/ndi-filter.cpp Outdated
Comment thread src/ndi-filter.cpp Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@paulpv paulpv left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am very surprised this is an issue at all.
I would have expected that NDI itself to gate/no-op if there are no connections.

The code that this PR gates:

That gated code is relatively pretty minimal.
Part of that code is just a buffer grow check that would be called very rarely once settled.
There isn't even a pthread_mutex_lock/pthread_mutex_unlock in the ndi-output.cpp code; there is in the ndi-filter.cpp code.
I would not expect a simple conv_function (only called in ndi-output.cpp) or memcpy (called in both ndi-output.cpp and ndi-filter.cpp) to be the reason for so much reported CPU usage.

Has this code (with or without the PR) been profiled with a 3rd party tool to confirm its CPU budget?

I also consider this reported problem a big of a moot red herring.
Am I correct in interpreting the problem to be "There is unexpected sending overhead when connections < 1, but there is expected sending overhead when sending to > 0".
Sure, that seems on the surface like a reasonable request, but effectively only a user that has recipients the minority of the time has anything to complain about.
The user is not concerned/complaining about the sending overhead when there are > 0 recipients, but only when there are not any recipients are they somehow magically not OK with the exact same overhead that they were OK with when they did have recipients.

Rephrased: The user accepts that the plugin has an overhead when in use. They are using the plugin. What real-world difference does it make that the plugin uses the same amount of overhead whether there are 0 recipients or > 0 recipients?

Regardless, I still think that:

  • The gated code overhead seems very minimal and should not be accounting for the reported CPU usage.
  • If there is a large CPU usage when sending to 0 recipients then that seems like an NDI problem.
  • Maybe it would be nice of us to self-gate to prevent this overhead, but this seems moot since there is no effective real-world use case difference between a user accepting that there is an overhead when there are > 0 recipients (which should be the case the vast majority of the time) and them being performance pedantic that same acceptable to them overhead is now not acceptable to them when there are 0 recipients (which should be the case the vast minority of the time).

The ground floor base overhead of the plugin is the overhead that it uses when it is in use.
It does not real-world use case matter if we optimize out any overhead of the plugin when it is not in use.

It would be like someone expecting a radio broadcast transmitter to use less power when nobody is listening.

Self-gating when connections == 0 may still be a pragmatic optimization, but architecturally it’s an opportunistic idle-path optimization, not a correction of an abnormal runtime condition.

Or maybe I missed the point of the problem or the overhead of that gated code really is that high. :/

@BitRate27 BitRate27 changed the title Only send NDI video output when a receiver is connected Log debug messages when the number of connections to output changes Feb 27, 2026
@BitRate27

Copy link
Copy Markdown
Contributor Author

Since there is not real observable improvement in performance by not outputting if there are no receivers, we will only output a LOG_DEBUG message whenever the no of connections on an output changes. We only check once every second.

Comment thread src/ndi-filter.cpp
@Trouffman
Trouffman merged commit 1402224 into DistroAV:master Mar 30, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants