WwiseMediaFileState.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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/WwiseMediaFileState.h"
  16. #include "Wwise/WwiseMediaManager.h"
  17. #include "Wwise/WwiseStreamingManagerHooks.h"
  18. #include "Wwise/WwiseTask.h"
  19. #include "Wwise/API/WwiseSoundEngineAPI.h"
  20. #include "Wwise/Stats/FileHandlerMemory.h"
  21. #include "WwiseUnrealHelper.h"
  22. #include "Async/MappedFileHandle.h"
  23. #include <inttypes.h>
  24. #include "Wwise/WwiseSoundEngineUtils.h"
  25. FWwiseMediaFileState::FWwiseMediaFileState(const FWwiseMediaCookedData& InCookedData, const FString& InRootPath) :
  26. FWwiseMediaCookedData(InCookedData),
  27. RootPath(InRootPath)
  28. {
  29. INC_DWORD_STAT(STAT_WwiseFileHandlerKnownMedia);
  30. }
  31. FWwiseMediaFileState::~FWwiseMediaFileState()
  32. {
  33. DEC_DWORD_STAT(STAT_WwiseFileHandlerKnownMedia);
  34. }
  35. FWwiseInMemoryMediaFileState::FWwiseInMemoryMediaFileState(const FWwiseMediaCookedData& InCookedData, const FString& InRootPath) :
  36. FWwiseMediaFileState(InCookedData, InRootPath)
  37. {
  38. pMediaMemory = nullptr;
  39. sourceID = MediaId;
  40. uMediaSize = 0;
  41. }
  42. void FWwiseInMemoryMediaFileState::OpenFile(FOpenFileCallback&& InCallback)
  43. {
  44. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemoryMediaFileState::OpenFile"));
  45. if (UNLIKELY(uMediaSize || pMediaMemory))
  46. {
  47. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemoryMediaFileState::OpenFile %" PRIu32 " (%s): Seems to be already opened."), MediaId, *DebugName.ToString());
  48. return OpenFileFailed(MoveTemp(InCallback));
  49. }
  50. const auto FullPathName = RootPath / MediaPathName.ToString();
  51. int64 FileSize = 0;
  52. if (LIKELY(GetFileToPtr(const_cast<const uint8*&>(pMediaMemory), FileSize,
  53. FullPathName, bDeviceMemory, MemoryAlignment, true,
  54. STAT_WwiseMemoryMedia_FName, STAT_WwiseMemoryMediaDevice_FName)))
  55. {
  56. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemoryMediaFileState::OpenFile %" PRIu32 " (%s)"), MediaId, *DebugName.ToString());
  57. uMediaSize = FileSize;
  58. return OpenFileSucceeded(MoveTemp(InCallback));
  59. }
  60. else
  61. {
  62. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemoryMediaFileState::OpenFile %" PRIu32 " (%s): Failed to open In-Memory Media (%s)."), MediaId, *DebugName.ToString(), *FullPathName);
  63. pMediaMemory = nullptr;
  64. FileSize = 0;
  65. return OpenFileFailed(MoveTemp(InCallback));
  66. }
  67. }
  68. void FWwiseInMemoryMediaFileState::LoadInSoundEngine(FLoadInSoundEngineCallback&& InCallback)
  69. {
  70. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemoryMediaFileState::LoadInSoundEngine"));
  71. if (UNLIKELY(!uMediaSize || !pMediaMemory))
  72. {
  73. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemoryMediaFileState::LoadInSoundEngine %" PRIu32 " (%s): No data, but supposed to be loaded."), MediaId, *DebugName.ToString());
  74. return LoadInSoundEngineFailed(MoveTemp(InCallback));
  75. }
  76. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  77. if (UNLIKELY(!SoundEngine))
  78. {
  79. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemoryMediaFileState::LoadInSoundEngine %" PRIu32 " (%s): Failed loading media without a SoundEngine."), MediaId, *DebugName.ToString());
  80. return LoadInSoundEngineFailed(MoveTemp(InCallback));
  81. }
  82. const auto SetMediaResult = SoundEngine->SetMedia(this, 1);
  83. if (LIKELY(SetMediaResult == AK_Success))
  84. {
  85. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemoryMediaFileState::LoadInSoundEngine %" PRIu32 " (%s)"), MediaId, *DebugName.ToString());
  86. INC_DWORD_STAT(STAT_WwiseFileHandlerLoadedMedia);
  87. return LoadInSoundEngineSucceeded(MoveTemp(InCallback));
  88. }
  89. else
  90. {
  91. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemoryMediaFileState::LoadInSoundEngine %" PRIu32 " (%s): Failed to load Media: %d (%s)."), MediaId, *DebugName.ToString(), SetMediaResult, WwiseUnrealHelper::GetResultString(SetMediaResult));
  92. return LoadInSoundEngineFailed(MoveTemp(InCallback));
  93. }
  94. }
  95. void FWwiseInMemoryMediaFileState::UnloadFromSoundEngine(FUnloadFromSoundEngineCallback&& InCallback)
  96. {
  97. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemoryMediaFileState::UnloadFromSoundEngine"));
  98. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  99. if (UNLIKELY(!SoundEngine))
  100. {
  101. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseInMemoryMediaFileState::UnloadFromSoundEngine %" PRIu32 " (%s): Failed unloading media without a SoundEngine."), MediaId, *DebugName.ToString());
  102. return CloseFileDone(MoveTemp(InCallback));
  103. }
  104. const auto Result = SoundEngine->TryUnsetMedia(this, 1, nullptr);
  105. if (UNLIKELY(Result == AK_ResourceInUse))
  106. {
  107. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemoryMediaFileState::UnloadFromSoundEngine %" PRIu32 " (%s): Deferred."), MediaId, *DebugName.ToString());
  108. return UnloadFromSoundEngineDefer(MoveTemp(InCallback));
  109. }
  110. else
  111. {
  112. UE_CLOG(UNLIKELY(Result != AK_Success), LogWwiseFileHandler, Error, TEXT("FWwiseInMemoryMediaFileState::UnloadFromSoundEngine %" PRIu32 " (%s): TryUnsetMedia failed: %d (%s)"), MediaId, *DebugName.ToString(), Result, WwiseUnrealHelper::GetResultString(Result));
  113. UE_CLOG(LIKELY(Result == AK_Success), LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemoryMediaFileState::UnloadFromSoundEngine %" PRIu32 " (%s)"), MediaId, *DebugName.ToString());
  114. DEC_DWORD_STAT(STAT_WwiseFileHandlerLoadedMedia);
  115. return UnloadFromSoundEngineDone(MoveTemp(InCallback));
  116. }
  117. }
  118. void FWwiseInMemoryMediaFileState::CloseFile(FCloseFileCallback&& InCallback)
  119. {
  120. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemoryMediaFileState::CloseFile"));
  121. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemoryMediaFileState::CloseFile %" PRIu32 " (%s)"), MediaId, *DebugName.ToString());
  122. DeallocateMemory(pMediaMemory, uMediaSize, bDeviceMemory, MemoryAlignment, true, STAT_WwiseMemoryMedia_FName, STAT_WwiseMemoryMediaDevice_FName);
  123. pMediaMemory = nullptr;
  124. uMediaSize = 0;
  125. CloseFileDone(MoveTemp(InCallback));
  126. }
  127. FWwiseStreamedMediaFileState::FWwiseStreamedMediaFileState(const FWwiseMediaCookedData& InCookedData,
  128. const FString& InRootPath, uint32 InStreamingGranularity) :
  129. FWwiseMediaFileState(InCookedData, InRootPath),
  130. StreamingGranularity(InStreamingGranularity),
  131. StreamedFile(nullptr)
  132. {
  133. sourceID = InCookedData.MediaId;
  134. pMediaMemory = nullptr;
  135. uMediaSize = 0;
  136. }
  137. void FWwiseStreamedMediaFileState::CloseStreaming()
  138. {
  139. auto* MediaManager = IWwiseMediaManager::Get();
  140. if (UNLIKELY(!MediaManager))
  141. {
  142. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseStreamedMediaFileState::CloseStreaming %" PRIu32 " (%s): Closing without a MediaManager."), MediaId, *DebugName.ToString());
  143. return;
  144. }
  145. MediaManager->GetStreamingHooks().CloseStreaming(MediaId, *this);
  146. }
  147. void FWwiseStreamedMediaFileState::OpenFile(FOpenFileCallback&& InCallback)
  148. {
  149. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseStreamedMediaFileState::OpenFile"));
  150. if (UNLIKELY(iFileSize != 0 || StreamedFile))
  151. {
  152. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedMediaFileState::OpenFile %" PRIu32 " (%s): Stream seems to be already opened."), MediaId, *DebugName.ToString());
  153. return OpenFileFailed(MoveTemp(InCallback));
  154. }
  155. if (PrefetchSize == 0)
  156. {
  157. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedMediaFileState::OpenFile %" PRIu32 " (%s)"), MediaId, *DebugName.ToString());
  158. return OpenFileSucceeded(MoveTemp(InCallback));
  159. }
  160. // Process PrefetchSize and send as SetMedia
  161. const auto FullPathName = RootPath / MediaPathName.ToString();
  162. int64 FileSize = 0;
  163. if (UNLIKELY(!GetFileToPtr(const_cast<const uint8*&>(pMediaMemory), FileSize,
  164. FullPathName, bDeviceMemory, MemoryAlignment, true,
  165. STAT_WwiseMemoryMediaPrefetch_FName, STAT_WwiseMemoryMediaPrefetchDevice_FName,
  166. PrefetchSize)))
  167. {
  168. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedMediaFileState::OpenFile %" PRIu32 " (%s): Failed to Read prefetch media (%s)."), MediaId, *DebugName.ToString(), *FullPathName);
  169. pMediaMemory = nullptr;
  170. return OpenFileFailed(MoveTemp(InCallback));
  171. }
  172. uMediaSize = FileSize;
  173. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  174. if (UNLIKELY(!SoundEngine))
  175. {
  176. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseStreamedMediaFileState::OpenFile %" PRIu32 " (%s): Failed prefetch media without a SoundEngine."), MediaId, *DebugName.ToString());
  177. DeallocateMemory(pMediaMemory, uMediaSize, bDeviceMemory, MemoryAlignment, true, STAT_WwiseMemoryMediaPrefetch_FName, STAT_WwiseMemoryMediaPrefetchDevice_FName);
  178. pMediaMemory = nullptr;
  179. uMediaSize = 0;
  180. return OpenFileFailed(MoveTemp(InCallback));
  181. }
  182. const auto SetMediaResult = SoundEngine->SetMedia(this, 1);
  183. if (LIKELY(SetMediaResult == AK_Success))
  184. {
  185. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedMediaFileState::OpenFile %" PRIu32 " (%s): Prefetched %" PRIu32 " bytes."), MediaId, *DebugName.ToString(), uMediaSize);
  186. INC_DWORD_STAT(STAT_WwiseFileHandlerPrefetchedMedia);
  187. return OpenFileSucceeded(MoveTemp(InCallback));
  188. }
  189. else
  190. {
  191. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedMediaFileState::OpenFile %" PRIu32 " (%s): Failed to prefetch media: %d (%s)."), MediaId, *DebugName.ToString(), SetMediaResult, WwiseUnrealHelper::GetResultString(SetMediaResult));
  192. DeallocateMemory(pMediaMemory, uMediaSize, bDeviceMemory, MemoryAlignment, true, STAT_WwiseMemoryMediaPrefetch_FName, STAT_WwiseMemoryMediaPrefetchDevice_FName);
  193. pMediaMemory = nullptr;
  194. uMediaSize = 0;
  195. return OpenFileFailed(MoveTemp(InCallback));
  196. }
  197. }
  198. void FWwiseStreamedMediaFileState::LoadInSoundEngine(FLoadInSoundEngineCallback&& InCallback)
  199. {
  200. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseStreamedMediaFileState::LoadInSoundEngine"));
  201. if (UNLIKELY(iFileSize != 0 || StreamedFile))
  202. {
  203. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedMediaFileState::LoadInSoundEngine %" PRIu32 " (%s): Stream seems to be already loaded."), MediaId, *DebugName.ToString());
  204. return LoadInSoundEngineFailed(MoveTemp(InCallback));
  205. }
  206. FWwiseFileCache* FileCache = FWwiseFileCache::Get();
  207. if (UNLIKELY(!FileCache))
  208. {
  209. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedMediaFileState::LoadInSoundEngine %" PRIu32 " (%s): WwiseFileCache not available."), MediaId, *DebugName.ToString());
  210. return LoadInSoundEngineFailed(MoveTemp(InCallback));
  211. }
  212. const auto FullPathName = RootPath / MediaPathName.ToString();
  213. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseStreamedMediaFileState::LoadInSoundEngine %" PRIu32 " (%s): Opening file"), MediaId, *DebugName.ToString());
  214. FileCache->CreateFileCacheHandle(StreamedFile, FullPathName, [this, Callback = MoveTemp(InCallback)](bool bResult) mutable
  215. {
  216. if (UNLIKELY(!bResult))
  217. {
  218. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedMediaFileState::LoadInSoundEngine %" PRIu32 ": Failed to load Streaming Media (%s)."), MediaId, *DebugName.ToString());
  219. LaunchWwiseTask(WWISEFILEHANDLER_ASYNC_NAME("FWwiseStreamedMediaFileState::LoadInSoundEngine delete"), [StreamedFile=StreamedFile]
  220. {
  221. delete StreamedFile;
  222. });
  223. StreamedFile = nullptr;
  224. return LoadInSoundEngineFailed(MoveTemp(Callback));
  225. }
  226. iFileSize = StreamedFile->GetFileSize();
  227. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedMediaFileState::LoadInSoundEngine %" PRIu32 " (%s)"), MediaId, *DebugName.ToString());
  228. INC_DWORD_STAT(STAT_WwiseFileHandlerLoadedMedia);
  229. return LoadInSoundEngineSucceeded(MoveTemp(Callback));
  230. });
  231. }
  232. void FWwiseStreamedMediaFileState::UnloadFromSoundEngine(FUnloadFromSoundEngineCallback&& InCallback)
  233. {
  234. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseStreamedMediaFileState::UnloadFromSoundEngine"));
  235. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedMediaFileState::UnloadFromSoundEngine %" PRIu32 " (%s)"), MediaId, *DebugName.ToString());
  236. const auto* StreamedFileToDelete = StreamedFile;
  237. StreamedFile = nullptr;
  238. iFileSize = 0;
  239. delete StreamedFileToDelete;
  240. DEC_DWORD_STAT(STAT_WwiseFileHandlerLoadedMedia);
  241. UnloadFromSoundEngineDone(MoveTemp(InCallback));
  242. }
  243. void FWwiseStreamedMediaFileState::CloseFile(FCloseFileCallback&& InCallback)
  244. {
  245. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseStreamedMediaFileState::CloseFile"));
  246. if (pMediaMemory == nullptr)
  247. {
  248. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedMediaFileState::CloseFile %" PRIu32 " (%s)"), MediaId, *DebugName.ToString());
  249. return CloseFileDone(MoveTemp(InCallback));
  250. }
  251. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  252. if (UNLIKELY(!SoundEngine))
  253. {
  254. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseStreamedMediaFileState::CloseFile %" PRIu32 " (%s): Failed closing prefetch without a SoundEngine. Leaking."), MediaId, *DebugName.ToString());
  255. pMediaMemory = nullptr;
  256. uMediaSize = 0;
  257. return CloseFileDone(MoveTemp(InCallback));
  258. }
  259. const auto Result = SoundEngine->TryUnsetMedia(this, 1, nullptr);
  260. if (UNLIKELY(Result == AK_ResourceInUse))
  261. {
  262. return CloseFileDefer(MoveTemp(InCallback));
  263. }
  264. else
  265. {
  266. if (LIKELY(Result == AK_Success))
  267. {
  268. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedMediaFileState::CloseFile %" PRIu32 " (%s): Unloaded prefetch."), MediaId, *DebugName.ToString());
  269. DEC_DWORD_STAT(STAT_WwiseFileHandlerPrefetchedMedia);
  270. DeallocateMemory(pMediaMemory, uMediaSize, bDeviceMemory, MemoryAlignment, true, STAT_WwiseMemoryMediaPrefetch_FName, STAT_WwiseMemoryMediaPrefetchDevice_FName);
  271. }
  272. else
  273. {
  274. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedMediaFileState::CloseFile %" PRIu32 " (%s): TryUnsetMedia of prefetch failed: %d (%s). Leaking."), MediaId, *DebugName.ToString(), Result, WwiseUnrealHelper::GetResultString(Result));
  275. }
  276. pMediaMemory = nullptr;
  277. uMediaSize = 0;
  278. return CloseFileDone(MoveTemp(InCallback));
  279. }
  280. }
  281. bool FWwiseStreamedMediaFileState::CanProcessFileOp() const
  282. {
  283. if (UNLIKELY(State != EState::Loaded))
  284. {
  285. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedMediaFileState::CanProcessFileOp %" PRIu32 " (%s): IO Hook asked for a file operation, but state is not ready."), MediaId, *DebugName.ToString());
  286. return false;
  287. }
  288. return true;
  289. }
  290. AKRESULT FWwiseStreamedMediaFileState::ProcessRead(
  291. AkFileDesc& InFileDesc, const AkIoHeuristics& InHeuristics,
  292. AkAsyncIOTransferInfo& OutTransferInfo, FWwiseAkFileOperationDone&& InFileOpDoneCallback)
  293. {
  294. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseStreamedMediaFileState::ProcessRead: Reading %" PRIu32 " bytes @ %" PRIu64 " in file %" PRIu32 " (%s)"),
  295. OutTransferInfo.uRequestedSize, OutTransferInfo.uFilePosition, MediaId, *DebugName.ToString());
  296. StreamedFile->ReadAkData(InHeuristics, OutTransferInfo, MoveTemp(InFileOpDoneCallback));
  297. return AK_Success;
  298. }