AkGameObject.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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);
  71. }
  72. int32 UAkGameObject::PostAkEvent(UAkAudioEvent* AkEvent, int32 CallbackMask,
  73. const FOnAkPostEventCallback& PostEventCallback
  74. )
  75. {
  76. if (LIKELY(IsValid(AkEvent)))
  77. {
  78. return AkEvent->PostOnGameObject(this, PostEventCallback, CallbackMask);
  79. }
  80. AkPlayingID playingID = AK_INVALID_PLAYING_ID;
  81. auto AudioDevice = FAkAudioDevice::Get();
  82. if (AudioDevice)
  83. {
  84. AkEvent->PostOnGameObject(this, PostEventCallback, CallbackMask);
  85. }
  86. return playingID;
  87. }
  88. AkPlayingID UAkGameObject::PostAkEvent(UAkAudioEvent* AkEvent, AkUInt32 Flags, AkCallbackFunc UserCallback,
  89. void* UserCookie)
  90. {
  91. if (UNLIKELY(!IsValid(AkEvent)))
  92. {
  93. UE_LOG(LogAkAudio, Error, TEXT("Failed to post invalid AkAudioEvent on game object '%s'."), *GetName());
  94. return AK_INVALID_PLAYING_ID;
  95. }
  96. return AkEvent->PostOnGameObject(this, nullptr, UserCallback, UserCookie, static_cast<AkCallbackType>(Flags), nullptr);
  97. }
  98. void UAkGameObject::PostAssociatedAkEventAsync(const UObject* WorldContextObject, int32 CallbackMask, const FOnAkPostEventCallback& PostEventCallback, FLatentActionInfo LatentInfo, int32& PlayingID)
  99. {
  100. AkDeviceAndWorld DeviceAndWorld(WorldContextObject);
  101. FLatentActionManager& LatentActionManager = DeviceAndWorld.CurrentWorld->GetLatentActionManager();
  102. FPostAssociatedEventAction* NewAction = LatentActionManager.FindExistingAction<FPostAssociatedEventAction>(LatentInfo.CallbackTarget, LatentInfo.UUID);
  103. if (!NewAction)
  104. {
  105. NewAction = new FPostAssociatedEventAction(LatentInfo, &PlayingID, AkAudioEvent, &bEventPosted);
  106. AkAudioEvent->PostOnGameObject(this, PostEventCallback, CallbackMask);
  107. LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, NewAction);
  108. }
  109. }
  110. void UAkGameObject::PostAkEventAsync(const UObject* WorldContextObject,
  111. UAkAudioEvent* AkEvent,
  112. int32& PlayingID,
  113. int32 CallbackMask,
  114. const FOnAkPostEventCallback& PostEventCallback,
  115. FLatentActionInfo LatentInfo
  116. )
  117. {
  118. AkDeviceAndWorld DeviceAndWorld(WorldContextObject);
  119. FLatentActionManager& LatentActionManager = DeviceAndWorld.CurrentWorld->GetLatentActionManager();
  120. FPostAssociatedEventAction* NewAction = LatentActionManager.FindExistingAction<FPostAssociatedEventAction>(LatentInfo.CallbackTarget, LatentInfo.UUID);
  121. if (!NewAction)
  122. {
  123. NewAction = new FPostAssociatedEventAction(LatentInfo, &PlayingID, AkEvent, &bEventPosted);
  124. AkEvent->PostOnGameObject(this, PostEventCallback, CallbackMask);
  125. LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, NewAction);
  126. }
  127. }
  128. void UAkGameObject::SetRTPCValue(const UAkRtpc* RTPCValue, float Value, int32 InterpolationTimeMs, FString RTPC) const
  129. {
  130. if (FAkAudioDevice::Get())
  131. {
  132. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  133. if (UNLIKELY(!SoundEngine))
  134. {
  135. return;
  136. }
  137. auto GameObjectID = GetAkGameObjectID();
  138. if (UNLIKELY(GameObjectID == AK_INVALID_GAME_OBJECT || GameObjectID == 0))
  139. {
  140. return;
  141. }
  142. if (RTPCValue)
  143. {
  144. SoundEngine->SetRTPCValue(RTPCValue->GetShortID(), Value, GameObjectID, InterpolationTimeMs);
  145. }
  146. else
  147. {
  148. SoundEngine->SetRTPCValue(TCHAR_TO_AK(*RTPC), Value, GameObjectID, InterpolationTimeMs);
  149. }
  150. }
  151. }
  152. void UAkGameObject::GetRTPCValue(const UAkRtpc* RTPCValue, ERTPCValueType InputValueType, float& Value, ERTPCValueType& OutputValueType, FString RTPC, int32 PlayingID) const
  153. {
  154. if (FAkAudioDevice::Get())
  155. {
  156. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  157. if (UNLIKELY(!SoundEngine)) return;
  158. AK::SoundEngine::Query::RTPCValue_type RTPCType = (AK::SoundEngine::Query::RTPCValue_type)InputValueType;
  159. if (RTPCValue)
  160. {
  161. SoundEngine->Query->GetRTPCValue(RTPCValue->GetShortID(), GetAkGameObjectID(), PlayingID, Value, RTPCType);
  162. }
  163. else
  164. {
  165. SoundEngine->Query->GetRTPCValue(TCHAR_TO_AK(*RTPC), GetAkGameObjectID(), PlayingID, Value, RTPCType);
  166. }
  167. OutputValueType = (ERTPCValueType)RTPCType;
  168. }
  169. }
  170. bool UAkGameObject::VerifyEventName(const FString& InEventName) const
  171. {
  172. const bool IsEventNameEmpty = InEventName.IsEmpty();
  173. if (IsEventNameEmpty)
  174. {
  175. FString OwnerName = FString(TEXT(""));
  176. FString ObjectName = GetName();
  177. const auto owner = GetOwner();
  178. if (owner)
  179. OwnerName = owner->GetName();
  180. UE_LOG(LogAkAudio, Warning, TEXT("[%s.%s] AkGameObject: Attempted to post an empty AkEvent name."), *OwnerName, *ObjectName);
  181. }
  182. return !IsEventNameEmpty;
  183. }
  184. bool UAkGameObject::AllowAudioPlayback() const
  185. {
  186. UWorld* CurrentWorld = GetWorld();
  187. return (CurrentWorld && CurrentWorld->AllowAudioPlayback() && !IsBeingDestroyed());
  188. }
  189. AkGameObjectID UAkGameObject::GetAkGameObjectID() const
  190. {
  191. return (AkGameObjectID)this;
  192. }
  193. void UAkGameObject::Stop()
  194. {
  195. if (HasActiveEvents() && FAkAudioDevice::Get() && IsRegisteredWithWwise)
  196. {
  197. auto* SoundEngine = IWwiseSoundEngineAPI::Get();
  198. if (UNLIKELY(!SoundEngine)) return;
  199. SoundEngine->StopAll(GetAkGameObjectID());
  200. SoundEngine->RenderAudio();
  201. }
  202. }
  203. bool UAkGameObject::HasActiveEvents() const
  204. {
  205. auto CallbackManager = FAkComponentCallbackManager::GetInstance();
  206. return (CallbackManager != nullptr) && CallbackManager->HasActiveEvents(GetAkGameObjectID());
  207. }