2023-09-07 10:53:04 +02:00

317 lines
13 KiB
C++

/*******************************************************************************
The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
Technology released in source code form as part of the game integration package.
The content of this file may not be used without valid licenses to the
AUDIOKINETIC Wwise Technology.
Note that the use of the game engine is subject to the Unreal(R) Engine End User
License Agreement at https://www.unrealengine.com/en-US/eula/unreal
License Usage
Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
this file in accordance with the end user license agreement provided with the
software or, alternatively, in accordance with the terms contained
in a written agreement between you and Audiokinetic Inc.
Copyright (c) 2023 Audiokinetic Inc.
*******************************************************************************/
#include "Wwise/WwiseSoundBankFileState.h"
#include "Wwise/API/WwiseSoundEngineAPI.h"
#include "Wwise/Stats/AsyncStats.h"
#include "Wwise/Stats/FileHandler.h"
#include "AkUnrealHelper.h"
#include "Async/MappedFileHandle.h"
#include "Async/Async.h"
#include <inttypes.h>
FWwiseSoundBankFileState::FWwiseSoundBankFileState(const FWwiseSoundBankCookedData& InCookedData, const FString& InRootPath):
FWwiseSoundBankCookedData(InCookedData),
RootPath(InRootPath)
{
INC_DWORD_STAT(STAT_WwiseFileHandlerKnownSoundBanks);
}
FWwiseSoundBankFileState::~FWwiseSoundBankFileState()
{
DEC_DWORD_STAT(STAT_WwiseFileHandlerKnownSoundBanks);
}
FWwiseInMemorySoundBankFileState::FWwiseInMemorySoundBankFileState(const FWwiseSoundBankCookedData& InCookedData, const FString& InRootPath) :
FWwiseSoundBankFileState(InCookedData, InRootPath),
Ptr(nullptr),
FileSize(0),
MappedHandle(nullptr),
MappedRegion(nullptr)
{
}
bool FWwiseInMemorySoundBankFileState::LoadAsMemoryView() const
{
#if WITH_EDITOR
return false;
#else
return bContainsMedia;
#endif
}
void FWwiseInMemorySoundBankFileState::OpenFile(FOpenFileCallback&& InCallback)
{
SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::OpenFile"));
if (UNLIKELY(FileSize != 0 || Ptr))
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::OpenFile %" PRIu32 " (%s): Seems to be already opened."), SoundBankId, *DebugName.ToString());
OpenFileFailed(MoveTemp(InCallback));
return;
}
const auto FullPathName = RootPath / SoundBankPathName.ToString();
const bool bCanTryMemoryMapping = !bContainsMedia || (!bDeviceMemory && !MemoryAlignment);
if (bCanTryMemoryMapping
&& GetMemoryMapped(MappedHandle, MappedRegion, FileSize, FullPathName, 0))
{
UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemorySoundBankFileState::OpenFile %" PRIu32 " (%s): Loading Memory Mapped SoundBank as %s."), SoundBankId, *DebugName.ToString(), LoadAsMemoryView() ? TEXT("View") : TEXT("Copy"));
Ptr = MappedRegion->GetMappedPtr();
FileSize = MappedRegion->GetMappedSize();
OpenFileSucceeded(MoveTemp(InCallback));
}
else if (LIKELY(GetFileToPtr(Ptr, FileSize, FullPathName, bDeviceMemory, MemoryAlignment, bContainsMedia)))
{
UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemorySoundBankFileState::OpenFile %" PRIu32 " (%s): Loading SoundBank as %s."), SoundBankId, *DebugName.ToString(), LoadAsMemoryView() ? TEXT("View") : TEXT("Copy"));
OpenFileSucceeded(MoveTemp(InCallback));
}
else
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::OpenFile %" PRIu32 " (%s): Failed to load SoundBank (%s)."), SoundBankId, *DebugName.ToString(), *FullPathName);
Ptr = nullptr;
FileSize = 0;
OpenFileFailed(MoveTemp(InCallback));
}
}
void FWwiseInMemorySoundBankFileState::LoadInSoundEngine(FLoadInSoundEngineCallback&& InCallback)
{
SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine"));
if (UNLIKELY(!FileSize || !Ptr))
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): No data, but supposed to be loaded."), SoundBankId, *DebugName.ToString());
LoadInSoundEngineFailed(MoveTemp(InCallback));
return;
}
auto* SoundEngine = IWwiseSoundEngineAPI::Get();
if (UNLIKELY(!SoundEngine))
{
UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): Failed loading without a SoundEngine."), SoundBankId, *DebugName.ToString());
LoadInSoundEngineFailed(MoveTemp(InCallback));
return;
}
AkBankID LoadedSoundBankId;
AkBankType LoadedSoundBankType;
BankLoadCookie* Cookie = new BankLoadCookie(this);
UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %p: Cookie %p."), this, Cookie);
if (!Cookie)
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): Failed to load SoundBank: Could not allocate cookie."), SoundBankId, *DebugName.ToString());
LoadInSoundEngineFailed(MoveTemp(InCallback));
return;
}
Cookie->Callback = MoveTemp(InCallback);
const auto LoadResult =
LoadAsMemoryView()
? SoundEngine->LoadBankMemoryView(Ptr, FileSize, &FWwiseInMemorySoundBankFileState::BankLoadCallback, Cookie, LoadedSoundBankId, LoadedSoundBankType)
: SoundEngine->LoadBankMemoryCopy(Ptr, FileSize, &FWwiseInMemorySoundBankFileState::BankLoadCallback, Cookie, LoadedSoundBankId, LoadedSoundBankType);
UE_CLOG(UNLIKELY(LoadedSoundBankType != static_cast<uint8>(SoundBankType)), LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): Incorrect SoundBank type: %" PRIu8 " expected %" PRIu8), SoundBankId, *DebugName.ToString(), (uint8)LoadedSoundBankType, (uint8)SoundBankType);
if(LoadResult != AK_Success)
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): Failed to load SoundBank: %d (%s)."), SoundBankId, *DebugName.ToString(), LoadResult, AkUnrealHelper::GetResultString(LoadResult));
auto Callback = MoveTemp(Cookie->Callback);
delete Cookie;
LoadInSoundEngineFailed(MoveTemp(Callback));
return;
}
}
void FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine(FUnloadFromSoundEngineCallback&& InCallback)
{
SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine"));
auto* SoundEngine = IWwiseSoundEngineAPI::Get();
if (UNLIKELY(!SoundEngine))
{
UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine %" PRIu32 " (%s): Failed unloading without a SoundEngine."), SoundBankId, *DebugName.ToString());
return CloseFileDone(MoveTemp(InCallback));
}
BankUnloadCookie* Cookie = new BankUnloadCookie(this);
UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine %p: Cookie %p."), this, Cookie);
if(!Cookie)
{
UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine %" PRIu32 " (%s): Could not allocate cookie for unload operation."), SoundBankId, *DebugName.ToString());
return CloseFileDone(MoveTemp(InCallback));
}
Cookie->Callback = MoveTemp(InCallback);
const auto Result = SoundEngine->UnloadBank(SoundBankId, Ptr, &FWwiseInMemorySoundBankFileState::BankUnloadCallback, Cookie, static_cast<AkBankType>(SoundBankType));
if(Result != AK_Success)
{
UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine %" PRIu32 " (%s): Call to SoundEngine failed with result %s"), SoundBankId, *DebugName.ToString(), AkUnrealHelper::GetResultString(Result));
auto Callback = MoveTemp(Cookie->Callback);
delete Cookie;
CloseFileDone(MoveTemp(Callback));
return;
}
}
bool FWwiseInMemorySoundBankFileState::CanCloseFile() const
{
// LoadFromSoundEngine will copy and delete the pointer. If succeeded, we are already closed.
return (State == EState::Opened && Ptr == nullptr) || FWwiseSoundBankFileState::CanCloseFile();
}
void FWwiseInMemorySoundBankFileState::CloseFile(FCloseFileCallback&& InCallback)
{
SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::CloseFile"));
UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemorySoundBankFileState::CloseFile %" PRIu32 " (%s): Closing Memory Mapped SoundBank."), SoundBankId, *DebugName.ToString());
if (MappedHandle)
{
if (LIKELY(MappedRegion))
{
UnmapRegion(*MappedRegion);
}
UnmapHandle(*MappedHandle);
MappedRegion = nullptr;
MappedHandle = nullptr;
}
else if (Ptr)
{
DeallocateMemory(Ptr, FileSize, bDeviceMemory, MemoryAlignment, bContainsMedia);
}
Ptr = nullptr;
FileSize = 0;
CloseFileDone(MoveTemp(InCallback));
}
void FWwiseInMemorySoundBankFileState::FreeMemoryIfNeeded()
{
// We don't need the memory anymore if we copied it, whether the load succeeded or not.
if (!LoadAsMemoryView())
{
if (MappedHandle)
{
UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::FreeMemoryIfNeeded %" PRIu32 " (%s): Freeing Mapped Handle"), SoundBankId, *DebugName.ToString());
if (LIKELY(MappedRegion))
{
UnmapRegion(*MappedRegion);
}
UnmapHandle(*MappedHandle);
MappedRegion = nullptr;
MappedHandle = nullptr;
}
else if (Ptr)
{
UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::FreeMemoryIfNeeded %" PRIu32 " (%s): Freeing Pointer"), SoundBankId, *DebugName.ToString());
DeallocateMemory(Ptr, FileSize, bDeviceMemory, MemoryAlignment, bContainsMedia);
}
Ptr = nullptr;
FileSize = 0;
}
}
void FWwiseInMemorySoundBankFileState::BankLoadCallback(
AkUInt32 InBankID,
const void* InMemoryBankPtr,
AKRESULT InLoadResult,
void* InCookie
)
{
SCOPED_WWISEFILEHANDLER_EVENT_4(TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback"));
UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback %p: Cookie %p."), ((BankLoadCookie*)InCookie)->BankFileState, InCookie);
if (!InCookie)
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback %" PRIu32 " (%s): Failed to load SoundBank: %d. Cookie given by SoundEngine is invalid."), InBankID, InLoadResult, AkUnrealHelper::GetResultString(InLoadResult));
return;
}
AsyncTask(ENamedThreads::AnyThread, [=]() {
SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback Async"));
BankLoadCookie Cookie((BankLoadCookie*)InCookie);
delete (BankLoadCookie*)InCookie;
if (!Cookie.BankFileState)
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback %" PRIu32 " (%s): Failed to load SoundBank: %d. Cookie given by SoundEngine is invalid."), InBankID, InLoadResult, AkUnrealHelper::GetResultString(InLoadResult));
return;
}
auto* BankFileState = Cookie.BankFileState;
if (LIKELY(InLoadResult == AK_Success))
{
UE_CLOG(UNLIKELY(InBankID != BankFileState->SoundBankId), LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback: Incorrect SoundBank loaded: %" PRIu32 " expected %" PRIu32 " (%s)"), InBankID, BankFileState->SoundBankId, *BankFileState->DebugName.ToString());
INC_DWORD_STAT(STAT_WwiseFileHandlerLoadedSoundBanks);
BankFileState->FreeMemoryIfNeeded();
BankFileState->LoadInSoundEngineSucceeded(MoveTemp(Cookie.Callback));
}
else
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback %" PRIu32 " (%s): Failed to load SoundBank: %d (%s)."), InBankID, *BankFileState->DebugName.ToString(), InLoadResult, AkUnrealHelper::GetResultString(InLoadResult));
BankFileState->FreeMemoryIfNeeded();
BankFileState->LoadInSoundEngineFailed(MoveTemp(Cookie.Callback));
}
});
}
void FWwiseInMemorySoundBankFileState::BankUnloadCallback(
AkUInt32 InBankID,
const void* InMemoryBankPtr,
AKRESULT InUnloadResult,
void* InCookie
)
{
SCOPED_WWISEFILEHANDLER_EVENT_4(TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback"));
UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback %p: Cookie %p."), ((BankUnloadCookie*)InCookie)->BankFileState, InCookie);
if (!InCookie)
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback %" PRIu32 ": Cookie given by SoundEngine is invalid."), InBankID);
return;
}
AsyncTask(ENamedThreads::AnyThread, [=]() {
SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback Async"));
BankUnloadCookie Cookie((BankUnloadCookie*)InCookie);
delete (BankUnloadCookie*)InCookie;
if (!Cookie.BankFileState)
{
UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback %" PRIu32 ": Cookie given by SoundEngine is invalid."), InBankID);
return;
}
auto* BankFileState = Cookie.BankFileState;
if (UNLIKELY(InUnloadResult == AK_ResourceInUse))
{
BankFileState->UnloadFromSoundEngineDefer(MoveTemp(Cookie.Callback));
}
else
{
UE_CLOG(InUnloadResult != AK_Success, LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback %" PRIu32 " (%s): UnloadBank failed: %d (%s)"), InBankID, *BankFileState->DebugName.ToString(), InUnloadResult, AkUnrealHelper::GetResultString(InUnloadResult));
DEC_DWORD_STAT(STAT_WwiseFileHandlerLoadedSoundBanks);
if (InMemoryBankPtr)
{
BankFileState->UnloadFromSoundEngineDone(MoveTemp(Cookie.Callback));
}
else
{
BankFileState->UnloadFromSoundEngineToClosedFile(MoveTemp(Cookie.Callback));
}
}
});
}