fmod / fmod-for-unreal

FMOD Studio integration with Unreal.
https://fmod.com/resources/documentation-unreal
MIT License
202 stars 84 forks source link

UFMODAudioComponent inside AFMODAmbientSound does not handle streaming levels properly #39

Closed mcsab closed 2 years ago

mcsab commented 5 years ago

Unreal engine version: 4.20.

Issue: If I have an AFMODAmbientSound placed in a streaming level with auto-play enabled, every second time the level is hidden and enabled the AFMODAmbientSound won't play.

Explanation:

When a streaming level is deactivated (hidden) the actor components are unregisterred, but not deactivated. The FMOD plugin stops the audio in the OnUnregister() function, but won't start it the next time the component is registerred. After this happened the next TickComponent() call will deactivate the component - because the fmod state is stopped.

Possible fix:

Remove the macro around UFMODAudioComponent::OnRegister() in the header, and modify the cpp:

void UFMODAudioComponent::OnRegister()
{
    Super::OnRegister();

#if WITH_EDITORONLY_DATA
    if (!bDefaultParameterValuesCached)
        CacheDefaultParameterValues();

    UpdateSpriteTexture();
#endif

    if (bIsActive && bAutoActivate)
    {
        FMOD_STUDIO_PLAYBACK_STATE state = FMOD_STUDIO_PLAYBACK_STOPPED;
        StudioInstance->getPlaybackState(&state);
        if (state == FMOD_STUDIO_PLAYBACK_STOPPED)
            Play();
    }
}
fmod-cameron commented 5 years ago

I'm having trouble reproducing this issue. Even though OnRegister isn't used in game, the objects Activate function should still be getting called when the level is loaded.

Can you provide any more information on this?

mcsab commented 5 years ago

Streaming levels can be loaded once, then it is possible to change their visibility. The issue occurs if I hide the streaming level the audio component is in, and then unhide it again.

You can find more about level streaming here: https://docs.unrealengine.com/en-us/Engine/LevelStreaming

To change the visibility of a sublevel, you can use:

if (ULevelStreaming* Level = UGameplayStatics::GetStreamingLevel(ContextObj, LevelName))
{
    Level->SetShouldBeVisible(bShouldBeVisible);
}
fmod-cameron commented 5 years ago

Thanks for that, I can see what you mean now.

Is there a reason you are just changing the visibility rather than loading and unloading the level?

mcsab commented 5 years ago

Yes, this way I can show/hide the streaming levels realtime without waiting/loading screen, etc.

fmod-cameron commented 5 years ago

Thanks, it does sound like this would be a good solution.

We will run some more tests to make sure this is the best way to implement this.

Thanks again!

fmod-andrew commented 2 years ago

Fixed in 2.01.14, 2.02.05.