WwiseExternalSourceManagerImpl.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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/WwiseExternalSourceManagerImpl.h"
  16. #include "Wwise/API/WwiseSoundEngineAPI.h"
  17. #include "Wwise/Stats/AsyncStats.h"
  18. #include "Wwise/Stats/FileHandler.h"
  19. #include <inttypes.h>
  20. #include "Wwise/WwiseExternalSourceFileState.h"
  21. FWwiseExternalSourceState::FWwiseExternalSourceState(const FWwiseExternalSourceCookedData& InCookedData) :
  22. FWwiseExternalSourceCookedData(InCookedData),
  23. LoadCount(0)
  24. {
  25. INC_DWORD_STAT(STAT_WwiseFileHandlerCreatedExternalSourceStates);
  26. }
  27. FWwiseExternalSourceState::~FWwiseExternalSourceState()
  28. {
  29. DEC_DWORD_STAT(STAT_WwiseFileHandlerCreatedExternalSourceStates);
  30. }
  31. void FWwiseExternalSourceState::IncrementLoadCount()
  32. {
  33. const auto NewLoadCount = LoadCount.IncrementExchange() + 1;
  34. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("ExternalSource State %" PRIu32 " (%s): ++LoadCount=%d"), Cookie, *DebugName.ToString(), NewLoadCount);
  35. }
  36. bool FWwiseExternalSourceState::DecrementLoadCount()
  37. {
  38. const auto NewLoadCount = LoadCount.DecrementExchange() - 1;
  39. const bool bResult = (NewLoadCount == 0);
  40. if (bResult)
  41. {
  42. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("ExternalSource State %" PRIu32 " (%s): --LoadCount=%d. Deleting."), Cookie, *DebugName.ToString(), NewLoadCount);
  43. }
  44. else
  45. {
  46. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("ExternalSource State %" PRIu32 " (%s): --LoadCount=%d"), Cookie, *DebugName.ToString(), NewLoadCount);
  47. }
  48. return bResult;
  49. }
  50. FWwiseExternalSourceManagerImpl::FWwiseExternalSourceManagerImpl() :
  51. StreamingGranularity(0)
  52. {
  53. }
  54. FWwiseExternalSourceManagerImpl::~FWwiseExternalSourceManagerImpl()
  55. {
  56. }
  57. void FWwiseExternalSourceManagerImpl::LoadExternalSource(
  58. const FWwiseExternalSourceCookedData& InExternalSourceCookedData, const FName& InRootPath,
  59. const FWwiseLanguageCookedData& InLanguage, FLoadExternalSourceCallback&& InCallback)
  60. {
  61. FileHandlerExecutionQueue.Async([this, InExternalSourceCookedData, InRootPath, InLanguage, InCallback = MoveTemp(InCallback)]() mutable
  62. {
  63. LoadExternalSourceImpl(InExternalSourceCookedData, InRootPath, InLanguage, MoveTemp(InCallback));
  64. });
  65. }
  66. void FWwiseExternalSourceManagerImpl::UnloadExternalSource(
  67. const FWwiseExternalSourceCookedData& InExternalSourceCookedData, const FName& InRootPath,
  68. const FWwiseLanguageCookedData& InLanguage, FUnloadExternalSourceCallback&& InCallback)
  69. {
  70. FileHandlerExecutionQueue.Async([this, InExternalSourceCookedData, InRootPath, InLanguage, InCallback = MoveTemp(InCallback)]() mutable
  71. {
  72. UnloadExternalSourceImpl(InExternalSourceCookedData, InRootPath, InLanguage, MoveTemp(InCallback));
  73. });
  74. }
  75. void FWwiseExternalSourceManagerImpl::SetGranularity(AkUInt32 InStreamingGranularity)
  76. {
  77. StreamingGranularity = InStreamingGranularity;
  78. }
  79. TArray<uint32> FWwiseExternalSourceManagerImpl::PrepareExternalSourceInfos(TArray<AkExternalSourceInfo>& OutInfo,
  80. const TArray<FWwiseExternalSourceCookedData>
  81. &&
  82. InCookedData)
  83. {
  84. SCOPED_WWISEFILEHANDLER_EVENT_2(TEXT("FWwiseExternalSourceManagerImpl::PrepareExternalSourceInfos"));
  85. if (InCookedData.Num() == 0)
  86. {
  87. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("PrepareExternalSourceInfos: No External Sources to process"));
  88. return {};
  89. }
  90. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("GetExternalSourceInfos: Preparing %d external sources."), InCookedData.Num());
  91. TArray<uint32> Result;
  92. OutInfo.Reset();
  93. OutInfo.Reserve(InCookedData.Num());
  94. Result.Reserve(InCookedData.Num());
  95. {
  96. FRWScopeLock Lock(CookieToMediaLock, FRWScopeLockType::SLT_ReadOnly);
  97. for (const auto& Data : InCookedData)
  98. {
  99. AkExternalSourceInfo Info;
  100. const auto MediaId = PrepareExternalSourceInfo(Info, Data);
  101. if (LIKELY(MediaId != AK_INVALID_UNIQUE_ID))
  102. {
  103. OutInfo.Add(MoveTemp(Info));
  104. Result.Add(MediaId);
  105. }
  106. }
  107. }
  108. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("GetExternalSourceInfos: Successfuly retrieved requested %d of %d external sources."), OutInfo.Num(), InCookedData.Num());
  109. return Result;
  110. }
  111. #if WITH_EDITORONLY_DATA
  112. void FWwiseExternalSourceManagerImpl::Cook(FWwiseResourceCooker& InResourceCooker, const FWwiseExternalSourceCookedData& InCookedData,
  113. TFunctionRef<void(const TCHAR* Filename, void* Data, int64 Size)> WriteAdditionalFile,
  114. const FWwiseSharedPlatformId& InPlatform, const FWwiseSharedLanguageId& InLanguage)
  115. {
  116. UE_LOG(LogWwiseFileHandler, Error, TEXT("FWwiseExternalSourceManagerImpl::Cook: External Source manager needs to be overridden."));
  117. }
  118. #endif
  119. void FWwiseExternalSourceManagerImpl::LoadExternalSourceImpl(
  120. const FWwiseExternalSourceCookedData& InExternalSourceCookedData, const FName& InRootPath, const FWwiseLanguageCookedData& InLanguage,
  121. FLoadExternalSourceCallback&& InCallback)
  122. {
  123. SCOPED_WWISEFILEHANDLER_EVENT_2(TEXT("FWwiseExternalSourceManagerImpl::LoadExternalSourceImpl"));
  124. FWwiseExternalSourceStateSharedPtr State;
  125. if (const auto* StatePtr = ExternalSourceStatesById.Find(InExternalSourceCookedData.Cookie))
  126. {
  127. State = *StatePtr;
  128. State->IncrementLoadCount();
  129. }
  130. else
  131. {
  132. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("Creating new State for %s %" PRIu32), GetManagingTypeName(), InExternalSourceCookedData.Cookie);
  133. State = CreateExternalSourceState(InExternalSourceCookedData, InRootPath);
  134. if (UNLIKELY(!State.IsValid()))
  135. {
  136. SCOPED_WWISEFILEHANDLER_EVENT_4(TEXT("FWwiseExternalSourceManagerImpl::LoadExternalSourceImpl Callback"));
  137. InCallback(false);
  138. return;
  139. }
  140. else
  141. {
  142. State->IncrementLoadCount();
  143. ExternalSourceStatesById.Add(InExternalSourceCookedData.Cookie, State);
  144. }
  145. }
  146. LoadExternalSourceMedia(InExternalSourceCookedData.Cookie, InExternalSourceCookedData.DebugName, InRootPath, MoveTemp(InCallback));
  147. }
  148. void FWwiseExternalSourceManagerImpl::UnloadExternalSourceImpl(
  149. const FWwiseExternalSourceCookedData& InExternalSourceCookedData, const FName& InRootPath, const FWwiseLanguageCookedData& InLanguage,
  150. FUnloadExternalSourceCallback&& InCallback)
  151. {
  152. SCOPED_WWISEFILEHANDLER_EVENT_2(TEXT("FWwiseExternalSourceManagerImpl::UnloadExternalSourceImpl"));
  153. FWwiseExternalSourceStateSharedPtr State;
  154. if (const auto* StatePtr = ExternalSourceStatesById.Find(InExternalSourceCookedData.Cookie))
  155. {
  156. State = *StatePtr;
  157. }
  158. if (UNLIKELY(!State.IsValid()))
  159. {
  160. UE_LOG(LogWwiseFileHandler, Error, TEXT("ExternalSource %" PRIu32 " (%s): Unloading an unknown External Source"), InExternalSourceCookedData.Cookie, *InExternalSourceCookedData.DebugName.ToString());
  161. SCOPED_WWISEFILEHANDLER_EVENT_4(TEXT("FWwiseExternalSourceManagerImpl::UnloadExternalSourceImpl Callback"));
  162. InCallback();
  163. }
  164. else
  165. {
  166. FWwiseExternalSourceState* ExternalSourceState = State.Get();
  167. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("ExternalSource %" PRIu32 " (%s): Closing State instance"), InExternalSourceCookedData.Cookie, *InExternalSourceCookedData.DebugName.ToString());
  168. if (CloseExternalSourceState(*State) && InExternalSourceCookedData.Cookie != 0)
  169. {
  170. ExternalSourceStatesById.Remove(InExternalSourceCookedData.Cookie);
  171. State.Reset();
  172. }
  173. if (LIKELY(InExternalSourceCookedData.Cookie != 0))
  174. {
  175. UnloadExternalSourceMedia(InExternalSourceCookedData.Cookie, InExternalSourceCookedData.DebugName, InRootPath, MoveTemp(InCallback));
  176. }
  177. else
  178. {
  179. SCOPED_WWISEFILEHANDLER_EVENT_4(TEXT("FWwiseExternalSourceManagerImpl::UnloadExternalSourceImpl Callback"));
  180. InCallback();
  181. }
  182. }
  183. }
  184. FWwiseExternalSourceStateSharedPtr FWwiseExternalSourceManagerImpl::CreateExternalSourceState(
  185. const FWwiseExternalSourceCookedData& InExternalSourceCookedData, const FName& InRootPath)
  186. {
  187. return FWwiseExternalSourceStateSharedPtr(new FWwiseExternalSourceState(InExternalSourceCookedData));
  188. }
  189. bool FWwiseExternalSourceManagerImpl::CloseExternalSourceState(FWwiseExternalSourceState& InExternalSourceState)
  190. {
  191. return InExternalSourceState.DecrementLoadCount();
  192. }
  193. void FWwiseExternalSourceManagerImpl::LoadExternalSourceMedia(const uint32 InExternalSourceCookie,
  194. const FName& InExternalSourceName, const FName& InRootPath, FLoadExternalSourceCallback&& InCallback)
  195. {
  196. UE_LOG(LogWwiseFileHandler, Error, TEXT("External Source manager needs to be overridden."));
  197. InCallback(false);
  198. }
  199. void FWwiseExternalSourceManagerImpl::UnloadExternalSourceMedia(const uint32 InExternalSourceCookie,
  200. const FName& InExternalSourceName, const FName& InRootPath, FUnloadExternalSourceCallback&& InCallback)
  201. {
  202. UE_LOG(LogWwiseFileHandler, Error, TEXT("External Source manager needs to be overridden."));
  203. InCallback();
  204. }
  205. uint32 FWwiseExternalSourceManagerImpl::PrepareExternalSourceInfo(AkExternalSourceInfo& OutInfo,
  206. const FWwiseExternalSourceCookedData& InCookedData)
  207. {
  208. const auto* ExternalSourceFileStatePtr = CookieToMedia.Find(InCookedData.Cookie);
  209. if (UNLIKELY(!ExternalSourceFileStatePtr))
  210. {
  211. UE_LOG(LogWwiseFileHandler, Warning, TEXT("PrepareExternalSourceInfo %" PRIu32 " (%s): CookieToMedia not defined"), InCookedData.Cookie, *InCookedData.DebugName.ToString());
  212. return AK_INVALID_UNIQUE_ID;
  213. }
  214. auto* ExternalSourceFileState = *ExternalSourceFileStatePtr;
  215. if (UNLIKELY(!ExternalSourceFileState->GetExternalSourceInfo(OutInfo)))
  216. {
  217. UE_LOG(LogWwiseFileHandler, Log, TEXT("Getting external source %" PRIu32 " (%s): AkExternalSourceInfo not initialized"), InCookedData.Cookie, *InCookedData.DebugName.ToString());
  218. return AK_INVALID_UNIQUE_ID;
  219. }
  220. ExternalSourceFileState->IncrementPlayCount();
  221. OutInfo.iExternalSrcCookie = InCookedData.Cookie;
  222. UE_CLOG(OutInfo.idFile != 0, LogWwiseFileHandler, VeryVerbose, TEXT("Getting external source %" PRIu32 " (%s): Using file %" PRIu32), InCookedData.Cookie, *InCookedData.DebugName.ToString(), OutInfo.idFile);
  223. UE_CLOG(OutInfo.idFile == 0, LogWwiseFileHandler, VeryVerbose, TEXT("Getting external source %" PRIu32 " (%s): Using memory file"), InCookedData.Cookie, *InCookedData.DebugName.ToString());
  224. return ExternalSourceFileState->MediaId;
  225. }
  226. void FWwiseExternalSourceManagerImpl::BindPlayingIdToExternalSources(const uint32 InPlayingId,
  227. const TArray<uint32>& InMediaIds)
  228. {
  229. if (InMediaIds.Num() == 0)
  230. {
  231. return;
  232. }
  233. SCOPED_WWISEFILEHANDLER_EVENT_2(TEXT("FWwiseExternalSourceManagerImpl::BindPlayingIdToExternalSources"));
  234. if (UNLIKELY(InPlayingId == AK_INVALID_PLAYING_ID))
  235. {
  236. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("BindPlayingIdToExternalSources: Failed PostEvent. Unpreparing %d Media."), InMediaIds.Num());
  237. FRWScopeLock Lock(CookieToMediaLock, FRWScopeLockType::SLT_ReadOnly);
  238. for (const auto MediaId : InMediaIds)
  239. {
  240. FWwiseFileStateSharedPtr State;
  241. {
  242. FRWScopeLock StateLock(FileStatesByIdLock, FRWScopeLockType::SLT_ReadOnly);
  243. const auto* StatePtr = FileStatesById.Find(MediaId);
  244. if (UNLIKELY(!StatePtr || !StatePtr->IsValid()))
  245. {
  246. UE_LOG(LogWwiseFileHandler, Warning, TEXT("BindPlayingIdToExternalSources: Getting external source media state %" PRIu32 " failed to decrement after failed PostEvent."), MediaId);
  247. continue;
  248. }
  249. State = *StatePtr;
  250. }
  251. auto* ExternalSourceFileState = State->GetStateAs<FWwiseExternalSourceFileState>();
  252. if (UNLIKELY(!ExternalSourceFileState))
  253. {
  254. UE_LOG(LogWwiseFileHandler, Error, TEXT("BindPlayingIdToExternalSources: Getting external source media %" PRIu32 ": Could not cast to ExternalSourceState"), MediaId);
  255. continue;
  256. }
  257. FileHandlerExecutionQueue.Async([this, MediaId, ExternalSourceFileState]() mutable
  258. {
  259. // This type is safe as long as we don't decrement its usage
  260. if (ExternalSourceFileState->DecrementPlayCount() && ExternalSourceFileState->CanDelete())
  261. {
  262. OnDeleteState(MediaId, *ExternalSourceFileState, EWwiseFileStateOperationOrigin::Loading, []{});
  263. }
  264. });
  265. }
  266. }
  267. else
  268. {
  269. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("BindPlayingIdToExternalSources: Binding %d ExtSrc Media to Playing ID %" PRIu32 "."), InMediaIds.Num(), InPlayingId);
  270. for (const auto MediaId : InMediaIds)
  271. {
  272. PlayingIdToMediaIds.AddUnique(InPlayingId, MediaId);
  273. }
  274. }
  275. }
  276. void FWwiseExternalSourceManagerImpl::OnEndOfEvent(const uint32 InPlayingId)
  277. {
  278. if (!PlayingIdToMediaIds.Contains(InPlayingId))
  279. {
  280. return;
  281. }
  282. SCOPED_WWISEFILEHANDLER_EVENT_2(TEXT("FWwiseExternalSourceManagerImpl::OnEndOfEvent"));
  283. TArray<uint32> MediaIds;
  284. PlayingIdToMediaIds.MultiFind(InPlayingId, MediaIds);
  285. PlayingIdToMediaIds.Remove(InPlayingId);
  286. UE_LOG(LogWwiseFileHandler, VeryVerbose, TEXT("OnEndOfEvent: Unbinding %d ExtSrc Media from Playing ID %" PRIu32 "."), MediaIds.Num(), InPlayingId);
  287. FRWScopeLock Lock(CookieToMediaLock, FRWScopeLockType::SLT_ReadOnly);
  288. for (const auto MediaId : MediaIds)
  289. {
  290. FWwiseFileStateSharedPtr State;
  291. {
  292. FRWScopeLock StateLock(FileStatesByIdLock, FRWScopeLockType::SLT_ReadOnly);
  293. const auto* StatePtr = FileStatesById.Find(MediaId);
  294. if (UNLIKELY(!StatePtr || !StatePtr->IsValid()))
  295. {
  296. UE_LOG(LogWwiseFileHandler, Warning, TEXT("OnEndOfEvent: Getting external source media state %" PRIu32 " failed to decrement after failed PostEvent."), MediaId);
  297. continue;
  298. }
  299. State = *StatePtr;
  300. }
  301. auto* ExternalSourceFileState = State->GetStateAs<FWwiseExternalSourceFileState>();
  302. if (UNLIKELY(!ExternalSourceFileState))
  303. {
  304. UE_LOG(LogWwiseFileHandler, Error, TEXT("OnEndOfEvent: Getting external source media %" PRIu32 ": Could not cast to ExternalSourceState"), MediaId);
  305. continue;
  306. }
  307. FileHandlerExecutionQueue.Async([this, MediaId, ExternalSourceFileState]() mutable
  308. {
  309. // This type is safe as long as we don't decrement its usage
  310. if (ExternalSourceFileState->DecrementPlayCount() && ExternalSourceFileState->CanDelete())
  311. {
  312. OnDeleteState(MediaId, *ExternalSourceFileState, EWwiseFileStateOperationOrigin::Loading, []{});
  313. }
  314. });
  315. }
  316. }
  317. void FWwiseExternalSourceManagerImpl::OnDeleteState(uint32 InShortId, FWwiseFileState& InFileState,
  318. EWwiseFileStateOperationOrigin InOperationOrigin, FDecrementStateCallback&& InCallback)
  319. {
  320. if (InFileState.CanDelete())
  321. {
  322. FRWScopeLock Lock(CookieToMediaLock, FRWScopeLockType::SLT_Write);
  323. TArray<uint32> CookiesToRemove;
  324. for (const auto Item : CookieToMedia)
  325. {
  326. if (Item.Value == &InFileState)
  327. {
  328. CookiesToRemove.Add(Item.Key);
  329. }
  330. }
  331. for (const auto Cookie : CookiesToRemove)
  332. {
  333. UE_LOG(LogWwiseFileHandler, Verbose, TEXT("Removing Cookie %" PRIu32 " binding to media %" PRIu32 "."), Cookie, InFileState.GetShortId());
  334. CookieToMedia.Remove(Cookie);
  335. }
  336. }
  337. FWwiseFileHandlerBase::OnDeleteState(InShortId, InFileState, InOperationOrigin, MoveTemp(InCallback));
  338. }
  339. void FWwiseExternalSourceManagerImpl::SetExternalSourceMediaById(const FName& ExternalSourceName, const int32 MediaId)
  340. {
  341. UE_LOG(LogWwiseFileHandler, Error, TEXT("External Source manager needs to be overridden."));
  342. }
  343. void FWwiseExternalSourceManagerImpl::SetExternalSourceMediaByName(const FName& ExternalSourceName,
  344. const FName& MediaName)
  345. {
  346. UE_LOG(LogWwiseFileHandler, Error, TEXT("External Source manager needs to be overridden."));
  347. }
  348. void FWwiseExternalSourceManagerImpl::SetExternalSourceMediaWithIds(const int32 ExternalSourceCookie,
  349. const int32 MediaId)
  350. {
  351. UE_LOG(LogWwiseFileHandler, Error, TEXT("External Source manager needs to be overridden."));
  352. }