Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Audio only master #1043

Merged
merged 21 commits into from
Aug 2, 2024
Merged

Audio only master #1043

merged 21 commits into from
Aug 2, 2024

Conversation

paulpv
Copy link
Member

@paulpv paulpv commented Jul 21, 2024

This is a master based cherry pick of @Trouffman 's main commit in #1027 to give him credit for the fix.

This will be released as 4.14.1 in a few days.

Trouffman and others added 2 commits July 21, 2024 15:06
The audio-only was resetting the frame and settings parameter only when it was set. This created other issues that the "ndi receiver" reset was not done uniformly depending if there was video or audio only. This also created issue at launch to throw some error.
@paulpv paulpv added bug audio Seeking Testers PRs with this label will package the plugin so that others can test labels Jul 21, 2024
@paulpv paulpv self-assigned this Jul 21, 2024
@Trouffman
Copy link
Collaborator

There is a known issue in this PR that might collide with a V6 feature.

Let me test it on master before merging.

@Trouffman
Copy link
Collaborator

Trouffman commented Jul 26, 2024

Test Settings / steps:

  • NDI Source set as "Audio Only"
  • Restart OBS
  • Start Recording

Results possibles:

  • Success : Audio-Only Source is audible in recording when expected.
  • Fail : Audio-Only Source does not behave as expected (ie.: missing on Recording)

Test results :

Behavior when hidden: Keep source connected Disconnect source when not visible
Keep last frame when disconnected : ticked Success Success
Keep last frame when disconnected : unticked FAIL(1) Success

Failure status #1 :

  • Audio level is visible in UI
  • Audio is NOT in recorded file / missing

@Trouffman
Copy link
Collaborator

HOLD ON for merge!
Found a better way to address this issue and keep it compatible with other features.

Adding a first Frame creation before any drawing start should help with the "frame not seen", "blank frame" and "audio only not on recording" issues.
@Trouffman
Copy link
Collaborator

This is now compatible with the latest added features.

It should also fix some other issues where the "frame" of and NDI source is not visible (because size is 0x0 for some reasons).

This also should follow the concept that :

  • When you start : start with a clean state then apply settings

Tested on MacOS (M2) with OBS 30.1.2 + test Pattern Generator and a 1K tone

@paulpv
Copy link
Member Author

paulpv commented Jul 26, 2024

This is now compatible with the latest added features.

It should also fix some other issues where the "frame" of and NDI source is not visible (because size is 0x0 for some reasons).

This also should follow the concept that :

  • When you start : start with a clean state then apply settings

Tested on MacOS (M2) with OBS 30.1.2 + test Pattern Generator and a 1K tone

Related to the 0x0 frame, I have noticed in the latest OBS log output that it says:

info: [obs-ndi] +ndi_source_create('NDI™ Source'...)
error: bmalloc: Allocating 0 bytes is broken behavior, please fix your code! This will crash in future versions of OBS.
info: [obs-ndi] +ndi_source_update('NDI™ Source'...)

So we will need to address the 0x0 problem soon anyway! :)

@paulpv
Copy link
Member Author

paulpv commented Jul 27, 2024

@Trouffman Are we good/safe/ok to merge this?

@Trouffman
Copy link
Collaborator

That error message is new it seems ! (The bmalloc 0 byte allocation)

This has been tested on Mac, not yet windows/Linux.

Can merge, will need testing anyway.

@paulpv
Copy link
Member Author

paulpv commented Jul 27, 2024

Can merge, will need testing anyway.

This PR would be the place to test the changes on Linux and Windows.
This PR will generate installers because of the Seeking Testers label.

Once merged to master there won't be any installers generated until an actual release is tagged.
I supposed we could tag a release and just not create a Release entry at https://github.com/DistroAV/DistroAV/releases and test that tag and once it is working then create a Release entry.

@Trouffman
Copy link
Collaborator

Let do the test on this PR!
I can have windows tested soon.

@Trouffman
Copy link
Collaborator

Trouffman commented Jul 27, 2024

I quickly tested on Windows (11) but I need more people to test it on windows.

Behavior when hidden: Keep source connected Disconnect source when not visible
Keep last frame when disconnected : ticked tbc tbc
Keep last frame when disconnected : unticked tbc no audio on recording after obs restart

@@ -440,6 +440,16 @@ void *ndi_source_thread(void *data)

NDIlib_recv_create_v3_t *reset_recv_desc = &recv_desc;

if (!s->running) {
Copy link
Member Author

@paulpv paulpv Jul 30, 2024

Choose a reason for hiding this comment

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

I don't get this.
This line is:

if (!s->running) { ... }

The next immediate line after this if statement is:

while (s->running) { ... }

If the if statement is entered, then s->running is false, then the while loop never will be entered.
If the if statement isn't entered, then s->running is true, then the while loop will be entered.

I know this ndi_source_thread runs inside of the while loop.

So, this tells me that this if (!s->running) { ... } statement is not doing anything.

😕

@@ -440,6 +440,16 @@ void *ndi_source_thread(void *data)

NDIlib_recv_create_v3_t *reset_recv_desc = &recv_desc;

if (!s->running) {
// Force a clean frame at first start
obs_source_output_video(obs_source, blank_video_frame());
Copy link
Member Author

@paulpv paulpv Jul 30, 2024

Choose a reason for hiding this comment

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

This allocates a blank video frame and never releases it.

We should probably just reuse s->config.blank_frame

src/obs-ndi-source.cpp Outdated Show resolved Hide resolved
@paulpv
Copy link
Member Author

paulpv commented Jul 30, 2024

Around

static obs_source_frame *blank_video_frame()
{
obs_source_frame *frame =
obs_source_frame_create(VIDEO_FORMAT_NONE, 0, 0);
frame->timestamp = os_gettime_ns();
return frame;
}

I looked into the bmalloc: Allocating 0 bytes is broken behavior log warning and it has been around for over 2 years.
We should probably fix this soon too! :)

static obs_source_frame *blank_video_frame()
{
	obs_source_frame *frame =
		obs_source_frame_create(VIDEO_FORMAT_NONE, 0, 0);
	frame->timestamp = os_gettime_ns();
	return frame;
}

This is causing the following OBS log message(s):

info: [obs-ndi] +ndi_source_create('NDI™ Source'...)
error: bmalloc: Allocating 0 bytes is broken behavior, please fix your code! This will crash in future versions of OBS.
info: [obs-ndi] +ndi_source_update('NDI™ Source'...)

I wonder what OBS dev's recommendation is for the best way to have an audio/video capable source that intentionally wants to use only audio and no video.

Making a 0x0 video made sense at the time and is obviously a borderline hack.
A 1x1 video might also have weird side-effects and even be visible in the video!
I wonder if just creating a more non-extreme 10x10, 50x50, or 100x100 might make more sense.
Maybe have some reasonable transparency color mask and allow the user to user to set their own.
Seems complicated. 😦

Maybe what we should really be doing is defining two separate NDI Source types:

  1. NDI Audio/Video Source: If you don't want the audio, just mute the source!
    We could maybe have an option in the Source to save a little overhead and not process audio, essentially Video Only.
    Video Only sources don't care if audio isn't pumped
  2. NDI Audio Only Source: would show up in OBS as a standard audio only source and would never need any blank_[video_]frame logic.

@paulpv
Copy link
Member Author

paulpv commented Jul 30, 2024

@Trouffman I think we should hold off on this code change and not push it to master.
Any objections?

Maybe still keep it open to discuss?

@Trouffman
Copy link
Collaborator

Agreed. This is not ready for prime time yet.

@Trouffman
Copy link
Collaborator

So whenever I try to fix one behavior, this brings another side issue or another "combo" of settings that breaks

Could be about time to rework that part more deeply.

@paulpv paulpv marked this pull request as draft July 30, 2024 11:10
@Trouffman
Copy link
Collaborator

@paulpv This would be the new audio-Only fix approach.
Has been tested on : MACos (M2).

@@ -1075,7 +1098,7 @@ void *ndi_source_create(obs_data_t *settings, obs_source_t *obs_source)
QString("OBS-NDI '%1'").arg(name).toUtf8();

// Allocate blank video frame
s->config.blank_frame = blank_video_frame();
// s->config.blank_frame = blank_video_frame();
Copy link
Member Author

Choose a reason for hiding this comment

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

Intentionally not creating any blank_frame?
Does this work?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Correct, the creation of the blank frame moved to ndi_source_update().

Copy link
Member Author

@paulpv paulpv Aug 1, 2024

Choose a reason for hiding this comment

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

This is the only line where config.blank_frame is ever assigned.
There are no other calls to blank_video_frame().
So, nothing else is ever creating a blank frame.
If this is commented out then all uses of s->config.blank_frame are just sending nullptr.

Maybe this is intentional.
Maybe this is accidental.
Maybe you stumbled on a solution accidentally? 😃

If not calling blank_video_frame() is intentional and fixes this, then maybe the whole static obs_source_frame *blank_video_frame() method should be removed?

Copy link
Collaborator

@Trouffman Trouffman Aug 1, 2024

Choose a reason for hiding this comment

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

This is a happy little accident :D that fixed the bug!

If we call "blank_video_frame()" = the bug exist. Setting config.blank_frame = nullptr (explicitly or not) fixes the problem.

I am looking though commit history to find the reason of that blank frame to see what it was used for. (fixing a bug maybe?)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Digging deeper :

This blank_frame was added to fix the Audio only that was "keeping the last frame/not cleaning the frame".
7d1cf13

This was part of v4.3.0 : "Source bugfix: video not cleared when switching to Audio Only mode"
https://github.com/DistroAV/DistroAV/releases/tag/4.3.0

src/obs-ndi-source.cpp Outdated Show resolved Hide resolved
@paulpv
Copy link
Member Author

paulpv commented Jul 31, 2024

@Trouffman I will test this on Windows [and maybe Linux] once you reply to my comments.

That commented out s->config.blank_frame = blank_video_frame(); makes me think you might have miss-committed/pushed this line.

@Trouffman
Copy link
Collaborator

Tested and confirmed it works & fix the bug on MACOS & Windows 11.

@Trouffman Trouffman marked this pull request as ready for review August 1, 2024 07:00
@Trouffman Trouffman mentioned this pull request Aug 1, 2024
// Force a clean (blank) frame when settings change to Audio only
if (recv_desc.bandwidth ==
NDIlib_recv_bandwidth_audio_only) {
obs_source_output_video(obs_source,
Copy link
Member Author

Choose a reason for hiding this comment

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

Per https://docs.obsproject.com/reference-sources#c.obs_source_output_video
Just use:

obs_source_output_video(obs_source, nullptr);

Copy link
Collaborator

Choose a reason for hiding this comment

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

Will update everywhere and get rid of the config.blank_frame then

if (config.bandwidth ==
NDIlib_recv_bandwidth_audio_only) {
// Force a clean frame when source is updated
obs_source_output_video(obs_source,
Copy link
Member Author

Choose a reason for hiding this comment

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

Per https://docs.obsproject.com/reference-sources#c.obs_source_output_video
Just use:

obs_source_output_video(obs_source, nullptr);

src/obs-ndi-source.cpp Outdated Show resolved Hide resolved
@paulpv
Copy link
Member Author

paulpv commented Aug 2, 2024

@Trouffman Looks good! I will test this my tonight or tomorrow before approving the code.

@paulpv
Copy link
Member Author

paulpv commented Aug 2, 2024

Tests out fine on both Mac and Windows.
I tested combinations of:

  • Bandwidth: Highest, Lowest, Audio Only
  • Behavior: Keep source connected, Disconnect source when not visible
  • Keep last frame when disconnected: On, Off

All behaved as I would expect it to.

More importantly:

  1. I closed OBS
  2. Reopened OBS
  3. Immediately start recording/streaming
  4. Wait ~10 seconds
  5. Stop recording/streaming
  6. Open recording and verify audio can be heard

I will merge to master.

Thanks @Trouffman !

@paulpv paulpv merged commit ab3c22b into master Aug 2, 2024
6 checks passed
@paulpv paulpv deleted the audio_only_master branch August 2, 2024 08:01
@Trouffman
Copy link
Collaborator

@paulpv Added clarity or the Bug fix :

BugFix : Audio is missing from audio-only NDI Source after OBS restart.

Main bug with workaround solution: #592

Should fix the issues :
#429
#578
#981
#906
#621
#467
#298

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
audio bug Seeking Testers PRs with this label will package the plugin so that others can test
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants