AkGameObject.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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. /*=============================================================================
  16. AkGameObject.cpp:
  17. =============================================================================*/
  18. #include "AkGameObject.h"
  19. #include "AkAudioEvent.h"
  20. #include "AkComponentCallbackManager.h"
  21. #include "AkRtpc.h"
  22. #include "Wwise/WwiseExternalSourceManager.h"
  23. #include "Wwise/API/WwiseSoundEngineAPI.h"
  24. class FPostAssociatedEventAction : public FAkPendingLatentAction
  25. {
  26. public:
  27. FName ExecutionFunction;
  28. int32 OutputLink = 0;
  29. FWeakObjectPtr CallbackTarget;
  30. int32* PlayingID = nullptr;
  31. TFuture<AkPlayingID> FuturePlayingID;
  32. UAkAudioEvent* AkEvent = nullptr;
  33. bool* bGameObjectStarted= nullptr;
  34. FPostAssociatedEventAction(const FLatentActionInfo& LatentInfo, int32* PlayingID, UAkAudioEvent* Event, bool* bStarted)
  35. : ExecutionFunction(LatentInfo.ExecutionFunction)
  36. , OutputLink(LatentInfo.Linkage)
  37. , CallbackTarget(LatentInfo.CallbackTarget)
  38. , PlayingID(PlayingID)
  39. , AkEvent(Event)
  40. , bGameObjectStarted(bStarted)
  41. {
  42. }
  43. virtual void UpdateOperation(FLatentResponse& Response) override
  44. {
  45. bool futureIsReady = FuturePlayingID.IsReady();
  46. if (futureIsReady)
  47. {
  48. *PlayingID = FuturePlayingID.Get();
  49. if (bGameObjectStarted!=nullptr)
  50. {
  51. *bGameObjectStarted = true;
  52. }
  53. }
  54. Response.FinishAndTriggerIf(futureIsReady, ExecutionFunction, OutputLink, CallbackTarget);
  55. }
  56. #if WITH_EDITOR
  57. virtual FString GetDescription() const override
  58. {
  59. return TEXT("Waiting for posted AkEvent to load media.");
  60. }
  61. #endif
  62. };
  63. UAkGameObject::UAkGameObject(const class FObjectInitializer& ObjectInitializer) :
  64. Super(ObjectInitializer)
  65. {
  66. bEventPosted = false;
  67. }
  68. int32 UAkGameObject::PostAssociatedAkEvent(int32 CallbackMask, const FOnAkPostEventCallback& PostEventCallback)
  69. {
  70. return PostAkEvent(AkAudioEvent, CallbackMask, PostEventCallback, EventName);
  71. }
  72. int32 UAkGameObject::PostAkEvent(UAkAudioEvent* AkEvent, int32 CallbackMask,
  73. const FOnAkPostEventCallback& PostEventCallback,
  74. const FString& InEventName
  75. )
  76. {
  77. if (LIKELY(IsValid(AkEvent)))
  78. {
  79. return AkEvent->PostOnGameObject(this, PostEventCallback, CallbackMask);
  80. }
  81. AkPlayingID playingID = AK_INVALID_PLAYING_ID;
  82. auto AudioDevice = FAkAudioDevice::Get();
  83. if (AudioDevice)
  84. {
  85. playingID = AudioDevice->PostEventOnAkGameObject(AudioDevice->GetShortID(AkEvent, InEventName), this, PostEventCallback, CallbackMask, {});
  86. }
  87. return playingID;
  88. }
  89. AkPlayingID UAkGameObject::PostAkEvent(UAkAudioEvent* AkEvent, AkUInt32 Flags, AkCallbackFunc UserCallback,
  90. void* UserCookie)
  91. {
  92. if (UNLIKELY(!IsValid(AkEvent)))
  93. {
  94. UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid AkAudioEvent on game object '%s'."), *GetName());
  95. return AK_INVALID_PLAYING_ID;
  96. }
  97. return AkEvent->PostOnGameObject(this, nullptr, UserCallback, UserCookie, static_cast<AkCallbackType>(Flags), nullptr);
  98. }
  99. AkPlayingID UAkGameObject::PostAkEventByNameWithDelegate(class UAkAudioEvent * AkEvent, const FString& InEventName, int32 CallbackMask, const FOnAkPostEventCallback& PostEventCallback)
  100. {
  101. if (AkEvent)
  102. {
  103. return AkEvent->PostOnGameObject(this, &PostEventCallback, nullptr, nullptr, (AkCallbackType)CallbackMask, nullptr);
  104. }
  105. AkPlayingID playingID = AK_INVALID_PLAYING_ID;
  106. auto AudioDevice = FAkAudioDevice::Get();
  107. if (AudioDevice)
  108. {
  109. playingID = AudioDevice->PostEventOnAkGameObject(AudioDevice->GetShortID(AkEvent, InEventName), this, PostEventCallback, CallbackMask, {});
  110. }
  111. return playingID;
  112. }
  113. void UAkGameObject::PostAssociatedAkEventAsync(const UObject* WorldContextObject, int32 CallbackMask, const FOnAkPostEventCallback& PostEventCallback, FLatentActionInfo LatentInfo, int32& PlayingID)
  114. {
  115. AkDeviceAndWorld DeviceAndWorld(WorldContextObject);
  116. FLatentActionManager& LatentActionManager = DeviceAndWorld.CurrentWorld->GetLatentActionManager();
  117. FPostAssociatedEventAction* NewAction = LatentActionManager.FindExistingAction<FPostAssociatedEventAction>(LatentInfo.CallbackTarget, LatentInfo.UUID);
  118. if (!NewAction)
  119. {
  120. NewAction = new FPostAssociatedEventAction(LatentInfo, &PlayingID, AkAudioEvent, &bEventPosted);
  121. NewAction->FuturePlayingID = DeviceAndWorld.AkAudioDevice->PostAkAudioEventOnAkGameObjectAsync(AkAudioEvent, this, PostEventCallback, CallbackMask);
  122. LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, NewAction);
  123. }
  124. }
  125. void UAkGameObject::PostAkEventAsync(const UObject* WorldContextObject,
  126. UAkAudioEvent* AkEvent,
  127. int32& PlayingID,
  128. int32 CallbackMask,
  129. const FOnAkPostEventCallback& PostEventCallback,
  130. FLatentActionInfo LatentInfo
  131. )
  132. {
  133. AkDeviceAndWorld DeviceAndWorld(WorldContextObject);
  134. FLatentActionManager& LatentActionManager = DeviceAndWorld.CurrentWorld->GetLatentActionManager();
  135. FPostAssociatedEventAction* NewAction = LatentActionManager.FindExistingAction<FPostAssociatedEventAction>(LatentInfo.CallbackTarget, LatentInfo.UUID);
  136. if (!NewAction)
  137. {
  138. NewAction = new FPostAssociatedEventAction(LatentInfo, &PlayingID, AkEvent, &bEventPosted);
  139. NewAction->FuturePlayingID = DeviceAndWorld.AkAudioDevice->PostAkAudioEventOnAkGameObjectAsync(AkEvent, this, PostEventCallback, CallbackMask);
  140. LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, NewAction);
  141. }
  142. }
  143. void UAkGameObject::PostAkEventAsyncByEvent(const UObject* WorldContextObject,
  144. class UAkAudioEvent* AkEvent,
  145. int32 CallbackMask,
  146. const FOnAkPostEventCallback& PostEventCallback,
  147. FLatentActionInfo LatentInfo,
  148. int32& PlayingID
  149. )
  150. {
  151. AkDeviceAndWorld DeviceAndWorld(WorldContextObject);
  152. FLatentActionManager& LatentActionManager = DeviceAndWorld.CurrentWorld->GetLatentActionManager();
  153. FPostAssociatedEventAction* NewAction = LatentActionManager.FindExistingAction<FPostAssociatedEventAction>(LatentInfo.CallbackTarget, LatentInfo.UUID);
  154. if (!NewAction)
  155. {
  156. NewAction = new FPostAssociatedEventAction(LatentInfo, &PlayingID, AkEvent, &bEventPosted);
  157. NewAction->FuturePlayingID = DeviceAndWorld.AkAudioDevice->PostAkAudioEventOnAkGameObjectAsync(AkEvent, this, PostEventCallback, CallbackMask);
  158. LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, NewAction);
  159. }
  160. }
  161. void UAkGameObject::SetRTPCValue(const UAkRtpc* RTPCValue, float Value, int32 InterpolationTimeMs, FString RTPC) const
  162. {
  163. if (FAkAudioDevice::Get())
  164. {
  165. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  166. if (UNLIKELY(!SoundEngine)) return;
  167. if (RTPCValue)
  168. {
  169. SoundEngine->SetRTPCValue(RTPCValue->GetShortID(), Value, GetAkGameObjectID(), InterpolationTimeMs);
  170. }
  171. else
  172. {
  173. SoundEngine->SetRTPCValue(TCHAR_TO_AK(*RTPC), Value, GetAkGameObjectID(), InterpolationTimeMs);
  174. }
  175. }
  176. }
  177. void UAkGameObject::GetRTPCValue(const UAkRtpc* RTPCValue, ERTPCValueType InputValueType, float& Value, ERTPCValueType& OutputValueType, FString RTPC, int32 PlayingID) const
  178. {
  179. if (FAkAudioDevice::Get())
  180. {
  181. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  182. if (UNLIKELY(!SoundEngine)) return;
  183. AK::SoundEngine::Query::RTPCValue_type RTPCType = (AK::SoundEngine::Query::RTPCValue_type)InputValueType;
  184. if (RTPCValue)
  185. {
  186. SoundEngine->Query->GetRTPCValue(RTPCValue->GetShortID(), GetAkGameObjectID(), PlayingID, Value, RTPCType);
  187. }
  188. else
  189. {
  190. SoundEngine->Query->GetRTPCValue(TCHAR_TO_AK(*RTPC), GetAkGameObjectID(), PlayingID, Value, RTPCType);
  191. }
  192. OutputValueType = (ERTPCValueType)RTPCType;
  193. }
  194. }
  195. void UAkGameObject::GetRTPCValue(FString RTPC, int32 PlayingID, ERTPCValueType InputValueType, float& Value, ERTPCValueType& OutputValueType) const
  196. {
  197. GetRTPCValue(nullptr, InputValueType, Value, OutputValueType, RTPC, PlayingID);
  198. }
  199. bool UAkGameObject::VerifyEventName(const FString& InEventName) const
  200. {
  201. const bool IsEventNameEmpty = InEventName.IsEmpty();
  202. if (IsEventNameEmpty)
  203. {
  204. FString OwnerName = FString(TEXT(""));
  205. FString ObjectName = GetName();
  206. const auto owner = GetOwner();
  207. if (owner)
  208. OwnerName = owner->GetName();
  209. UE_LOG(LogAkAudio, Warning, TEXT("[%s.%s] AkGameObject: Attempted to post an empty AkEvent name."), *OwnerName, *ObjectName);
  210. }
  211. return !IsEventNameEmpty;
  212. }
  213. bool UAkGameObject::AllowAudioPlayback() const
  214. {
  215. UWorld* CurrentWorld = GetWorld();
  216. return (CurrentWorld && CurrentWorld->AllowAudioPlayback() && !IsBeingDestroyed());
  217. }
  218. AkGameObjectID UAkGameObject::GetAkGameObjectID() const
  219. {
  220. return (AkGameObjectID)this;
  221. }
  222. void UAkGameObject::Stop()
  223. {
  224. if (HasActiveEvents() && FAkAudioDevice::Get() && IsRegisteredWithWwise)
  225. {
  226. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  227. if (UNLIKELY(!SoundEngine)) return;
  228. SoundEngine->StopAll(GetAkGameObjectID());
  229. SoundEngine->RenderAudio();
  230. }
  231. }
  232. bool UAkGameObject::HasActiveEvents() const
  233. {
  234. auto CallbackManager = FAkComponentCallbackManager::GetInstance();
  235. return (CallbackManager != nullptr) && CallbackManager->HasActiveEvents(GetAkGameObjectID());
  236. }