WwiseExternalSourceFileState.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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/WwiseExternalSourceFileState.h"
  16. #include "Wwise/WwiseExternalSourceManager.h"
  17. #include "Wwise/WwiseFileCache.h"
  18. #include "Wwise/WwiseStreamingManagerHooks.h"
  19. #include "Wwise/API/WwiseSoundEngineAPI.h"
  20. #include "Async/MappedFileHandle.h"
  21. #include <inttypes.h>
  22. FWwiseExternalSourceFileState::FWwiseExternalSourceFileState(uint32 InMemoryAlignment, bool bInDeviceMemory,
  23. uint32 InMediaId, const FName& InMediaPathName, const FName& InRootPath, int32 InCodecId) :
  24. AkExternalSourceInfo(),
  25. MemoryAlignment(InMemoryAlignment),
  26. bDeviceMemory(bInDeviceMemory),
  27. MediaId(InMediaId),
  28. MediaPathName(InMediaPathName),
  29. RootPath(InRootPath),
  30. PlayCount(0)
  31. {
  32. idCodec = InCodecId;
  33. INC_DWORD_STAT(STAT_WwiseFileHandlerKnownExternalSourceMedia);
  34. }
  35. FWwiseExternalSourceFileState::~FWwiseExternalSourceFileState()
  36. {
  37. DEC_DWORD_STAT(STAT_WwiseFileHandlerKnownExternalSourceMedia);
  38. }
  39. bool FWwiseExternalSourceFileState::GetExternalSourceInfo(AkExternalSourceInfo& OutInfo)
  40. {
  41. OutInfo = static_cast<AkExternalSourceInfo>(*this);
  42. return szFile != nullptr || pInMemory != nullptr || idFile != 0;
  43. }
  44. void FWwiseExternalSourceFileState::IncrementPlayCount()
  45. {
  46. ++PlayCount;
  47. }
  48. bool FWwiseExternalSourceFileState::DecrementPlayCount()
  49. {
  50. const auto NewPlayCount = PlayCount.DecrementExchange() - 1;
  51. if (PlayCount < 0)
  52. {
  53. PlayCount.Store(0);
  54. UE_LOG(LogWwiseFileHandler, Warning, TEXT("FWwiseExternalSourceFileState: Play count went below zero for media %" PRIu32 " (%s)"),
  55. MediaId, *MediaPathName.ToString());
  56. }
  57. return NewPlayCount == 0;
  58. }
  59. FWwiseInMemoryExternalSourceFileState::FWwiseInMemoryExternalSourceFileState(uint32 InMemoryAlignment, bool bInDeviceMemory,
  60. uint32 InMediaId, const FName& InMediaPathName, const FName& InRootPath, int32 InCodecId) :
  61. FWwiseExternalSourceFileState(InMemoryAlignment, bInDeviceMemory, InMediaId, InMediaPathName, InRootPath, InCodecId),
  62. Ptr(nullptr),
  63. MappedHandle(nullptr),
  64. MappedRegion(nullptr)
  65. {
  66. #if WITH_EDITOR
  67. if (bDeviceMemory)
  68. {
  69. UE_LOG(LogWwiseFileHandler, Warning, TEXT("FWwiseExternalSourceFileState: Loading External Source Media with DeviceMemory=true while in in editor. Expect to see \"No Device Memory\" errors in the log."));
  70. }
  71. #endif
  72. }
  73. void FWwiseInMemoryExternalSourceFileState::OpenFile(FOpenFileCallback&& InCallback)
  74. {
  75. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemoryExternalSourceFileState::OpenFile"));
  76. if (UNLIKELY(uiMemorySize || pInMemory))
  77. {
  78. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemoryExternalSourceFileState::OpenFile %" PRIu32 " (%s): Seems to be already opened."), MediaId, *MediaPathName.ToString());
  79. return OpenFileFailed(MoveTemp(InCallback));
  80. }
  81. const auto FullPathName = RootPath.ToString() / MediaPathName.ToString();
  82. int64 FileSize = 0;
  83. if (LIKELY(GetFileToPtr(const_cast<const uint8*&>(reinterpret_cast<uint8*&>(pInMemory)), FileSize, FullPathName, bDeviceMemory, MemoryAlignment, true)))
  84. {
  85. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemoryExternalSourceFileState::OpenFile %" PRIu32 " (%s)"), MediaId, *MediaPathName.ToString());
  86. uiMemorySize = FileSize;
  87. return OpenFileSucceeded(MoveTemp(InCallback));
  88. }
  89. else
  90. {
  91. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseInMemoryExternalSourceFileState::OpenFile %" PRIu32 ": Failed to open In-Memory External Source (%s)."), MediaId, *FullPathName);
  92. pInMemory = nullptr;
  93. FileSize = 0;
  94. return OpenFileFailed(MoveTemp(InCallback));
  95. }
  96. }
  97. void FWwiseInMemoryExternalSourceFileState::LoadInSoundEngine(FLoadInSoundEngineCallback&& InCallback)
  98. {
  99. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemoryExternalSourceFileState::LoadInSoundEngine"));
  100. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemoryExternalSourceFileState::LoadInSoundEngine %" PRIu32 " (%s)"), MediaId, *MediaPathName.ToString());
  101. INC_DWORD_STAT(STAT_WwiseFileHandlerLoadedExternalSourceMedia);
  102. LoadInSoundEngineSucceeded(MoveTemp(InCallback));
  103. }
  104. void FWwiseInMemoryExternalSourceFileState::UnloadFromSoundEngine(FUnloadFromSoundEngineCallback&& InCallback)
  105. {
  106. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemoryExternalSourceFileState::UnloadFromSoundEngine"));
  107. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseInMemoryExternalSourceFileState::UnloadFromSoundEngine %" PRIu32 " (%s)"), MediaId, *MediaPathName.ToString());
  108. DEC_DWORD_STAT(STAT_WwiseFileHandlerLoadedExternalSourceMedia);
  109. UnloadFromSoundEngineDone(MoveTemp(InCallback));
  110. }
  111. void FWwiseInMemoryExternalSourceFileState::CloseFile(FCloseFileCallback&& InCallback)
  112. {
  113. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseInMemoryExternalSourceFileState::CloseFile"));
  114. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseInMemoryExternalSourceFileState::CloseFile %" PRIu32 " (%s)"), MediaId, *MediaPathName.ToString());
  115. DeallocateMemory(const_cast<const uint8*&>(reinterpret_cast<uint8*&>(pInMemory)), uiMemorySize, bDeviceMemory, MemoryAlignment, true);
  116. pInMemory = nullptr;
  117. uiMemorySize = 0;
  118. CloseFileDone(MoveTemp(InCallback));
  119. }
  120. FWwiseStreamedExternalSourceFileState::FWwiseStreamedExternalSourceFileState(uint32 InMemoryAlignment, bool bInDeviceMemory,
  121. uint32 InPrefetchSize, uint32 InStreamingGranularity,
  122. uint32 InMediaId, const FName& InMediaPathName, const FName& InRootPath, int32 InCodecId) :
  123. FWwiseExternalSourceFileState(InMemoryAlignment, bInDeviceMemory, InMediaId, InMediaPathName, InRootPath, InCodecId),
  124. PrefetchSize(InPrefetchSize),
  125. StreamingGranularity(InStreamingGranularity),
  126. StreamedFile(nullptr)
  127. {
  128. sourceID = InMediaId;
  129. pMediaMemory = nullptr;
  130. uMediaSize = 0;
  131. idFile = InMediaId;
  132. }
  133. void FWwiseStreamedExternalSourceFileState::CloseStreaming()
  134. {
  135. auto* ExternalSourceManager = IWwiseExternalSourceManager::Get();
  136. if (UNLIKELY(!ExternalSourceManager))
  137. {
  138. UE_LOG(LogWwiseFileHandler, Log, TEXT("FWwiseStreamedExternalSourceFileState::CloseStreaming %" PRIu32 " (%s): Closing without an ExternalSourceManager."), MediaId, *MediaPathName.ToString());
  139. return;
  140. }
  141. ExternalSourceManager->GetStreamingHooks().CloseStreaming(MediaId, *this);
  142. }
  143. void FWwiseStreamedExternalSourceFileState::OpenFile(FOpenFileCallback&& InCallback)
  144. {
  145. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseStreamedExternalSourceFileState::OpenFile"));
  146. if (UNLIKELY(iFileSize != 0 || StreamedFile))
  147. {
  148. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedExternalSourceFileState::OpenFile %" PRIu32 " (%s): Stream seems to be already opened."), MediaId, *MediaPathName.ToString());
  149. return OpenFileFailed(MoveTemp(InCallback));
  150. }
  151. if (PrefetchSize == 0)
  152. {
  153. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedExternalSourceFileState::OpenFile %" PRIu32 " (%s)"), MediaId, *MediaPathName.ToString());
  154. return OpenFileSucceeded(MoveTemp(InCallback));
  155. }
  156. // Process PrefetchSize and send as SetMedia
  157. const auto FullPathName = RootPath.ToString() / MediaPathName.ToString();
  158. auto PrefetchWithGranularity = PrefetchSize;
  159. if (StreamingGranularity > 1)
  160. {
  161. auto PrefetchChunks = PrefetchSize / StreamingGranularity;
  162. if (PrefetchSize % StreamingGranularity > 0)
  163. {
  164. PrefetchChunks += 1;
  165. }
  166. PrefetchWithGranularity = PrefetchChunks * StreamingGranularity;
  167. }
  168. int64 FileSize = 0;
  169. if (UNLIKELY(!GetFileToPtr(const_cast<const uint8*&>(pMediaMemory), FileSize, FullPathName, false, 0, false, PrefetchWithGranularity)))
  170. {
  171. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedExternalSourceFileState::OpenFile %" PRIu32 " (%s): Failed to Read prefetch ExternalSource (%s)."), MediaId, *MediaPathName.ToString(), *FullPathName);
  172. pMediaMemory = nullptr;
  173. return OpenFileFailed(MoveTemp(InCallback));
  174. }
  175. uMediaSize = FileSize;
  176. UE_CLOG(FileSize == PrefetchSize, LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedExternalSourceFileState::OpenFile %" PRIu32 " (%s): Prefetched %" PRIu32 " bytes."), MediaId, *MediaPathName.ToString(), uMediaSize);
  177. UE_CLOG(PrefetchSize != PrefetchWithGranularity && PrefetchWithGranularity == FileSize, LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedExternalSourceFileState::OpenFile %" PRIu32 " (%s): Prefetched (%" PRIu32 ") -> %" PRIu32 " bytes."), MediaId, *MediaPathName.ToString(), PrefetchSize, PrefetchWithGranularity);
  178. UE_CLOG(PrefetchWithGranularity != FileSize, LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedExternalSourceFileState::OpenFile %" PRIu32 " (%s): Prefetched (%" PRIu32 " -> %" PRIu32 ") -> %" PRIu32 " bytes."), MediaId, *MediaPathName.ToString(), PrefetchSize, PrefetchWithGranularity, uMediaSize);
  179. INC_MEMORY_STAT_BY(STAT_WwiseFileHandlerPrefetchMemoryAllocated, uMediaSize);
  180. return OpenFileSucceeded(MoveTemp(InCallback));
  181. }
  182. void FWwiseStreamedExternalSourceFileState::LoadInSoundEngine(FLoadInSoundEngineCallback&& InCallback)
  183. {
  184. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseStreamedExternalSourceFileState::LoadInSoundEngine"));
  185. if (UNLIKELY(iFileSize != 0 || StreamedFile))
  186. {
  187. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedExternalSourceFileState::LoadInSoundEngine %" PRIu32 " (%s): Stream seems to be already loaded."), MediaId, *MediaPathName.ToString());
  188. return LoadInSoundEngineFailed(MoveTemp(InCallback));
  189. }
  190. FWwiseFileCache* FileCache = FWwiseFileCache::Get();
  191. if (UNLIKELY(!FileCache))
  192. {
  193. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedExternalSourceFileState::LoadInSoundEngine %" PRIu32 " (%s): WwiseFileCache not available."), MediaId, *MediaPathName.ToString());
  194. return LoadInSoundEngineFailed(MoveTemp(InCallback));
  195. }
  196. const auto FullPathName = RootPath.ToString() / MediaPathName.ToString();
  197. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseStreamedExternalSourceFileState::LoadInSoundEngine %" PRIu32 " (%s): Opening file"), MediaId, *MediaPathName.ToString());
  198. FileCache->CreateFileCacheHandle(StreamedFile, FullPathName, [this, Callback = MoveTemp(InCallback)](bool bResult) mutable
  199. {
  200. if (UNLIKELY(!bResult))
  201. {
  202. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedExternalSourceFileState::LoadInSoundEngine %" PRIu32 ": Failed to load Streaming ExternalSource (%s)."), MediaId, *MediaPathName.ToString());
  203. FFunctionGraphTask::CreateAndDispatchWhenReady([StreamedFile = StreamedFile]
  204. {
  205. delete StreamedFile;
  206. });
  207. StreamedFile = nullptr;
  208. return LoadInSoundEngineFailed(MoveTemp(Callback));
  209. }
  210. iFileSize = StreamedFile->GetFileSize();
  211. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedExternalSourceFileState::LoadInSoundEngine %" PRIu32 " (%s)"), MediaId, *MediaPathName.ToString());
  212. INC_DWORD_STAT(STAT_WwiseFileHandlerLoadedExternalSourceMedia);
  213. return LoadInSoundEngineSucceeded(MoveTemp(Callback));
  214. });
  215. }
  216. void FWwiseStreamedExternalSourceFileState::UnloadFromSoundEngine(FUnloadFromSoundEngineCallback&& InCallback)
  217. {
  218. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseStreamedExternalSourceFileState::UnloadFromSoundEngine"));
  219. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedExternalSourceFileState::UnloadFromSoundEngine %" PRIu32 " (%s)"), MediaId, *MediaPathName.ToString());
  220. const auto* StreamedFileToDelete = StreamedFile;
  221. StreamedFile = nullptr;
  222. iFileSize = 0;
  223. delete StreamedFileToDelete;
  224. DEC_DWORD_STAT(STAT_WwiseFileHandlerLoadedExternalSourceMedia);
  225. UnloadFromSoundEngineDone(MoveTemp(InCallback));
  226. }
  227. void FWwiseStreamedExternalSourceFileState::CloseFile(FCloseFileCallback&& InCallback)
  228. {
  229. SCOPED_WWISEFILEHANDLER_EVENT_3(TEXT("FWwiseStreamedExternalSourceFileState::CloseFile"));
  230. if (pMediaMemory == nullptr)
  231. {
  232. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedExternalSourceFileState::CloseFile %" PRIu32 " (%s)"), MediaId, *MediaPathName.ToString());
  233. return CloseFileDone(MoveTemp(InCallback));
  234. }
  235. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("FWwiseStreamedExternalSourceFileState::CloseFile %" PRIu32 " (%s): Unloaded prefetch."), MediaId, *MediaPathName.ToString());
  236. DeallocateMemory(pMediaMemory, uMediaSize, bDeviceMemory, MemoryAlignment, true);
  237. DEC_MEMORY_STAT_BY(STAT_WwiseFileHandlerPrefetchMemoryAllocated, uMediaSize);
  238. pMediaMemory = nullptr;
  239. uMediaSize = 0;
  240. return CloseFileDone(MoveTemp(InCallback));
  241. }
  242. bool FWwiseStreamedExternalSourceFileState::CanProcessFileOp() const
  243. {
  244. if (UNLIKELY(State != EState::Loaded))
  245. {
  246. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseStreamedExternalSourceFileState::CanProcessFileOp %" PRIu32 " (%s): IO Hook asked for a file operation, but state is not ready."), MediaId, *MediaPathName.ToString());
  247. return false;
  248. }
  249. return true;
  250. }
  251. AKRESULT FWwiseStreamedExternalSourceFileState::ProcessRead(AkFileDesc& InFileDesc, const AkIoHeuristics& InHeuristics, AkAsyncIOTransferInfo& OutTransferInfo, FWwiseAkFileOperationDone&& InFileOpDoneCallback)
  252. {
  253. if (pMediaMemory && OutTransferInfo.uFilePosition + OutTransferInfo.uRequestedSize <= uMediaSize)
  254. {
  255. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseStreamedExternalSourceFileState::ProcessRead: Reading prefetch %" PRIu32 " bytes @ %" PRIu64 " in file %" PRIu32 " (%s)"),
  256. OutTransferInfo.uRequestedSize, OutTransferInfo.uFilePosition, MediaId, *MediaPathName.ToString());
  257. FMemory::Memcpy(OutTransferInfo.pBuffer, pMediaMemory + OutTransferInfo.uFilePosition, OutTransferInfo.uRequestedSize);
  258. SCOPED_WWISEFILEHANDLER_EVENT_4(TEXT("FWwiseStreamedExternalSourceFileState::ProcessRead Callback"));
  259. InFileOpDoneCallback(&OutTransferInfo, AK_Success);
  260. return AK_Success;
  261. }
  262. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("FWwiseStreamedExternalSourceFileState::ProcessRead: Reading %" PRIu32 " bytes @ %" PRIu64 " in file %" PRIu32 " (%s)"),
  263. OutTransferInfo.uRequestedSize, OutTransferInfo.uFilePosition, MediaId, *MediaPathName.ToString());
  264. StreamedFile->ReadAkData(InHeuristics, OutTransferInfo, MoveTemp(InFileOpDoneCallback));
  265. return AK_Success;
  266. }