커뮤니티 Q&A

Audiokinetic의 커뮤니티 Q&A 포럼에 오신 것을 환영합니다. 이 포럼은 Wwise와 Strata 사용자들이 서로 도움을 주는 곳입니다. Audiokinetic의 직접적인 도움을 얻으려면 지원 티켓 페이지를 사용하세요. 버그를 보고하려면 Audiokinetic 런처에서 Bug Report 옵션을 사용하세요. (Q&A 포럼에 제출된 버그 보고는 거절됩니다. 전용 Bug Report 시스템을 사용하면 보고 내용이 담당자에게 정확히 전달되어 문제 해결 가능성이 크게 높아집니다.)<segment 6493>

빠르고 정확한 답변을 얻으려면 질문을 올릴 때 다음 팁을 참고하세요.

  • 구체적인 내용을 적어주세요: 무엇을 하려는지, 혹은 어떤 특정 문제에 부딪혔는지 설명하세요.
  • 핵심 정보를 포함하세요: Wwise와 게임 엔진 버전, 운영체제 등 관련 정보를 함께 제공하세요.
  • 시도한 방법들을 알려주세요: 문제 해결을 위해 이미 어떤 단계를 시도해봤는지 설명해주세요.
  • 객관적인 사실에 초점을 맞추세요: 문제의 기술적 사실을 중심으로 설명하세요. 문제에 집중할수록 다른 사람들이 더 빠르게 해결책을 찾을 수 있습니다.

+6 투표

We've followed the migration instructions (on both the Wwise project and the unreal side), everything went well. We generated the soundbanks, then Unreal got a notification that Wwise assets were going to be reloaded. Upon reload, the editor crashed in a stack overflow, in  

FWwiseResourceLoaderImpl::WaitForFutures(...)

This function seems not shielded against infinite (or at least, very long) recursion. Anybody was able to fix this? From what I see in the callstack when the stack overflow happens, the originating operation leading to this cascade of recursive calls is from the execution of the lambda defined in 

FWwiseFileHandlerBase::DecrementFileStateUse(...)

Did anybody encounter this? Did you solve it? Can Audiokinetic give any support on that or publish a hotfix? This is completely broken on our end (editor crashes at every launch now) and prevents us to migrate from 2021 to 2022...

EDIT
I tried fixing the WaitForFutures function like this:

void FWwiseResourceLoaderImpl::WaitForFutures(FCompletionFutureArray&& FutureArray, FCompletionCallback&& Callback, int NextId) const
{
   if (FutureArray.Num() <= NextId)
   {
      return Callback();
   }

   // Prevent unbounded recursion and stack overflows in case FutureArray contains a LOT of completed futures
   // (Indeed, Future.Next calls its callback in-stack if Future.IsReady !!)
   TFuture<void> Future;
   do 
   {
      Future = MoveTemp(FutureArray[NextId]);
      NextId += 1;
   } while (Future.IsReady() && NextId < FutureArray.Num());

   if (FutureArray.Num() <= NextId)
   {
      return Callback();
   }
   
   Future.Next([this, FutureArray = MoveTemp(FutureArray), Callback = MoveTemp(Callback), NextId/* = NextId + 1*/](int) mutable
   {
      WaitForFutures(MoveTemp(FutureArray), MoveTemp(Callback), NextId);
   });
}

It doesn't stack overflow anymore but I have three of these errors after loading:
> Error        LogWwiseResourceLoader    LoadEventResources: Could not load 1 prerequisites for Event \Events\Default Work Unit\SomeEvent (737333533). Unloading and failing.
> Error        LogWwiseResourceLoader    LoadEventAsync: Could not load Event \Events\Default Work Unit\SomeEvent (737333533) in language SFX (0)

Could it be that those three assets lead the asset loading in a state not foreseen by the original WaitForFutures function?

EDIT2
Those events do play correctly from the editor content browser though, so not really sure why the error messages if those events work.
Then, I proceeded to open another map... and it crashed again, this time in 

FWwiseResourceLoaderImpl::AddLoadSoundBankFutures(...)

in the FileExecutionQueue lambda. The LoadedSoundbanks reference is not valid anymore when the lambda gets executed.

Sigh.

General Discussion David T. (220 포인트) 로 부터

3 답변

0 투표
I am having the exact same issue (Wwise 2022.1.1 with unreal 5.1).
This happens both when closing a map in editor, and also when simply traveling from one map to another in our cooked build.

This issue was not present in 2022.1.0, which we used to migrate our data.
Now we had to update to 2022.1.1 to fix some crashes we had in Spatial Audio.

I'll try to make a homemade fix inspired by the one described in the original EDIT and will report back if I find something working better (since based on EDIT2, this does not seem to fix the whole issue).

If anyone from audiokinetic wants to jump in with a potential solution, that would be very appreciated.
Olivier Belletete (190 포인트) 로 부터
0 투표

Update:

I think I have a pretty good version of the fix.
Similar to David T. fix but instead of simply skipping over ready futures, it calls their next but without any continuation, preventing useless recursion:

void FWwiseResourceLoaderImpl::WaitForFutures(FCompletionFutureArray&& FutureArray, FCompletionCallback&& Callback, int NextId) const
{
    for (;NextId < FutureArray.Num(); ++NextId)
    {
        auto Future = MoveTemp(FutureArray[NextId]);
        if (!Future.IsReady())
        {
            Future.Next([this, FutureArray = MoveTemp(FutureArray), Callback = MoveTemp(Callback), NextId = NextId + 1](int) mutable
            {
                WaitForFutures(MoveTemp(FutureArray), MoveTemp(Callback), NextId);
            });
            return;
        }
        
        Future.Next([](int){});
    }

    return Callback();
}
 
Olivier Belletete (190 포인트) 로 부터
+1 투표

I actually found a solution to the EDIT2 issue too, it was a bug in my code where if the very last future is the only one that wasn't ready, I wouldn't wait for it. I just needed to add a check for that in the if after the loop:

   if (FutureArray.Num() <= NextId && Future.IsReady())
   {
      return Callback();
   }

 

Careful that there is yet another bug in the integration, if you are storing UAkAudioEvent assets in settings classes. If you do, you might run into an issue where the default object for your USettings class (the one returned by GetDefault<UMySettings>()) is created and loading its dependencies before the AkAudio module is loaded and initialized.
To fix this, you have to code yourself some delay loading of the UAkAudioEvent object that waits for the audio module to be initialized before trying to load the event data:

In AkAudioEvent.cpp:

...
void UAkAudioEvent::UnloadEventData()
{
   if (LoadedEvent)
   {
      auto* ResourceLoader = FWwiseResourceLoader::Get();
      if (UNLIKELY(!ResourceLoader))
      {
         return;
      }
      UE_LOG(LogAkAudio, Verbose, TEXT("%s - UnloadEventData"), *GetName());
      ResourceLoader->UnloadEvent(MoveTemp(LoadedEvent));
      LoadedEvent = nullptr;
   }
   // new branch:
   else if (DelayedLoadHandle.IsValid())
   {
      FAkAudioModule::OnModuleInitialized.Remove(DelayedLoadHandle);
      DelayedLoadHandle.Reset();
   }
}
void UAkAudioEvent::PostLoad()
{
   Super::PostLoad();

   if (bAutoLoad)
   {
      // new branch
      if (UNLIKELY(FAkAudioModule::AkAudioModuleInstance == nullptr || !FAkAudioModule::AkAudioModuleInstance->bModuleInitialized))
      {
         if (!DelayedLoadHandle.IsValid())
         {
            DelayedLoadHandle = FAkAudioModule::OnModuleInitialized.AddWeakLambda(this, [this]()
            {
               LoadEventData();
               DelayedLoadHandle.Reset();
            });
         }
      }
      else
      {
         LoadEventData();
      }
   }
}
...

And in AkAudioEvent.h:

...
private:
   void LoadEventData();
   void UnloadEventData();
   FWwiseLoadedEvent LoadedEvent;
   FDelegateHandle DelayedLoadHandle;  // new field
...

 

I hope Audiokinetic will fix those for the next release, it's pretty breaking.

David T. (220 포인트) 로 부터
Is it fixed?
...