gtreshchev / RuntimeAudioImporter

Runtime Audio Importer plugin for Unreal Engine. Importing audio of various formats at runtime.
MIT License
336 stars 69 forks source link

Crash when loading #51

Closed mmhtx closed 1 year ago

mmhtx commented 1 year ago

Hello, excellent plugin, I have a crashing bug or I'm doing something wrong.

We are using RuntimeAudioImporter with the UnrealReplay system. Wave files are loaded as a result of time scrubbing. While loading the wave file, there is a chance that the RuntimeAudioImporter crashes, note the callstack below. I'm actually getting several different callstacks, different each time, but it always centers around FGCObject. The below callstack, however, is the most indicative of the problem, note RuntimeAudioImporterLibrary.cpp:114. That code corresponds to an AsyncTask with a FGCObjectScopeGuard Guard(this); in it. If I comment out the FGCObjectScopeGuard Guard(this); then the issue is eliminated on Windows, and reduced on Android.

Is this a bug/limitation in RuntimeAudioImporter, loading wave files in rapid succession, or am I likely doing something wrong?

I'm loading the wave like so

        RuntimeAudioImporter->OnResultNative.AddWeakLambda(this,[this](URuntimeAudioImporterLibrary* Importer,
    UImportedSoundWave* ImportedSoundWave, ERuntimeImportStatus Status)
        {
            HandleRuntimeAudioImporterOnResult(Importer, ImportedSoundWave, Status);
        });

        RuntimeAudioImporter->ImportAudioFromFile(FilePath, ERuntimeAudioFormat::Auto);

And in HandleRuntimeAudioImporterOnResult I

if(IsValid(RuntimeAudioImporter))
        {
            RuntimeAudioImporter->ConditionalBeginDestroy();
        }

Also, I don't understand the exact purpose of FGCObjectScopeGuard Guard(this);. I understand that I locks the AsyncTask so that only 1 can execute at a time, but in this case why is it necessary?

Best Regards


UGCObjectReferencer::RemoveObject(FGCObject *) GCObjectReferencer.cpp:114
FGCObject::UnregisterGCObject() GCObjectReferencer.cpp:345
FGCObject::~FGCObject() GCObject.h:168
[Inlined] TGCObjectScopeGuard<UObject const >::{dtor}() GCObjectScopeGuard.h:24
<lambda_310faebb452011eae4338baaf60a1085>::operator()() RuntimeAudioImporterLibrary.cpp:114
[Inlined] UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<1>,void __cdecl(void)>::operator()() Function.h:600
[Inlined] FAsyncGraphTask::DoTask(Type,const TRefCountPtr<FGraphEvent> &) Async.cpp:26
TGraphTask<FAsyncGraphTask>::ExecuteTask(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32> > &,Type,bool) TaskGraphInterfaces.h:1310
[Inlined] FBaseGraphTask::Execute(TArray<FBaseGraphTask *,TSizedDefaultAllocator<32> > &,Type,bool) TaskGraphInterfaces.h:919
[Inlined] FTaskGraphCompatibilityImplementation::QueueTask::__l5::<lambda_13c427d0bfcf321a066cb5a2badfbc27>::operator()() TaskGraph.cpp:1971
<lambda_17c904c32264d0348d15245fba0e1bff>::operator()(const bool) Task.h:499
[Inlined] Invoke(LowLevelTasks::FTask::<lambda_17c904c32264d0348d15245fba0e1bff> &,bool &) Invoke.h:47
[Inlined] LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<<lambda_17c904c32264d0348d15245fba0e1bff>,0>::Call(void *,bool) TaskDelegate.h:162
LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::TTaskDelegateImpl<<lambda_17c904c32264d0348d15245fba0e1bff>,0>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> &,void *,unsigned int,bool) TaskDelegate.h:171
[Inlined] LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48>::CallAndMove(LowLevelTasks::TTaskDelegate<LowLevelTasks::FTask * __cdecl(bool),48> &,bool) TaskDelegate.h:308
LowLevelTasks::FTask::ExecuteTask() Task.h:627
LowLevelTasks::FScheduler::ExecuteTask(LowLevelTasks::FTask *&) Scheduler.cpp:172
LowLevelTasks::FScheduler::TryExecuteTaskFrom<LowLevelTasks::TLocalQueueRegistry<1024>::TLocalQueue,&LowLevelTasks::TLocalQueueRegistry<1024>::TLocalQueue::DequeueGlobal,0>(LowLevelTasks::TLocalQueueRegistry<1024>::TLocalQueue *,LowLevelTasks::TLocalQueueRegistry<1024>::FOutOfWork &,bool,bool) Scheduler.cpp:349
LowLevelTasks::FScheduler::WorkerMain(LowLevelTasks::FSleepEvent *,LowLevelTasks::TLocalQueueRegistry<1024>::TLocalQueue *,unsigned int,bool) Scheduler.cpp:378
[Inlined] LowLevelTasks::FScheduler::CreateWorker::__l2::<lambda_be2218a0adc66e92e8734764b1b5dd37>::operator()() Scheduler.cpp:70
[Inlined] Invoke(<lambda_be2218a0adc66e92e8734764b1b5dd37> &) Invoke.h:47
UE::Core::Private::Function::TFunctionRefCaller<<lambda_be2218a0adc66e92e8734764b1b5dd37>,void __cdecl(void)>::Call(void *) Function.h:474
[Inlined] UE::Core::Private::Function::TFunctionRefBase<UE::Core::Private::Function::TFunctionStorage<1>,void __cdecl(void)>::operator()() Function.h:600
FThreadImpl::Run() Thread.cpp:67
FRunnableThreadWin::Run() WindowsRunnableThread.cpp:146
FRunnableThreadWin::GuardedRun() WindowsRunnableThread.cpp:71
<unknown> 0x00007ffbcbe35590
<unknown> 0x00007ffbcd3e485b```
mmhtx commented 1 year ago

Also, I do cache RuntimeAudioImporter as a UPROPERTY()

per https://github.com/gtreshchev/RuntimeAudioImporter/issues/48

gtreshchev commented 1 year ago

FGCObjectScopeGuard is needed to ensure that the object isn't destroyed as garbage while it's within scope. It's a workaround for developers who might forget about garbage collection in their code. But this scope guard isn't essential and won't affect behavior if both RuntimeAudioImporter and Sound Wave instances are handled properly, considering garbage collection.

I think your issue arises from not adding either the RuntimeAudioImporter or ImportedSoundWave instances to separate UPROPERTYs. This leads to garbage collection destroying those objects while they're still in use. So, ensure the objects have strong references.

Regarding ConditionalBeginDestroy, ideally, this should be managed by the garbage collection itself. Instead of explicitly destroying the object like you did, it's better to simply nullify it in your UPROPERTY. The object will then become eligible for garbage collection and will be destroyed in the next GC iteration.

gtreshchev commented 1 year ago

Please reopen this ticket if still relevant.