コミュニティQ&A

Audiokineticのコミュニティ主導のQ&Aフォーラムへようこそ。ここはWwiseとStrataのユーザのみなさまがお互いに協力し合う場です。弊社チームによる直接のサポートをご希望の場合はサポートチケットページをご利用ください。バグを報告するには、Audiokinetic LauncherのBug Reportオプションをご利用ください。(Q&AフォーラムではBug Reportを受け付けておりませんのでご注意ください。専用のBug Reportシステムをご利用いただくことで、バグの報告が適切な担当部門に届き、修正される可能性が高まります。)

最適な回答を迅速に得られるよう、ご質問を投稿される際は以下のヒントをご参考ください。

  • 具体的に示す:何を達成したいのか、またはどんな問題に直面しているのかを具体的に示してください。
  • 重要な詳細情報を含める:Wwiseとゲームエンジンのバージョンやご利用のOSなど詳細情報を記載してください。
  • 試したことを説明する:すでに試してみたトラブルシューティングの手順を教えてください。
  • 事実に焦点を当てる:問題の技術的な事実を記載してください。問題に焦点を当てることで、ほかのユーザのみなさまが解決策を迅速に見つけやすくなります。

+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.

David T. (220 ポイント) General Discussion

回答 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?
...