WwiseSoundBankFileState.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. /*******************************************************************************
  2. The content of this file includes portions of the proprietary AUDIOKINETIC Wwise
  3. Technology released in source code form as part of the game integration package.
  4. The content of this file may not be used without valid licenses to the
  5. AUDIOKINETIC Wwise Technology.
  6. Note that the use of the game engine is subject to the Unreal(R) Engine End User
  7. License Agreement at https://www.unrealengine.com/en-US/eula/unreal
  8. License Usage
  9. Licensees holding valid licenses to the AUDIOKINETIC Wwise Technology may use
  10. this file in accordance with the end user license agreement provided with the
  11. software or, alternatively, in accordance with the terms contained
  12. in a written agreement between you and Audiokinetic Inc.
  13. Copyright (c) 2023 Audiokinetic Inc.
  14. *******************************************************************************/
  15. #include "Wwise/WwiseSoundBankFileState.h"
  16. #include "Wwise/API/WwiseSoundEngineAPI.h"
  17. #include "Wwise/Stats/AsyncStats.h"
  18. #include "Wwise/Stats/FileHandler.h"
  19. #include "AkUnrealHelper.h"
  20. #include "Async/MappedFileHandle.h"
  21. #include "Async/Async.h"
  22. #include <inttypes.h>
  23. FWwiseSoundBankFileState::FWwiseSoundBankFileState(const FWwiseSoundBankCookedData& InCookedData, const FString& InRootPath):
  24. FWwiseSoundBankCookedData(InCookedData),
  25. RootPath(InRootPath)
  26. {
  27. INC_DWORD_STAT(STAT_WwiseFileHandlerKnownSoundBanks);
  28. }
  29. FWwiseSoundBankFileState::~FWwiseSoundBankFileState()
  30. {
  31. DEC_DWORD_STAT(STAT_WwiseFileHandlerKnownSoundBanks);
  32. }
  33. FWwiseInMemorySoundBankFileState::FWwiseInMemorySoundBankFileState(const FWwiseSoundBankCookedData& InCookedData, const FString& InRootPath) :
  34. FWwiseSoundBankFileState(InCookedData, InRootPath),
  35. Ptr(nullptr),
  36. FileSize(0),
  37. MappedHandle(nullptr),
  38. MappedRegion(nullptr)
  39. {
  40. }
  41. bool FWwiseInMemorySoundBankFileState::LoadAsMemoryView() const
  42. {
  43. #if WITH_EDITOR
  44. return false;
  45. #else
  46. return bContainsMedia;
  47. #endif
  48. }
  49. void FWwiseInMemorySoundBankFileState::OpenFile(FOpenFileCallback&& InCallback)
  50. {
  51. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::OpenFile"));
  52. if (UNLIKELY(FileSize != 0 || Ptr))
  53. {
  54. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::OpenFile %" PRIu32 " (%s): Seems to be already opened."), SoundBankId, *DebugName.ToString());
  55. OpenFileFailed(MoveTemp(InCallback));
  56. return;
  57. }
  58. const auto FullPathName = RootPath / SoundBankPathName.ToString();
  59. const bool bCanTryMemoryMapping = !bContainsMedia || (!bDeviceMemory && !MemoryAlignment);
  60. if (bCanTryMemoryMapping
  61. && GetMemoryMapped(MappedHandle, MappedRegion, FileSize, FullPathName, 0))
  62. {
  63. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemorySoundBankFileState::OpenFile %" PRIu32 " (%s): Loading Memory Mapped SoundBank as %s."), SoundBankId, *DebugName.ToString(), LoadAsMemoryView() ? TEXT("View") : TEXT("Copy"));
  64. Ptr = MappedRegion->GetMappedPtr();
  65. FileSize = MappedRegion->GetMappedSize();
  66. OpenFileSucceeded(MoveTemp(InCallback));
  67. }
  68. else if (LIKELY(GetFileToPtr(Ptr, FileSize, FullPathName, bDeviceMemory, MemoryAlignment, bContainsMedia)))
  69. {
  70. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemorySoundBankFileState::OpenFile %" PRIu32 " (%s): Loading SoundBank as %s."), SoundBankId, *DebugName.ToString(), LoadAsMemoryView() ? TEXT("View") : TEXT("Copy"));
  71. OpenFileSucceeded(MoveTemp(InCallback));
  72. }
  73. else
  74. {
  75. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::OpenFile %" PRIu32 " (%s): Failed to load SoundBank (%s)."), SoundBankId, *DebugName.ToString(), *FullPathName);
  76. Ptr = nullptr;
  77. FileSize = 0;
  78. OpenFileFailed(MoveTemp(InCallback));
  79. }
  80. }
  81. void FWwiseInMemorySoundBankFileState::LoadInSoundEngine(FLoadInSoundEngineCallback&& InCallback)
  82. {
  83. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine"));
  84. if (UNLIKELY(!FileSize || !Ptr))
  85. {
  86. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): No data, but supposed to be loaded."), SoundBankId, *DebugName.ToString());
  87. LoadInSoundEngineFailed(MoveTemp(InCallback));
  88. return;
  89. }
  90. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  91. if (UNLIKELY(!SoundEngine))
  92. {
  93. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): Failed loading without a SoundEngine."), SoundBankId, *DebugName.ToString());
  94. LoadInSoundEngineFailed(MoveTemp(InCallback));
  95. return;
  96. }
  97. AkBankID LoadedSoundBankId;
  98. AkBankType LoadedSoundBankType;
  99. BankLoadCookie* Cookie = new BankLoadCookie(this);
  100. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %p: Cookie %p."), this, Cookie);
  101. if (!Cookie)
  102. {
  103. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): Failed to load SoundBank: Could not allocate cookie."), SoundBankId, *DebugName.ToString());
  104. LoadInSoundEngineFailed(MoveTemp(InCallback));
  105. return;
  106. }
  107. Cookie->Callback = MoveTemp(InCallback);
  108. const auto LoadResult =
  109. LoadAsMemoryView()
  110. ? SoundEngine->LoadBankMemoryView(Ptr, FileSize, &FWwiseInMemorySoundBankFileState::BankLoadCallback, Cookie, LoadedSoundBankId, LoadedSoundBankType)
  111. : SoundEngine->LoadBankMemoryCopy(Ptr, FileSize, &FWwiseInMemorySoundBankFileState::BankLoadCallback, Cookie, LoadedSoundBankId, LoadedSoundBankType);
  112. 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);
  113. if(LoadResult != AK_Success)
  114. {
  115. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::LoadInSoundEngine %" PRIu32 " (%s): Failed to load SoundBank: %d (%s)."), SoundBankId, *DebugName.ToString(), LoadResult, AkUnrealHelper::GetResultString(LoadResult));
  116. auto Callback = MoveTemp(Cookie->Callback);
  117. delete Cookie;
  118. LoadInSoundEngineFailed(MoveTemp(Callback));
  119. return;
  120. }
  121. }
  122. void FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine(FUnloadFromSoundEngineCallback&& InCallback)
  123. {
  124. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine"));
  125. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  126. if (UNLIKELY(!SoundEngine))
  127. {
  128. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine %" PRIu32 " (%s): Failed unloading without a SoundEngine."), SoundBankId, *DebugName.ToString());
  129. return CloseFileDone(MoveTemp(InCallback));
  130. }
  131. BankUnloadCookie* Cookie = new BankUnloadCookie(this);
  132. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine %p: Cookie %p."), this, Cookie);
  133. if(!Cookie)
  134. {
  135. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine %" PRIu32 " (%s): Could not allocate cookie for unload operation."), SoundBankId, *DebugName.ToString());
  136. return CloseFileDone(MoveTemp(InCallback));
  137. }
  138. Cookie->Callback = MoveTemp(InCallback);
  139. const auto Result = SoundEngine->UnloadBank(SoundBankId, Ptr, &FWwiseInMemorySoundBankFileState::BankUnloadCallback, Cookie, static_cast<AkBankType>(SoundBankType));
  140. if(Result != AK_Success)
  141. {
  142. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemorySoundBankFileState::UnloadFromSoundEngine %" PRIu32 " (%s): Call to SoundEngine failed with result %s"), SoundBankId, *DebugName.ToString(), AkUnrealHelper::GetResultString(Result));
  143. auto Callback = MoveTemp(Cookie->Callback);
  144. delete Cookie;
  145. CloseFileDone(MoveTemp(Callback));
  146. return;
  147. }
  148. }
  149. bool FWwiseInMemorySoundBankFileState::CanCloseFile() const
  150. {
  151. // LoadFromSoundEngine will copy and delete the pointer. If succeeded, we are already closed.
  152. return (State == EState::Opened && Ptr == nullptr) || FWwiseSoundBankFileState::CanCloseFile();
  153. }
  154. void FWwiseInMemorySoundBankFileState::CloseFile(FCloseFileCallback&& InCallback)
  155. {
  156. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::CloseFile"));
  157. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemorySoundBankFileState::CloseFile %" PRIu32 " (%s): Closing Memory Mapped SoundBank."), SoundBankId, *DebugName.ToString());
  158. if (MappedHandle)
  159. {
  160. if (LIKELY(MappedRegion))
  161. {
  162. UnmapRegion(*MappedRegion);
  163. }
  164. UnmapHandle(*MappedHandle);
  165. MappedRegion = nullptr;
  166. MappedHandle = nullptr;
  167. }
  168. else if (Ptr)
  169. {
  170. DeallocateMemory(Ptr, FileSize, bDeviceMemory, MemoryAlignment, bContainsMedia);
  171. }
  172. Ptr = nullptr;
  173. FileSize = 0;
  174. CloseFileDone(MoveTemp(InCallback));
  175. }
  176. void FWwiseInMemorySoundBankFileState::FreeMemoryIfNeeded()
  177. {
  178. // We don't need the memory anymore if we copied it, whether the load succeeded or not.
  179. if (!LoadAsMemoryView())
  180. {
  181. if (MappedHandle)
  182. {
  183. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::FreeMemoryIfNeeded %" PRIu32 " (%s): Freeing Mapped Handle"), SoundBankId, *DebugName.ToString());
  184. if (LIKELY(MappedRegion))
  185. {
  186. UnmapRegion(*MappedRegion);
  187. }
  188. UnmapHandle(*MappedHandle);
  189. MappedRegion = nullptr;
  190. MappedHandle = nullptr;
  191. }
  192. else if (Ptr)
  193. {
  194. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::FreeMemoryIfNeeded %" PRIu32 " (%s): Freeing Pointer"), SoundBankId, *DebugName.ToString());
  195. DeallocateMemory(Ptr, FileSize, bDeviceMemory, MemoryAlignment, bContainsMedia);
  196. }
  197. Ptr = nullptr;
  198. FileSize = 0;
  199. }
  200. }
  201. void FWwiseInMemorySoundBankFileState::BankLoadCallback(
  202. AkUInt32 InBankID,
  203. const void* InMemoryBankPtr,
  204. AKRESULT InLoadResult,
  205. void* InCookie
  206. )
  207. {
  208. SCOPED_WWISEFILEHANDLER_EVENT_4(TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback"));
  209. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback %p: Cookie %p."), ((BankLoadCookie*)InCookie)->BankFileState, InCookie);
  210. if (!InCookie)
  211. {
  212. 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));
  213. return;
  214. }
  215. AsyncTask(ENamedThreads::AnyThread, [=]() {
  216. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback Async"));
  217. BankLoadCookie Cookie((BankLoadCookie*)InCookie);
  218. delete (BankLoadCookie*)InCookie;
  219. if (!Cookie.BankFileState)
  220. {
  221. 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));
  222. return;
  223. }
  224. auto* BankFileState = Cookie.BankFileState;
  225. if (LIKELY(InLoadResult == AK_Success))
  226. {
  227. UE_CLOG(UNLIKELY(InBankID != BankFileState->SoundBankId), LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback: Incorrect SoundBank loaded: %" PRIu32 " expected %" PRIu32 " (%s)"), InBankID, BankFileState->SoundBankId, *BankFileState->DebugName.ToString());
  228. INC_DWORD_STAT(STAT_WwiseFileHandlerLoadedSoundBanks);
  229. BankFileState->FreeMemoryIfNeeded();
  230. BankFileState->LoadInSoundEngineSucceeded(MoveTemp(Cookie.Callback));
  231. }
  232. else
  233. {
  234. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankLoadCallback %" PRIu32 " (%s): Failed to load SoundBank: %d (%s)."), InBankID, *BankFileState->DebugName.ToString(), InLoadResult, AkUnrealHelper::GetResultString(InLoadResult));
  235. BankFileState->FreeMemoryIfNeeded();
  236. BankFileState->LoadInSoundEngineFailed(MoveTemp(Cookie.Callback));
  237. }
  238. });
  239. }
  240. void FWwiseInMemorySoundBankFileState::BankUnloadCallback(
  241. AkUInt32 InBankID,
  242. const void* InMemoryBankPtr,
  243. AKRESULT InUnloadResult,
  244. void* InCookie
  245. )
  246. {
  247. SCOPED_WWISEFILEHANDLER_EVENT_4(TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback"));
  248. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback %p: Cookie %p."), ((BankUnloadCookie*)InCookie)->BankFileState, InCookie);
  249. if (!InCookie)
  250. {
  251. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback %" PRIu32 ": Cookie given by SoundEngine is invalid."), InBankID);
  252. return;
  253. }
  254. AsyncTask(ENamedThreads::AnyThread, [=]() {
  255. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback Async"));
  256. BankUnloadCookie Cookie((BankUnloadCookie*)InCookie);
  257. delete (BankUnloadCookie*)InCookie;
  258. if (!Cookie.BankFileState)
  259. {
  260. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback %" PRIu32 ": Cookie given by SoundEngine is invalid."), InBankID);
  261. return;
  262. }
  263. auto* BankFileState = Cookie.BankFileState;
  264. if (UNLIKELY(InUnloadResult == AK_ResourceInUse))
  265. {
  266. BankFileState->UnloadFromSoundEngineDefer(MoveTemp(Cookie.Callback));
  267. }
  268. else
  269. {
  270. UE_CLOG(InUnloadResult != AK_Success, LogWwiseFileHandler, Error, TEXT("FWwiseInMemorySoundBankFileState::BankUnloadCallback %" PRIu32 " (%s): UnloadBank failed: %d (%s)"), InBankID, *BankFileState->DebugName.ToString(), InUnloadResult, AkUnrealHelper::GetResultString(InUnloadResult));
  271. DEC_DWORD_STAT(STAT_WwiseFileHandlerLoadedSoundBanks);
  272. if (InMemoryBankPtr)
  273. {
  274. BankFileState->UnloadFromSoundEngineDone(MoveTemp(Cookie.Callback));
  275. }
  276. else
  277. {
  278. BankFileState->UnloadFromSoundEngineToClosedFile(MoveTemp(Cookie.Callback));
  279. }
  280. }
  281. });
  282. }